diff --git a/Happiggy-bank/Happiggy-bank.xcodeproj/project.pbxproj b/Happiggy-bank/Happiggy-bank.xcodeproj/project.pbxproj index 933fb29f..b15f8db5 100644 --- a/Happiggy-bank/Happiggy-bank.xcodeproj/project.pbxproj +++ b/Happiggy-bank/Happiggy-bank.xcodeproj/project.pbxproj @@ -65,6 +65,10 @@ A46B2E8129B5EBDA006A7870 /* NoteDetailListViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = A46B2E8029B5EBDA006A7870 /* NoteDetailListViewModel.swift */; }; A46B2E8329B5EBE6006A7870 /* NoteDetailListViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A46B2E8229B5EBE6006A7870 /* NoteDetailListViewController.swift */; }; A46BC1EF2800626A00C2E5B4 /* TabItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = A46BC1EE2800626A00C2E5B4 /* TabItem.swift */; }; + A472C5F529C2DCEA00097432 /* NewNoteInputToolbar.swift in Sources */ = {isa = PBXBuildFile; fileRef = A472C5F429C2DCEA00097432 /* NewNoteInputToolbar.swift */; }; + A472C5F729C2DDFF00097432 /* NewNoteInputViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = A472C5F629C2DDFF00097432 /* NewNoteInputViewModel.swift */; }; + A472C5F929C2ED5000097432 /* HBError.swift in Sources */ = {isa = PBXBuildFile; fileRef = A472C5F829C2ED5000097432 /* HBError.swift */; }; + A472C5FB29C2F21600097432 /* NewNoteSavingDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = A472C5FA29C2F21600097432 /* NewNoteSavingDelegate.swift */; }; A47D83462966C0C60028AA1D /* NotificationSettingsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D22ADF7E27F72F7300ECB77B /* NotificationSettingsViewModel.swift */; }; A47D83482966D3870028AA1D /* FontSelectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A47D83472966D3870028AA1D /* FontSelectionView.swift */; }; A47D834A296716BF0028AA1D /* FontCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = A47D8349296716BF0028AA1D /* FontCell.swift */; }; @@ -110,12 +114,11 @@ A49B25F12812BF6800399630 /* dovemayo_bold.otf in Resources */ = {isa = PBXBuildFile; fileRef = A49B25F02812BF4100399630 /* dovemayo_bold.otf */; }; A49B25F22812BF6B00399630 /* dovemayo.otf in Resources */ = {isa = PBXBuildFile; fileRef = A49B25EF2812BF4100399630 /* dovemayo.otf */; }; A49B25F42812FFB400399630 /* UILabel+Color.swift in Sources */ = {isa = PBXBuildFile; fileRef = A49B25F32812FFB400399630 /* UILabel+Color.swift */; }; - A4A55A0528FFC64A004ABE00 /* NewNoteInputView.xib in Resources */ = {isa = PBXBuildFile; fileRef = A4A55A0428FFC64A004ABE00 /* NewNoteInputView.xib */; }; A4A55A0728FFC664004ABE00 /* UIView+ConfigureXib.swift in Sources */ = {isa = PBXBuildFile; fileRef = A4A55A0628FFC664004ABE00 /* UIView+ConfigureXib.swift */; }; A4A55A0928FFC675004ABE00 /* NewNoteInputView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A4A55A0828FFC675004ABE00 /* NewNoteInputView.swift */; }; A4B285FD27D8A060008769EB /* Calendar+Duration.swift in Sources */ = {isa = PBXBuildFile; fileRef = A4B285FC27D8A060008769EB /* Calendar+Duration.swift */; }; A4B2860527D9A546008769EB /* NewNoteDatePickerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A4B2860427D9A546008769EB /* NewNoteDatePickerViewController.swift */; }; - A4B2860927D9A56A008769EB /* NewNoteTextViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A4B2860827D9A56A008769EB /* NewNoteTextViewController.swift */; }; + A4B2860927D9A56A008769EB /* NewNoteInputViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A4B2860827D9A56A008769EB /* NewNoteInputViewController.swift */; }; A4B2860B27D9B434008769EB /* UIViewController+FadeInOut.swift in Sources */ = {isa = PBXBuildFile; fileRef = A4B2860A27D9B434008769EB /* UIViewController+FadeInOut.swift */; }; A4B2860F27D9F539008769EB /* NewNoteDatePickerViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = A4B2860E27D9F539008769EB /* NewNoteDatePickerViewModel.swift */; }; A4C1AFC027E477180096CD3E /* NSMutableAttributedString+ColorBold.swift in Sources */ = {isa = PBXBuildFile; fileRef = A4C1AFBF27E477180096CD3E /* NSMutableAttributedString+ColorBold.swift */; }; @@ -123,7 +126,6 @@ A4C1AFC427E47DC50096CD3E /* String+NSMutableAttributedStringify.swift in Sources */ = {isa = PBXBuildFile; fileRef = A4C1AFC327E47DC50096CD3E /* String+NSMutableAttributedStringify.swift */; }; A4C1AFC627E482E10096CD3E /* CGFloat+Values.swift in Sources */ = {isa = PBXBuildFile; fileRef = A4C1AFC527E482E10096CD3E /* CGFloat+Values.swift */; }; A4C1AFCE27E4F8150096CD3E /* UIView+FadeInOut.swift in Sources */ = {isa = PBXBuildFile; fileRef = A4C1AFCD27E4F8150096CD3E /* UIView+FadeInOut.swift */; }; - A4C1AFD227E5C60E0096CD3E /* NewNoteTextViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = A4C1AFD127E5C60E0096CD3E /* NewNoteTextViewModel.swift */; }; A4C1AFD427E5E6120096CD3E /* UITextView+ParagraphStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = A4C1AFD327E5E6120096CD3E /* UITextView+ParagraphStyle.swift */; }; A4CF2C7C27C71FF5001B01B1 /* CATransition+PopupAnimation.swift in Sources */ = {isa = PBXBuildFile; fileRef = A4CF2C7B27C71FF5001B01B1 /* CATransition+PopupAnimation.swift */; }; A4CF2C8027C733FE001B01B1 /* ColorButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = A4CF2C7F27C733FE001B01B1 /* ColorButton.swift */; }; @@ -246,6 +248,10 @@ A46B2E8029B5EBDA006A7870 /* NoteDetailListViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NoteDetailListViewModel.swift; sourceTree = ""; }; A46B2E8229B5EBE6006A7870 /* NoteDetailListViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NoteDetailListViewController.swift; sourceTree = ""; }; A46BC1EE2800626A00C2E5B4 /* TabItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabItem.swift; sourceTree = ""; }; + A472C5F429C2DCEA00097432 /* NewNoteInputToolbar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewNoteInputToolbar.swift; sourceTree = ""; }; + A472C5F629C2DDFF00097432 /* NewNoteInputViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewNoteInputViewModel.swift; sourceTree = ""; }; + A472C5F829C2ED5000097432 /* HBError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HBError.swift; sourceTree = ""; }; + A472C5FA29C2F21600097432 /* NewNoteSavingDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewNoteSavingDelegate.swift; sourceTree = ""; }; A47D83472966D3870028AA1D /* FontSelectionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FontSelectionView.swift; sourceTree = ""; }; A47D8349296716BF0028AA1D /* FontCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FontCell.swift; sourceTree = ""; }; A47D83532973A4860028AA1D /* FontPublishing.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FontPublishing.swift; sourceTree = ""; }; @@ -290,12 +296,11 @@ A49B25EF2812BF4100399630 /* dovemayo.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = dovemayo.otf; sourceTree = ""; }; A49B25F02812BF4100399630 /* dovemayo_bold.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = dovemayo_bold.otf; sourceTree = ""; }; A49B25F32812FFB400399630 /* UILabel+Color.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UILabel+Color.swift"; sourceTree = ""; }; - A4A55A0428FFC64A004ABE00 /* NewNoteInputView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = NewNoteInputView.xib; sourceTree = ""; }; A4A55A0628FFC664004ABE00 /* UIView+ConfigureXib.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIView+ConfigureXib.swift"; sourceTree = ""; }; A4A55A0828FFC675004ABE00 /* NewNoteInputView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NewNoteInputView.swift; sourceTree = ""; }; A4B285FC27D8A060008769EB /* Calendar+Duration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Calendar+Duration.swift"; sourceTree = ""; }; A4B2860427D9A546008769EB /* NewNoteDatePickerViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewNoteDatePickerViewController.swift; sourceTree = ""; }; - A4B2860827D9A56A008769EB /* NewNoteTextViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewNoteTextViewController.swift; sourceTree = ""; }; + A4B2860827D9A56A008769EB /* NewNoteInputViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewNoteInputViewController.swift; sourceTree = ""; }; A4B2860A27D9B434008769EB /* UIViewController+FadeInOut.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIViewController+FadeInOut.swift"; sourceTree = ""; }; A4B2860E27D9F539008769EB /* NewNoteDatePickerViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewNoteDatePickerViewModel.swift; sourceTree = ""; }; A4C1AFBF27E477180096CD3E /* NSMutableAttributedString+ColorBold.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSMutableAttributedString+ColorBold.swift"; sourceTree = ""; }; @@ -303,7 +308,6 @@ A4C1AFC327E47DC50096CD3E /* String+NSMutableAttributedStringify.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "String+NSMutableAttributedStringify.swift"; sourceTree = ""; }; A4C1AFC527E482E10096CD3E /* CGFloat+Values.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CGFloat+Values.swift"; sourceTree = ""; }; A4C1AFCD27E4F8150096CD3E /* UIView+FadeInOut.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIView+FadeInOut.swift"; sourceTree = ""; }; - A4C1AFD127E5C60E0096CD3E /* NewNoteTextViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewNoteTextViewModel.swift; sourceTree = ""; }; A4C1AFD327E5E6120096CD3E /* UITextView+ParagraphStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UITextView+ParagraphStyle.swift"; sourceTree = ""; }; A4CF2C7B27C71FF5001B01B1 /* CATransition+PopupAnimation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CATransition+PopupAnimation.swift"; sourceTree = ""; }; A4CF2C7F27C733FE001B01B1 /* ColorButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = ColorButton.swift; path = "Happiggy-bank/HomeTab/NewNote/UI/View/ColorButton.swift"; sourceTree = SOURCE_ROOT; }; @@ -548,6 +552,7 @@ A46BC1EE2800626A00C2E5B4 /* TabItem.swift */, A4569CB9280FBA23001E3FD6 /* CustomResult.swift */, A49B25EC2812B5A400399630 /* CustomFont.swift */, + A472C5F829C2ED5000097432 /* HBError.swift */, ); path = Enum; sourceTree = ""; @@ -569,6 +574,7 @@ A4569CB7280FB979001E3FD6 /* Presenter.swift */, A4569CC528111EFA001E3FD6 /* InformationTextViewDataSource.swift */, A4EDFE7E2902D5CB0056C2DC /* ColorPickerDelegate.swift */, + A472C5FA29C2F21600097432 /* NewNoteSavingDelegate.swift */, ); path = Protocol; sourceTree = ""; @@ -791,7 +797,7 @@ isa = PBXGroup; children = ( A4B2860E27D9F539008769EB /* NewNoteDatePickerViewModel.swift */, - A4C1AFD127E5C60E0096CD3E /* NewNoteTextViewModel.swift */, + A472C5F629C2DDFF00097432 /* NewNoteInputViewModel.swift */, ); path = ViewModel; sourceTree = ""; @@ -809,7 +815,7 @@ isa = PBXGroup; children = ( A4B2860427D9A546008769EB /* NewNoteDatePickerViewController.swift */, - A4B2860827D9A56A008769EB /* NewNoteTextViewController.swift */, + A4B2860827D9A56A008769EB /* NewNoteInputViewController.swift */, ); path = Controller; sourceTree = ""; @@ -817,13 +823,13 @@ A896FBEF2966B5DE00A3400B /* View */ = { isa = PBXGroup; children = ( - A4A55A0428FFC64A004ABE00 /* NewNoteInputView.xib */, A467B5C927DA289500AC702D /* NewNoteDatePickerRowView.xib */, A4A55A0828FFC675004ABE00 /* NewNoteInputView.swift */, A467B5C727DA258700AC702D /* NewNoteDatePickerRowView.swift */, A4CF2C7F27C733FE001B01B1 /* ColorButton.swift */, A4EDFE802902D72A0056C2DC /* ColorPickerBarItem.swift */, A4845B5C2900DF0B00A6007C /* ColorPicker.swift */, + A472C5F429C2DCEA00097432 /* NewNoteInputToolbar.swift */, ); path = View; sourceTree = ""; @@ -1324,7 +1330,6 @@ A46B110A28146171004AB185 /* GowunBatang-Regular.ttf in Resources */, A49B25F12812BF6800399630 /* dovemayo_bold.otf in Resources */, A46B110D2814617B004AB185 /* IBMPlexSansKR-Regular.otf in Resources */, - A4A55A0528FFC64A004ABE00 /* NewNoteInputView.xib in Resources */, A8FC07DD27B3EF030077A758 /* .swiftlint.yml in Resources */, A467B5CA27DA289600AC702D /* NewNoteDatePickerRowView.xib in Resources */, A46B111128146188004AB185 /* Cafe24SsurroundAir.ttf in Resources */, @@ -1378,14 +1383,15 @@ A467B5C827DA258700AC702D /* NewNoteDatePickerRowView.swift in Sources */, A484A3052958945E00A58312 /* BaseTextView.swift in Sources */, A484A327295EE22000A58312 /* String+SubstringsMatchingRegex.swift in Sources */, - A4C1AFD227E5C60E0096CD3E /* NewNoteTextViewModel.swift in Sources */, A819CFA127DE034F00DE8E72 /* NewBottle.swift in Sources */, A4569CBC2810455B001E3FD6 /* CustomerServiceViewController.swift in Sources */, A4EDFE812902D72A0056C2DC /* ColorPickerBarItem.swift in Sources */, + A472C5F929C2ED5000097432 /* HBError.swift in Sources */, A49AC5E92917CBFB009315BC /* UIStackView+AddArrangedSubviews.swift in Sources */, A4569CC628111EFA001E3FD6 /* InformationTextViewDataSource.swift in Sources */, A80248252963E58A00F2EA81 /* BottleTitleStack.swift in Sources */, D236DB8627FDC43200D7B8F0 /* NewBottleDatePickerViewModel.swift in Sources */, + A472C5F729C2DDFF00097432 /* NewNoteInputViewModel.swift in Sources */, A47D83562973A4970028AA1D /* FontManager.swift in Sources */, A499318327BF5158009FF5A8 /* BottleNoteView.swift in Sources */, A4CF2C8E27CBA49D001B01B1 /* UIViewController+NotificationCenter.swift in Sources */, @@ -1424,6 +1430,7 @@ A4CF2C8227C73B42001B01B1 /* UIColor+AssetColors.swift in Sources */, A819CF9F27DDD97C00DE8E72 /* HapticManager.swift in Sources */, A4569CCF28128B4B001E3FD6 /* SettingsNonIconButtonCell.swift in Sources */, + A472C5F529C2DCEA00097432 /* NewNoteInputToolbar.swift in Sources */, A4396B1B29325D70005D9D3A /* PhotoViewController.swift in Sources */, A8ECD4A727E33BFA00886BC0 /* ListTabViewModel.swift in Sources */, A49AC5EB2917FFAB009315BC /* PhotoNoteCellViewModel.swift in Sources */, @@ -1442,7 +1449,7 @@ A49AC5E52917C6E2009315BC /* UILabel+ChangeFontSize.swift in Sources */, A4A55A0928FFC675004ABE00 /* NewNoteInputView.swift in Sources */, A46B2E8329B5EBE6006A7870 /* NoteDetailListViewController.swift in Sources */, - A4B2860927D9A56A008769EB /* NewNoteTextViewController.swift in Sources */, + A4B2860927D9A56A008769EB /* NewNoteInputViewController.swift in Sources */, A843332127DA026D00A12A54 /* NewBottleDatePickerViewController.swift in Sources */, A4D6EB75282E2E6700553E43 /* VersionChecking.swift in Sources */, A8FC07CA27B3ECF00077A758 /* SceneDelegate.swift in Sources */, @@ -1450,6 +1457,7 @@ A466A31028018CD800D655F4 /* UIWindowScene+TopMostViewController.swift in Sources */, A4569CC428111E1D001E3FD6 /* LicenseViewModel.swift in Sources */, A466A30E28018BBD00D655F4 /* UIVIewController+TopMostViewController.swift in Sources */, + A472C5FB29C2F21600097432 /* NewNoteSavingDelegate.swift in Sources */, D2C48C0127E9DFA1006FC59E /* NoteView.swift in Sources */, A49B25E72812AC2800399630 /* FontSelectionViewController.swift in Sources */, A456657E27CC77A9007CF70A /* Date+Formatted.swift in Sources */, diff --git a/Happiggy-bank/Happiggy-bank/Base/UI/Controller/CustomNavigationController.swift b/Happiggy-bank/Happiggy-bank/Base/UI/Controller/CustomNavigationController.swift index 39e31326..c3abc1b7 100644 --- a/Happiggy-bank/Happiggy-bank/Base/UI/Controller/CustomNavigationController.swift +++ b/Happiggy-bank/Happiggy-bank/Base/UI/Controller/CustomNavigationController.swift @@ -57,7 +57,7 @@ final class CustomNavigationController: UINavigationController { private func subscribeToFontPublisher() { self.cancellable = fontManager.fontPublisher - .receive(on: DispatchQueue.main) +// .receive(on: DispatchQueue.main) .sink { [weak self] in self?.updateFont(to: $0) } } diff --git a/Happiggy-bank/Happiggy-bank/Base/UI/Controller/CustomTabBarController.swift b/Happiggy-bank/Happiggy-bank/Base/UI/Controller/CustomTabBarController.swift index bd81d446..b01b9b79 100644 --- a/Happiggy-bank/Happiggy-bank/Base/UI/Controller/CustomTabBarController.swift +++ b/Happiggy-bank/Happiggy-bank/Base/UI/Controller/CustomTabBarController.swift @@ -77,7 +77,7 @@ final class CustomTabBarController: UITabBarController { private func subscribeToFontPublisher() { self.cancellable = fontManager.fontPublisher - .receive(on: DispatchQueue.main) +// .receive(on: DispatchQueue.main) .sink { [weak self] in self?.updateFont(to: $0) } } diff --git a/Happiggy-bank/Happiggy-bank/Base/UI/View/BaseButton.swift b/Happiggy-bank/Happiggy-bank/Base/UI/View/BaseButton.swift index beb27651..19b0797c 100644 --- a/Happiggy-bank/Happiggy-bank/Base/UI/View/BaseButton.swift +++ b/Happiggy-bank/Happiggy-bank/Base/UI/View/BaseButton.swift @@ -45,7 +45,7 @@ final class BaseButton: UIButton { private func subscribeToFontPublisher() { self.cancellable = fontManager.fontPublisher - .receive(on: DispatchQueue.main) +// .receive(on: DispatchQueue.main) .sink { [weak self] in self?.updateFont(to: $0, isBold: self?.titleLabel?.font.isBold == true) } diff --git a/Happiggy-bank/Happiggy-bank/Base/UI/View/BaseLabel.swift b/Happiggy-bank/Happiggy-bank/Base/UI/View/BaseLabel.swift index 2dddd3f6..8afe534c 100644 --- a/Happiggy-bank/Happiggy-bank/Base/UI/View/BaseLabel.swift +++ b/Happiggy-bank/Happiggy-bank/Base/UI/View/BaseLabel.swift @@ -45,7 +45,7 @@ final class BaseLabel: UILabel { private func subscribeToFontPublisher() { self.cancellable = fontManager.fontPublisher - .receive(on: DispatchQueue.main) +// .receive(on: DispatchQueue.main) .sink { [weak self] in self?.updateFont(to: $0, isBold: self?.font.isBold == true) } } diff --git a/Happiggy-bank/Happiggy-bank/Base/UI/View/BaseTextField.swift b/Happiggy-bank/Happiggy-bank/Base/UI/View/BaseTextField.swift index 198071c3..055fe4d5 100644 --- a/Happiggy-bank/Happiggy-bank/Base/UI/View/BaseTextField.swift +++ b/Happiggy-bank/Happiggy-bank/Base/UI/View/BaseTextField.swift @@ -45,7 +45,7 @@ final class BaseTextField: UITextField { private func subscribeToFontPublisher() { self.cancellable = fontManager.fontPublisher - .receive(on: DispatchQueue.main) +// .receive(on: DispatchQueue.main) .sink { [weak self] in self?.updateFont(to: $0, isBold: self?.font?.isBold == true) } } diff --git a/Happiggy-bank/Happiggy-bank/Base/UI/View/BaseTextView.swift b/Happiggy-bank/Happiggy-bank/Base/UI/View/BaseTextView.swift index f6650642..431b89bf 100644 --- a/Happiggy-bank/Happiggy-bank/Base/UI/View/BaseTextView.swift +++ b/Happiggy-bank/Happiggy-bank/Base/UI/View/BaseTextView.swift @@ -45,7 +45,7 @@ final class BaseTextView: UITextView { private func subscribeToFontPublisher() { self.cancellable = fontManager.fontPublisher - .receive(on: DispatchQueue.main) +// .receive(on: DispatchQueue.main) .sink { [weak self] in self?.updateFont(to: $0, isBold: self?.font?.isBold == true) } } diff --git a/Happiggy-bank/Happiggy-bank/HomeTab/Home/UI/Controller/HomeTabViewController.swift b/Happiggy-bank/Happiggy-bank/HomeTab/Home/UI/Controller/HomeTabViewController.swift index b09ae705..7b55fa7c 100644 --- a/Happiggy-bank/Happiggy-bank/HomeTab/Home/UI/Controller/HomeTabViewController.swift +++ b/Happiggy-bank/Happiggy-bank/HomeTab/Home/UI/Controller/HomeTabViewController.swift @@ -92,9 +92,10 @@ final class HomeTabViewController: UIViewController { } if bottle.isEmtpyToday { - // NewNoteTextViewController + // NewNoteInputViewController + let viewModel = NewNoteInputViewModel(date: Date(), bottle: bottle) self.navigationController?.pushViewControllerWithFade( - to: UIViewController().then { $0.view.backgroundColor = .gray } + to: NewNoteInputViewController(viewModel: viewModel) ) } else { // NewNoteDatePickerViewController diff --git a/Happiggy-bank/Happiggy-bank/HomeTab/Home/UI/Controller/HomeViewController.swift b/Happiggy-bank/Happiggy-bank/HomeTab/Home/UI/Controller/HomeViewController.swift index c255c464..c16d3b4f 100644 --- a/Happiggy-bank/Happiggy-bank/HomeTab/Home/UI/Controller/HomeViewController.swift +++ b/Happiggy-bank/Happiggy-bank/HomeTab/Home/UI/Controller/HomeViewController.swift @@ -189,14 +189,7 @@ final class HomeViewController: UIViewController { let viewModel = NewNoteDatePickerViewModel(initialDate: Date(), bottle: bottle) dateViewController.viewModel = viewModel } - if segue.identifier == SegueIdentifier.presentNewNoteTextView { - guard let textViewController = segue.destination as? NewNoteTextViewController, - let bottle = self.viewModel.bottle - else { return } - - let viewModel = NewNoteTextViewModel(date: Date(), bottle: bottle) - textViewController.viewModel = viewModel - } + if segue.identifier == SegueIdentifier.presentBottleMessageView { guard let bottleMessageController = segue.destination as? BottleMessageViewController, let (fakeBackground, bottle) = sender as? (UIView, Bottle) diff --git a/Happiggy-bank/Happiggy-bank/HomeTab/NewNote/UI/Controller/NewNoteDatePickerViewController.swift b/Happiggy-bank/Happiggy-bank/HomeTab/NewNote/UI/Controller/NewNoteDatePickerViewController.swift index 22defff1..a940b848 100644 --- a/Happiggy-bank/Happiggy-bank/HomeTab/NewNote/UI/Controller/NewNoteDatePickerViewController.swift +++ b/Happiggy-bank/Happiggy-bank/HomeTab/NewNote/UI/Controller/NewNoteDatePickerViewController.swift @@ -232,12 +232,12 @@ final class NewNoteDatePickerViewController: UIViewController { override func prepare(for segue: UIStoryboardSegue, sender: Any?) { if segue.identifier == SegueIdentifier.presentNewNoteTextViewFromDatePicker { - - guard let textViewController = segue.destination as? NewNoteTextViewController - else { return } - - let viewModel = NewNoteTextViewModel(date: self.viewModel.selectedDate, bottle: self.viewModel.bottle) - textViewController.viewModel = viewModel +// +// guard let textViewController = segue.destination as? NewNoteTextViewController +// else { return } +// +// let viewModel = NewNoteTextViewModel(date: self.viewModel.selectedDate, bottle: self.viewModel.bottle) +// textViewController.viewModel = viewModel } } } diff --git a/Happiggy-bank/Happiggy-bank/HomeTab/NewNote/UI/Controller/NewNoteInputViewController.swift b/Happiggy-bank/Happiggy-bank/HomeTab/NewNote/UI/Controller/NewNoteInputViewController.swift new file mode 100644 index 00000000..0cea86c5 --- /dev/null +++ b/Happiggy-bank/Happiggy-bank/HomeTab/NewNote/UI/Controller/NewNoteInputViewController.swift @@ -0,0 +1,470 @@ +// +// NewNoteInputViewController.swift +// Happiggy-bank +// +// Created by sun on 2022/03/10. +// + +import PhotosUI +import UIKit + +import SnapKit +import Then + +/// 새로운 쪽지를 추가할 때 사용하는 뷰 컨트롤러 +/// 쪽지 추가 시 이를 알리기 위해 델리게이트 설정 필요 +final class NewNoteInputViewController: UIViewController { + + // MARK: - Properties + + weak var delegate: NewNoteSavingDelegate? + private let viewModel: NewNoteInputViewModel + private let noteInputView = NewNoteInputView() + /// 에러 로그 방지를 위해 임의의 초기값 설정 + private let toolbar = NewNoteInputToolbar(frame: .init(origin: .zero, size: .init(width: 1000, height: 50))) + private var showWarningLabel = false + private var noteInputViewBotttomConstraint: Constraint? + private var toolbarBottomConstraint: Constraint? + + + // MARK: - Init(s) + + init(viewModel: NewNoteInputViewModel) { + self.viewModel = viewModel + super.init(nibName: nil, bundle: nil) + + self.hidesBottomBarWhenPushed = true + } + + @available(*, unavailable) + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + + // MARK: - Life Cycle + + override func viewDidLoad() { + super.viewDidLoad() + + self.configureNavigationBar() + self.configureViews() + self.configureToolbar() + } + + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + + self.noteInputView.textView.becomeFirstResponder() + self.updateCalendarButtonTitleText() + } + + + // MARK: - NavigationBar Configuration Functions + + private func configureNavigationBar() { + let cancelButton = UIBarButtonItem( + image: AssetImage.xmark, + primaryAction: .init { [weak self] _ in + self?.noteInputView.textView.endEditing(true) + self?.navigationController?.popToRootViewControllerWithFade() + } + ) + let saveButton = UIBarButtonItem( + image: AssetImage.checkmark, + primaryAction: .init { [weak self] _ in self?.saveButtonDidTap() } + ) + self.navigationItem.setLeftBarButton(cancelButton, animated: true) + self.navigationItem.setRightBarButton(saveButton, animated: true) + + self.navigationController?.navigationBar.standardAppearance.backgroundColor = .none + } + + private func saveButtonDidTap() { + let textView = self.noteInputView.textView + guard !textView.text.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty + else { + HapticManager.instance.notification(type: .error) + self.showWarningLabel = true + self.noteInputView.warningLabel.fadeIn() + self.noteInputView.placeholderLabel.fadeOut() + return + } + + textView.endEditing(true) + self.present(makeConfirmationAlert(), animated: true) + } + + private func makeConfirmationAlert() -> UIAlertController { + let confirmAction = UIAlertAction.confirmAction(title: StringLiteral.confirmButtonTitle) { [weak self] _ in + guard let text = self?.noteInputView.textView.text, + let saveStatus = self?.viewModel.saveNote(withImage: self?.noteInputView.photo, text: text) + else { + return + } + + switch saveStatus { + case .success(let note): + self?.delegate?.newNoteDidSave(note) + self?.navigationController?.popToRootViewControllerWithFade() + case .failure(let error): + self?.presentSaveFailureAlert(withDescription: error.localizedDescription) + } + } + let cancelAction = UIAlertAction.cancelAction { [weak self] _ in + self?.noteInputView.textView.becomeFirstResponder() + } + + return .basic( + alertTitle: StringLiteral.saveConfirmationAlertTitle, + alertMessage: StringLiteral.saveConfirmationAlertMessage, + confirmAction: confirmAction, + cancelAction: cancelAction + ) + } + + private func presentSaveFailureAlert(withDescription description: String) { + let alert = UIAlertController.basic( + alertTitle: StringLiteral.saveFailureAlertTItle, + alertMessage: description, + preferredStyle: .alert, + confirmAction: .confirmAction() + ) + self.present(alert, animated: true) + } + + + // MARK: - View Configuration Functions + + private func configureViews() { + self.configureSubviews() + self.configureConstraints() + self.observeKeyboardAppearnce() + } + + private func configureSubviews() { + self.view.addSubview(self.noteInputView) + self.noteInputView.backgroundNoteImageView.addGestureRecognizer(UITapGestureRecognizer( + target: self, + action: #selector(backgroundDidTap(_:)) + )) + self.updateColor() + self.configureTextView() + self.configureCalendarButton() + self.updateLetterCountLabel(count: .zero) + self.noteInputView.removePhotoButton.addAction(UIAction(handler: { [weak self] _ in + self?.noteInputView.photo = nil + self?.viewModel.newNote.imageID = nil + self?.toolbar.photoButton.isEnabled = true + }), for: .touchUpInside) + } + + @objc private func backgroundDidTap(_ sender: UITapGestureRecognizer) { + self.noteInputView.textView.resignFirstResponder() + + self.toolbarBottomConstraint?.update(inset: Int.zero) + let toolbarHeight = self.toolbar.frame.height + + self.noteInputViewBotttomConstraint?.deactivate() + self.noteInputView.snp.makeConstraints { + self.noteInputViewBotttomConstraint = $0.bottom.equalTo(self.view.safeAreaLayoutGuide) + .inset(toolbarHeight) + .priority(.high) + .constraint + } + } + + private func updateColor() { + self.view.backgroundColor = self.viewModel.backgroundColor + self.noteInputView.backgroundNoteImageView.tintColor = self.viewModel.lineColor + self.noteInputView.calendarButton.tintColor = self.viewModel.textColor + self.noteInputView.letterCountLabel.textColor = self.viewModel.textColor + self.updateCalendarButtonTitleText() + } + + private func configureCalendarButton() { + let action = UIAction { [weak self] _ in + print("move to date select view controller ") + self?.navigationController?.pushViewControllerWithFade(to: UIViewController()) + self?.noteInputView.textView.resignFirstResponder() + } + self.noteInputView.calendarButton.addAction(action, for: .touchUpInside) + self.updateCalendarButtonTitleText() + } + + private func updateCalendarButtonTitleText() { + let calendarButton = self.noteInputView.calendarButton + let customFont = (calendarButton.customFont ?? .current) + let fontSize = calendarButton.titleLabel?.font.pointSize ?? FontSize.body3 + let font = UIFont(name: customFont.regular, size: fontSize) ?? .systemFont(ofSize: fontSize) + let boldFont = UIFont(name: customFont.bold, size: fontSize) ?? .boldSystemFont(ofSize: fontSize) + let title = " \(viewModel.yearString) \(viewModel.dateString)" + .nsMutableAttributedStringify() + .color(color: viewModel.textColor ?? .black) + .font(font) + .bold(font: boldFont, targetString: viewModel.yearString) + + self.noteInputView.calendarButton.setAttributedTitle(title, for: .normal) + } + + private func configureTextView() { + self.noteInputView.textView.delegate = self + self.noteInputView.textView.becomeFirstResponder() + } + + private func updateLetterCountLabel(count: Int) { + let label = self.noteInputView.letterCountLabel + let customFont = (label.customFont ?? .current) + let fontSize = label.font.pointSize + let font = UIFont(name: customFont.regular, size: fontSize) ?? .systemFont(ofSize: fontSize) + let boldFont = UIFont(name: customFont.bold, size: fontSize) ?? .boldSystemFont(ofSize: fontSize) + let isLongerThanLimit = self.noteInputView.textView.text.count > Metric.noteTextMaxLength + let countColor = isLongerThanLimit ? AssetColor.etcAlert : self.viewModel.textColor + + let title = "\(count) / \(Metric.noteTextMaxLength)" + .nsMutableAttributedStringify() + .color(color: self.viewModel.textColor ?? .black) + .color(targetString: count.description, color: countColor ?? .black) + .font(font) + .bold(font: boldFont, targetString: count.description) + + self.noteInputView.letterCountLabel.attributedText = title + } + + func attributedLetterCountString(count: Int) -> NSMutableAttributedString { + let label = self.noteInputView.letterCountLabel + let customFont = (label.customFont ?? .current) + let fontSize = label.font.pointSize + let font = UIFont(name: customFont.regular, size: fontSize) ?? .systemFont(ofSize: fontSize) + let boldFont = UIFont(name: customFont.bold, size: fontSize) ?? .boldSystemFont(ofSize: fontSize) + let color = viewModel.textColor ?? .black + + return "\(count) / \(Metric.noteTextMaxLength)" + .nsMutableAttributedStringify() + .color(color: color) + .font(font) + .bold(font: boldFont, targetString: count.description) + } + + private func configureConstraints() { + self.noteInputView.snp.makeConstraints { + $0.top.horizontalEdges.equalTo(self.view.safeAreaLayoutGuide) + self.noteInputViewBotttomConstraint = $0.bottom.equalTo(self.view.safeAreaLayoutGuide).constraint + } + } + + private func observeKeyboardAppearnce() { + NotificationCenter.default.addObserver( + forName: UIResponder.keyboardWillShowNotification, + object: nil, + queue: nil, + using: self.updateRelatedConstraints(notification:) + ) + } + + /// 키보드에 맞춰 noteInputView의 길이와 toolbar의 위치 변경 + private func updateRelatedConstraints(notification: Notification) { + guard let info = notification.userInfo, + let keyboardFrame = info[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect + else { return } + + let keyboardHeight = keyboardFrame.height - self.view.safeAreaInsets.bottom + self.toolbarBottomConstraint?.update(inset: keyboardHeight) + + let toolbarHeight = self.toolbar.frame.height + self.noteInputViewBotttomConstraint?.deactivate() + self.noteInputView.snp.makeConstraints { + self.noteInputViewBotttomConstraint = $0.bottom.equalTo(self.view.safeAreaLayoutGuide) + .inset(keyboardHeight + toolbarHeight) + .constraint + } + } + + + // MARK: - Toolbar Configuration Functions + + private func configureToolbar() { + self.view.addSubview(self.toolbar) + self.toolbar.snp.makeConstraints { + $0.horizontalEdges.equalTo(self.view.safeAreaLayoutGuide) + self.toolbarBottomConstraint = $0.bottom.equalTo(self.view.safeAreaLayoutGuide).constraint + } + self.toolbar.photoButton.addAction(UIAction { [weak self] _ in + self?.presentPhotoPicker() }, for: .touchUpInside) + self.toolbar.colorPicker.delegate = self + } + + private func presentPhotoPicker() { + var configuration = PHPickerConfiguration(photoLibrary: .shared()) + configuration.filter = .images + + let picker = PHPickerViewController(configuration: configuration) + picker.delegate = self + self.noteInputView.textView.resignFirstResponder() + self.present(picker, animated: true) + } +} + + +// MARK: - UITextViewDelegate +extension NewNoteInputViewController: UITextViewDelegate { + + func textViewDidEndEditing(_ textView: UITextView) { + + /// 100자 초과 시 초과분 삭제 + if textView.text.count > Metric.noteTextMaxLength { + textView.text = String(textView.text.prefix(Metric.noteTextMaxLength)) + self.updateLetterCountLabel(count: textView.text.count) + } + + /// 키보드 아래로 내리는 애니메이션 + textView.resignFirstResponder() + } + + func textView( + _ textView: UITextView, + shouldChangeTextIn range: NSRange, + replacementText text: String + ) -> Bool { + + /// 텍스트가 유효한지, 편집한 범위를 찾을 수 있는 지 확인 + guard let currentText = textView.text, + Range(range, in: currentText) != nil + else { return false } + + /// 경고 라벨이 나와 있으면 숨김처리 + if self.showWarningLabel { + self.showWarningLabel = false + self.noteInputView.warningLabel.fadeOut() + } + + let updatedTextLength = textView.text.count - range.length + text.count + let trimLength = updatedTextLength - Metric.krOverflowCap + + guard updatedTextLength > Metric.krOverflowCap, + text.count >= trimLength + else { + /// 내용이 빈 상태에서 백스페이스를 누르는 경우 + if textView.text.isEmpty, text.isEmpty { + self.noteInputView.placeholderLabel.fadeIn() + } + return true + } + + /// 새로 입력된 문자열의 초과분을 삭제 + let index = text.index(text.endIndex, offsetBy: -trimLength) + let trimmedReplacementText = text[.. Note { - Note.create( - id: self.viewModel.newNote.id, - date: self.viewModel.newNote.date, - color: self.viewModel.newNote.color, - content: self.newNoteInputView.textView.text, - imageURL: imageURL, - bottle: self.viewModel.newNote.bottle - ) - } - - /// 새로 생성한 노트 엔티티를 저장하고 성공 여부에 따라 불 리턴 - private func saveAndPostNewNote() -> Bool { - guard let (errorTitle, errorMessage) = PersistenceStore.shared.saveOld() - else { return true } - - let alert = PersistenceStore.shared.makeErrorAlert( - title: errorTitle, - message: errorMessage - ) { [weak self] _ in - self?.dismissWithAnimation() - } - self.present(alert, animated: true) - - return false - } - - /// 쪽지 저장 의사를 재확인 하는 알림을 띄움 - private func showNoteSavingConfirmationAlert() { - let alert = self.makeConfirmationAlert() - self.present(alert, animated: true) - } - - /// 쪽지 저장 의사를 재확인하는 알림 생성 - private func makeConfirmationAlert() -> UIAlertController { - let confirmAction = UIAlertAction.confirmAction( - title: StringLiteral.confirmButtonTitle - ) { [weak self] _ in - - var imageURL = String?.none - - if let image = self?.newNoteInputView.photo, - image != (.error ?? UIImage()) { - guard let url = self?.viewModel.saveImage(image) - else { - let alert = UIAlertController.basic( - alertTitle: "저장에 실패했습니다.", - preferredStyle: .alert, - confirmAction: .confirmAction() - ) - self?.present(alert, animated: true) - return - } - imageURL = url - } - - guard let note = self?.makeNewNote(withImageURL: imageURL) - else { - return - } - - guard self?.saveAndPostNewNote() == true - else { - PersistenceStore.shared.delete(note) - if let imageURL = note.imageURL { - self?.viewModel.deleteImage(withImageURL: imageURL) - } - return - } - - let noteAndDelay = (note: note, delay: CATransition.transitionDuration) - self?.post(name: .noteDidAdd, object: noteAndDelay) - self?.dismissWithAnimation() - } - - let cancelAction = UIAlertAction.cancelAction { [weak self] _ in - self?.newNoteInputView.textView.becomeFirstResponder() - } - - return UIAlertController.basic( - alertTitle: StringLiteral.alertTitle, - alertMessage: StringLiteral.message, - confirmAction: confirmAction, - cancelAction: cancelAction - ) - } - - /// 페이드아웃 효과와 함께 종료 - private func dismissWithAnimation() { - self.fadeOut() - self.performSegue( - withIdentifier: SegueIdentifier.unwindFromNoteTextViewToHomeView, - sender: self - ) - } - - - // MARK: - Photo Selecting Functions - - private func presentPhotoPicker() { - var configuration = PHPickerConfiguration(photoLibrary: .shared()) - configuration.filter = .images - - let picker = PHPickerViewController(configuration: configuration) - picker.delegate = self - self.newNoteInputView.textView.resignFirstResponder() - self.present(picker, animated: true) - } - - - - // MARK: - Navigation - - override func prepare(for segue: UIStoryboardSegue, sender: Any?) { - if segue.identifier == SegueIdentifier.presentDatePickerFromNoteTextView { - guard let dateViewController = segue.destination as? NewNoteDatePickerViewController - else { return } - - let viewModel = NewNoteDatePickerViewModel( - initialDate: self.viewModel.newNote.date, - bottle: self.viewModel.newNote.bottle - ) - - dateViewController.viewModel = viewModel - dateViewController.isFromNoteTextView = true - } - } -} - - -// MARK: - UITextViewDelegate - -extension NewNoteTextViewController: UITextViewDelegate { - - func textViewDidEndEditing(_ textView: UITextView) { - - /// 100자 초과 시 초과분 삭제 - if textView.text.count > Metric.noteTextMaxLength { - textView.text = String(textView.text.prefix(Metric.noteTextMaxLength)) - self.updateLetterCountLabel(count: textView.text.count) - } - - /// 키보드 아래로 내리는 애니메이션 - textView.resignFirstResponder() - } - - func textView( - _ textView: UITextView, - shouldChangeTextIn range: NSRange, - replacementText text: String - ) -> Bool { - - /// 텍스트가 유효한지, 편집한 범위를 찾을 수 있는 지 확인 - guard let currentText = textView.text, - Range(range, in: currentText) != nil - else { return false } - - /// 경고 라벨이 나와 있으면 숨김처리 - if self.showWarningLabel { - self.showWarningLabel = false - self.newNoteInputView.warningLabel.fadeOut() - } - - var overflowCap = Metric.noteTextMaxLength - // if textView.textInputMode?.primaryLanguage == StringLiteral.korean { - // /// 한글의 경우 초성, 중성, 종성으로 이루어져 있어서 100자를 제대로 받기 위해 제한을 1글자 키움 - // overflowCap = Metric.krOverflowCap - // } - overflowCap = Metric.krOverflowCap - - let updatedTextLength = textView.text.count - range.length + text.count - let trimLength = updatedTextLength - overflowCap - - guard updatedTextLength > overflowCap, - text.count >= trimLength - else { - /// 내용이 빈 상태에서 백스페이스를 누르는 경우 - if textView.text.isEmpty, text.isEmpty { - self.newNoteInputView.placeholderLabel.fadeIn() - } - return true - } - - /// 새로 입력된 문자열의 초과분을 삭제 - let index = text.index(text.endIndex, offsetBy: -trimLength) - let trimmedReplacementText = text[.. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Happiggy-bank/Happiggy-bank/HomeTab/NewNote/ViewModel/NewNoteInputViewModel.swift b/Happiggy-bank/Happiggy-bank/HomeTab/NewNote/ViewModel/NewNoteInputViewModel.swift new file mode 100644 index 00000000..7ff32845 --- /dev/null +++ b/Happiggy-bank/Happiggy-bank/HomeTab/NewNote/ViewModel/NewNoteInputViewModel.swift @@ -0,0 +1,117 @@ +// +// NewNoteInputViewModel.swift +// Happiggy-bank +// +// Created by sun on 2023/03/16. +// + +import UIKit + +final class NewNoteInputViewModel { + + // MARK: - Properties + + /// 이미지 처리 객체 + + /// 임시 쪽지 객체 + var newNote: NewNote + + /// 배경 색상 + var backgroundColor: UIColor? { AssetColor.noteBG(for: self.newNote.color) } + + /// 테두리 줄 색상 + var lineColor: UIColor? { AssetColor.noteLine(for: self.newNote.color) } + + /// 글자 색상 + var textColor: UIColor? { AssetColor.noteText(for: self.newNote.color) } + + var yearString: String { self.newNote.date.yearString } + + var dateString: String { self.newNote.date.monthDotDayWithDayOfWeekString } + + private let imageMananger = ImageManager() + + + // MARK: - Inits + + init(date: Date, bottle: Bottle) { + self.newNote = NewNote(date: date, bottle: bottle) + } + + + // MARK: - Functions + + func saveNote(withImage image: UIImage?, text: String) -> Result { + var imageURL: String? + + switch self.saveImageIfNeeded(image) { + case .failure(let error): + return .failure(error) + case .success(let url): + imageURL = url + } + + let note = self.makeNewNote(withText: text, imageURL: imageURL) + + switch PersistenceStore.shared.save() { + case .success: + return .success(note) + case .failure(let error): + PersistenceStore.shared.delete(note) + if let imageURL { + self.deleteImage(withImageURL: imageURL) + } + return .failure(error) + } + } + + /// 이미지가 없는 경우 nil, 있는데 저장에 실패한 경우 에러, 있고 저장에 성공한 경우 경로 리턴 + private func saveImageIfNeeded(_ image: UIImage?) -> Result { + guard let image + else { + return .success(nil) + } + + guard image != .error ?? UIImage(), + let url = self.saveImage(image) + else { + return .failure(HBError.imageSaveFailure) + } + + return .success(url) + } + + /// 새로운 노트 엔티티를 생성 + private func makeNewNote(withText text: String, imageURL: String?) -> Note { + Note.create( + id: self.newNote.id, + date: self.newNote.date, + color: self.newNote.color, + content: text, + imageURL: imageURL, + bottle: self.newNote.bottle + ) + } + + /// 이미지를 저장하고, 성공한 경우 경로 엔드포인트를, 실패한 경우 nil 리턴 + private func saveImage(_ image: UIImage) -> String? { + guard let imageID = newNote.imageID + else { + return nil + } + + return self.imageMananger.saveImage(image, noteID: newNote.id, imageID: imageID) + } + + /// 인자로 주어진 경로에 있는 이미지를 삭제 + /// + /// 삭제에 실패하는 경우 한 번 더 시도하고 리턴 + private func deleteImage(withImageURL imageURL: String) { + guard !self.imageMananger.deleteImage(forNote: newNote.id, imageURL: imageURL) + else { + return + } + + self.imageMananger.deleteImage(forNote: newNote.id, imageURL: imageURL) + } +} diff --git a/Happiggy-bank/Happiggy-bank/HomeTab/NewNote/ViewModel/NewNoteTextViewModel.swift b/Happiggy-bank/Happiggy-bank/HomeTab/NewNote/ViewModel/NewNoteTextViewModel.swift deleted file mode 100644 index 4f140584..00000000 --- a/Happiggy-bank/Happiggy-bank/HomeTab/NewNote/ViewModel/NewNoteTextViewModel.swift +++ /dev/null @@ -1,106 +0,0 @@ -// -// NewNoteTextViewModel.swift -// Happiggy-bank -// -// Created by sun on 2022/03/19. -// - -import UIKit - -/// 새 쪽지 추가 텍스트 뷰에 필요한 형식으로 데이터를 변환해주는 뷰모델 -final class NewNoteTextViewModel { - - // MARK: - Properties - - /// 이미지 처리 객체 - let imageMananger = ImageManager() - - /// 임시 쪽지 객체 - var newNote: NewNote! - - /// 강조 색깔 - var tintColor: UIColor { - UIColor.noteHighlight(for: newNote.color) - } - - /// 배경 색깔 - var backgroundColor: UIColor { - UIColor.note(color: newNote.color) - } - - /// 테두리 색깔 - var borderColor: UIColor { - UIColor.noteBorder(for: newNote.color) - } - - /// 달력 버튼 제목 - var attributedDateButtonTitle: NSMutableAttributedString { - let string = self.attributedYearString - string.append(.init(string: StringLiteral.spacing)) - string.append(self.attributedMonthDayString) - - return string - } - - /// 색깔 적용하고 볼드처리한 연도 텍스트 - private var attributedYearString: NSMutableAttributedString { - self.newNote.date - .yearString - .nsMutableAttributedStringify() - .bold() - } - - /// 색깔 적용한 월, 일 텍스트 - private var attributedMonthDayString: NSMutableAttributedString { - self.newNote.date - .monthDotDayWithDayOfWeekString - .nsMutableAttributedStringify() - } - - - // MARK: - Inits - - init(date: Date, bottle: Bottle) { - self.newNote = NewNote(date: date, bottle: bottle) - } - - - // MARK: - Functions - - /// 색깔 적용한 글자수 라벨 텍스트 - func attributedLetterCountString(count: Int) -> NSMutableAttributedString { - let color = (count > NewNoteTextViewController.Metric.noteTextMaxLength) ? - UIColor.customWarningLabel : self.tintColor - - let countString = "\(count)" - .nsMutableAttributedStringify() - .bold() - .color(color: color) - - countString.append(StringLiteral.letterCountText.nsMutableAttributedStringify()) - - return countString - } - - /// 이미지를 저장하고, 성공한 경우 경로 엔드포인트를, 실패한 경우 nil 리턴 - func saveImage(_ image: UIImage) -> String? { - guard let imageID = newNote.imageID - else { - return nil - } - - return self.imageMananger.saveImage(image, noteID: newNote.id, imageID: imageID) - } - - /// 인자로 주어진 경로에 있는 이미지를 삭제 - /// - /// 삭제에 실패하는 경우 한 번 더 시도하고 리턴 - func deleteImage(withImageURL imageURL: String) { - guard !self.imageMananger.deleteImage(forNote: newNote.id, imageURL: imageURL) - else { - return - } - - self.imageMananger.deleteImage(forNote: newNote.id, imageURL: imageURL) - } -} diff --git a/Happiggy-bank/Happiggy-bank/Resource/AssetImage.swift b/Happiggy-bank/Happiggy-bank/Resource/AssetImage.swift index 8f0598d7..4b26440f 100644 --- a/Happiggy-bank/Happiggy-bank/Resource/AssetImage.swift +++ b/Happiggy-bank/Happiggy-bank/Resource/AssetImage.swift @@ -83,7 +83,7 @@ enum AssetImage { // MARK: - Note input view static let gallery = UIImage(named: "gallery") - static let date = UIImage(named: "date") + static let calendar = UIImage(named: "calendar") static let deleteImage = UIImage(named: "deleteImage") diff --git a/Happiggy-bank/Happiggy-bank/Resource/Assets.xcassets/images/buttons/newNoteInputView/date.imageset/Contents.json b/Happiggy-bank/Happiggy-bank/Resource/Assets.xcassets/images/buttons/newNoteInputView/calendar.imageset/Contents.json similarity index 100% rename from Happiggy-bank/Happiggy-bank/Resource/Assets.xcassets/images/buttons/newNoteInputView/date.imageset/Contents.json rename to Happiggy-bank/Happiggy-bank/Resource/Assets.xcassets/images/buttons/newNoteInputView/calendar.imageset/Contents.json diff --git a/Happiggy-bank/Happiggy-bank/Resource/Assets.xcassets/images/buttons/newNoteInputView/date.imageset/ico_date.svg b/Happiggy-bank/Happiggy-bank/Resource/Assets.xcassets/images/buttons/newNoteInputView/calendar.imageset/ico_date.svg similarity index 100% rename from Happiggy-bank/Happiggy-bank/Resource/Assets.xcassets/images/buttons/newNoteInputView/date.imageset/ico_date.svg rename to Happiggy-bank/Happiggy-bank/Resource/Assets.xcassets/images/buttons/newNoteInputView/calendar.imageset/ico_date.svg diff --git a/Happiggy-bank/Happiggy-bank/Utils/Constants.swift b/Happiggy-bank/Happiggy-bank/Utils/Constants.swift index d1b254a9..6a88ba99 100644 --- a/Happiggy-bank/Happiggy-bank/Utils/Constants.swift +++ b/Happiggy-bank/Happiggy-bank/Utils/Constants.swift @@ -412,72 +412,6 @@ enum Asset: String { case settings } -extension NewNoteTextViewController { - - /// NewNoteTextViewController에서 사용하는 상수값 - enum Metric { - - /// 텍스트 뷰 컨테이너 인셋: (위: 16, 왼쪽: 24, 아래: 24, 오른쪽: 24) - static let textViewInset = UIEdgeInsets( - top: 16, - left: 24, - bottom: 24, - right: 24 - ) - - /// note 의 최대 작성 가능 길이 : 100 자 - static let noteTextMaxLength = 100 - - /// 한국 글자수 제한을 위한 오버플로우 cap 추가 값: 1 - static let krOverflowCap = noteTextMaxLength + 1 - - /// 애니메이션 지속 시간: 0.2 - static let animationDuration = CATransition.transitionDuration - - /// 내용 스택이 내비게이션바, safe area top inset, 키보드 크기를 제외한 나머지 영역을 다 차지할 수 있도록 높이를 계산해서 리턴 - static func contentStackHeight( - keyboardFrame: CGRect, - navigationBarFrame: CGRect - ) -> CGFloat { - let keyboardHeight = keyboardFrame.size.height - let navigationBarHeight = navigationBarFrame.size.height - let screenHeight = UIScreen.main.bounds.height - let safeAreaTopInset = navigationBarFrame.origin.y - let removingHeight = safeAreaTopInset + navigationBarHeight + keyboardHeight - - return screenHeight - removingHeight - } - - /// 컬러 버튼 컨테이너 뷰 페이드 인 지속 시간: 0.1 - static let colorButtonContainerViewFadeInDuration: TimeInterval = 0.1 - - /// 컬러 버튼 컨테이너 뷰 페이드 아웃 지속 시간: 0.1 - static let colorButtonContainerViewFadeOutDuration: TimeInterval = 0.1 - } - - /// NewNoteTextViewController 에서 설정하는 제목들 - enum StringLiteral { - - /// 키보드 언어 설정이 한글인 경우 - static let korean = "ko-KR" - - /// 저장 확인 알림 제목 - static let alertTitle = "쪽지를 추가하시겠어요?" - - /// 알림 내용 - static let message = """ -쪽지는 하루에 한 번 작성할 수 있고, -추가 후에는 수정/삭제가 불가능합니다 -""" - - /// 취소 버튼 제목: "취소" - static let cancelButtonTitle = "취소" - - /// 확인 버튼 제목: "추가" - static let confirmButtonTitle = "추가" - } -} - extension NewNoteDatePickerViewModel { /// NoteNoteDatePickerViewModel 에서 지정하는 폰트 크기 @@ -488,26 +422,6 @@ extension NewNoteDatePickerViewModel { } } -extension NewNoteTextViewModel { - - /// NewNoteTextViewModel 에서 사용하는 문자열 - enum StringLiteral { - - /// 글자수 라벨 텍스트를 반환 - static let letterCountText = " / \(NewNoteTextViewController.Metric.noteTextMaxLength)" - - /// 날짜 레이블 간격 - static let spacing = " " - } - - /// NewNoteTextViewModel 에서 사용하는 폰트 크기 - enum Font { - - /// 날짜 버튼과 글자수 라벨 폰트 크기: 15 - static let secondaryText: CGFloat = 15 - } -} - extension SettingsViewCell { /// 상수값 diff --git a/Happiggy-bank/Happiggy-bank/Utils/Enum/HBError.swift b/Happiggy-bank/Happiggy-bank/Utils/Enum/HBError.swift new file mode 100644 index 00000000..34976cef --- /dev/null +++ b/Happiggy-bank/Happiggy-bank/Utils/Enum/HBError.swift @@ -0,0 +1,22 @@ +// +// HBError.swift +// Happiggy-bank +// +// Created by sun on 2023/03/16. +// + +import Foundation + +enum HBError: LocalizedError { + case imageSaveFailure + + + // MARK: - Properties + + var errorDescription: String? { + switch self { + case .imageSaveFailure: + return NSLocalizedString("사진 저장에 실패했습니다.", comment: "image save failure") + } + } +} diff --git a/Happiggy-bank/Happiggy-bank/Utils/Protocol/NewNoteSavingDelegate.swift b/Happiggy-bank/Happiggy-bank/Utils/Protocol/NewNoteSavingDelegate.swift new file mode 100644 index 00000000..b7b3e0fe --- /dev/null +++ b/Happiggy-bank/Happiggy-bank/Utils/Protocol/NewNoteSavingDelegate.swift @@ -0,0 +1,15 @@ +// +// NewNoteSavingDelegate.swift +// Happiggy-bank +// +// Created by sun on 2023/03/16. +// + +import Foundation + +/// 새로운 쪽지를 추가했을 때 이를 알림받아야 하는 클래스가 채택하는 프로토콜 +protocol NewNoteSavingDelegate: AnyObject { + + /// 새로운 쪽지가 추가되었음을 전달 + func newNoteDidSave(_ note: Note) +}