diff --git a/Projects/Chat/Sources/View/ChatViewController.swift b/Projects/Chat/Sources/View/ChatViewController.swift index 8a6aadf..0f47d48 100644 --- a/Projects/Chat/Sources/View/ChatViewController.swift +++ b/Projects/Chat/Sources/View/ChatViewController.swift @@ -44,6 +44,7 @@ public class ChatViewController: BaseViewController { // 초기에 endButton 숨기기 chatView.hideEndButton() + setupTapGesture() } public override func setupViewProperty() { @@ -242,4 +243,14 @@ public class ChatViewController: BaseViewController { // 이전 화면으로 이동 navigationController?.popViewController(animated: true) } + + private func setupTapGesture() { + let tapGesture = UITapGestureRecognizer(target: self, action: #selector(dismissKeyboard)) + tapGesture.cancelsTouchesInView = false + view.addGestureRecognizer(tapGesture) + } + + @objc private func dismissKeyboard() { + view.endEditing(true) + } } diff --git a/Projects/CommonUI/Derived/Sources/TuistAssets+CommonUI.swift b/Projects/CommonUI/Derived/Sources/TuistAssets+CommonUI.swift index dd4c897..10842f0 100644 --- a/Projects/CommonUI/Derived/Sources/TuistAssets+CommonUI.swift +++ b/Projects/CommonUI/Derived/Sources/TuistAssets+CommonUI.swift @@ -39,7 +39,7 @@ public enum CommonUIAsset: Sendable { public static let lmRed02 = CommonUIColors(name: "LMRed02") } public enum Images { - public static let add = CommonUIImages(name: "add") + public static let add = CommonUIImages(name: "add") public static let back = CommonUIImages(name: "back") public static let bubble = CommonUIImages(name: "bubble") public static let close = CommonUIImages(name: "close") diff --git a/Projects/CommonUI/Sources/Assets/Images.xcassets/Icon/profile.imageset/Contents.json b/Projects/CommonUI/Sources/Assets/Images.xcassets/Icon/profile.imageset/Contents.json new file mode 100644 index 0000000..72f72b4 --- /dev/null +++ b/Projects/CommonUI/Sources/Assets/Images.xcassets/Icon/profile.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "profile@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "profile@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Projects/CommonUI/Sources/Assets/Images.xcassets/Icon/profile.imageset/profile@2x.png b/Projects/CommonUI/Sources/Assets/Images.xcassets/Icon/profile.imageset/profile@2x.png new file mode 100644 index 0000000..f37ae7e Binary files /dev/null and b/Projects/CommonUI/Sources/Assets/Images.xcassets/Icon/profile.imageset/profile@2x.png differ diff --git a/Projects/CommonUI/Sources/Assets/Images.xcassets/Icon/profile.imageset/profile@3x.png b/Projects/CommonUI/Sources/Assets/Images.xcassets/Icon/profile.imageset/profile@3x.png new file mode 100644 index 0000000..4563e2a Binary files /dev/null and b/Projects/CommonUI/Sources/Assets/Images.xcassets/Icon/profile.imageset/profile@3x.png differ diff --git a/Projects/CommonUI/Sources/Component/LMAlert.swift b/Projects/CommonUI/Sources/Component/LMAlert.swift index 4fb1a40..bafb6fd 100644 --- a/Projects/CommonUI/Sources/Component/LMAlert.swift +++ b/Projects/CommonUI/Sources/Component/LMAlert.swift @@ -57,6 +57,8 @@ public class LMAlert: UIView { // MARK: - Properties private var cancelAction: (() -> Void)? private var confirmAction: (() -> Void)? + private var titleTopConstraint: Constraint? + private var buttonTopConstraint: Constraint? // MARK: - Initialization public init(title: String, cancelTitle: String = "아니요", confirmTitle: String = "네") { @@ -102,7 +104,7 @@ public class LMAlert: UIView { } titleLabel.snp.makeConstraints { - $0.top.equalToSuperview().inset(24) + self.titleTopConstraint = $0.top.equalToSuperview().inset(24).constraint $0.horizontalEdges.equalToSuperview().inset(20) $0.bottom.lessThanOrEqualTo(buttonStackView.snp.top).offset(-16) } @@ -111,7 +113,7 @@ public class LMAlert: UIView { $0.bottom.equalToSuperview().inset(20) $0.horizontalEdges.equalToSuperview().inset(20) $0.height.equalTo(44) - $0.top.greaterThanOrEqualTo(titleLabel.snp.bottom).offset(16) + self.buttonTopConstraint = $0.top.greaterThanOrEqualTo(titleLabel.snp.bottom).offset(16).constraint } } @@ -137,7 +139,10 @@ public class LMAlert: UIView { // cancelTitle이 비어있으면 취소 버튼 숨기기 if cancelTitle.isEmpty { cancelButton.isHidden = true + } else { + cancelButton.isHidden = false } + updateSpacing(for: attributedString) } // MARK: - Actions @@ -195,4 +200,40 @@ public class LMAlert: UIView { completion() } } + + // MARK: - Layout Helpers + private func updateSpacing(for attributedString: NSAttributedString) { + let contentWidth: CGFloat = 280 - 40 // container width - horizontal inset + let lineCount = calculateLineCount(for: attributedString, maxWidth: contentWidth) + let spacing = spacingConfiguration(for: lineCount) + titleTopConstraint?.update(offset: spacing.topInset) + buttonTopConstraint?.update(offset: spacing.betweenSpacing) + layoutIfNeeded() + } + + private func spacingConfiguration(for lineCount: Int) -> (topInset: CGFloat, betweenSpacing: CGFloat) { + switch lineCount { + case ..<2: + return (32, 24) + case 2: + return (28, 20) + default: + return (24, 16) + } + } + + private func calculateLineCount(for attributedString: NSAttributedString, maxWidth: CGFloat) -> Int { + guard attributedString.length > 0 else { return 1 } + let boundingRect = attributedString.boundingRect( + with: CGSize(width: maxWidth, height: .greatestFiniteMagnitude), + options: [.usesLineFragmentOrigin, .usesFontLeading], + context: nil + ) + let font = (attributedString.attribute(.font, at: 0, effectiveRange: nil) as? UIFont) ?? titleLabel.font ?? .systemFont(ofSize: 16) + let paragraphStyle = attributedString.attribute(.paragraphStyle, at: 0, effectiveRange: nil) as? NSParagraphStyle + let lineHeight = font.lineHeight + (paragraphStyle?.lineSpacing ?? 0) + if lineHeight == 0 { return 1 } + let rawCount = Int(ceil(boundingRect.height / lineHeight)) + return max(1, rawCount) + } } diff --git a/Projects/CommonUI/Sources/Enum/CommonUIAssets.swift b/Projects/CommonUI/Sources/Enum/CommonUIAssets.swift index cdeae2c..04efddd 100644 --- a/Projects/CommonUI/Sources/Enum/CommonUIAssets.swift +++ b/Projects/CommonUI/Sources/Enum/CommonUIAssets.swift @@ -58,6 +58,7 @@ public enum CommonUIAssets { public static let IconNext = image(named: "next") public static let IconNext2 = image(named: "next2") public static let IconAdd = image(named: "add") + public static let IconProfile = image(named: "profile") /// color public static let LMOrange0 = color(named: "LMOrange00") diff --git a/Projects/CommonUI/Sources/View/Chat/ChatView.swift b/Projects/CommonUI/Sources/View/Chat/ChatView.swift index aafc748..79b50e6 100644 --- a/Projects/CommonUI/Sources/View/Chat/ChatView.swift +++ b/Projects/CommonUI/Sources/View/Chat/ChatView.swift @@ -156,13 +156,19 @@ open class ChatView: UIView { $0.center.equalToSuperview() $0.leading.trailing.equalToSuperview().inset(16) } + + // 탭 이벤트 설정 + view.tag = index + view.isUserInteractionEnabled = true + let tap = UITapGestureRecognizer(target: self, action: #selector(handleRecommendTap(_:))) + view.addGestureRecognizer(tap) } titleLabel.snp.makeConstraints { $0.top.equalTo(self.safeAreaLayoutGuide).offset(20) $0.leading.equalToSuperview().inset(20) } - + subtitleLabel.snp.makeConstraints { $0.top.equalTo(titleLabel.snp.bottom).offset(10) $0.leading.equalToSuperview().inset(20) @@ -213,6 +219,18 @@ open class ChatView: UIView { } } + @objc private func handleRecommendTap(_ gesture: UITapGestureRecognizer) { + guard let view = gesture.view else { return } + let index = view.tag + guard index >= 0 && index < recommendLabels.count else { return } + let text = recommendLabels[index].text ?? "" + guard !text.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty else { return } + + // 추천 섹션 숨기고 바로 전송 콜백 호출 + hideRecommendSection() + onSendButtonTapped?(text) + } + // 추천 섹션 숨기기 메서드 public func hideRecommendSection() { UIView.animate(withDuration: 0.3) { diff --git a/Projects/CommonUI/Sources/View/Diary/DiaryView.swift b/Projects/CommonUI/Sources/View/Diary/DiaryView.swift index d89923d..92e6335 100644 --- a/Projects/CommonUI/Sources/View/Diary/DiaryView.swift +++ b/Projects/CommonUI/Sources/View/Diary/DiaryView.swift @@ -56,24 +56,12 @@ open class DiaryView: UIView { bindEvents() calendarView.configureSubviews() calendarView.makeConstraints() - setupSampleEmotionData() updateMonthButtonTitle() } required public init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } - - private func setupSampleEmotionData() { - // 샘플 이모지 데이터 설정 (이미지와 동일하게) - let sampleEmotions: [Int: String] = [ - 1: "😢", // 우는 얼굴 - 7: "😐", // 무표정한 얼굴 - 12: "🥳", // 파티 모자 - 13: "😡" // 화난 얼굴 - ] - calendarView.setEmotionData(sampleEmotions) - } // MARK: Configuration func configureSubviews() { @@ -108,11 +96,11 @@ open class DiaryView: UIView { $0.height.width.equalTo(monthLabel.snp.height) } - addButton.snp.makeConstraints { - $0.centerY.equalTo(monthLabel) - $0.trailing.equalToSuperview().inset(20) - $0.height.width.equalTo(monthLabel.snp.height) - } +// addButton.snp.makeConstraints { +// $0.centerY.equalTo(monthLabel) +// $0.trailing.equalToSuperview().inset(20) +// $0.height.width.equalTo(monthLabel.snp.height) +// } calendarView.snp.makeConstraints { $0.top.equalTo(monthLabel.snp.bottom).offset(17) @@ -121,7 +109,7 @@ open class DiaryView: UIView { } diaryTodayView.snp.makeConstraints { - $0.top.equalTo(calendarView.snp.bottom).offset(3) + $0.top.equalTo(calendarView.snp.bottom).offset(30) $0.centerX.equalToSuperview() $0.width.equalToSuperview().inset(20) $0.height.equalTo(141) diff --git a/Projects/CommonUI/Sources/View/Home/HomeProgressView.swift b/Projects/CommonUI/Sources/View/Home/HomeProgressView.swift index 9522a9a..1cb30fc 100644 --- a/Projects/CommonUI/Sources/View/Home/HomeProgressView.swift +++ b/Projects/CommonUI/Sources/View/Home/HomeProgressView.swift @@ -126,7 +126,6 @@ open class HomeProgressView: UIView { self.layer.cornerRadius = 12 courseLabel = courseLabel.then { - $0.text = "한국어 훈련 1단계" $0.textColor = CommonUIAssets.LMBlack $0.font = .systemFont(ofSize: 18, weight: .semibold) } diff --git a/Projects/CommonUI/Sources/View/Home/HomeQuizView.swift b/Projects/CommonUI/Sources/View/Home/HomeQuizView.swift index 17dd337..9ec9d7d 100644 --- a/Projects/CommonUI/Sources/View/Home/HomeQuizView.swift +++ b/Projects/CommonUI/Sources/View/Home/HomeQuizView.swift @@ -34,14 +34,13 @@ open class HomeQuizView: UIView, UICollectionViewDataSource, UICollectionViewDel } public func bind(course: CourseVO) { -// courseLabel.text = "\(course.courseLv ?? 1)단계 퀴즈" + courseLabel.text = "\(course.courseLv)단계 퀴즈" } func initAttribute() { self.backgroundColor = .clear courseLabel = courseLabel.then { - $0.text = "1단계 퀴즈" $0.textColor = CommonUIAssets.LMBlack $0.font = .systemFont(ofSize: 16, weight: .medium) } diff --git a/Projects/CommonUI/Sources/View/Home/HomeView.swift b/Projects/CommonUI/Sources/View/Home/HomeView.swift index d97ea17..f7fdc96 100644 --- a/Projects/CommonUI/Sources/View/Home/HomeView.swift +++ b/Projects/CommonUI/Sources/View/Home/HomeView.swift @@ -13,7 +13,7 @@ import Then open class HomeView: UIView { let logoImageView = UIImageView() - var profileView = UIView() + var profileView = UIImageView() var titleLabelStackView = UIStackView() var titleLabel = UILabel() var subtitleLabel = UILabel() @@ -26,13 +26,20 @@ open class HomeView: UIView { public func bind(course: CourseVO) { } + + public func updateGreeting(name: String?) { + if let name = name, !name.isEmpty { + titleLabel.text = "안녕하세요 \(name)님!" + } else { + titleLabel.text = "안녕하세요!" + } + } func initAttribute() { self.backgroundColor = .clear profileView = profileView.then { - $0.backgroundColor = CommonUIAssets.LMOrange3 - $0.layer.cornerRadius = 28 + $0.image = CommonUIAssets.IconProfile } titleLabelStackView = titleLabelStackView.then { diff --git a/Projects/CommonUI/Sources/View/Home/QuizCollectionViewCell.swift b/Projects/CommonUI/Sources/View/Home/QuizCollectionViewCell.swift index 293a24c..49f62a0 100644 --- a/Projects/CommonUI/Sources/View/Home/QuizCollectionViewCell.swift +++ b/Projects/CommonUI/Sources/View/Home/QuizCollectionViewCell.swift @@ -30,7 +30,7 @@ final class HomeQuizCell: UICollectionViewCell { private func initAttribute() { contentView.backgroundColor = .white - contentView.layer.cornerRadius = 12 + contentView.layer.cornerRadius = 10 contentView.layer.borderWidth = 2 contentView.layer.borderColor = CommonUIAssets.LMOrange1?.cgColor @@ -106,18 +106,38 @@ final class HomeQuizCell: UICollectionViewCell { private func updateButtonTitle(_ title: String) { var config = startButton.configuration ?? UIButton.Configuration.plain() - let attributedTitle = AttributedString(title, attributes: AttributeContainer([ - .font: UIFont.systemFont(ofSize: 12, weight: .regular) - ])) - config.attributedTitle = attributedTitle if title == "완료" { config.image = nil - config.baseBackgroundColor = CommonUIAssets.LMOrange4 - config.baseForegroundColor = CommonUIAssets.LMGray1 + var background = UIBackgroundConfiguration.clear() + background.backgroundColor = CommonUIAssets.LMOrange3 + background.cornerRadius = 10 + config.background = background + let attributedTitle = AttributedString(title, attributes: AttributeContainer([ + .font: UIFont.systemFont(ofSize: 12, weight: .regular), + .foregroundColor: CommonUIAssets.LMGray3 ?? UIColor.black + ])) + config.attributedTitle = attributedTitle + config.baseForegroundColor = .white + startButton.layer.borderWidth = 0 + startButton.layer.borderColor = UIColor.clear.cgColor + startButton.isEnabled = false + startButton.isUserInteractionEnabled = false } else { config.image = CommonUIAssets.IconPlay - config.baseForegroundColor = CommonUIAssets.LMGray1 + var background = UIBackgroundConfiguration.clear() + background.cornerRadius = 10 + config.background = background + let attributedTitle = AttributedString(title, attributes: AttributeContainer([ + .font: UIFont.systemFont(ofSize: 12, weight: .regular), + .foregroundColor: CommonUIAssets.LMGray3 ?? .gray + ])) + config.attributedTitle = attributedTitle + config.baseForegroundColor = CommonUIAssets.LMGray3 + startButton.layer.borderWidth = 1 + startButton.layer.borderColor = CommonUIAssets.LMOrange1?.cgColor + startButton.isEnabled = true + startButton.isUserInteractionEnabled = true } startButton.configuration = config diff --git a/Projects/CommonUI/Sources/View/Login/LoginView.swift b/Projects/CommonUI/Sources/View/Login/LoginView.swift index e513f3d..e19e721 100644 --- a/Projects/CommonUI/Sources/View/Login/LoginView.swift +++ b/Projects/CommonUI/Sources/View/Login/LoginView.swift @@ -99,7 +99,7 @@ open class LoginView: UIView { [logoLabel, logoView, loginButtonStackView] .forEach { self.addSubview($0) } - [lmLoginButton, googleLoginButton, appleLoginButton] + [lmLoginButton] .forEach { loginButtonStackView.addArrangedSubview($0)} logoLabel.snp.makeConstraints { @@ -115,8 +115,8 @@ open class LoginView: UIView { loginButtonStackView.snp.makeConstraints { $0.horizontalEdges.equalToSuperview().inset(20) - $0.height.equalTo(205) - $0.bottom.equalToSuperview().inset(70) + $0.height.equalTo(55) // 205 + $0.bottom.equalToSuperview().inset(85) // 70 } } diff --git a/Projects/CommonUI/Sources/View/MyPageView.swift b/Projects/CommonUI/Sources/View/MyPageView.swift index a3c3443..196e993 100644 --- a/Projects/CommonUI/Sources/View/MyPageView.swift +++ b/Projects/CommonUI/Sources/View/MyPageView.swift @@ -59,14 +59,15 @@ open class MyPageView: UIView { title: "내 정보", items: [ MyPageItem(title: "내 정보", icon: "person.fill", hasChevron: false), - MyPageItem(title: "사용자 이름", subtitle: "", hasChevron: false) + MyPageItem(title: "사용자 이름", subtitle: "", hasChevron: false), + MyPageItem(title: "사용자 id", subtitle: "", hasChevron: false) ] ), MyPageSection( title: "앱 정보", items: [ MyPageItem(title: "앱 정보", icon: "info.circle.fill", hasChevron: false), - MyPageItem(title: "앱 버전", subtitle: "v 1.0.0", hasChevron: false) + MyPageItem(title: "앱 버전", subtitle: "v 1.0.2", hasChevron: false) ] ), MyPageSection( @@ -82,11 +83,12 @@ open class MyPageView: UIView { } // MARK: - Public Methods - public func updateUserName(_ name: String) { - // "내 정보" 섹션의 두 번째 아이템(사용자 이름) 업데이트 + public func updateUserName(_ name: String, _ id: Int) { if sections.count > 0 && sections[0].items.count > 1 { var updatedItems = sections[0].items + updatedItems[1] = MyPageItem(title: "사용자 이름", subtitle: name, hasChevron: false) + updatedItems[2] = MyPageItem(title: "사용자 id", subtitle: "\(id)", hasChevron: false) sections[0] = MyPageSection(title: sections[0].title, items: updatedItems) tableView.reloadData() } diff --git a/Projects/Data/Sources/Repository/SignRepository.swift b/Projects/Data/Sources/Repository/SignRepository.swift index d54b8b2..e16f525 100644 --- a/Projects/Data/Sources/Repository/SignRepository.swift +++ b/Projects/Data/Sources/Repository/SignRepository.swift @@ -8,6 +8,7 @@ import Domain import RxSwift import Alamofire +import Foundation public class DefaultSignRepository: SignRepository { @@ -79,10 +80,28 @@ public class DefaultSignRepository: SignRepository { print("✅ API 응답 성공: \(value)") single(.success(value)) case .failure(let error): - print("❌ API 응답 실패: \(error)") - single(.failure(error)) + if + let data = response.data, + let apiError = try? JSONDecoder().decode(DefaultDTO.self, from: data) + { + let statusCode = response.response?.statusCode ?? -1 + let customError = NSError( + domain: "APIError", + code: statusCode, + userInfo: [ + NSLocalizedDescriptionKey: apiError.message, + "code": apiError.code + ] + ) + print("⚠️ API 응답 실패: \(apiError.message) (code: \(apiError.code))") + single(.failure(customError)) + } else { + print("❌ API 응답 실패: \(error)") + single(.failure(error)) + } } } + return Disposables.create { request.cancel() } } } diff --git a/Projects/Diary/Sources/View/DiaryAddViewController.swift b/Projects/Diary/Sources/View/DiaryAddViewController.swift index f1be2fe..bccfd0c 100644 --- a/Projects/Diary/Sources/View/DiaryAddViewController.swift +++ b/Projects/Diary/Sources/View/DiaryAddViewController.swift @@ -48,6 +48,7 @@ public class DiaryAddViewController: BaseViewController { setupLayout() bindData() bindEvents() + setupTapGesture() } public override func setupViewProperty() { @@ -170,4 +171,14 @@ public class DiaryAddViewController: BaseViewController { self.viewModel.postDiary(content: content) } } + + private func setupTapGesture() { + let tapGesture = UITapGestureRecognizer(target: self, action: #selector(dismissKeyboard)) + tapGesture.cancelsTouchesInView = false + view.addGestureRecognizer(tapGesture) + } + + @objc private func dismissKeyboard() { + view.endEditing(true) + } } diff --git a/Projects/Diary/Sources/View/DiaryResultViewController.swift b/Projects/Diary/Sources/View/DiaryResultViewController.swift index b6ef14a..993e3a4 100644 --- a/Projects/Diary/Sources/View/DiaryResultViewController.swift +++ b/Projects/Diary/Sources/View/DiaryResultViewController.swift @@ -112,6 +112,9 @@ public class DiaryResultViewController: BaseViewController { print("🔄 handleSaveDiary 호출됨") print("🔄 navigationController: \(String(describing: navigationController))") + // 일기 저장 완료 Notification 발송 + NotificationCenter.default.post(name: NSNotification.Name("DiarySaved"), object: nil) + self.navigationController?.popToRootViewController(animated: true) } diff --git a/Projects/Diary/Sources/View/DiaryViewController.swift b/Projects/Diary/Sources/View/DiaryViewController.swift index cb4b79a..f125411 100644 --- a/Projects/Diary/Sources/View/DiaryViewController.swift +++ b/Projects/Diary/Sources/View/DiaryViewController.swift @@ -58,6 +58,24 @@ public class DiaryViewController: BaseViewController { // 첫 진입 시 오늘 날짜로 초기 상태 설정 setupInitialState() + + // 일기 저장 완료 Notification 구독 + NotificationCenter.default.addObserver( + self, + selector: #selector(handleDiarySaved), + name: NSNotification.Name("DiarySaved"), + object: nil + ) + } + + deinit { + NotificationCenter.default.removeObserver(self) + } + + @objc private func handleDiarySaved() { + // 일기 저장 후 오늘 날짜의 일기 데이터 다시 호출 + let today = Date() + viewModel.getDiary(date: today) } public override func setupViewProperty() { @@ -235,27 +253,13 @@ public class DiaryViewController: BaseViewController { print("📱 diary.score: \(diary.spellingDto.score)") print("📱 diary.content: \(diary.spellingDto.revisedContent)") - // 선택된 날짜의 일기 데이터로 DiaryTodayView 업데이트 - let formatter = DateFormatter() - formatter.dateFormat = "yyyy년 MM월 dd일" - if let date = formatter.date(from: diary.createdAt) { - print("📱 Date 파싱 성공: \(date)") - diaryView.diaryTodayView.setDiaryTodayData( - date: date, - diaryId: diary.diaryId, - score: diary.spellingDto.score, - content: diary.spellingDto.revisedContent - ) - } else { - print("📱 Date 파싱 실패, 문자열로 직접 설정") - // 날짜 파싱 실패 시 문자열로 직접 설정 - diaryView.diaryTodayView.setDiaryTodayData( - date: diary.createdAt, - diaryId: diary.diaryId, - score: diary.spellingDto.score, - content: diary.spellingDto.revisedContent - ) - } + // 선택된 날짜의 일기 데이터로 DiaryTodayView 업데이트 (String 버전 사용) + diaryView.diaryTodayView.setDiaryTodayData( + date: diary.createdAt, + diaryId: diary.diaryId, + score: diary.spellingDto.score, + content: diary.spellingDto.revisedContent + ) // DiaryVO 데이터 설정 (탭 이벤트용) diaryView.diaryTodayView.setDiaryData(diary) diff --git a/Projects/Home/Sources/View/HomeViewController.swift b/Projects/Home/Sources/View/HomeViewController.swift index 5e7e1e9..15b7f7f 100644 --- a/Projects/Home/Sources/View/HomeViewController.swift +++ b/Projects/Home/Sources/View/HomeViewController.swift @@ -39,6 +39,7 @@ public class HomeViewController: BaseViewController { public override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) self.navigationController?.setNavigationBarHidden(true, animated: false) + updateGreeting() } public override func viewDidLoad() { @@ -53,6 +54,12 @@ public class HomeViewController: BaseViewController { bindCourseList() bindQuiz() bindPatchStepSuccess() + updateGreeting() + } + + private func updateGreeting() { + let userName = UserDefaults.standard.string(forKey: "userName") + homeView.updateGreeting(name: userName) } private func bindActions() { @@ -97,6 +104,7 @@ public class HomeViewController: BaseViewController { .observe(on: MainScheduler.instance) .subscribe(onNext: { [weak self] course in self?.currentCourse = course + self?.homeQuizView.bind(course: course) }) .disposed(by: disposeBag) } @@ -121,6 +129,7 @@ public class HomeViewController: BaseViewController { let currentCourse = homeProgressView.courseList[homeProgressView.currentCourseIndex] self.currentCourse = currentCourse homeQuizView.setQuizList(currentCourse.stepList) + homeQuizView.bind(course: currentCourse) } private func bindPatchStepSuccess() { diff --git a/Projects/LearnMate/LearnMate.xcodeproj/project.pbxproj b/Projects/LearnMate/LearnMate.xcodeproj/project.pbxproj index b96fc04..142f409 100644 --- a/Projects/LearnMate/LearnMate.xcodeproj/project.pbxproj +++ b/Projects/LearnMate/LearnMate.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 55; + objectVersion = 56; objects = { /* Begin PBXBuildFile section */ @@ -19,6 +19,7 @@ 53EE0AA2C503F809334F8412 /* Diary.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 7459B5071C1C3E12A6519672 /* Diary.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 5EB1027699ED6A51784245ED /* HomeAssembly.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9AEA88AC00680DC27F375FB6 /* HomeAssembly.swift */; }; 94D749E4159727E7A20216D4 /* Data.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 0FF6CED28AB52ACEA2B7ED2A /* Data.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + 95F6D9912E94CFD9001EAD53 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 95F6D9902E94CFD9001EAD53 /* Assets.xcassets */; }; 9713AE7BE3A3D893CE4835B5 /* Then.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 69B232119647519D26142C64 /* Then.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 9B765992712E2980E25157AB /* RxSwift_RxRelay.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 2AF08E5B77E47043288AA7D6 /* RxSwift_RxRelay.bundle */; }; 9ED6C34369DCA2A469096622 /* Diary.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7459B5071C1C3E12A6519672 /* Diary.framework */; }; @@ -125,18 +126,19 @@ 669C3493E1AAB7F5F8D7488D /* Login.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Login.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 69B232119647519D26142C64 /* Then.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Then.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 7459B5071C1C3E12A6519672 /* Diary.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Diary.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 75AF6F9390E20101F1F4BFB3 /* LearnMate-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = "LearnMate-Info.plist"; sourceTree = ""; }; + 75AF6F9390E20101F1F4BFB3 /* LearnMate-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "LearnMate-Info.plist"; sourceTree = ""; }; 7C422FE2DDF9127C2F4B2DF0 /* RxSwift.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = RxSwift.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 7FA4CF63932EB8F052E582CE /* RxSwift_RxCocoa.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RxSwift_RxCocoa.bundle; sourceTree = BUILT_PRODUCTS_DIR; }; 89F58ED76FC4C0973305766F /* DependencyInjector.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DependencyInjector.swift; sourceTree = ""; }; 8A00D2BDD6B9A0B6E62CF3CC /* LearnMateTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = LearnMateTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 95F6D9902E94CFD9001EAD53 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 9ACFF0B3105009DD7646173E /* Domain.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Domain.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 9AEA88AC00680DC27F375FB6 /* HomeAssembly.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeAssembly.swift; sourceTree = ""; }; A4DC536F09A4A8284AA20CE7 /* CommonUI.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = CommonUI.framework; sourceTree = BUILT_PRODUCTS_DIR; }; AE77FC6A5C33846C3A0F4938 /* Swinject.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Swinject.framework; sourceTree = BUILT_PRODUCTS_DIR; }; B097E64BFDAE1FCC4E0AB423 /* LoginAssembly.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginAssembly.swift; sourceTree = ""; }; C25294FAE7464C63791082A4 /* MyPageAssembly.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyPageAssembly.swift; sourceTree = ""; }; - E7792C9340E2B053D136A839 /* LearnMateTests-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = "LearnMateTests-Info.plist"; sourceTree = ""; }; + E7792C9340E2B053D136A839 /* LearnMateTests-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "LearnMateTests-Info.plist"; sourceTree = ""; }; EEAA29E105D3AB0BAD502401 /* DomainAssembly.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DomainAssembly.swift; sourceTree = ""; }; F39319B32F0C0DD673EA6D68 /* ChatAssembly.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatAssembly.swift; sourceTree = ""; }; F59511B963866C713AAADAF5 /* Alamofire.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Alamofire.framework; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -189,11 +191,20 @@ path = Support; sourceTree = ""; }; + 95F6D98F2E94CFCE001EAD53 /* Resources */ = { + isa = PBXGroup; + children = ( + 95F6D9902E94CFD9001EAD53 /* Assets.xcassets */, + ); + path = Resources; + sourceTree = ""; + }; B074F9F8E730729626040CA5 /* Project */ = { isa = PBXGroup; children = ( - 02DEB0AB87622688EABA33D7 /* Sources */, + 95F6D98F2E94CFCE001EAD53 /* Resources */, 1E95FEDCBD464D7BF64D5488 /* Support */, + 02DEB0AB87622688EABA33D7 /* Sources */, ); name = Project; sourceTree = ""; @@ -356,6 +367,7 @@ files = ( F42CAFC3E0AD2D5D8F947284 /* RxSwift_RxCocoa.bundle in Resources */, 21A7912572BEAEA147C984C8 /* RxSwift_RxCocoaRuntime.bundle in Resources */, + 95F6D9912E94CFD9001EAD53 /* Assets.xcassets in Resources */, 9B765992712E2980E25157AB /* RxSwift_RxRelay.bundle in Resources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -407,6 +419,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_IDENTITY = "iPhone Developer"; + DEVELOPMENT_TEAM = 4P6BZ8CR69; ENABLE_PREVIEWS = YES; HEADER_SEARCH_PATHS = ( "$(inherited)", @@ -423,23 +436,18 @@ "-fmodule-map-file=$(SRCROOT)/../../Tuist/.build/checkouts/FSCalendar/FSCalendar/include/module.modulemap", "-fmodule-map-file=$(SRCROOT)/../../Tuist/.build/tuist-derived/RxCocoaRuntime/RxCocoaRuntime.modulemap", ); - OTHER_SWIFT_FLAGS = ( - "$(inherited)", - "-Xcc", - "-fmodule-map-file=$(SRCROOT)/../../Tuist/.build/checkouts/FSCalendar/FSCalendar/include/module.modulemap", - "-Xcc", - "-fmodule-map-file=$(SRCROOT)/../../Tuist/.build/tuist-derived/RxCocoaRuntime/RxCocoaRuntime.modulemap", - ); + OTHER_SWIFT_FLAGS = "$(inherited) -Xcc -fmodule-map-file=$(SRCROOT)/../../Tuist/.build/checkouts/FSCalendar/FSCalendar/include/module.modulemap -Xcc -fmodule-map-file=$(SRCROOT)/../../Tuist/.build/tuist-derived/RxCocoaRuntime/RxCocoaRuntime.modulemap"; PRODUCT_BUNDLE_IDENTIFIER = io.tuist.LearnMate; PRODUCT_NAME = LearnMate; SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; SUPPORTS_MACCATALYST = NO; - SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = YES; + SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO; SWIFT_COMPILATION_MODE = wholemodule; SWIFT_OPTIMIZATION_LEVEL = "-O"; SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; + TARGETED_DEVICE_FAMILY = 1; }; name = Release; }; @@ -449,6 +457,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_IDENTITY = "iPhone Developer"; + DEVELOPMENT_TEAM = 4P6BZ8CR69; ENABLE_PREVIEWS = YES; HEADER_SEARCH_PATHS = ( "$(inherited)", @@ -465,27 +474,19 @@ "-fmodule-map-file=$(SRCROOT)/../../Tuist/.build/checkouts/FSCalendar/FSCalendar/include/module.modulemap", "-fmodule-map-file=$(SRCROOT)/../../Tuist/.build/tuist-derived/RxCocoaRuntime/RxCocoaRuntime.modulemap", ); - OTHER_SWIFT_FLAGS = ( - "$(inherited)", - "-Xcc", - "-fmodule-map-file=$(SRCROOT)/../../Tuist/.build/checkouts/FSCalendar/FSCalendar/include/module.modulemap", - "-Xcc", - "-fmodule-map-file=$(SRCROOT)/../../Tuist/.build/tuist-derived/RxCocoaRuntime/RxCocoaRuntime.modulemap", - ); + OTHER_SWIFT_FLAGS = "$(inherited) -Xcc -fmodule-map-file=$(SRCROOT)/../../Tuist/.build/checkouts/FSCalendar/FSCalendar/include/module.modulemap -Xcc -fmodule-map-file=$(SRCROOT)/../../Tuist/.build/tuist-derived/RxCocoaRuntime/RxCocoaRuntime.modulemap"; PRODUCT_BUNDLE_IDENTIFIER = io.tuist.LearnMate; PRODUCT_NAME = LearnMate; SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; SUPPORTS_MACCATALYST = NO; - SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = YES; + SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO; - SWIFT_ACTIVE_COMPILATION_CONDITIONS = ( - "$(inherited)", - DEBUG, - ); + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) DEBUG"; SWIFT_COMPILATION_MODE = singlefile; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; + TARGETED_DEVICE_FAMILY = 1; }; name = Debug; }; @@ -569,23 +570,14 @@ "-fmodule-map-file=$(SRCROOT)/../../Tuist/.build/checkouts/FSCalendar/FSCalendar/include/module.modulemap", "-fmodule-map-file=$(SRCROOT)/../../Tuist/.build/tuist-derived/RxCocoaRuntime/RxCocoaRuntime.modulemap", ); - OTHER_SWIFT_FLAGS = ( - "$(inherited)", - "-Xcc", - "-fmodule-map-file=$(SRCROOT)/../../Tuist/.build/checkouts/FSCalendar/FSCalendar/include/module.modulemap", - "-Xcc", - "-fmodule-map-file=$(SRCROOT)/../../Tuist/.build/tuist-derived/RxCocoaRuntime/RxCocoaRuntime.modulemap", - ); + OTHER_SWIFT_FLAGS = "$(inherited) -Xcc -fmodule-map-file=$(SRCROOT)/../../Tuist/.build/checkouts/FSCalendar/FSCalendar/include/module.modulemap -Xcc -fmodule-map-file=$(SRCROOT)/../../Tuist/.build/tuist-derived/RxCocoaRuntime/RxCocoaRuntime.modulemap"; PRODUCT_BUNDLE_IDENTIFIER = io.tuist.LearnMateTests; PRODUCT_NAME = LearnMateTests; SDKROOT = iphoneos; SUPPORTS_MACCATALYST = NO; SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = YES; SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO; - SWIFT_ACTIVE_COMPILATION_CONDITIONS = ( - "$(inherited)", - DEBUG, - ); + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) DEBUG"; SWIFT_COMPILATION_MODE = singlefile; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; @@ -616,13 +608,7 @@ "-fmodule-map-file=$(SRCROOT)/../../Tuist/.build/checkouts/FSCalendar/FSCalendar/include/module.modulemap", "-fmodule-map-file=$(SRCROOT)/../../Tuist/.build/tuist-derived/RxCocoaRuntime/RxCocoaRuntime.modulemap", ); - OTHER_SWIFT_FLAGS = ( - "$(inherited)", - "-Xcc", - "-fmodule-map-file=$(SRCROOT)/../../Tuist/.build/checkouts/FSCalendar/FSCalendar/include/module.modulemap", - "-Xcc", - "-fmodule-map-file=$(SRCROOT)/../../Tuist/.build/tuist-derived/RxCocoaRuntime/RxCocoaRuntime.modulemap", - ); + OTHER_SWIFT_FLAGS = "$(inherited) -Xcc -fmodule-map-file=$(SRCROOT)/../../Tuist/.build/checkouts/FSCalendar/FSCalendar/include/module.modulemap -Xcc -fmodule-map-file=$(SRCROOT)/../../Tuist/.build/tuist-derived/RxCocoaRuntime/RxCocoaRuntime.modulemap"; PRODUCT_BUNDLE_IDENTIFIER = io.tuist.LearnMateTests; PRODUCT_NAME = LearnMateTests; SDKROOT = iphoneos; diff --git a/Projects/LearnMate/Resources/Assets.xcassets/AppIcon.appiconset/100.png b/Projects/LearnMate/Resources/Assets.xcassets/AppIcon.appiconset/100.png new file mode 100644 index 0000000..7038dc0 Binary files /dev/null and b/Projects/LearnMate/Resources/Assets.xcassets/AppIcon.appiconset/100.png differ diff --git a/Projects/LearnMate/Assets.xcassets/AppIcon.appiconset/1024 1.png b/Projects/LearnMate/Resources/Assets.xcassets/AppIcon.appiconset/1024 1.png similarity index 100% rename from Projects/LearnMate/Assets.xcassets/AppIcon.appiconset/1024 1.png rename to Projects/LearnMate/Resources/Assets.xcassets/AppIcon.appiconset/1024 1.png diff --git a/Projects/LearnMate/Assets.xcassets/AppIcon.appiconset/114.png b/Projects/LearnMate/Resources/Assets.xcassets/AppIcon.appiconset/114.png similarity index 100% rename from Projects/LearnMate/Assets.xcassets/AppIcon.appiconset/114.png rename to Projects/LearnMate/Resources/Assets.xcassets/AppIcon.appiconset/114.png diff --git a/Projects/LearnMate/Assets.xcassets/AppIcon.appiconset/120 1.png b/Projects/LearnMate/Resources/Assets.xcassets/AppIcon.appiconset/120 1.png similarity index 100% rename from Projects/LearnMate/Assets.xcassets/AppIcon.appiconset/120 1.png rename to Projects/LearnMate/Resources/Assets.xcassets/AppIcon.appiconset/120 1.png diff --git a/Projects/LearnMate/Assets.xcassets/AppIcon.appiconset/120.png b/Projects/LearnMate/Resources/Assets.xcassets/AppIcon.appiconset/120.png similarity index 100% rename from Projects/LearnMate/Assets.xcassets/AppIcon.appiconset/120.png rename to Projects/LearnMate/Resources/Assets.xcassets/AppIcon.appiconset/120.png diff --git a/Projects/LearnMate/Resources/Assets.xcassets/AppIcon.appiconset/144.png b/Projects/LearnMate/Resources/Assets.xcassets/AppIcon.appiconset/144.png new file mode 100644 index 0000000..f008d61 Binary files /dev/null and b/Projects/LearnMate/Resources/Assets.xcassets/AppIcon.appiconset/144.png differ diff --git a/Projects/LearnMate/Assets.xcassets/AppIcon.appiconset/152.png b/Projects/LearnMate/Resources/Assets.xcassets/AppIcon.appiconset/152.png similarity index 100% rename from Projects/LearnMate/Assets.xcassets/AppIcon.appiconset/152.png rename to Projects/LearnMate/Resources/Assets.xcassets/AppIcon.appiconset/152.png diff --git a/Projects/LearnMate/Resources/Assets.xcassets/AppIcon.appiconset/167.png b/Projects/LearnMate/Resources/Assets.xcassets/AppIcon.appiconset/167.png new file mode 100644 index 0000000..d5986cf Binary files /dev/null and b/Projects/LearnMate/Resources/Assets.xcassets/AppIcon.appiconset/167.png differ diff --git a/Projects/LearnMate/Assets.xcassets/AppIcon.appiconset/180.png b/Projects/LearnMate/Resources/Assets.xcassets/AppIcon.appiconset/180.png similarity index 100% rename from Projects/LearnMate/Assets.xcassets/AppIcon.appiconset/180.png rename to Projects/LearnMate/Resources/Assets.xcassets/AppIcon.appiconset/180.png diff --git a/Projects/LearnMate/Assets.xcassets/AppIcon.appiconset/20.png b/Projects/LearnMate/Resources/Assets.xcassets/AppIcon.appiconset/20.png similarity index 100% rename from Projects/LearnMate/Assets.xcassets/AppIcon.appiconset/20.png rename to Projects/LearnMate/Resources/Assets.xcassets/AppIcon.appiconset/20.png diff --git a/Projects/LearnMate/Assets.xcassets/AppIcon.appiconset/29 1.png b/Projects/LearnMate/Resources/Assets.xcassets/AppIcon.appiconset/29 1.png similarity index 100% rename from Projects/LearnMate/Assets.xcassets/AppIcon.appiconset/29 1.png rename to Projects/LearnMate/Resources/Assets.xcassets/AppIcon.appiconset/29 1.png diff --git a/Projects/LearnMate/Assets.xcassets/AppIcon.appiconset/29.png b/Projects/LearnMate/Resources/Assets.xcassets/AppIcon.appiconset/29.png similarity index 100% rename from Projects/LearnMate/Assets.xcassets/AppIcon.appiconset/29.png rename to Projects/LearnMate/Resources/Assets.xcassets/AppIcon.appiconset/29.png diff --git a/Projects/LearnMate/Assets.xcassets/AppIcon.appiconset/40 1.png b/Projects/LearnMate/Resources/Assets.xcassets/AppIcon.appiconset/40 1.png similarity index 100% rename from Projects/LearnMate/Assets.xcassets/AppIcon.appiconset/40 1.png rename to Projects/LearnMate/Resources/Assets.xcassets/AppIcon.appiconset/40 1.png diff --git a/Projects/LearnMate/Assets.xcassets/AppIcon.appiconset/40 2.png b/Projects/LearnMate/Resources/Assets.xcassets/AppIcon.appiconset/40 2.png similarity index 100% rename from Projects/LearnMate/Assets.xcassets/AppIcon.appiconset/40 2.png rename to Projects/LearnMate/Resources/Assets.xcassets/AppIcon.appiconset/40 2.png diff --git a/Projects/LearnMate/Assets.xcassets/AppIcon.appiconset/40 3.png b/Projects/LearnMate/Resources/Assets.xcassets/AppIcon.appiconset/40 3.png similarity index 100% rename from Projects/LearnMate/Assets.xcassets/AppIcon.appiconset/40 3.png rename to Projects/LearnMate/Resources/Assets.xcassets/AppIcon.appiconset/40 3.png diff --git a/Projects/LearnMate/Resources/Assets.xcassets/AppIcon.appiconset/50.png b/Projects/LearnMate/Resources/Assets.xcassets/AppIcon.appiconset/50.png new file mode 100644 index 0000000..db3a53f Binary files /dev/null and b/Projects/LearnMate/Resources/Assets.xcassets/AppIcon.appiconset/50.png differ diff --git a/Projects/LearnMate/Assets.xcassets/AppIcon.appiconset/57.png b/Projects/LearnMate/Resources/Assets.xcassets/AppIcon.appiconset/57.png similarity index 100% rename from Projects/LearnMate/Assets.xcassets/AppIcon.appiconset/57.png rename to Projects/LearnMate/Resources/Assets.xcassets/AppIcon.appiconset/57.png diff --git a/Projects/LearnMate/Assets.xcassets/AppIcon.appiconset/58 1.png b/Projects/LearnMate/Resources/Assets.xcassets/AppIcon.appiconset/58 1.png similarity index 100% rename from Projects/LearnMate/Assets.xcassets/AppIcon.appiconset/58 1.png rename to Projects/LearnMate/Resources/Assets.xcassets/AppIcon.appiconset/58 1.png diff --git a/Projects/LearnMate/Assets.xcassets/AppIcon.appiconset/58.png b/Projects/LearnMate/Resources/Assets.xcassets/AppIcon.appiconset/58.png similarity index 100% rename from Projects/LearnMate/Assets.xcassets/AppIcon.appiconset/58.png rename to Projects/LearnMate/Resources/Assets.xcassets/AppIcon.appiconset/58.png diff --git a/Projects/LearnMate/Assets.xcassets/AppIcon.appiconset/60.png b/Projects/LearnMate/Resources/Assets.xcassets/AppIcon.appiconset/60.png similarity index 100% rename from Projects/LearnMate/Assets.xcassets/AppIcon.appiconset/60.png rename to Projects/LearnMate/Resources/Assets.xcassets/AppIcon.appiconset/60.png diff --git a/Projects/LearnMate/Resources/Assets.xcassets/AppIcon.appiconset/72.png b/Projects/LearnMate/Resources/Assets.xcassets/AppIcon.appiconset/72.png new file mode 100644 index 0000000..6bb937f Binary files /dev/null and b/Projects/LearnMate/Resources/Assets.xcassets/AppIcon.appiconset/72.png differ diff --git a/Projects/LearnMate/Resources/Assets.xcassets/AppIcon.appiconset/76.png b/Projects/LearnMate/Resources/Assets.xcassets/AppIcon.appiconset/76.png new file mode 100644 index 0000000..2d5b3b6 Binary files /dev/null and b/Projects/LearnMate/Resources/Assets.xcassets/AppIcon.appiconset/76.png differ diff --git a/Projects/LearnMate/Assets.xcassets/AppIcon.appiconset/80 1.png b/Projects/LearnMate/Resources/Assets.xcassets/AppIcon.appiconset/80 1.png similarity index 100% rename from Projects/LearnMate/Assets.xcassets/AppIcon.appiconset/80 1.png rename to Projects/LearnMate/Resources/Assets.xcassets/AppIcon.appiconset/80 1.png diff --git a/Projects/LearnMate/Assets.xcassets/AppIcon.appiconset/80.png b/Projects/LearnMate/Resources/Assets.xcassets/AppIcon.appiconset/80.png similarity index 100% rename from Projects/LearnMate/Assets.xcassets/AppIcon.appiconset/80.png rename to Projects/LearnMate/Resources/Assets.xcassets/AppIcon.appiconset/80.png diff --git a/Projects/LearnMate/Assets.xcassets/AppIcon.appiconset/87 1.png b/Projects/LearnMate/Resources/Assets.xcassets/AppIcon.appiconset/87 1.png similarity index 100% rename from Projects/LearnMate/Assets.xcassets/AppIcon.appiconset/87 1.png rename to Projects/LearnMate/Resources/Assets.xcassets/AppIcon.appiconset/87 1.png diff --git a/Projects/LearnMate/Assets.xcassets/AppIcon.appiconset/Contents.json b/Projects/LearnMate/Resources/Assets.xcassets/AppIcon.appiconset/Contents.json similarity index 97% rename from Projects/LearnMate/Assets.xcassets/AppIcon.appiconset/Contents.json rename to Projects/LearnMate/Resources/Assets.xcassets/AppIcon.appiconset/Contents.json index 1073ac6..381ac1b 100644 --- a/Projects/LearnMate/Assets.xcassets/AppIcon.appiconset/Contents.json +++ b/Projects/LearnMate/Resources/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -103,26 +103,31 @@ "size" : "40x40" }, { + "filename" : "50.png", "idiom" : "ipad", "scale" : "1x", "size" : "50x50" }, { + "filename" : "100.png", "idiom" : "ipad", "scale" : "2x", "size" : "50x50" }, { + "filename" : "72.png", "idiom" : "ipad", "scale" : "1x", "size" : "72x72" }, { + "filename" : "144.png", "idiom" : "ipad", "scale" : "2x", "size" : "72x72" }, { + "filename" : "76.png", "idiom" : "ipad", "scale" : "1x", "size" : "76x76" @@ -134,6 +139,7 @@ "size" : "76x76" }, { + "filename" : "167.png", "idiom" : "ipad", "scale" : "2x", "size" : "83.5x83.5" diff --git a/Projects/LearnMate/Assets.xcassets/Contents.json b/Projects/LearnMate/Resources/Assets.xcassets/Contents.json similarity index 100% rename from Projects/LearnMate/Assets.xcassets/Contents.json rename to Projects/LearnMate/Resources/Assets.xcassets/Contents.json diff --git a/Projects/LearnMate/Sources/DI/LoginAssembly.swift b/Projects/LearnMate/Sources/DI/LoginAssembly.swift index e09a32d..7f71c7c 100644 --- a/Projects/LearnMate/Sources/DI/LoginAssembly.swift +++ b/Projects/LearnMate/Sources/DI/LoginAssembly.swift @@ -29,7 +29,8 @@ public struct LoginAssembly: Assembly { container.register(SignViewModel.self) { resolver in let useCase = resolver.resolve(SignUseCase.self)! let tokenRepository = resolver.resolve(TokenRepository.self)! - return SignViewModel(signUseCase: useCase, tokenRepository: tokenRepository) + let userUseCase = resolver.resolve(UserUseCase.self)! + return SignViewModel(signUseCase: useCase, tokenRepository: tokenRepository, userUseCase: userUseCase) } container.register(SignInViewController.self) { resolver in diff --git a/Projects/LearnMate/Support/LearnMate-Info.plist b/Projects/LearnMate/Support/LearnMate-Info.plist index 9b001ce..d27c5ad 100644 --- a/Projects/LearnMate/Support/LearnMate-Info.plist +++ b/Projects/LearnMate/Support/LearnMate-Info.plist @@ -2,15 +2,6 @@ - CFBundleURLTypes - - - CFBundleURLSchemes - - com.learnmate.app - - - CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) CFBundleExecutable @@ -24,7 +15,16 @@ CFBundlePackageType APPL CFBundleShortVersionString - 1.0 + 1.0.1 + CFBundleURLTypes + + + CFBundleURLSchemes + + com.learnmate.app + + + CFBundleVersion 1 LSRequiresIPhoneOS @@ -38,10 +38,10 @@ UIWindowSceneSessionRoleApplication - UISceneDelegateClassName - $(PRODUCT_MODULE_NAME).SceneDelegate UISceneConfigurationName Default Configuration + UISceneDelegateClassName + $(PRODUCT_MODULE_NAME).SceneDelegate diff --git a/Projects/Login/Sources/View/SignInViewController.swift b/Projects/Login/Sources/View/SignInViewController.swift index 9df6205..ddec953 100644 --- a/Projects/Login/Sources/View/SignInViewController.swift +++ b/Projects/Login/Sources/View/SignInViewController.swift @@ -75,6 +75,12 @@ public class SignInViewController: BaseViewController { self?.onLoginSuccess?() } } + + viewModel.onSignInFailure = { [weak self] message in + DispatchQueue.main.async { + self?.showFailureAlert(message: message) + } + } } private func setupTapGesture() { @@ -110,4 +116,11 @@ public class SignInViewController: BaseViewController { $0.horizontalEdges.bottom.equalToSuperview() } } + + private func showFailureAlert(message: String) { + let alertView = LMAlert(title: message, + cancelTitle: "", + confirmTitle: "확인") + alertView.show(in: view) + } } diff --git a/Projects/Login/Sources/View/SignUpViewController.swift b/Projects/Login/Sources/View/SignUpViewController.swift index 04b8995..f76add9 100644 --- a/Projects/Login/Sources/View/SignUpViewController.swift +++ b/Projects/Login/Sources/View/SignUpViewController.swift @@ -64,12 +64,18 @@ public class SignUpViewController: BaseViewController { self?.signUpView.confirmInputField.showWarning() } } - + viewModel.onSignUpSuccess = { [weak self] in DispatchQueue.main.async { self?.showSignUpSuccessModal() } } + + viewModel.onSignUpFailure = { [weak self] message in + DispatchQueue.main.async { + self?.showFailureAlert(message: message) + } + } } private func bindActions() { @@ -80,6 +86,7 @@ public class SignUpViewController: BaseViewController { print("유효한 이메일: \(email)") self.email = email self.viewModel.postEmail(email: email) + self.signUpView.emailInputField.disableButton(buttonTitle: "전송중..") self.signUpView.emailInputField.hideWarning() } else { print("유효하지 않은 이메일: \(email)") @@ -227,4 +234,11 @@ public class SignUpViewController: BaseViewController { private func navigateToSignIn() { navigationController?.popViewController(animated: true) } + + private func showFailureAlert(message: String) { + let alertView = LMAlert(title: message, + cancelTitle: "", + confirmTitle: "확인") + alertView.show(in: view) + } } diff --git a/Projects/Login/Sources/ViewModel/SignViewModel.swift b/Projects/Login/Sources/ViewModel/SignViewModel.swift index 0df1d5c..85fc9c4 100644 --- a/Projects/Login/Sources/ViewModel/SignViewModel.swift +++ b/Projects/Login/Sources/ViewModel/SignViewModel.swift @@ -8,6 +8,7 @@ import Domain import RxSwift import RxRelay +import Foundation protocol SignViewModelProtocol { func postSignIn(email: String, password: String) @@ -20,18 +21,22 @@ public class SignViewModel: SignViewModelProtocol { private let disposeBag = DisposeBag() private let signUseCase: SignUseCase private let tokenRepository: TokenRepository + private let userUseCase: UserUseCase public weak var signInViewCoordinator: SignInCoordinator? public weak var signUpViewCoordinator: SignUpCoordinator? public var onEmailSuccess: (() -> Void)? public var onConfirmSuccess: (() -> Void)? public var onConfirmFailure: (() -> Void)? public var onSignInSuccess: (() -> Void)? + public var onSignInFailure: ((String) -> Void)? public var onSignUpSuccess: (() -> Void)? + public var onSignUpFailure: ((String) -> Void)? public let emailVerified = BehaviorRelay(value: false) - public init(signUseCase: SignUseCase, tokenRepository: TokenRepository) { + public init(signUseCase: SignUseCase, tokenRepository: TokenRepository, userUseCase: UserUseCase) { self.signUseCase = signUseCase self.tokenRepository = tokenRepository + self.userUseCase = userUseCase } func postSignIn(email: String, password: String) { @@ -49,9 +54,23 @@ public class SignViewModel: SignViewModelProtocol { print("🔄 리프레시 토큰 저장 완료: \(refreshToken)") } - self.onSignInSuccess?() - }, onFailure: { error in - print("로그인 실패: \(error)") + // 로그인 성공 후 사용자 정보 가져오기 + self.userUseCase.getUser() + .subscribe(onSuccess: { user in + UserDefaults.standard.set(user.name, forKey: "userName") + print("✅ 사용자 이름 저장 완료: \(user.name)") + self.onSignInSuccess?() + }, onFailure: { error in + print("❌ getUser 실패: \(error)") + // getUser 실패해도 로그인 성공 처리 + self.onSignInSuccess?() + }) + .disposed(by: self.disposeBag) + }, onFailure: { [weak self] error in + guard let self = self else { return } + let nsError = error as NSError + let message = nsError.userInfo[NSLocalizedDescriptionKey] as? String ?? error.localizedDescription + self.onSignInFailure?(message) }) .disposed(by: disposeBag) } @@ -90,7 +109,10 @@ public class SignViewModel: SignViewModelProtocol { self.onSignUpSuccess?() }, onFailure: { [weak self] error in guard let self = self else { return } - print("회원가입 실패: \(error)") + let nsError = error as NSError + let message = nsError.userInfo[NSLocalizedDescriptionKey] as? String ?? error.localizedDescription + print("here 1") + self.onSignUpFailure?(message) }) .disposed(by: disposeBag) } diff --git a/Projects/MyPage/Sources/View/MyPageViewController.swift b/Projects/MyPage/Sources/View/MyPageViewController.swift index 18d4b15..ab3e74a 100644 --- a/Projects/MyPage/Sources/View/MyPageViewController.swift +++ b/Projects/MyPage/Sources/View/MyPageViewController.swift @@ -70,8 +70,7 @@ public class MyPageViewController: BaseViewController { .observe(on: MainScheduler.instance) .subscribe(onNext: { [weak self] user in print("📱 사용자 정보 로드 성공: \(user)") - // 사용자 이름을 MyPageView에 업데이트 - self?.myPageView.updateUserName(user.name) + self?.myPageView.updateUserName(user.name, user.userId) }) .disposed(by: disposeBag) @@ -79,7 +78,6 @@ public class MyPageViewController: BaseViewController { .observe(on: MainScheduler.instance) .subscribe(onNext: { error in print("❌ 사용자 정보 로드 실패: \(error)") - // 에러 처리 로직 추가 }) .disposed(by: disposeBag)