From a89ad1947e66ba6103cb42e5268c043697d0bf2e Mon Sep 17 00:00:00 2001 From: ksiomng Date: Tue, 25 Mar 2025 11:05:11 +0900 Subject: [PATCH 01/39] =?UTF-8?q?Fix:=20=EC=82=AC=EC=A7=84=20=EB=8F=99?= =?UTF-8?q?=EB=B4=89=ED=95=98=EA=B8=B0=20=EB=B6=80=EB=B6=84=20=EC=82=AD?= =?UTF-8?q?=EC=A0=9C=20=EC=A7=84=ED=96=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Commons/CustomTabView/CustomTabView.swift | 42 ++---- .../Commons/CustomTabView/OptionOverlay.swift | 138 +++++------------- .../WriteLetter/StationerySelectionView.swift | 22 +-- .../View/WriteLetter/UserSelectionView.swift | 23 ++- .../StationerySelectionViewModel.swift | 1 - 5 files changed, 81 insertions(+), 145 deletions(-) diff --git a/Kabinett/Presentation/Commons/CustomTabView/CustomTabView.swift b/Kabinett/Presentation/Commons/CustomTabView/CustomTabView.swift index 0e398ab9..9b8040c1 100644 --- a/Kabinett/Presentation/Commons/CustomTabView/CustomTabView.swift +++ b/Kabinett/Presentation/Commons/CustomTabView/CustomTabView.swift @@ -59,38 +59,16 @@ struct CustomTabView: View { customTabViewModel.selectedTab = oldValue } } - .overlay( - Group { - if customTabViewModel.showOptions { - OptionOverlay( - customTabViewModel: customTabViewModel, - imageViewModel: imagePickerViewModel - ) - } - } - ) - .overlay( - ImportDialog( - viewModel: customTabViewModel, - envelopeStampSelectionViewModel: envelopeStampSelectionViewModel - ) - ) - .overlay( - ImagePickerView( - imageViewModel: imagePickerViewModel, - customViewModel: customTabViewModel, - envelopeStampSelectionViewModel: envelopeStampSelectionViewModel - ) - ) - .fullScreenCover(isPresented: $customTabViewModel.showCamera) { - CameraView(imagePickerViewModel: imagePickerViewModel) - } - .sheet(isPresented: $customTabViewModel.showWriteLetterView) { - ContentWriteView( - letterContent: $letterWriteViewModel, - imageViewModel: imagePickerViewModel, - customTabViewModel: customTabViewModel - ) + .sheet(isPresented: $customTabViewModel.showOptions) { + UserSelectionView(letterContent: $letterWriteViewModel, customViewModel: customTabViewModel, imageViewModel: imagePickerViewModel) + .presentationDetents([.height(300), .large]) } +// .overlay( +// ImagePickerView( +// imageViewModel: imagePickerViewModel, +// customViewModel: customTabViewModel, +// envelopeStampSelectionViewModel: envelopeStampSelectionViewModel +// ) +// ) } } diff --git a/Kabinett/Presentation/Commons/CustomTabView/OptionOverlay.swift b/Kabinett/Presentation/Commons/CustomTabView/OptionOverlay.swift index c36e9f8e..edb13637 100644 --- a/Kabinett/Presentation/Commons/CustomTabView/OptionOverlay.swift +++ b/Kabinett/Presentation/Commons/CustomTabView/OptionOverlay.swift @@ -1,101 +1,43 @@ +//// +//// OptionOverlay.swift +//// Kabinett +//// +//// Created by 김정우 on 8/13/24. +//// // -// OptionOverlay.swift -// Kabinett +//import SwiftUI // -// Created by 김정우 on 8/13/24. +//struct OptionOverlay: View { +// @AppStorage("isFirstWrite") private var isFirstWrite: Bool = true +// @ObservedObject var customTabViewModel: CustomTabViewModel +// @State private var letterContent = LetterWriteModel() +// @State private var isWritingLetter = false +// @ObservedObject var imageViewModel: ImagePickerViewModel +// +// var body: some View { +// VStack { +// +// } +// } +//} // - -import SwiftUI - -struct OptionOverlay: View { - @AppStorage("isFirstWrite") private var isFirstWrite: Bool = true - @ObservedObject var customTabViewModel: CustomTabViewModel - @State private var letterContent = LetterWriteModel() - @State private var isWritingLetter = false - @ObservedObject var imageViewModel: ImagePickerViewModel - - var body: some View { - NavigationStack { - ZStack { - Color.black.opacity(0.8) - .edgesIgnoringSafeArea(.all) - .onTapGesture { - withAnimation { - customTabViewModel.hideOptions() - } - } - - VStack(spacing: 0) { - Spacer() - - if isFirstWrite { - OptionGuideView() - } - - HStack(spacing: 2) { - Button(action: { - customTabViewModel.showImportDialogAndHideOptions() - customTabViewModel.hideOptions() - }) { - Text("편지 보관하기") - .font(.system(size: 16)) - .fontWeight(.semibold) - .frame(maxWidth: .infinity) - .frame(height: 24) - .padding() - .background(Color.primary100) - .foregroundColor(.contentPrimary) - } - - NavigationLink("편지 쓰기") { - StationerySelectionView( - letterContent: $letterContent, - customViewModel: customTabViewModel, - imageViewModel: imageViewModel - ) - } - .font(.system(size: 16)) - .fontWeight(.semibold) - .frame(maxWidth: .infinity) - .frame(height: 24) - .padding() - .background(Color.primary100) - .foregroundColor(.contentPrimary) - } - .cornerRadius(10) - .padding(.horizontal) - .padding(.bottom, customTabViewModel.calculateOptionOverlayBottomPadding()) - } - .background(Color.clear) - } - .background(ClearBackground()) - .onDisappear { - if isFirstWrite { - isFirstWrite = false - } - } - } - } -} - - -// MARK: - 배경색 제거를 위한 코드 -struct ClearBackground: UIViewRepresentable { - public func makeUIView(context: Context) -> UIView { - let view = ClearBackgroundView() - DispatchQueue.main.async { - view.superview?.superview?.backgroundColor = .clear - } - return view - } - public func updateUIView(_ uiView: UIView, context: Context) {} -} - -class ClearBackgroundView: UIView { - open override func layoutSubviews() { - guard let parentView = superview?.superview else { - return - } - parentView.backgroundColor = .clear - } -} +//// MARK: - 배경색 제거를 위한 코드 +//struct ClearBackground: UIViewRepresentable { +// public func makeUIView(context: Context) -> UIView { +// let view = ClearBackgroundView() +// DispatchQueue.main.async { +// view.superview?.superview?.backgroundColor = .clear +// } +// return view +// } +// public func updateUIView(_ uiView: UIView, context: Context) {} +//} +// +//class ClearBackgroundView: UIView { +// open override func layoutSubviews() { +// guard let parentView = superview?.superview else { +// return +// } +// parentView.backgroundColor = .clear +// } +//} diff --git a/Kabinett/Presentation/View/WriteLetter/StationerySelectionView.swift b/Kabinett/Presentation/View/WriteLetter/StationerySelectionView.swift index 1a6b6390..83895907 100644 --- a/Kabinett/Presentation/View/WriteLetter/StationerySelectionView.swift +++ b/Kabinett/Presentation/View/WriteLetter/StationerySelectionView.swift @@ -57,20 +57,20 @@ struct StationerySelectionView: View { .padding(.horizontal, UIScreen.main.bounds.width * 0.06) } } - .sheet(isPresented: $viewModel.showModal) { - UserSelectionView(letterContent: $letterContent) - .presentationDetents([.height(300), .large]) - } - .onAppear { - viewModel.showModal = true - - Task { - await viewModel.loadStationeries() - } - } .navigationBarTitleDisplayMode(.inline) .navigationTitle("편지지 고르기") .toolbar { + ToolbarItem(placement: .topBarLeading) { + Button(action: { + customViewModel.showOptions = false + dismiss() + }) { + Image(systemName: "chevron.backward") + .foregroundColor(Color.primary900) + .imageScale(.large) + .padding(.leading, -5) + } + } ToolbarItem(placement: .topBarTrailing) { NavigationLink(destination: ContentWriteView( letterContent: $letterContent, diff --git a/Kabinett/Presentation/View/WriteLetter/UserSelectionView.swift b/Kabinett/Presentation/View/WriteLetter/UserSelectionView.swift index 63650c1b..a74da960 100644 --- a/Kabinett/Presentation/View/WriteLetter/UserSelectionView.swift +++ b/Kabinett/Presentation/View/WriteLetter/UserSelectionView.swift @@ -13,15 +13,23 @@ struct UserSelectionView: View { @Binding var letterContent: LetterWriteModel @Environment(\.dismiss) var dismiss @StateObject var viewModel : UserSelectionViewModel + @ObservedObject var customViewModel: CustomTabViewModel + @ObservedObject var imageViewModel: ImagePickerViewModel + @State private var isFullScreen = false - init(letterContent: Binding) { + init( + letterContent: Binding, + customViewModel: CustomTabViewModel, + imageViewModel: ImagePickerViewModel + ) { @Injected(WriteLetterUseCaseKey.self) var writeLetterUseCase: WriteLetterUseCase _viewModel = StateObject(wrappedValue: UserSelectionViewModel(useCase: writeLetterUseCase)) self._letterContent = letterContent + self.customViewModel = customViewModel + self.imageViewModel = imageViewModel } var body: some View { - ZStack { Color(.primary100).ignoresSafeArea() .onTapGesture { @@ -32,13 +40,22 @@ struct UserSelectionView: View { HStack { Spacer() Button("완료") { - dismiss() + isFullScreen = true } } .fontWeight(.medium) .font(.system(size: 19)) .foregroundColor(.contentPrimary) .padding(.bottom, -3) + .fullScreenCover(isPresented: $isFullScreen) { + NavigationStack { + StationerySelectionView( + letterContent: $letterContent, + customViewModel: customViewModel, + imageViewModel: imageViewModel + ) + } + } FormToUser(letterContent: $letterContent, viewModel: viewModel) diff --git a/Kabinett/Presentation/ViewModel/WriteLetter/StationerySelectionViewModel.swift b/Kabinett/Presentation/ViewModel/WriteLetter/StationerySelectionViewModel.swift index 53e425a1..2817a7be 100644 --- a/Kabinett/Presentation/ViewModel/WriteLetter/StationerySelectionViewModel.swift +++ b/Kabinett/Presentation/ViewModel/WriteLetter/StationerySelectionViewModel.swift @@ -9,7 +9,6 @@ import Foundation import SwiftUI class StationerySelectionViewModel: ObservableObject { - @Published var showModal = true @Published var selectedIndex: (Int, Int) = (0, 0) @Published var stationerys: [String] = [] From b46c6b76c591bc1d12c75317aa7311b954a22458 Mon Sep 17 00:00:00 2001 From: ksiomng Date: Tue, 25 Mar 2025 11:31:11 +0900 Subject: [PATCH 02/39] =?UTF-8?q?Fix:=20=ED=95=84=EC=9A=94=EC=97=86?= =?UTF-8?q?=EB=8A=94=20=ED=8C=8C=EC=9D=BC=EC=82=AD=EC=A0=9C,=20=EC=82=AC?= =?UTF-8?q?=EC=A7=84=20=EB=8F=99=EB=B4=89=ED=95=98=EB=8A=94=20=EB=B6=80?= =?UTF-8?q?=EB=B6=84=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Kabinett.xcodeproj/project.pbxproj | 12 ------ .../Commons/CustomTabView/CustomTabView.swift | 7 --- .../Commons/CustomTabView/ImportDialog.swift | 31 ------------- .../CustomTabView/OptionGuideView.swift | 24 ----------- .../Commons/CustomTabView/OptionOverlay.swift | 43 ------------------- .../PhotoImporting/ImagePickerView.swift | 5 +-- .../PhotoImporting/ImagePreview.swift | 14 +----- .../View/WriteLetter/ContentWriteView.swift | 3 ++ 8 files changed, 6 insertions(+), 133 deletions(-) delete mode 100644 Kabinett/Presentation/Commons/CustomTabView/ImportDialog.swift delete mode 100644 Kabinett/Presentation/Commons/CustomTabView/OptionGuideView.swift delete mode 100644 Kabinett/Presentation/Commons/CustomTabView/OptionOverlay.swift diff --git a/Kabinett.xcodeproj/project.pbxproj b/Kabinett.xcodeproj/project.pbxproj index 7ec69fb1..7bdb19c4 100644 --- a/Kabinett.xcodeproj/project.pbxproj +++ b/Kabinett.xcodeproj/project.pbxproj @@ -86,9 +86,7 @@ 57ED9CE92C74262500A4312C /* SourceHanSerifK-Regular.otf in Resources */ = {isa = PBXBuildFile; fileRef = 57ED9CE82C74262400A4312C /* SourceHanSerifK-Regular.otf */; }; 7F23AD6C2C7432B8007E1F28 /* LetterCompletionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F23AD6B2C7432B8007E1F28 /* LetterCompletionView.swift */; }; 7F397C4E2C7C0ECE00388645 /* CustomTabViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F397C4D2C7C0ECE00388645 /* CustomTabViewModel.swift */; }; - 7F397C552C7DF20C00388645 /* ImportDialog.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F397C542C7DF20C00388645 /* ImportDialog.swift */; }; 7F6CE9C02C6B2FEA0074568E /* CustomTabView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F6CE9BF2C6B2FE90074568E /* CustomTabView.swift */; }; - 7F6CE9C22C6B33DD0074568E /* OptionOverlay.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F6CE9C12C6B33DD0074568E /* OptionOverlay.swift */; }; 7F6CE9C42C6B50050074568E /* ImagePickerViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F6CE9C32C6B50050074568E /* ImagePickerViewModel.swift */; }; 7F6CE9E22C6E25500074568E /* CameraViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F6CE9E12C6E25500074568E /* CameraViewModel.swift */; }; 7F6CE9E62C6E28400074568E /* CameraView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F6CE9E52C6E28400074568E /* CameraView.swift */; }; @@ -137,7 +135,6 @@ AFCFDFC32C7C3F2A00BEFFDF /* DefaultProfileUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83949C892C71BC0F0080D72C /* DefaultProfileUseCase.swift */; }; AFCFDFC42C7C3F2A00BEFFDF /* FirestoreLetterBoxManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = AFA58F252C6AE33D00A7C569 /* FirestoreLetterBoxManager.swift */; }; AFDE7D2E2C75797A0019F2DE /* FirestorageLetterManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = AFDE7D2D2C75797A0019F2DE /* FirestorageLetterManager.swift */; }; - AFE197A02D118277003597B9 /* OptionGuideView.swift in Sources */ = {isa = PBXBuildFile; fileRef = AFE1979F2D118277003597B9 /* OptionGuideView.swift */; }; E2E0DCD12CAED20800596DF7 /* LoadingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2E0DCD02CAED20800596DF7 /* LoadingView.swift */; }; /* End PBXBuildFile section */ @@ -237,9 +234,7 @@ 57ED9CE82C74262400A4312C /* SourceHanSerifK-Regular.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "SourceHanSerifK-Regular.otf"; sourceTree = ""; }; 7F23AD6B2C7432B8007E1F28 /* LetterCompletionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LetterCompletionView.swift; sourceTree = ""; }; 7F397C4D2C7C0ECE00388645 /* CustomTabViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomTabViewModel.swift; sourceTree = ""; }; - 7F397C542C7DF20C00388645 /* ImportDialog.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImportDialog.swift; sourceTree = ""; }; 7F6CE9BF2C6B2FE90074568E /* CustomTabView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomTabView.swift; sourceTree = ""; }; - 7F6CE9C12C6B33DD0074568E /* OptionOverlay.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OptionOverlay.swift; sourceTree = ""; }; 7F6CE9C32C6B50050074568E /* ImagePickerViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImagePickerViewModel.swift; sourceTree = ""; }; 7F6CE9E12C6E25500074568E /* CameraViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CameraViewModel.swift; sourceTree = ""; }; 7F6CE9E52C6E28400074568E /* CameraView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CameraView.swift; sourceTree = ""; }; @@ -288,7 +283,6 @@ AFA75B262D013F8900DA418F /* FirestoreLetterWriteManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FirestoreLetterWriteManager.swift; sourceTree = ""; }; AFB88B582C89410600E79F90 /* DefaultWriteLetterUseCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultWriteLetterUseCase.swift; sourceTree = ""; }; AFDE7D2D2C75797A0019F2DE /* FirestorageLetterManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FirestorageLetterManager.swift; sourceTree = ""; }; - AFE1979F2D118277003597B9 /* OptionGuideView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OptionGuideView.swift; sourceTree = ""; }; E2E0DCD02CAED20800596DF7 /* LoadingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoadingView.swift; sourceTree = ""; }; /* End PBXFileReference section */ @@ -431,9 +425,6 @@ children = ( 7F6CE9BF2C6B2FE90074568E /* CustomTabView.swift */, 7F9890812C7EF5C30035CB0D /* CustomTabBar.swift */, - 7F397C542C7DF20C00388645 /* ImportDialog.swift */, - 7F6CE9C12C6B33DD0074568E /* OptionOverlay.swift */, - AFE1979F2D118277003597B9 /* OptionGuideView.swift */, ); path = CustomTabView; sourceTree = ""; @@ -1015,11 +1006,9 @@ 577157032C75D7C300E21162 /* StationerySelectionViewModel.swift in Sources */, AF9B18FA2C894B7100F3E446 /* DefaultLetterBoxUseCase.swift in Sources */, 57ED9CD52C70E4A400A4312C /* OpenSourceLicenseModalView.swift in Sources */, - 7F397C552C7DF20C00388645 /* ImportDialog.swift in Sources */, 7F7868562C7B14220083D204 /* HorizontalPadding.swift in Sources */, 8356843F2CE0A43600120EC8 /* DIContainer.swift in Sources */, 538150542C8AF04B007B1E5A /* Extension+LetterType.swift in Sources */, - AFE197A02D118277003597B9 /* OptionGuideView.swift in Sources */, AF9B18F82C894B5900F3E446 /* DefaultImportLetterUseCase.swift in Sources */, 5358E0732CE16E630089C59F /* SearchBarViewModel.swift in Sources */, 83CA92AB2C8160CB00DFB68B /* Publisher+.swift in Sources */, @@ -1088,7 +1077,6 @@ 7F6CE9E22C6E25500074568E /* CameraViewModel.swift in Sources */, 573EE1F82D2BA55B00978283 /* CustomTextEditor.swift in Sources */, 7FCAE2BC2C73157C00228FA7 /* LetterWritingView.swift in Sources */, - 7F6CE9C22C6B33DD0074568E /* OptionOverlay.swift in Sources */, 57966B9C2C7D8DAF008D650B /* EnvelopeStampSelectionViewModel.swift in Sources */, 7F6CE9C02C6B2FEA0074568E /* CustomTabView.swift in Sources */, 53FC6B822C901F7700E7D9A8 /* Extension+Collection.swift in Sources */, diff --git a/Kabinett/Presentation/Commons/CustomTabView/CustomTabView.swift b/Kabinett/Presentation/Commons/CustomTabView/CustomTabView.swift index 9b8040c1..16ac1b9e 100644 --- a/Kabinett/Presentation/Commons/CustomTabView/CustomTabView.swift +++ b/Kabinett/Presentation/Commons/CustomTabView/CustomTabView.swift @@ -63,12 +63,5 @@ struct CustomTabView: View { UserSelectionView(letterContent: $letterWriteViewModel, customViewModel: customTabViewModel, imageViewModel: imagePickerViewModel) .presentationDetents([.height(300), .large]) } -// .overlay( -// ImagePickerView( -// imageViewModel: imagePickerViewModel, -// customViewModel: customTabViewModel, -// envelopeStampSelectionViewModel: envelopeStampSelectionViewModel -// ) -// ) } } diff --git a/Kabinett/Presentation/Commons/CustomTabView/ImportDialog.swift b/Kabinett/Presentation/Commons/CustomTabView/ImportDialog.swift deleted file mode 100644 index bc9fc415..00000000 --- a/Kabinett/Presentation/Commons/CustomTabView/ImportDialog.swift +++ /dev/null @@ -1,31 +0,0 @@ -// -// ImportDialog.swift -// Kabinett -// -// Created by 김정우 on 8/27/24. -// - -import SwiftUI - -struct ImportDialog: View { - @ObservedObject var viewModel: CustomTabViewModel - @ObservedObject var envelopeStampSelectionViewModel: EnvelopeStampSelectionViewModel - - var body: some View { - EmptyView() - .confirmationDialog("편지를 보관할 방법을 선택하세요.", isPresented: $viewModel.showImportDialog, titleVisibility: .visible) { - Button("촬영하기") { - viewModel.hideOptions() - viewModel.showCamera = true - } - Button("앨범에서 가져오기") { - viewModel.hideOptions() - viewModel.showPhotoLibrary = true - } - Button("취소", role: .cancel) { - viewModel.showImportDialog = false - viewModel.showOptions = true - } - } - } -} diff --git a/Kabinett/Presentation/Commons/CustomTabView/OptionGuideView.swift b/Kabinett/Presentation/Commons/CustomTabView/OptionGuideView.swift deleted file mode 100644 index dafa5b8f..00000000 --- a/Kabinett/Presentation/Commons/CustomTabView/OptionGuideView.swift +++ /dev/null @@ -1,24 +0,0 @@ -// -// OptionGuideView.swift -// Kabinett -// -// Created by JIHYE SEOK on 12/17/24. -// - -import SwiftUI - -struct OptionGuideView: View { - var body: some View { - HStack(spacing: 0) { - Image("LetterImportGuide") - .resizable() - .scaledToFit() - .frame(width: UIScreen.main.bounds.width/2 - 8) - - Image("LetterWriteGuide") - .resizable() - .scaledToFit() - .frame(width: UIScreen.main.bounds.width/2 - 8) - } - } -} diff --git a/Kabinett/Presentation/Commons/CustomTabView/OptionOverlay.swift b/Kabinett/Presentation/Commons/CustomTabView/OptionOverlay.swift deleted file mode 100644 index edb13637..00000000 --- a/Kabinett/Presentation/Commons/CustomTabView/OptionOverlay.swift +++ /dev/null @@ -1,43 +0,0 @@ -//// -//// OptionOverlay.swift -//// Kabinett -//// -//// Created by 김정우 on 8/13/24. -//// -// -//import SwiftUI -// -//struct OptionOverlay: View { -// @AppStorage("isFirstWrite") private var isFirstWrite: Bool = true -// @ObservedObject var customTabViewModel: CustomTabViewModel -// @State private var letterContent = LetterWriteModel() -// @State private var isWritingLetter = false -// @ObservedObject var imageViewModel: ImagePickerViewModel -// -// var body: some View { -// VStack { -// -// } -// } -//} -// -//// MARK: - 배경색 제거를 위한 코드 -//struct ClearBackground: UIViewRepresentable { -// public func makeUIView(context: Context) -> UIView { -// let view = ClearBackgroundView() -// DispatchQueue.main.async { -// view.superview?.superview?.backgroundColor = .clear -// } -// return view -// } -// public func updateUIView(_ uiView: UIView, context: Context) {} -//} -// -//class ClearBackgroundView: UIView { -// open override func layoutSubviews() { -// guard let parentView = superview?.superview else { -// return -// } -// parentView.backgroundColor = .clear -// } -//} diff --git a/Kabinett/Presentation/View/ImportLetter/PhotoImporting/ImagePickerView.swift b/Kabinett/Presentation/View/ImportLetter/PhotoImporting/ImagePickerView.swift index 7d07e544..f69903a2 100644 --- a/Kabinett/Presentation/View/ImportLetter/PhotoImporting/ImagePickerView.swift +++ b/Kabinett/Presentation/View/ImportLetter/PhotoImporting/ImagePickerView.swift @@ -6,11 +6,11 @@ // import SwiftUI +import _PhotosUI_SwiftUI struct ImagePickerView: View { @ObservedObject var imageViewModel: ImagePickerViewModel @ObservedObject var customViewModel: CustomTabViewModel - @ObservedObject var envelopeStampSelectionViewModel: EnvelopeStampSelectionViewModel var body: some View { EmptyView() @@ -35,8 +35,7 @@ struct ImagePickerView: View { .fullScreenCover(isPresented: $customViewModel.showImagePreview) { ImagePreview( imageViewModel: imageViewModel, - customViewModel: customViewModel, - envelopeStampSelectionViewModel: envelopeStampSelectionViewModel + customViewModel: customViewModel ) } } diff --git a/Kabinett/Presentation/View/ImportLetter/PhotoImporting/ImagePreview.swift b/Kabinett/Presentation/View/ImportLetter/PhotoImporting/ImagePreview.swift index 777f4e3a..f601a92a 100644 --- a/Kabinett/Presentation/View/ImportLetter/PhotoImporting/ImagePreview.swift +++ b/Kabinett/Presentation/View/ImportLetter/PhotoImporting/ImagePreview.swift @@ -11,7 +11,6 @@ import SwiftUI struct ImagePreview: View { @ObservedObject private var imageViewModel: ImagePickerViewModel @ObservedObject private var customViewModel: CustomTabViewModel - @ObservedObject private var envelopeStampSelectionViewModel: EnvelopeStampSelectionViewModel @Environment(\.dismiss) var dismiss @State private var showDetailView = false @State private var showLetterWritingView = false @@ -20,12 +19,10 @@ struct ImagePreview: View { init( imageViewModel: ImagePickerViewModel, - customViewModel: CustomTabViewModel, - envelopeStampSelectionViewModel: EnvelopeStampSelectionViewModel + customViewModel: CustomTabViewModel ) { self.imageViewModel = imageViewModel self.customViewModel = customViewModel - self.envelopeStampSelectionViewModel = envelopeStampSelectionViewModel } var body: some View { @@ -75,15 +72,6 @@ struct ImagePreview: View { showDetailView: $showDetailView ) } - .sheet(isPresented: $showLetterWritingView) { - LetterWritingView( - viewModel: imageViewModel, - customViewModel: customViewModel, - envelopeStampViewModel: envelopeStampSelectionViewModel, - letterContent: $letterContent, - showEnvelopeStamp: $navigateToEnvelopeStamp - ) - } .navigationDestination(isPresented: $navigateToEnvelopeStamp) { EnvelopeStampSelectionView( letterContent: $letterContent, diff --git a/Kabinett/Presentation/View/WriteLetter/ContentWriteView.swift b/Kabinett/Presentation/View/WriteLetter/ContentWriteView.swift index 1c5b29ba..70b083dd 100644 --- a/Kabinett/Presentation/View/WriteLetter/ContentWriteView.swift +++ b/Kabinett/Presentation/View/WriteLetter/ContentWriteView.swift @@ -105,6 +105,9 @@ struct ContentWriteView: View { keyBoard = false } } + .sheet(isPresented: $customTabViewModel.showPhotoLibrary) { + ImagePickerView(imageViewModel: imageViewModel, customViewModel: customTabViewModel) + } .analyticsScreen( name: "\(type(of:self))", extraParameters: [ From 6185d6b328649d32f825c3d6ab4d8fa1a50d95e1 Mon Sep 17 00:00:00 2001 From: ksiomng Date: Tue, 25 Mar 2025 11:40:02 +0900 Subject: [PATCH 03/39] =?UTF-8?q?Fix:=20=ED=95=84=EC=9A=94=EC=97=86?= =?UTF-8?q?=EB=8A=94=20=EB=8F=99=EB=B4=89=EB=B6=80=EB=B6=84=20=EC=A3=BC?= =?UTF-8?q?=EC=84=9D=EC=B2=98=EB=A6=AC=ED=95=98=EA=B3=A0=20=ED=95=84?= =?UTF-8?q?=EC=9A=94=ED=95=9C=20=ED=8C=8C=EC=9D=BC=EB=A7=8C=20=EC=9D=B4?= =?UTF-8?q?=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Kabinett.xcodeproj/project.pbxproj | 14 +- .../PhotoImporting/ImagePreview.swift | 168 +++--- .../PhotoImporting/LetterCompletionView.swift | 312 +++++------ .../PhotoImporting/LetterWritingView.swift | 528 +++++++++--------- .../OverlappingImagesView.swift | 116 ++-- .../EnvelopeStampSelectionView.swift | 45 +- .../ImportPhoto}/CameraView.swift | 0 .../ImportPhoto}/ImageDetailView.swift | 0 .../ImportPhoto}/ImagePickerView.swift | 12 +- .../WriteLetter/LetterWriteModel.swift | 6 - 10 files changed, 591 insertions(+), 610 deletions(-) rename Kabinett/Presentation/View/{ImportLetter/Camera => WriteLetter/ImportPhoto}/CameraView.swift (100%) rename Kabinett/Presentation/View/{ImportLetter/PhotoImporting => WriteLetter/ImportPhoto}/ImageDetailView.swift (100%) rename Kabinett/Presentation/View/{ImportLetter/PhotoImporting => WriteLetter/ImportPhoto}/ImagePickerView.swift (80%) diff --git a/Kabinett.xcodeproj/project.pbxproj b/Kabinett.xcodeproj/project.pbxproj index 7bdb19c4..6a0abd17 100644 --- a/Kabinett.xcodeproj/project.pbxproj +++ b/Kabinett.xcodeproj/project.pbxproj @@ -412,11 +412,20 @@ path = Font; sourceTree = ""; }; - 7F397C4F2C7C381E00388645 /* Camera */ = { + 57F7A5532D924E8A002E1209 /* ImportPhoto */ = { isa = PBXGroup; children = ( + 7F78684B2C78B41A0083D204 /* ImagePickerView.swift */, + 7FCAE2B92C73102900228FA7 /* ImageDetailView.swift */, 7F6CE9E52C6E28400074568E /* CameraView.swift */, ); + path = ImportPhoto; + sourceTree = ""; + }; + 7F397C4F2C7C381E00388645 /* Camera */ = { + isa = PBXGroup; + children = ( + ); path = Camera; sourceTree = ""; }; @@ -433,10 +442,8 @@ isa = PBXGroup; children = ( 7FCAE2B02C73080000228FA7 /* ImagePreview.swift */, - 7FCAE2B92C73102900228FA7 /* ImageDetailView.swift */, 7FCAE2B72C730E1700228FA7 /* OverlappingImagesView.swift */, 7FCAE2BB2C73157C00228FA7 /* LetterWritingView.swift */, - 7F78684B2C78B41A0083D204 /* ImagePickerView.swift */, 7F23AD6B2C7432B8007E1F28 /* LetterCompletionView.swift */, ); path = PhotoImporting; @@ -576,6 +583,7 @@ 8366B6F32C65ECE60021FAE0 /* WriteLetter */ = { isa = PBXGroup; children = ( + 57F7A5532D924E8A002E1209 /* ImportPhoto */, 579E35F92D2BB09700F92A87 /* Cells */, 579E35F82D2BAE0300F92A87 /* Components */, 57EBE5AF2C69E5F2003ECD7F /* UserSelectionView.swift */, diff --git a/Kabinett/Presentation/View/ImportLetter/PhotoImporting/ImagePreview.swift b/Kabinett/Presentation/View/ImportLetter/PhotoImporting/ImagePreview.swift index f601a92a..3f6954f3 100644 --- a/Kabinett/Presentation/View/ImportLetter/PhotoImporting/ImagePreview.swift +++ b/Kabinett/Presentation/View/ImportLetter/PhotoImporting/ImagePreview.swift @@ -5,87 +5,87 @@ // Created by 김정우 on 8/19/24. // -import FirebaseAnalytics -import SwiftUI - -struct ImagePreview: View { - @ObservedObject private var imageViewModel: ImagePickerViewModel - @ObservedObject private var customViewModel: CustomTabViewModel - @Environment(\.dismiss) var dismiss - @State private var showDetailView = false - @State private var showLetterWritingView = false - @State private var navigateToEnvelopeStamp = false - @State private var letterContent = LetterWriteModel() - - init( - imageViewModel: ImagePickerViewModel, - customViewModel: CustomTabViewModel - ) { - self.imageViewModel = imageViewModel - self.customViewModel = customViewModel - } - - var body: some View { - NavigationStack { - ZStack { - VStack { - Spacer() - OverlappingImagesView(images: imageViewModel.photoContents, showDetailView: $showDetailView) - Spacer() - Button(action: { - if customViewModel.isLetterWrite { - dismiss() - } else { - showLetterWritingView = true - } - }) { - Text(customViewModel.isLetterWrite ? "사진 동봉하기" : "편지 선택하기") - .font(.system(size: 16)) - .fontWeight(.semibold) - .foregroundStyle(Color.white) - .frame(maxWidth: .infinity, minHeight: 56) - .background(Color.primary900) - .cornerRadius(16) - } - .padding(.horizontal, UIScreen.main.bounds.width * 0.06) - } - .padding(.bottom, LayoutHelper.shared.getSize(forSE: 0.03, forOthers: 0.0)) - } - .navigationTitle("") - .navigationBarTitleDisplayMode(.inline) - .navigationBarItems( - leading: Button(action: { - imageViewModel.resetSelections() - customViewModel.showImagePreview = false - DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { - customViewModel.showPhotoLibrary = true - } - }) { - Image(systemName: "chevron.left") - .foregroundColor(.contentPrimary) - } - ) - .background(Color.background.edgesIgnoringSafeArea(.all)) - .navigationDestination(isPresented: $showDetailView) { - ImageDetailView( - images: imageViewModel.photoContents, - showDetailView: $showDetailView - ) - } - .navigationDestination(isPresented: $navigateToEnvelopeStamp) { - EnvelopeStampSelectionView( - letterContent: $letterContent, - customTabViewModel: customViewModel, - imageViewModel: imageViewModel - ) - } - } - .analyticsScreen( - name: "\(type(of:self))", - extraParameters: [ - AnalyticsParameterScreenName: "\(type(of:self))", - AnalyticsParameterScreenClass: "\(type(of:self))", - ] - ) - } -} +//import FirebaseAnalytics +//import SwiftUI +// +//struct ImagePreview: View { +// @ObservedObject private var imageViewModel: ImagePickerViewModel +// @ObservedObject private var customViewModel: CustomTabViewModel +// @Environment(\.dismiss) var dismiss +// @State private var showDetailView = false +// @State private var showLetterWritingView = false +// @State private var navigateToEnvelopeStamp = false +// @State private var letterContent = LetterWriteModel() +// +// init( +// imageViewModel: ImagePickerViewModel, +// customViewModel: CustomTabViewModel +// ) { +// self.imageViewModel = imageViewModel +// self.customViewModel = customViewModel +// } +// +// var body: some View { +// NavigationStack { +// ZStack { +// VStack { +// Spacer() +// OverlappingImagesView(images: imageViewModel.photoContents, showDetailView: $showDetailView) +// Spacer() +// Button(action: { +// if customViewModel.isLetterWrite { +// dismiss() +// } else { +// showLetterWritingView = true +// } +// }) { +// Text(customViewModel.isLetterWrite ? "사진 동봉하기" : "편지 선택하기") +// .font(.system(size: 16)) +// .fontWeight(.semibold) +// .foregroundStyle(Color.white) +// .frame(maxWidth: .infinity, minHeight: 56) +// .background(Color.primary900) +// .cornerRadius(16) +// } +// .padding(.horizontal, UIScreen.main.bounds.width * 0.06) +// } +// .padding(.bottom, LayoutHelper.shared.getSize(forSE: 0.03, forOthers: 0.0)) +// } +// .navigationTitle("") +// .navigationBarTitleDisplayMode(.inline) +// .navigationBarItems( +// leading: Button(action: { +// imageViewModel.resetSelections() +// customViewModel.showImagePreview = false +// DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { +// customViewModel.showPhotoLibrary = true +// } +// }) { +// Image(systemName: "chevron.left") +// .foregroundColor(.contentPrimary) +// } +// ) +// .background(Color.background.edgesIgnoringSafeArea(.all)) +// .navigationDestination(isPresented: $showDetailView) { +// ImageDetailView( +// images: imageViewModel.photoContents, +// showDetailView: $showDetailView +// ) +// } +// .navigationDestination(isPresented: $navigateToEnvelopeStamp) { +// EnvelopeStampSelectionView( +// letterContent: $letterContent, +// customTabViewModel: customViewModel, +// imageViewModel: imageViewModel +// ) +// } +// } +// .analyticsScreen( +// name: "\(type(of:self))", +// extraParameters: [ +// AnalyticsParameterScreenName: "\(type(of:self))", +// AnalyticsParameterScreenClass: "\(type(of:self))", +// ] +// ) +// } +//} diff --git a/Kabinett/Presentation/View/ImportLetter/PhotoImporting/LetterCompletionView.swift b/Kabinett/Presentation/View/ImportLetter/PhotoImporting/LetterCompletionView.swift index cde20158..22f8d99d 100644 --- a/Kabinett/Presentation/View/ImportLetter/PhotoImporting/LetterCompletionView.swift +++ b/Kabinett/Presentation/View/ImportLetter/PhotoImporting/LetterCompletionView.swift @@ -5,159 +5,159 @@ // Created by 김정우 on 8/20/24. // -import FirebaseAnalytics -import SwiftUI -import Kingfisher - -struct LetterCompletionView: View { - @Binding var letterContent: LetterWriteModel - @ObservedObject var viewModel: ImagePickerViewModel - @ObservedObject var customTabViewModel: CustomTabViewModel - @ObservedObject var envelopeStampSelectionViewModel: EnvelopeStampSelectionViewModel - @Environment(\.dismiss) private var dismiss - @State private var envelopeURL: String = "" - @State private var stampURL: String = "" - - var body: some View { - NavigationStack { - ZStack { - Color.background.edgesIgnoringSafeArea(.all) - - VStack(spacing: 20) { - Spacer() - letterPreviewView - completionMessageView - Spacer() - saveButton - } - } - } - .onAppear { - Task { - await viewModel.loadAndUpdateEnvelopeAndStamp() - envelopeURL = viewModel.envelopeURL ?? letterContent.envelopeImageUrlString - stampURL = viewModel.stampURL ?? letterContent.stampImageUrlString - } - } - .analyticsScreen( - name: "\(type(of:self))", - extraParameters: [ - AnalyticsParameterScreenName: "\(type(of:self))", - AnalyticsParameterScreenClass: "\(type(of:self))", - ] - ) - } - - private var letterPreviewView: some View { - ZStack(alignment: .topLeading) { - KFImage(URL(string: letterContent.envelopeImageUrlString)) - .resizable() - .placeholder { - ProgressView() - } - .shadow(color: Color(.primary300), radius: 5, x: 3, y: 3) - .aspectRatio(9/4, contentMode: .fit) - - VStack { - HStack(alignment: .top) { - VStack(alignment: .leading, spacing: 2) { - Text("보내는 사람") - .font(.system(size: 7)) - .foregroundStyle(.contentPrimary) - Text(viewModel.fromUserName) - .font(.system(size: 14)) - .foregroundStyle(.contentPrimary) - .frame(maxWidth: UIScreen.main.bounds.width * 0.57, alignment: .leading) - } - - Spacer() - - ZStack(alignment: .topTrailing) { - KFImage(URL(string: letterContent.stampImageUrlString)) - .resizable() - .placeholder { - ProgressView() - } - .frame(width: UIScreen.main.bounds.width * 0.09, height: UIScreen.main.bounds.height * 0.046) - .aspectRatio(contentMode: .fit) - - Text(viewModel.formattedDate) - .monospaced() - .font(.system(size: 12)) - .fontWeight(.medium) - .foregroundColor(.black) - .padding(2) - .background(Color.clear) - .cornerRadius(4) - .offset(x: -UIScreen.main.bounds.width * 0.06, y: -UIScreen.main.bounds.height * 0.005) - } - } - .padding(.horizontal, 25) - .padding(.top, 25) - - Spacer() - - HStack(alignment: .top) { - Text(viewModel.postScript ?? letterContent.postScript ?? "") - .font(.system(size: 10)) - .foregroundStyle(.contentPrimary) - .frame(width: UIScreen.main.bounds.width * 0.4, alignment: .leading) - - Spacer() - - VStack(alignment: .leading, spacing: 2) { - Text("받는 사람") - .font(.system(size: 7)) - .foregroundStyle(.contentPrimary) - Text(viewModel.toUserName) - .font(.system(size: 14)) - .foregroundStyle(.contentPrimary) - .frame(maxWidth: UIScreen.main.bounds.width * 0.26, alignment: .leading) - } - } - .padding(.horizontal, 25) - .padding(.bottom, 25) - } - } - .frame(width: UIScreen.main.bounds.width * 0.85, height: UIScreen.main.bounds.width * 0.85 * 4/9) - } - - private var completionMessageView: some View { - VStack(spacing: 10) { - Text("편지가 완성되었어요.") - Text("소중한 편지를 보관할게요.") - } - .font(.system(size: 18, weight: .semibold)) - } - - private var saveButton: some View { - Button(action: { - customTabViewModel.navigateToLetterBox() - dismiss() - customTabViewModel.selectedTab = 0 - - Task { - if viewModel.postScript == nil { - viewModel.postScript = letterContent.postScript - } - - let success = await viewModel.saveImportingImage() - NotificationCenter.default.post( - name: .showToast, - object: nil, - userInfo: success ? ["message": "편지가 성공적으로 보관되었어요.", "color": Color.primary900] : ["message": "앗..!! 편지 보관을 실패했어요..", "color": Color.alert]) - } - }) { - Text("편지 보관하기") - .font(.system(size: 16)) - .fontWeight(.semibold) - .foregroundStyle(Color.white) - .frame(maxWidth: .infinity, minHeight: 56) - .background(Color.primary900) - .cornerRadius(16) - } - .padding(.horizontal, UIScreen.main.bounds.width * 0.06) - .padding(.bottom, LayoutHelper.shared.getSize(forSE: 0.03, forOthers: 0.0)) - .disabled(viewModel.isLoading) - } -} +//import FirebaseAnalytics +//import SwiftUI +//import Kingfisher +// +//struct LetterCompletionView: View { +// @Binding var letterContent: LetterWriteModel +// @ObservedObject var viewModel: ImagePickerViewModel +// @ObservedObject var customTabViewModel: CustomTabViewModel +// @ObservedObject var envelopeStampSelectionViewModel: EnvelopeStampSelectionViewModel +// @Environment(\.dismiss) private var dismiss +// @State private var envelopeURL: String = "" +// @State private var stampURL: String = "" +// +// var body: some View { +// NavigationStack { +// ZStack { +// Color.background.edgesIgnoringSafeArea(.all) +// +// VStack(spacing: 20) { +// Spacer() +// letterPreviewView +// completionMessageView +// Spacer() +// saveButton +// } +// } +// } +// .onAppear { +// Task { +// await viewModel.loadAndUpdateEnvelopeAndStamp() +// envelopeURL = viewModel.envelopeURL ?? letterContent.envelopeImageUrlString +// stampURL = viewModel.stampURL ?? letterContent.stampImageUrlString +// } +// } +// .analyticsScreen( +// name: "\(type(of:self))", +// extraParameters: [ +// AnalyticsParameterScreenName: "\(type(of:self))", +// AnalyticsParameterScreenClass: "\(type(of:self))", +// ] +// ) +// } +// +// private var letterPreviewView: some View { +// ZStack(alignment: .topLeading) { +// KFImage(URL(string: letterContent.envelopeImageUrlString)) +// .resizable() +// .placeholder { +// ProgressView() +// } +// .shadow(color: Color(.primary300), radius: 5, x: 3, y: 3) +// .aspectRatio(9/4, contentMode: .fit) +// +// VStack { +// HStack(alignment: .top) { +// VStack(alignment: .leading, spacing: 2) { +// Text("보내는 사람") +// .font(.system(size: 7)) +// .foregroundStyle(.contentPrimary) +// Text(viewModel.fromUserName) +// .font(.system(size: 14)) +// .foregroundStyle(.contentPrimary) +// .frame(maxWidth: UIScreen.main.bounds.width * 0.57, alignment: .leading) +// } +// +// Spacer() +// +// ZStack(alignment: .topTrailing) { +// KFImage(URL(string: letterContent.stampImageUrlString)) +// .resizable() +// .placeholder { +// ProgressView() +// } +// .frame(width: UIScreen.main.bounds.width * 0.09, height: UIScreen.main.bounds.height * 0.046) +// .aspectRatio(contentMode: .fit) +// +// Text(viewModel.formattedDate) +// .monospaced() +// .font(.system(size: 12)) +// .fontWeight(.medium) +// .foregroundColor(.black) +// .padding(2) +// .background(Color.clear) +// .cornerRadius(4) +// .offset(x: -UIScreen.main.bounds.width * 0.06, y: -UIScreen.main.bounds.height * 0.005) +// } +// } +// .padding(.horizontal, 25) +// .padding(.top, 25) +// +// Spacer() +// +// HStack(alignment: .top) { +// Text(viewModel.postScript ?? letterContent.postScript ?? "") +// .font(.system(size: 10)) +// .foregroundStyle(.contentPrimary) +// .frame(width: UIScreen.main.bounds.width * 0.4, alignment: .leading) +// +// Spacer() +// +// VStack(alignment: .leading, spacing: 2) { +// Text("받는 사람") +// .font(.system(size: 7)) +// .foregroundStyle(.contentPrimary) +// Text(viewModel.toUserName) +// .font(.system(size: 14)) +// .foregroundStyle(.contentPrimary) +// .frame(maxWidth: UIScreen.main.bounds.width * 0.26, alignment: .leading) +// } +// } +// .padding(.horizontal, 25) +// .padding(.bottom, 25) +// } +// } +// .frame(width: UIScreen.main.bounds.width * 0.85, height: UIScreen.main.bounds.width * 0.85 * 4/9) +// } +// +// private var completionMessageView: some View { +// VStack(spacing: 10) { +// Text("편지가 완성되었어요.") +// Text("소중한 편지를 보관할게요.") +// } +// .font(.system(size: 18, weight: .semibold)) +// } +// +// private var saveButton: some View { +// Button(action: { +// customTabViewModel.navigateToLetterBox() +// dismiss() +// customTabViewModel.selectedTab = 0 +// +// Task { +// if viewModel.postScript == nil { +// viewModel.postScript = letterContent.postScript +// } +// +// let success = await viewModel.saveImportingImage() +// NotificationCenter.default.post( +// name: .showToast, +// object: nil, +// userInfo: success ? ["message": "편지가 성공적으로 보관되었어요.", "color": Color.primary900] : ["message": "앗..!! 편지 보관을 실패했어요..", "color": Color.alert]) +// } +// }) { +// Text("편지 보관하기") +// .font(.system(size: 16)) +// .fontWeight(.semibold) +// .foregroundStyle(Color.white) +// .frame(maxWidth: .infinity, minHeight: 56) +// .background(Color.primary900) +// .cornerRadius(16) +// } +// .padding(.horizontal, UIScreen.main.bounds.width * 0.06) +// .padding(.bottom, LayoutHelper.shared.getSize(forSE: 0.03, forOthers: 0.0)) +// .disabled(viewModel.isLoading) +// } +//} diff --git a/Kabinett/Presentation/View/ImportLetter/PhotoImporting/LetterWritingView.swift b/Kabinett/Presentation/View/ImportLetter/PhotoImporting/LetterWritingView.swift index a757a0a7..1c309721 100644 --- a/Kabinett/Presentation/View/ImportLetter/PhotoImporting/LetterWritingView.swift +++ b/Kabinett/Presentation/View/ImportLetter/PhotoImporting/LetterWritingView.swift @@ -8,267 +8,267 @@ import FirebaseAnalytics import SwiftUI -struct LetterWritingView: View { - @ObservedObject var viewModel: ImagePickerViewModel - @ObservedObject var customViewModel: CustomTabViewModel - @ObservedObject var envelopeStampViewModel: EnvelopeStampSelectionViewModel - @Environment(\.dismiss) var dismiss - @Binding var letterContent: LetterWriteModel - @Binding var showEnvelopeStamp: Bool - @State private var showCalendar = false - - var body: some View { - NavigationStack { - ZStack { - Color.primary100.edgesIgnoringSafeArea(.all) - - VStack(spacing: 20) { - FormToUserView(letterContent: $letterContent, viewModel: viewModel) - dateField() - Spacer() - } - .padding([.leading, .trailing], 20) - .padding(.top, 20) - } - .onTapGesture { - UIApplication.shared.endEditing() - } - .navigationBarItems( - trailing: Button(action: { - updateLetterWrite() - dismiss() - showEnvelopeStamp = true - }) { - Text("완료") - .fontWeight(.medium) - .font(.system(size: 19)) - .foregroundColor(.contentPrimary) - } - ) - } - .task { - await viewModel.fetchCurrentWriter() - viewModel.updateDefaultUsers() - updateLetterWriteFromViewModel() - } - .analyticsScreen( - name: "\(type(of:self))", - extraParameters: [ - AnalyticsParameterScreenName: "\(type(of:self))", - AnalyticsParameterScreenClass: "\(type(of:self))", - ] - ) - } - - private func updateLetterWriteFromViewModel() { - letterContent.fromUserName = viewModel.fromUserName - letterContent.fromUserId = viewModel.fromUserId - letterContent.toUserName = viewModel.toUserName - letterContent.toUserId = viewModel.toUserId - - } - - private func dateField() -> some View { - VStack(spacing: 1) { - HStack(alignment: .center, spacing: 10) { - Text("받은/보낸 날짜") - .foregroundStyle(Color.contentPrimary) - .bold() - .font(.system(size: 16)) - .frame(width: 100, alignment: .leading) - - Button(action: { - showCalendar.toggle() - }) { - Text(viewModel.formattedDate) - .foregroundStyle(Color.blue) - .font(.system(size: 15)) - .padding(.horizontal, 15) - .frame(height: 40) - .frame(maxWidth: .infinity) - .background(Color.contentTertiary) - .clipShape(RoundedRectangle(cornerRadius: 8)) - } - } - } - .sheet(isPresented: $showCalendar) { - DatePicker("", selection: $viewModel.date, displayedComponents: [.date]) - .datePickerStyle(.graphical) - .frame(maxHeight: 350) - .background(Color.white) - .cornerRadius(5) - .shadow(color: Color.black.opacity(0.1), radius: 5, x: 0, y: 2) - .padding() - .presentationDetents([.height(470)]) - .presentationBackground(.clear) - .presentationCornerRadius(5) - .interactiveDismissDisabled() - .onChange(of: viewModel.date) { oldValue, newValue in - if oldValue != newValue { - letterContent.date = newValue - DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { - showCalendar = false - } - } - } - } - } - - private func updateLetterWrite() { - letterContent.fromUserName = viewModel.fromUserName - letterContent.toUserName = viewModel.toUserName - letterContent.date = viewModel.date - letterContent.photoContents = viewModel.photoContents - letterContent.dataSource = .importLetter - } -} - -struct FormToUserView: View { - @Binding var letterContent: LetterWriteModel - @ObservedObject var viewModel: ImagePickerViewModel - - var body: some View { - VStack(spacing: 20) { - userField(title: "보내는 사람", name: $viewModel.fromUserName, search: $viewModel.fromUserSearch, isFromUser: true) - userField(title: "받는 사람", name: $viewModel.toUserName, search: $viewModel.toUserSearch, isFromUser: false) - } - - .onAppear { - if let fromUser = viewModel.fromUser { - letterContent.fromUserId = fromUser.id - letterContent.fromUserName = fromUser.name - viewModel.fromUserName = fromUser.name - viewModel.fromUserKabinettNumber = fromUser.kabinettNumber - } - - letterContent.toUserId = letterContent.fromUserId - letterContent.toUserName = letterContent.fromUserName - viewModel.toUserId = letterContent.fromUserId - viewModel.toUserName = letterContent.fromUserName - viewModel.toUserKabinettNumber = viewModel.fromUserKabinettNumber - } - - } - - private func userField(title: String, name: Binding, search: Binding, isFromUser: Bool) -> some View { - VStack(spacing: 10) { - HStack(alignment: .center, spacing: 10) { - Text(title) - .foregroundStyle(Color.contentPrimary) - .font(.system(size: 16)) - .bold() - .frame(width: 100, alignment: .leading) - - TextField(isFromUser ? name.wrappedValue : "", text: name) - .foregroundStyle(isFromUser ? Color.contentSecondary : .black) - .font(.system(size: 15)) - .padding(.horizontal, 15) - .frame(height: 40) - .background(Color.white) - .clipShape(RoundedRectangle(cornerRadius: 20)) - .multilineTextAlignment(.center) - } - - HStack(alignment: .center, spacing: 10) { - Spacer() - .frame(width: 100) - - SearchResultList(letterContent: $letterContent, searchText: search, viewModel: viewModel, isFromUser: isFromUser) - } - } - } - - struct SearchResultList: View { - @Binding var letterContent: LetterWriteModel - @Binding var searchText: String - @ObservedObject var viewModel: ImagePickerViewModel - let isFromUser: Bool - - var body: some View { - VStack { - HStack { - Image(systemName: "magnifyingglass") - .foregroundStyle(Color.contentPrimary) - - TextField("검색", text: $searchText) - .foregroundStyle(.primary) - - if !searchText.isEmpty { - Button(action: { - self.searchText = "" - }) { - Image(systemName: "xmark.circle.fill") - .foregroundStyle(Color.primary100) - } - } - } - .padding(EdgeInsets(top: 7, leading: 13, bottom: 7, trailing: 13)) - .background(Color(.white)) - .clipShape(.capsule) - - if !searchText.isEmpty { - Divider() - .padding([.leading, .trailing], 10) - .padding(.top, -6) - - List { - Text("\(searchText) 입력") - .onTapGesture { - updateUser(name: searchText) - searchText = "" - UIApplication.shared.endEditing() - } - .padding(.leading, 35) - .listRowSeparator(.hidden) - .foregroundStyle(Color.primary900) - - ForEach(isFromUser ? viewModel.fromUserSearchResults : viewModel.toUserSearchResults, id: \.name) { user in - HStack { - Image(systemName: "person.crop.circle") - .resizable() - .frame(width: 25, height: 25) - .clipShape(.circle) - .foregroundStyle(Color.primary100) - Text(user.name) - .foregroundStyle(Color.primary900) - Spacer() - Text("\(String(user.kabinettNumber.prefix(3)))-\(String(user.kabinettNumber.suffix(3)))") - .foregroundStyle(Color.primary900) - } - .listRowSeparator(.hidden) - .onTapGesture { - updateUser(name: user.name) - searchText = "" - UIApplication.shared.endEditing() - } - } - } - .listStyle(PlainListStyle()) - .frame(height: 200) - .background(Color.white) - .cornerRadius(20) - .padding(.top, -5) - } - } - .padding(.top, 2) - .background(searchText.isEmpty ? Color.clear : Color.white) - .cornerRadius(16) - } - - private func updateUser(name: String) { - if isFromUser { - viewModel.fromUserName = name - letterContent.fromUserName = name - if let user = viewModel.usersData.first(where: { $0.name == name }) { - letterContent.fromUserId = user.id - viewModel.fromUserKabinettNumber = user.kabinettNumber - } else { - viewModel.fromUserId = "" - viewModel.fromUserKabinettNumber = 0 - } - } else { - viewModel.updateSelectedUser(selectedUserName: name) - } - } - } -} +//struct LetterWritingView: View { +// @ObservedObject var viewModel: ImagePickerViewModel +// @ObservedObject var customViewModel: CustomTabViewModel +// @ObservedObject var envelopeStampViewModel: EnvelopeStampSelectionViewModel +// @Environment(\.dismiss) var dismiss +// @Binding var letterContent: LetterWriteModel +// @Binding var showEnvelopeStamp: Bool +// @State private var showCalendar = false +// +// var body: some View { +// NavigationStack { +// ZStack { +// Color.primary100.edgesIgnoringSafeArea(.all) +// +// VStack(spacing: 20) { +// FormToUserView(letterContent: $letterContent, viewModel: viewModel) +// dateField() +// Spacer() +// } +// .padding([.leading, .trailing], 20) +// .padding(.top, 20) +// } +// .onTapGesture { +// UIApplication.shared.endEditing() +// } +// .navigationBarItems( +// trailing: Button(action: { +// updateLetterWrite() +// dismiss() +// showEnvelopeStamp = true +// }) { +// Text("완료") +// .fontWeight(.medium) +// .font(.system(size: 19)) +// .foregroundColor(.contentPrimary) +// } +// ) +// } +// .task { +// await viewModel.fetchCurrentWriter() +// viewModel.updateDefaultUsers() +// updateLetterWriteFromViewModel() +// } +// .analyticsScreen( +// name: "\(type(of:self))", +// extraParameters: [ +// AnalyticsParameterScreenName: "\(type(of:self))", +// AnalyticsParameterScreenClass: "\(type(of:self))", +// ] +// ) +// } +// +// private func updateLetterWriteFromViewModel() { +// letterContent.fromUserName = viewModel.fromUserName +// letterContent.fromUserId = viewModel.fromUserId +// letterContent.toUserName = viewModel.toUserName +// letterContent.toUserId = viewModel.toUserId +// +// } +// +// private func dateField() -> some View { +// VStack(spacing: 1) { +// HStack(alignment: .center, spacing: 10) { +// Text("받은/보낸 날짜") +// .foregroundStyle(Color.contentPrimary) +// .bold() +// .font(.system(size: 16)) +// .frame(width: 100, alignment: .leading) +// +// Button(action: { +// showCalendar.toggle() +// }) { +// Text(viewModel.formattedDate) +// .foregroundStyle(Color.blue) +// .font(.system(size: 15)) +// .padding(.horizontal, 15) +// .frame(height: 40) +// .frame(maxWidth: .infinity) +// .background(Color.contentTertiary) +// .clipShape(RoundedRectangle(cornerRadius: 8)) +// } +// } +// } +// .sheet(isPresented: $showCalendar) { +// DatePicker("", selection: $viewModel.date, displayedComponents: [.date]) +// .datePickerStyle(.graphical) +// .frame(maxHeight: 350) +// .background(Color.white) +// .cornerRadius(5) +// .shadow(color: Color.black.opacity(0.1), radius: 5, x: 0, y: 2) +// .padding() +// .presentationDetents([.height(470)]) +// .presentationBackground(.clear) +// .presentationCornerRadius(5) +// .interactiveDismissDisabled() +// .onChange(of: viewModel.date) { oldValue, newValue in +// if oldValue != newValue { +// letterContent.date = newValue +// DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { +// showCalendar = false +// } +// } +// } +// } +// } +// +// private func updateLetterWrite() { +// letterContent.fromUserName = viewModel.fromUserName +// letterContent.toUserName = viewModel.toUserName +// letterContent.date = viewModel.date +// letterContent.photoContents = viewModel.photoContents +// letterContent.dataSource = .importLetter +// } +//} +// +//struct FormToUserView: View { +// @Binding var letterContent: LetterWriteModel +// @ObservedObject var viewModel: ImagePickerViewModel +// +// var body: some View { +// VStack(spacing: 20) { +// userField(title: "보내는 사람", name: $viewModel.fromUserName, search: $viewModel.fromUserSearch, isFromUser: true) +// userField(title: "받는 사람", name: $viewModel.toUserName, search: $viewModel.toUserSearch, isFromUser: false) +// } +// +// .onAppear { +// if let fromUser = viewModel.fromUser { +// letterContent.fromUserId = fromUser.id +// letterContent.fromUserName = fromUser.name +// viewModel.fromUserName = fromUser.name +// viewModel.fromUserKabinettNumber = fromUser.kabinettNumber +// } +// +// letterContent.toUserId = letterContent.fromUserId +// letterContent.toUserName = letterContent.fromUserName +// viewModel.toUserId = letterContent.fromUserId +// viewModel.toUserName = letterContent.fromUserName +// viewModel.toUserKabinettNumber = viewModel.fromUserKabinettNumber +// } +// +// } +// +// private func userField(title: String, name: Binding, search: Binding, isFromUser: Bool) -> some View { +// VStack(spacing: 10) { +// HStack(alignment: .center, spacing: 10) { +// Text(title) +// .foregroundStyle(Color.contentPrimary) +// .font(.system(size: 16)) +// .bold() +// .frame(width: 100, alignment: .leading) +// +// TextField(isFromUser ? name.wrappedValue : "", text: name) +// .foregroundStyle(isFromUser ? Color.contentSecondary : .black) +// .font(.system(size: 15)) +// .padding(.horizontal, 15) +// .frame(height: 40) +// .background(Color.white) +// .clipShape(RoundedRectangle(cornerRadius: 20)) +// .multilineTextAlignment(.center) +// } +// +// HStack(alignment: .center, spacing: 10) { +// Spacer() +// .frame(width: 100) +// +// SearchResultList(letterContent: $letterContent, searchText: search, viewModel: viewModel, isFromUser: isFromUser) +// } +// } +// } +// +// struct SearchResultList: View { +// @Binding var letterContent: LetterWriteModel +// @Binding var searchText: String +// @ObservedObject var viewModel: ImagePickerViewModel +// let isFromUser: Bool +// +// var body: some View { +// VStack { +// HStack { +// Image(systemName: "magnifyingglass") +// .foregroundStyle(Color.contentPrimary) +// +// TextField("검색", text: $searchText) +// .foregroundStyle(.primary) +// +// if !searchText.isEmpty { +// Button(action: { +// self.searchText = "" +// }) { +// Image(systemName: "xmark.circle.fill") +// .foregroundStyle(Color.primary100) +// } +// } +// } +// .padding(EdgeInsets(top: 7, leading: 13, bottom: 7, trailing: 13)) +// .background(Color(.white)) +// .clipShape(.capsule) +// +// if !searchText.isEmpty { +// Divider() +// .padding([.leading, .trailing], 10) +// .padding(.top, -6) +// +// List { +// Text("\(searchText) 입력") +// .onTapGesture { +// updateUser(name: searchText) +// searchText = "" +// UIApplication.shared.endEditing() +// } +// .padding(.leading, 35) +// .listRowSeparator(.hidden) +// .foregroundStyle(Color.primary900) +// +// ForEach(isFromUser ? viewModel.fromUserSearchResults : viewModel.toUserSearchResults, id: \.name) { user in +// HStack { +// Image(systemName: "person.crop.circle") +// .resizable() +// .frame(width: 25, height: 25) +// .clipShape(.circle) +// .foregroundStyle(Color.primary100) +// Text(user.name) +// .foregroundStyle(Color.primary900) +// Spacer() +// Text("\(String(user.kabinettNumber.prefix(3)))-\(String(user.kabinettNumber.suffix(3)))") +// .foregroundStyle(Color.primary900) +// } +// .listRowSeparator(.hidden) +// .onTapGesture { +// updateUser(name: user.name) +// searchText = "" +// UIApplication.shared.endEditing() +// } +// } +// } +// .listStyle(PlainListStyle()) +// .frame(height: 200) +// .background(Color.white) +// .cornerRadius(20) +// .padding(.top, -5) +// } +// } +// .padding(.top, 2) +// .background(searchText.isEmpty ? Color.clear : Color.white) +// .cornerRadius(16) +// } +// +// private func updateUser(name: String) { +// if isFromUser { +// viewModel.fromUserName = name +// letterContent.fromUserName = name +// if let user = viewModel.usersData.first(where: { $0.name == name }) { +// letterContent.fromUserId = user.id +// viewModel.fromUserKabinettNumber = user.kabinettNumber +// } else { +// viewModel.fromUserId = "" +// viewModel.fromUserKabinettNumber = 0 +// } +// } else { +// viewModel.updateSelectedUser(selectedUserName: name) +// } +// } +// } +//} diff --git a/Kabinett/Presentation/View/ImportLetter/PhotoImporting/OverlappingImagesView.swift b/Kabinett/Presentation/View/ImportLetter/PhotoImporting/OverlappingImagesView.swift index 211f329f..270d2426 100644 --- a/Kabinett/Presentation/View/ImportLetter/PhotoImporting/OverlappingImagesView.swift +++ b/Kabinett/Presentation/View/ImportLetter/PhotoImporting/OverlappingImagesView.swift @@ -5,61 +5,61 @@ // Created by 김정우 on 8/19/24. // -import SwiftUI - -struct OverlappingImagesView: View { - let images: [Data] - @Binding var showDetailView: Bool - - var body: some View { - GeometryReader { geometry in - ZStack { - ForEach(Array(images.prefix(3).enumerated().reversed()), id: \.offset) { index, imageData in - if let uiImage = UIImage(data: imageData) { - ImageView(uiImage: uiImage, index: index, totalImages: images.prefix(3).count, parentSize: geometry.size) - } - } - } - .frame(width: geometry.size.width, height: geometry.size.height) - .onTapGesture { - showDetailView = true - } - } - } -} - -struct ImageView: View { - let uiImage: UIImage - let index: Int - let totalImages: Int - let parentSize: CGSize - - var body: some View { - Image(uiImage: uiImage) - .resizable() - .aspectRatio(contentMode: .fill) - .frame(width: frameSize.width, height: frameSize.height) - .clipShape(RoundedRectangle(cornerRadius: 2)) - .rotationEffect(.degrees(rotationAngle), anchor: .center) - .position(x: parentSize.width / 2, y: parentSize.height / 2) - .shadow(color: .black.opacity(0.2), radius: 5, x: 0, y: 2) - } - - private var frameSize: CGSize { - let aspectRatio = uiImage.size.width / uiImage.size.height - let maxWidth = parentSize.width * 0.6 - let maxHeight = parentSize.height * 0.5 - - if aspectRatio > 1 { - let height = min(maxHeight, maxWidth / aspectRatio) - return CGSize(width: height * aspectRatio, height: height) - } else { - let width = min(maxWidth, maxHeight * aspectRatio) - return CGSize(width: width, height: width / aspectRatio) - } - } - - private var rotationAngle: Double { - Double(index) * -15 - } -} +//import SwiftUI +// +//struct OverlappingImagesView: View { +// let images: [Data] +// @Binding var showDetailView: Bool +// +// var body: some View { +// GeometryReader { geometry in +// ZStack { +// ForEach(Array(images.prefix(3).enumerated().reversed()), id: \.offset) { index, imageData in +// if let uiImage = UIImage(data: imageData) { +// ImageView(uiImage: uiImage, index: index, totalImages: images.prefix(3).count, parentSize: geometry.size) +// } +// } +// } +// .frame(width: geometry.size.width, height: geometry.size.height) +// .onTapGesture { +// showDetailView = true +// } +// } +// } +//} +// +//struct ImageView: View { +// let uiImage: UIImage +// let index: Int +// let totalImages: Int +// let parentSize: CGSize +// +// var body: some View { +// Image(uiImage: uiImage) +// .resizable() +// .aspectRatio(contentMode: .fill) +// .frame(width: frameSize.width, height: frameSize.height) +// .clipShape(RoundedRectangle(cornerRadius: 2)) +// .rotationEffect(.degrees(rotationAngle), anchor: .center) +// .position(x: parentSize.width / 2, y: parentSize.height / 2) +// .shadow(color: .black.opacity(0.2), radius: 5, x: 0, y: 2) +// } +// +// private var frameSize: CGSize { +// let aspectRatio = uiImage.size.width / uiImage.size.height +// let maxWidth = parentSize.width * 0.6 +// let maxHeight = parentSize.height * 0.5 +// +// if aspectRatio > 1 { +// let height = min(maxHeight, maxWidth / aspectRatio) +// return CGSize(width: height * aspectRatio, height: height) +// } else { +// let width = min(maxWidth, maxHeight * aspectRatio) +// return CGSize(width: width, height: width / aspectRatio) +// } +// } +// +// private var rotationAngle: Double { +// Double(index) * -15 +// } +//} diff --git a/Kabinett/Presentation/View/WriteLetter/EnvelopeStampSelectionView.swift b/Kabinett/Presentation/View/WriteLetter/EnvelopeStampSelectionView.swift index ae4a87ac..c13abf92 100644 --- a/Kabinett/Presentation/View/WriteLetter/EnvelopeStampSelectionView.swift +++ b/Kabinett/Presentation/View/WriteLetter/EnvelopeStampSelectionView.swift @@ -80,16 +80,9 @@ struct EnvelopeStampSelectionView: View { .task { await viewModel.loadStamps() await viewModel.loadEnvelopes() - - if letterContent.dataSource == .importLetter { - await imageViewModel.loadAndUpdateEnvelopeAndStamp() - envelopeImageUrl = imageViewModel.envelopeURL ?? "" - stampImageUrl = imageViewModel.stampURL ?? "" - } else { - await imageViewModel.loadAndUpdateEnvelopeAndStamp() - envelopeImageUrl = letterContent.envelopeImageUrlString - stampImageUrl = letterContent.stampImageUrlString - } + await imageViewModel.loadAndUpdateEnvelopeAndStamp() + envelopeImageUrl = letterContent.envelopeImageUrlString + stampImageUrl = letterContent.stampImageUrlString } .onChange(of: envelopeImageUrl) { _, newValue in imageViewModel.updateEnvelopeAndStamp(envelope: newValue, stamp: stampImageUrl) @@ -103,29 +96,15 @@ struct EnvelopeStampSelectionView: View { .navigationTitle("봉투와 우표 고르기") .toolbar { ToolbarItem(placement: .topBarTrailing) { - if letterContent.dataSource == .importLetter { - NavigationLink(destination: LetterCompletionView( - letterContent: $letterContent, - viewModel: imageViewModel, - customTabViewModel: customTabViewModel, - envelopeStampSelectionViewModel: viewModel - )) { - Text("다음") - .fontWeight(.medium) - .font(.system(size: 19)) - .foregroundStyle(.contentPrimary) - } - } else { - NavigationLink(destination: PreviewLetterView( - letterContent: $letterContent, - customTabViewModel: customTabViewModel, - imagePickerViewModel: imageViewModel - )) { - Text("다음") - .fontWeight(.medium) - .font(.system(size: 19)) - .foregroundStyle(.contentPrimary) - } + NavigationLink(destination: PreviewLetterView( + letterContent: $letterContent, + customTabViewModel: customTabViewModel, + imagePickerViewModel: imageViewModel + )) { + Text("다음") + .fontWeight(.medium) + .font(.system(size: 19)) + .foregroundStyle(.contentPrimary) } } } diff --git a/Kabinett/Presentation/View/ImportLetter/Camera/CameraView.swift b/Kabinett/Presentation/View/WriteLetter/ImportPhoto/CameraView.swift similarity index 100% rename from Kabinett/Presentation/View/ImportLetter/Camera/CameraView.swift rename to Kabinett/Presentation/View/WriteLetter/ImportPhoto/CameraView.swift diff --git a/Kabinett/Presentation/View/ImportLetter/PhotoImporting/ImageDetailView.swift b/Kabinett/Presentation/View/WriteLetter/ImportPhoto/ImageDetailView.swift similarity index 100% rename from Kabinett/Presentation/View/ImportLetter/PhotoImporting/ImageDetailView.swift rename to Kabinett/Presentation/View/WriteLetter/ImportPhoto/ImageDetailView.swift diff --git a/Kabinett/Presentation/View/ImportLetter/PhotoImporting/ImagePickerView.swift b/Kabinett/Presentation/View/WriteLetter/ImportPhoto/ImagePickerView.swift similarity index 80% rename from Kabinett/Presentation/View/ImportLetter/PhotoImporting/ImagePickerView.swift rename to Kabinett/Presentation/View/WriteLetter/ImportPhoto/ImagePickerView.swift index f69903a2..305442da 100644 --- a/Kabinett/Presentation/View/ImportLetter/PhotoImporting/ImagePickerView.swift +++ b/Kabinett/Presentation/View/WriteLetter/ImportPhoto/ImagePickerView.swift @@ -32,11 +32,11 @@ struct ImagePickerView: View { customViewModel.showImagePreview = true } } - .fullScreenCover(isPresented: $customViewModel.showImagePreview) { - ImagePreview( - imageViewModel: imageViewModel, - customViewModel: customViewModel - ) - } +// .fullScreenCover(isPresented: $customViewModel.showImagePreview) { +// ImagePreview( +// imageViewModel: imageViewModel, +// customViewModel: customViewModel +// ) +// } } } diff --git a/Kabinett/Presentation/ViewModel/WriteLetter/LetterWriteModel.swift b/Kabinett/Presentation/ViewModel/WriteLetter/LetterWriteModel.swift index 448e4e27..2dcb0721 100644 --- a/Kabinett/Presentation/ViewModel/WriteLetter/LetterWriteModel.swift +++ b/Kabinett/Presentation/ViewModel/WriteLetter/LetterWriteModel.swift @@ -27,10 +27,4 @@ class LetterWriteModel: ObservableObject { @Published var date: Date = Date() @Published var stationeryImageUrlString: String? = nil @Published var isRead: Bool = false - @Published var dataSource: DataSource = .writeLetter - - enum DataSource { - case writeLetter - case importLetter - } } From 2f382036b5a89e520b73dfbb5b037d0461405a80 Mon Sep 17 00:00:00 2001 From: ksiomng Date: Tue, 25 Mar 2025 11:49:32 +0900 Subject: [PATCH 04/39] =?UTF-8?q?Fix:=20=ED=95=84=EC=9A=94=EC=97=86?= =?UTF-8?q?=EB=8A=94=20=EB=B7=B0=20=EB=A8=BC=EC=A0=80=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Kabinett.xcodeproj/project.pbxproj | 44 --- .../Presentation/View/ImportLetter/.gitkeep | 0 .../View/ImportLetter/HorizontalPadding.swift | 28 -- .../PhotoImporting/ImagePreview.swift | 91 ------ .../PhotoImporting/LetterCompletionView.swift | 163 ----------- .../PhotoImporting/LetterWritingView.swift | 274 ------------------ .../OverlappingImagesView.swift | 65 ----- 7 files changed, 665 deletions(-) delete mode 100644 Kabinett/Presentation/View/ImportLetter/.gitkeep delete mode 100644 Kabinett/Presentation/View/ImportLetter/HorizontalPadding.swift delete mode 100644 Kabinett/Presentation/View/ImportLetter/PhotoImporting/ImagePreview.swift delete mode 100644 Kabinett/Presentation/View/ImportLetter/PhotoImporting/LetterCompletionView.swift delete mode 100644 Kabinett/Presentation/View/ImportLetter/PhotoImporting/LetterWritingView.swift delete mode 100644 Kabinett/Presentation/View/ImportLetter/PhotoImporting/OverlappingImagesView.swift diff --git a/Kabinett.xcodeproj/project.pbxproj b/Kabinett.xcodeproj/project.pbxproj index 6a0abd17..ccb8016c 100644 --- a/Kabinett.xcodeproj/project.pbxproj +++ b/Kabinett.xcodeproj/project.pbxproj @@ -84,19 +84,14 @@ 57ED9CE52C73760800A4312C /* goormSansOTF4.otf in Resources */ = {isa = PBXBuildFile; fileRef = 57ED9CE42C73760800A4312C /* goormSansOTF4.otf */; }; 57ED9CE72C73780100A4312C /* Pecita.otf in Resources */ = {isa = PBXBuildFile; fileRef = 57ED9CE62C73780100A4312C /* Pecita.otf */; }; 57ED9CE92C74262500A4312C /* SourceHanSerifK-Regular.otf in Resources */ = {isa = PBXBuildFile; fileRef = 57ED9CE82C74262400A4312C /* SourceHanSerifK-Regular.otf */; }; - 7F23AD6C2C7432B8007E1F28 /* LetterCompletionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F23AD6B2C7432B8007E1F28 /* LetterCompletionView.swift */; }; 7F397C4E2C7C0ECE00388645 /* CustomTabViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F397C4D2C7C0ECE00388645 /* CustomTabViewModel.swift */; }; 7F6CE9C02C6B2FEA0074568E /* CustomTabView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F6CE9BF2C6B2FE90074568E /* CustomTabView.swift */; }; 7F6CE9C42C6B50050074568E /* ImagePickerViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F6CE9C32C6B50050074568E /* ImagePickerViewModel.swift */; }; 7F6CE9E22C6E25500074568E /* CameraViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F6CE9E12C6E25500074568E /* CameraViewModel.swift */; }; 7F6CE9E62C6E28400074568E /* CameraView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F6CE9E52C6E28400074568E /* CameraView.swift */; }; 7F78684C2C78B41A0083D204 /* ImagePickerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F78684B2C78B41A0083D204 /* ImagePickerView.swift */; }; - 7F7868562C7B14220083D204 /* HorizontalPadding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F7868552C7B14220083D204 /* HorizontalPadding.swift */; }; 7F9890822C7EF5C30035CB0D /* CustomTabBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F9890812C7EF5C30035CB0D /* CustomTabBar.swift */; }; - 7FCAE2B12C73080000228FA7 /* ImagePreview.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7FCAE2B02C73080000228FA7 /* ImagePreview.swift */; }; - 7FCAE2B82C730E1700228FA7 /* OverlappingImagesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7FCAE2B72C730E1700228FA7 /* OverlappingImagesView.swift */; }; 7FCAE2BA2C73102900228FA7 /* ImageDetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7FCAE2B92C73102900228FA7 /* ImageDetailView.swift */; }; - 7FCAE2BC2C73157C00228FA7 /* LetterWritingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7FCAE2BB2C73157C00228FA7 /* LetterWritingView.swift */; }; 8314013F2C69C34500F601FB /* Letter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8314013E2C69C34500F601FB /* Letter.swift */; }; 832C72672C71CF7B0071E8D0 /* SignUpUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 832C72662C71CF7B0071E8D0 /* SignUpUseCase.swift */; }; 8356843D2CE0A43600120EC8 /* ServiceKeys.swift in Sources */ = {isa = PBXBuildFile; fileRef = 835684352CE0A43600120EC8 /* ServiceKeys.swift */; }; @@ -232,19 +227,14 @@ 57ED9CE42C73760800A4312C /* goormSansOTF4.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = goormSansOTF4.otf; sourceTree = ""; }; 57ED9CE62C73780100A4312C /* Pecita.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = Pecita.otf; sourceTree = ""; }; 57ED9CE82C74262400A4312C /* SourceHanSerifK-Regular.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "SourceHanSerifK-Regular.otf"; sourceTree = ""; }; - 7F23AD6B2C7432B8007E1F28 /* LetterCompletionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LetterCompletionView.swift; sourceTree = ""; }; 7F397C4D2C7C0ECE00388645 /* CustomTabViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomTabViewModel.swift; sourceTree = ""; }; 7F6CE9BF2C6B2FE90074568E /* CustomTabView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomTabView.swift; sourceTree = ""; }; 7F6CE9C32C6B50050074568E /* ImagePickerViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImagePickerViewModel.swift; sourceTree = ""; }; 7F6CE9E12C6E25500074568E /* CameraViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CameraViewModel.swift; sourceTree = ""; }; 7F6CE9E52C6E28400074568E /* CameraView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CameraView.swift; sourceTree = ""; }; 7F78684B2C78B41A0083D204 /* ImagePickerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImagePickerView.swift; sourceTree = ""; }; - 7F7868552C7B14220083D204 /* HorizontalPadding.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HorizontalPadding.swift; sourceTree = ""; }; 7F9890812C7EF5C30035CB0D /* CustomTabBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomTabBar.swift; sourceTree = ""; }; - 7FCAE2B02C73080000228FA7 /* ImagePreview.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImagePreview.swift; sourceTree = ""; }; - 7FCAE2B72C730E1700228FA7 /* OverlappingImagesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OverlappingImagesView.swift; sourceTree = ""; }; 7FCAE2B92C73102900228FA7 /* ImageDetailView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageDetailView.swift; sourceTree = ""; }; - 7FCAE2BB2C73157C00228FA7 /* LetterWritingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LetterWritingView.swift; sourceTree = ""; }; 8314013E2C69C34500F601FB /* Letter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Letter.swift; sourceTree = ""; }; 832C72662C71CF7B0071E8D0 /* SignUpUseCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignUpUseCase.swift; sourceTree = ""; }; 835684352CE0A43600120EC8 /* ServiceKeys.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ServiceKeys.swift; sourceTree = ""; }; @@ -422,13 +412,6 @@ path = ImportPhoto; sourceTree = ""; }; - 7F397C4F2C7C381E00388645 /* Camera */ = { - isa = PBXGroup; - children = ( - ); - path = Camera; - sourceTree = ""; - }; 7F397C502C7C382A00388645 /* CustomTabView */ = { isa = PBXGroup; children = ( @@ -438,17 +421,6 @@ path = CustomTabView; sourceTree = ""; }; - 7F397C512C7C386500388645 /* PhotoImporting */ = { - isa = PBXGroup; - children = ( - 7FCAE2B02C73080000228FA7 /* ImagePreview.swift */, - 7FCAE2B72C730E1700228FA7 /* OverlappingImagesView.swift */, - 7FCAE2BB2C73157C00228FA7 /* LetterWritingView.swift */, - 7F23AD6B2C7432B8007E1F28 /* LetterCompletionView.swift */, - ); - path = PhotoImporting; - sourceTree = ""; - }; 830CE3CD2CA2E35B00740627 /* Services */ = { isa = PBXGroup; children = ( @@ -556,16 +528,6 @@ path = UseCase; sourceTree = ""; }; - 8366B6F12C65ECDB0021FAE0 /* ImportLetter */ = { - isa = PBXGroup; - children = ( - 7F397C512C7C386500388645 /* PhotoImporting */, - 7F397C4F2C7C381E00388645 /* Camera */, - 7F7868552C7B14220083D204 /* HorizontalPadding.swift */, - ); - path = ImportLetter; - sourceTree = ""; - }; 8366B6F22C65ECE10021FAE0 /* LetterBox */ = { isa = PBXGroup; children = ( @@ -720,7 +682,6 @@ 8366B6F42C65ECEC0021FAE0 /* Profile */, 8366B6F32C65ECE60021FAE0 /* WriteLetter */, 8366B6F22C65ECE10021FAE0 /* LetterBox */, - 8366B6F12C65ECDB0021FAE0 /* ImportLetter */, ); path = View; sourceTree = ""; @@ -1014,7 +975,6 @@ 577157032C75D7C300E21162 /* StationerySelectionViewModel.swift in Sources */, AF9B18FA2C894B7100F3E446 /* DefaultLetterBoxUseCase.swift in Sources */, 57ED9CD52C70E4A400A4312C /* OpenSourceLicenseModalView.swift in Sources */, - 7F7868562C7B14220083D204 /* HorizontalPadding.swift in Sources */, 8356843F2CE0A43600120EC8 /* DIContainer.swift in Sources */, 538150542C8AF04B007B1E5A /* Extension+LetterType.swift in Sources */, AF9B18F82C894B5900F3E446 /* DefaultImportLetterUseCase.swift in Sources */, @@ -1060,9 +1020,7 @@ 530912CC2C7045F200964130 /* ToastView.swift in Sources */, 5771570B2C77071400E21162 /* ContentWriteViewModel.swift in Sources */, 53A99EA92C81914B00896AAC /* CalendarViewModel.swift in Sources */, - 7FCAE2B12C73080000228FA7 /* ImagePreview.swift in Sources */, 83CA92AE2C8181DB00DFB68B /* FirestorageWriterManager.swift in Sources */, - 7FCAE2B82C730E1700228FA7 /* OverlappingImagesView.swift in Sources */, AFA58F302C6C4B2A00A7C569 /* LetterBoxUseCase.swift in Sources */, AFA58F222C6A004C00A7C569 /* WriteLetterUseCase.swift in Sources */, 8314013F2C69C34500F601FB /* Letter.swift in Sources */, @@ -1075,7 +1033,6 @@ AFDE7D2E2C75797A0019F2DE /* FirestorageLetterManager.swift in Sources */, 57966B9E2C7DB267008D650B /* Extension+TextField.swift in Sources */, 7F78684C2C78B41A0083D204 /* ImagePickerView.swift in Sources */, - 7F23AD6C2C7432B8007E1F28 /* LetterCompletionView.swift in Sources */, AFB88B592C89410600E79F90 /* DefaultWriteLetterUseCase.swift in Sources */, 53FC6B8A2C90221600E7D9A8 /* LetterHelper.swift in Sources */, 57ED94FA2C84AFAC00A6F187 /* LetterWriteModel.swift in Sources */, @@ -1084,7 +1041,6 @@ 04DEC0DD2C6A3AD600D289EA /* SignUpView.swift in Sources */, 7F6CE9E22C6E25500074568E /* CameraViewModel.swift in Sources */, 573EE1F82D2BA55B00978283 /* CustomTextEditor.swift in Sources */, - 7FCAE2BC2C73157C00228FA7 /* LetterWritingView.swift in Sources */, 57966B9C2C7D8DAF008D650B /* EnvelopeStampSelectionViewModel.swift in Sources */, 7F6CE9C02C6B2FEA0074568E /* CustomTabView.swift in Sources */, 53FC6B822C901F7700E7D9A8 /* Extension+Collection.swift in Sources */, diff --git a/Kabinett/Presentation/View/ImportLetter/.gitkeep b/Kabinett/Presentation/View/ImportLetter/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/Kabinett/Presentation/View/ImportLetter/HorizontalPadding.swift b/Kabinett/Presentation/View/ImportLetter/HorizontalPadding.swift deleted file mode 100644 index 114d3991..00000000 --- a/Kabinett/Presentation/View/ImportLetter/HorizontalPadding.swift +++ /dev/null @@ -1,28 +0,0 @@ -// -// HorizontalPadding.swift -// Kabinett -// -// Created by 김정우 on 8/25/24. -// - -import SwiftUI - -struct HorizontalPadding: ViewModifier { - @State private var padding: CGFloat = 0 - - func body(content: Content) -> some View { - GeometryReader { geometry in - content - .padding(.horizontal, geometry.size.width * 0.06) - .onAppear { - padding = geometry.size.width * 0.06 - } - } - } -} - -extension View { - func horizontalPadding() -> some View { - self.modifier(HorizontalPadding()) - } -} diff --git a/Kabinett/Presentation/View/ImportLetter/PhotoImporting/ImagePreview.swift b/Kabinett/Presentation/View/ImportLetter/PhotoImporting/ImagePreview.swift deleted file mode 100644 index 3f6954f3..00000000 --- a/Kabinett/Presentation/View/ImportLetter/PhotoImporting/ImagePreview.swift +++ /dev/null @@ -1,91 +0,0 @@ -// -// ImagePreview.swift -// Kabinett -// -// Created by 김정우 on 8/19/24. -// - -//import FirebaseAnalytics -//import SwiftUI -// -//struct ImagePreview: View { -// @ObservedObject private var imageViewModel: ImagePickerViewModel -// @ObservedObject private var customViewModel: CustomTabViewModel -// @Environment(\.dismiss) var dismiss -// @State private var showDetailView = false -// @State private var showLetterWritingView = false -// @State private var navigateToEnvelopeStamp = false -// @State private var letterContent = LetterWriteModel() -// -// init( -// imageViewModel: ImagePickerViewModel, -// customViewModel: CustomTabViewModel -// ) { -// self.imageViewModel = imageViewModel -// self.customViewModel = customViewModel -// } -// -// var body: some View { -// NavigationStack { -// ZStack { -// VStack { -// Spacer() -// OverlappingImagesView(images: imageViewModel.photoContents, showDetailView: $showDetailView) -// Spacer() -// Button(action: { -// if customViewModel.isLetterWrite { -// dismiss() -// } else { -// showLetterWritingView = true -// } -// }) { -// Text(customViewModel.isLetterWrite ? "사진 동봉하기" : "편지 선택하기") -// .font(.system(size: 16)) -// .fontWeight(.semibold) -// .foregroundStyle(Color.white) -// .frame(maxWidth: .infinity, minHeight: 56) -// .background(Color.primary900) -// .cornerRadius(16) -// } -// .padding(.horizontal, UIScreen.main.bounds.width * 0.06) -// } -// .padding(.bottom, LayoutHelper.shared.getSize(forSE: 0.03, forOthers: 0.0)) -// } -// .navigationTitle("") -// .navigationBarTitleDisplayMode(.inline) -// .navigationBarItems( -// leading: Button(action: { -// imageViewModel.resetSelections() -// customViewModel.showImagePreview = false -// DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { -// customViewModel.showPhotoLibrary = true -// } -// }) { -// Image(systemName: "chevron.left") -// .foregroundColor(.contentPrimary) -// } -// ) -// .background(Color.background.edgesIgnoringSafeArea(.all)) -// .navigationDestination(isPresented: $showDetailView) { -// ImageDetailView( -// images: imageViewModel.photoContents, -// showDetailView: $showDetailView -// ) -// } -// .navigationDestination(isPresented: $navigateToEnvelopeStamp) { -// EnvelopeStampSelectionView( -// letterContent: $letterContent, -// customTabViewModel: customViewModel, -// imageViewModel: imageViewModel -// ) -// } -// } -// .analyticsScreen( -// name: "\(type(of:self))", -// extraParameters: [ -// AnalyticsParameterScreenName: "\(type(of:self))", -// AnalyticsParameterScreenClass: "\(type(of:self))", -// ] -// ) -// } -//} diff --git a/Kabinett/Presentation/View/ImportLetter/PhotoImporting/LetterCompletionView.swift b/Kabinett/Presentation/View/ImportLetter/PhotoImporting/LetterCompletionView.swift deleted file mode 100644 index 22f8d99d..00000000 --- a/Kabinett/Presentation/View/ImportLetter/PhotoImporting/LetterCompletionView.swift +++ /dev/null @@ -1,163 +0,0 @@ -// -// LetterCompletionView.swift -// Kabinett -// -// Created by 김정우 on 8/20/24. -// - -//import FirebaseAnalytics -//import SwiftUI -//import Kingfisher -// -//struct LetterCompletionView: View { -// @Binding var letterContent: LetterWriteModel -// @ObservedObject var viewModel: ImagePickerViewModel -// @ObservedObject var customTabViewModel: CustomTabViewModel -// @ObservedObject var envelopeStampSelectionViewModel: EnvelopeStampSelectionViewModel -// @Environment(\.dismiss) private var dismiss -// @State private var envelopeURL: String = "" -// @State private var stampURL: String = "" -// -// var body: some View { -// NavigationStack { -// ZStack { -// Color.background.edgesIgnoringSafeArea(.all) -// -// VStack(spacing: 20) { -// Spacer() -// letterPreviewView -// completionMessageView -// Spacer() -// saveButton -// } -// } -// } -// .onAppear { -// Task { -// await viewModel.loadAndUpdateEnvelopeAndStamp() -// envelopeURL = viewModel.envelopeURL ?? letterContent.envelopeImageUrlString -// stampURL = viewModel.stampURL ?? letterContent.stampImageUrlString -// } -// } -// .analyticsScreen( -// name: "\(type(of:self))", -// extraParameters: [ -// AnalyticsParameterScreenName: "\(type(of:self))", -// AnalyticsParameterScreenClass: "\(type(of:self))", -// ] -// ) -// } -// -// private var letterPreviewView: some View { -// ZStack(alignment: .topLeading) { -// KFImage(URL(string: letterContent.envelopeImageUrlString)) -// .resizable() -// .placeholder { -// ProgressView() -// } -// .shadow(color: Color(.primary300), radius: 5, x: 3, y: 3) -// .aspectRatio(9/4, contentMode: .fit) -// -// VStack { -// HStack(alignment: .top) { -// VStack(alignment: .leading, spacing: 2) { -// Text("보내는 사람") -// .font(.system(size: 7)) -// .foregroundStyle(.contentPrimary) -// Text(viewModel.fromUserName) -// .font(.system(size: 14)) -// .foregroundStyle(.contentPrimary) -// .frame(maxWidth: UIScreen.main.bounds.width * 0.57, alignment: .leading) -// } -// -// Spacer() -// -// ZStack(alignment: .topTrailing) { -// KFImage(URL(string: letterContent.stampImageUrlString)) -// .resizable() -// .placeholder { -// ProgressView() -// } -// .frame(width: UIScreen.main.bounds.width * 0.09, height: UIScreen.main.bounds.height * 0.046) -// .aspectRatio(contentMode: .fit) -// -// Text(viewModel.formattedDate) -// .monospaced() -// .font(.system(size: 12)) -// .fontWeight(.medium) -// .foregroundColor(.black) -// .padding(2) -// .background(Color.clear) -// .cornerRadius(4) -// .offset(x: -UIScreen.main.bounds.width * 0.06, y: -UIScreen.main.bounds.height * 0.005) -// } -// } -// .padding(.horizontal, 25) -// .padding(.top, 25) -// -// Spacer() -// -// HStack(alignment: .top) { -// Text(viewModel.postScript ?? letterContent.postScript ?? "") -// .font(.system(size: 10)) -// .foregroundStyle(.contentPrimary) -// .frame(width: UIScreen.main.bounds.width * 0.4, alignment: .leading) -// -// Spacer() -// -// VStack(alignment: .leading, spacing: 2) { -// Text("받는 사람") -// .font(.system(size: 7)) -// .foregroundStyle(.contentPrimary) -// Text(viewModel.toUserName) -// .font(.system(size: 14)) -// .foregroundStyle(.contentPrimary) -// .frame(maxWidth: UIScreen.main.bounds.width * 0.26, alignment: .leading) -// } -// } -// .padding(.horizontal, 25) -// .padding(.bottom, 25) -// } -// } -// .frame(width: UIScreen.main.bounds.width * 0.85, height: UIScreen.main.bounds.width * 0.85 * 4/9) -// } -// -// private var completionMessageView: some View { -// VStack(spacing: 10) { -// Text("편지가 완성되었어요.") -// Text("소중한 편지를 보관할게요.") -// } -// .font(.system(size: 18, weight: .semibold)) -// } -// -// private var saveButton: some View { -// Button(action: { -// customTabViewModel.navigateToLetterBox() -// dismiss() -// customTabViewModel.selectedTab = 0 -// -// Task { -// if viewModel.postScript == nil { -// viewModel.postScript = letterContent.postScript -// } -// -// let success = await viewModel.saveImportingImage() -// NotificationCenter.default.post( -// name: .showToast, -// object: nil, -// userInfo: success ? ["message": "편지가 성공적으로 보관되었어요.", "color": Color.primary900] : ["message": "앗..!! 편지 보관을 실패했어요..", "color": Color.alert]) -// } -// }) { -// Text("편지 보관하기") -// .font(.system(size: 16)) -// .fontWeight(.semibold) -// .foregroundStyle(Color.white) -// .frame(maxWidth: .infinity, minHeight: 56) -// .background(Color.primary900) -// .cornerRadius(16) -// } -// .padding(.horizontal, UIScreen.main.bounds.width * 0.06) -// .padding(.bottom, LayoutHelper.shared.getSize(forSE: 0.03, forOthers: 0.0)) -// .disabled(viewModel.isLoading) -// } -//} diff --git a/Kabinett/Presentation/View/ImportLetter/PhotoImporting/LetterWritingView.swift b/Kabinett/Presentation/View/ImportLetter/PhotoImporting/LetterWritingView.swift deleted file mode 100644 index 1c309721..00000000 --- a/Kabinett/Presentation/View/ImportLetter/PhotoImporting/LetterWritingView.swift +++ /dev/null @@ -1,274 +0,0 @@ -// -// LetterWritingView.swift -// Kabinett -// -// Created by 김정우 on 8/19/24. -// - -import FirebaseAnalytics -import SwiftUI - -//struct LetterWritingView: View { -// @ObservedObject var viewModel: ImagePickerViewModel -// @ObservedObject var customViewModel: CustomTabViewModel -// @ObservedObject var envelopeStampViewModel: EnvelopeStampSelectionViewModel -// @Environment(\.dismiss) var dismiss -// @Binding var letterContent: LetterWriteModel -// @Binding var showEnvelopeStamp: Bool -// @State private var showCalendar = false -// -// var body: some View { -// NavigationStack { -// ZStack { -// Color.primary100.edgesIgnoringSafeArea(.all) -// -// VStack(spacing: 20) { -// FormToUserView(letterContent: $letterContent, viewModel: viewModel) -// dateField() -// Spacer() -// } -// .padding([.leading, .trailing], 20) -// .padding(.top, 20) -// } -// .onTapGesture { -// UIApplication.shared.endEditing() -// } -// .navigationBarItems( -// trailing: Button(action: { -// updateLetterWrite() -// dismiss() -// showEnvelopeStamp = true -// }) { -// Text("완료") -// .fontWeight(.medium) -// .font(.system(size: 19)) -// .foregroundColor(.contentPrimary) -// } -// ) -// } -// .task { -// await viewModel.fetchCurrentWriter() -// viewModel.updateDefaultUsers() -// updateLetterWriteFromViewModel() -// } -// .analyticsScreen( -// name: "\(type(of:self))", -// extraParameters: [ -// AnalyticsParameterScreenName: "\(type(of:self))", -// AnalyticsParameterScreenClass: "\(type(of:self))", -// ] -// ) -// } -// -// private func updateLetterWriteFromViewModel() { -// letterContent.fromUserName = viewModel.fromUserName -// letterContent.fromUserId = viewModel.fromUserId -// letterContent.toUserName = viewModel.toUserName -// letterContent.toUserId = viewModel.toUserId -// -// } -// -// private func dateField() -> some View { -// VStack(spacing: 1) { -// HStack(alignment: .center, spacing: 10) { -// Text("받은/보낸 날짜") -// .foregroundStyle(Color.contentPrimary) -// .bold() -// .font(.system(size: 16)) -// .frame(width: 100, alignment: .leading) -// -// Button(action: { -// showCalendar.toggle() -// }) { -// Text(viewModel.formattedDate) -// .foregroundStyle(Color.blue) -// .font(.system(size: 15)) -// .padding(.horizontal, 15) -// .frame(height: 40) -// .frame(maxWidth: .infinity) -// .background(Color.contentTertiary) -// .clipShape(RoundedRectangle(cornerRadius: 8)) -// } -// } -// } -// .sheet(isPresented: $showCalendar) { -// DatePicker("", selection: $viewModel.date, displayedComponents: [.date]) -// .datePickerStyle(.graphical) -// .frame(maxHeight: 350) -// .background(Color.white) -// .cornerRadius(5) -// .shadow(color: Color.black.opacity(0.1), radius: 5, x: 0, y: 2) -// .padding() -// .presentationDetents([.height(470)]) -// .presentationBackground(.clear) -// .presentationCornerRadius(5) -// .interactiveDismissDisabled() -// .onChange(of: viewModel.date) { oldValue, newValue in -// if oldValue != newValue { -// letterContent.date = newValue -// DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { -// showCalendar = false -// } -// } -// } -// } -// } -// -// private func updateLetterWrite() { -// letterContent.fromUserName = viewModel.fromUserName -// letterContent.toUserName = viewModel.toUserName -// letterContent.date = viewModel.date -// letterContent.photoContents = viewModel.photoContents -// letterContent.dataSource = .importLetter -// } -//} -// -//struct FormToUserView: View { -// @Binding var letterContent: LetterWriteModel -// @ObservedObject var viewModel: ImagePickerViewModel -// -// var body: some View { -// VStack(spacing: 20) { -// userField(title: "보내는 사람", name: $viewModel.fromUserName, search: $viewModel.fromUserSearch, isFromUser: true) -// userField(title: "받는 사람", name: $viewModel.toUserName, search: $viewModel.toUserSearch, isFromUser: false) -// } -// -// .onAppear { -// if let fromUser = viewModel.fromUser { -// letterContent.fromUserId = fromUser.id -// letterContent.fromUserName = fromUser.name -// viewModel.fromUserName = fromUser.name -// viewModel.fromUserKabinettNumber = fromUser.kabinettNumber -// } -// -// letterContent.toUserId = letterContent.fromUserId -// letterContent.toUserName = letterContent.fromUserName -// viewModel.toUserId = letterContent.fromUserId -// viewModel.toUserName = letterContent.fromUserName -// viewModel.toUserKabinettNumber = viewModel.fromUserKabinettNumber -// } -// -// } -// -// private func userField(title: String, name: Binding, search: Binding, isFromUser: Bool) -> some View { -// VStack(spacing: 10) { -// HStack(alignment: .center, spacing: 10) { -// Text(title) -// .foregroundStyle(Color.contentPrimary) -// .font(.system(size: 16)) -// .bold() -// .frame(width: 100, alignment: .leading) -// -// TextField(isFromUser ? name.wrappedValue : "", text: name) -// .foregroundStyle(isFromUser ? Color.contentSecondary : .black) -// .font(.system(size: 15)) -// .padding(.horizontal, 15) -// .frame(height: 40) -// .background(Color.white) -// .clipShape(RoundedRectangle(cornerRadius: 20)) -// .multilineTextAlignment(.center) -// } -// -// HStack(alignment: .center, spacing: 10) { -// Spacer() -// .frame(width: 100) -// -// SearchResultList(letterContent: $letterContent, searchText: search, viewModel: viewModel, isFromUser: isFromUser) -// } -// } -// } -// -// struct SearchResultList: View { -// @Binding var letterContent: LetterWriteModel -// @Binding var searchText: String -// @ObservedObject var viewModel: ImagePickerViewModel -// let isFromUser: Bool -// -// var body: some View { -// VStack { -// HStack { -// Image(systemName: "magnifyingglass") -// .foregroundStyle(Color.contentPrimary) -// -// TextField("검색", text: $searchText) -// .foregroundStyle(.primary) -// -// if !searchText.isEmpty { -// Button(action: { -// self.searchText = "" -// }) { -// Image(systemName: "xmark.circle.fill") -// .foregroundStyle(Color.primary100) -// } -// } -// } -// .padding(EdgeInsets(top: 7, leading: 13, bottom: 7, trailing: 13)) -// .background(Color(.white)) -// .clipShape(.capsule) -// -// if !searchText.isEmpty { -// Divider() -// .padding([.leading, .trailing], 10) -// .padding(.top, -6) -// -// List { -// Text("\(searchText) 입력") -// .onTapGesture { -// updateUser(name: searchText) -// searchText = "" -// UIApplication.shared.endEditing() -// } -// .padding(.leading, 35) -// .listRowSeparator(.hidden) -// .foregroundStyle(Color.primary900) -// -// ForEach(isFromUser ? viewModel.fromUserSearchResults : viewModel.toUserSearchResults, id: \.name) { user in -// HStack { -// Image(systemName: "person.crop.circle") -// .resizable() -// .frame(width: 25, height: 25) -// .clipShape(.circle) -// .foregroundStyle(Color.primary100) -// Text(user.name) -// .foregroundStyle(Color.primary900) -// Spacer() -// Text("\(String(user.kabinettNumber.prefix(3)))-\(String(user.kabinettNumber.suffix(3)))") -// .foregroundStyle(Color.primary900) -// } -// .listRowSeparator(.hidden) -// .onTapGesture { -// updateUser(name: user.name) -// searchText = "" -// UIApplication.shared.endEditing() -// } -// } -// } -// .listStyle(PlainListStyle()) -// .frame(height: 200) -// .background(Color.white) -// .cornerRadius(20) -// .padding(.top, -5) -// } -// } -// .padding(.top, 2) -// .background(searchText.isEmpty ? Color.clear : Color.white) -// .cornerRadius(16) -// } -// -// private func updateUser(name: String) { -// if isFromUser { -// viewModel.fromUserName = name -// letterContent.fromUserName = name -// if let user = viewModel.usersData.first(where: { $0.name == name }) { -// letterContent.fromUserId = user.id -// viewModel.fromUserKabinettNumber = user.kabinettNumber -// } else { -// viewModel.fromUserId = "" -// viewModel.fromUserKabinettNumber = 0 -// } -// } else { -// viewModel.updateSelectedUser(selectedUserName: name) -// } -// } -// } -//} diff --git a/Kabinett/Presentation/View/ImportLetter/PhotoImporting/OverlappingImagesView.swift b/Kabinett/Presentation/View/ImportLetter/PhotoImporting/OverlappingImagesView.swift deleted file mode 100644 index 270d2426..00000000 --- a/Kabinett/Presentation/View/ImportLetter/PhotoImporting/OverlappingImagesView.swift +++ /dev/null @@ -1,65 +0,0 @@ -// -// OverlappingImagesView.swift -// Kabinett -// -// Created by 김정우 on 8/19/24. -// - -//import SwiftUI -// -//struct OverlappingImagesView: View { -// let images: [Data] -// @Binding var showDetailView: Bool -// -// var body: some View { -// GeometryReader { geometry in -// ZStack { -// ForEach(Array(images.prefix(3).enumerated().reversed()), id: \.offset) { index, imageData in -// if let uiImage = UIImage(data: imageData) { -// ImageView(uiImage: uiImage, index: index, totalImages: images.prefix(3).count, parentSize: geometry.size) -// } -// } -// } -// .frame(width: geometry.size.width, height: geometry.size.height) -// .onTapGesture { -// showDetailView = true -// } -// } -// } -//} -// -//struct ImageView: View { -// let uiImage: UIImage -// let index: Int -// let totalImages: Int -// let parentSize: CGSize -// -// var body: some View { -// Image(uiImage: uiImage) -// .resizable() -// .aspectRatio(contentMode: .fill) -// .frame(width: frameSize.width, height: frameSize.height) -// .clipShape(RoundedRectangle(cornerRadius: 2)) -// .rotationEffect(.degrees(rotationAngle), anchor: .center) -// .position(x: parentSize.width / 2, y: parentSize.height / 2) -// .shadow(color: .black.opacity(0.2), radius: 5, x: 0, y: 2) -// } -// -// private var frameSize: CGSize { -// let aspectRatio = uiImage.size.width / uiImage.size.height -// let maxWidth = parentSize.width * 0.6 -// let maxHeight = parentSize.height * 0.5 -// -// if aspectRatio > 1 { -// let height = min(maxHeight, maxWidth / aspectRatio) -// return CGSize(width: height * aspectRatio, height: height) -// } else { -// let width = min(maxWidth, maxHeight * aspectRatio) -// return CGSize(width: width, height: width / aspectRatio) -// } -// } -// -// private var rotationAngle: Double { -// Double(index) * -15 -// } -//} From 62873a1e464fc5c7b3c8d4c45979ad51013bcb52 Mon Sep 17 00:00:00 2001 From: ksiomng Date: Tue, 25 Mar 2025 12:13:49 +0900 Subject: [PATCH 05/39] =?UTF-8?q?Fix:=20=EC=BB=A4=EC=8A=A4=ED=85=80=20?= =?UTF-8?q?=ED=83=AD=20=EB=B7=B0=EB=AA=A8=EB=8D=B8=EC=97=90=EC=84=9C=20?= =?UTF-8?q?=ED=95=84=EC=9A=94=EC=97=86=EB=8A=94=20=EC=BD=94=EB=93=9C=20?= =?UTF-8?q?=EC=82=AD=EC=A0=9C,=20=ED=97=B7=EA=B0=88=EB=A6=AC=EB=8A=94=20?= =?UTF-8?q?=EC=9D=B4=EB=A6=84=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Commons/CustomTabView/CustomTabView.swift | 4 +- .../CustomTabViewModel.swift | 39 ++++--------------- .../Components/MiniTabBarView.swift | 1 - .../View/WriteLetter/PreviewLetterView.swift | 2 +- .../WriteLetter/StationerySelectionView.swift | 3 +- 5 files changed, 11 insertions(+), 38 deletions(-) diff --git a/Kabinett/Presentation/Commons/CustomTabView/CustomTabView.swift b/Kabinett/Presentation/Commons/CustomTabView/CustomTabView.swift index 16ac1b9e..6bd51fde 100644 --- a/Kabinett/Presentation/Commons/CustomTabView/CustomTabView.swift +++ b/Kabinett/Presentation/Commons/CustomTabView/CustomTabView.swift @@ -54,12 +54,12 @@ struct CustomTabView: View { .onChange(of: customTabViewModel.selectedTab) { oldValue, newValue in if newValue == 1 { withAnimation { - customTabViewModel.showOptions = true + customTabViewModel.showWriteView = true } customTabViewModel.selectedTab = oldValue } } - .sheet(isPresented: $customTabViewModel.showOptions) { + .sheet(isPresented: $customTabViewModel.showWriteView) { UserSelectionView(letterContent: $letterWriteViewModel, customViewModel: customTabViewModel, imageViewModel: imagePickerViewModel) .presentationDetents([.height(300), .large]) } diff --git a/Kabinett/Presentation/Commons/CustomTabViewModel/CustomTabViewModel.swift b/Kabinett/Presentation/Commons/CustomTabViewModel/CustomTabViewModel.swift index 1dbcd282..34da405f 100644 --- a/Kabinett/Presentation/Commons/CustomTabViewModel/CustomTabViewModel.swift +++ b/Kabinett/Presentation/Commons/CustomTabViewModel/CustomTabViewModel.swift @@ -9,22 +9,18 @@ import SwiftUI final class CustomTabViewModel: ObservableObject { @Published var selectedTab: Int = 0 - @Published var showOptions: Bool = false + @Published var showWriteView: Bool = false @Published var showImportDialog: Bool = false + @Published var showCamera: Bool = false @Published var showPhotoLibrary: Bool = false @Published var showImagePreview: Bool = false - @Published var showWriteLetterView: Bool = false + @Published var letterBoxNavigationPath = NavigationPath() @Published var profileNavigationPath = NavigationPath() - @Published var isLetterWrite: Bool = false - @Published var previousTab: Int? static let profileTabTappedNotification = Notification.Name("profileTabTappedNotification") - private var lastTabSelectionTime: Date? - private let doubleTapInterval: TimeInterval = 0.2 - // MARK: TabView SystemImage Size let envelopeImage: UIImage let plusImage: UIImage @@ -59,7 +55,7 @@ final class CustomTabViewModel: ObservableObject { } } else if tab == 1 { withAnimation(.easeInOut(duration: 0.3)) { - showOptions = true + showWriteView = true } } else { selectedTab = tab @@ -77,30 +73,9 @@ final class CustomTabViewModel: ObservableObject { } } - func navigateToLetterBox() { - selectedTab = 0 - showOptions = false - showImportDialog = false - showPhotoLibrary = false - showCamera = false - showImagePreview = false - showWriteLetterView = false - } - - // MARK: OptionOverlay sheet 관련 Method - func hideOptions() { - showOptions = false - } - - func showImportDialogAndHideOptions() { - showOptions = false - showImportDialog = true - isLetterWrite = false - } - - func showWriteLetterViewAndHideOptions() { - showOptions = false - showWriteLetterView = true + // MARK: OptionOverlay sheet 관련 Method + func hideWriteView() { + showWriteView = false } // MARK: ImagePicker sheet 관련 Method diff --git a/Kabinett/Presentation/View/WriteLetter/Components/MiniTabBarView.swift b/Kabinett/Presentation/View/WriteLetter/Components/MiniTabBarView.swift index 26c05a37..5f83cd95 100644 --- a/Kabinett/Presentation/View/WriteLetter/Components/MiniTabBarView.swift +++ b/Kabinett/Presentation/View/WriteLetter/Components/MiniTabBarView.swift @@ -63,7 +63,6 @@ struct MiniTabBarView: View { } Button { customTabViewModel.showPhotoLibrary = true - customTabViewModel.isLetterWrite = true } label: { Image(systemName: "photo.on.rectangle.angled") .font(.system(size: 15)) diff --git a/Kabinett/Presentation/View/WriteLetter/PreviewLetterView.swift b/Kabinett/Presentation/View/WriteLetter/PreviewLetterView.swift index 3d9f0405..7b207ac8 100644 --- a/Kabinett/Presentation/View/WriteLetter/PreviewLetterView.swift +++ b/Kabinett/Presentation/View/WriteLetter/PreviewLetterView.swift @@ -69,7 +69,7 @@ struct PreviewLetterView: View { date: letterContent.date, stationery: letterContent.stationeryImageUrlString ?? "", isRead: false) - customTabViewModel.hideOptions() + customTabViewModel.hideWriteView() imagePickerViewModel.resetSelections() } label: { Text("편지 보내기") diff --git a/Kabinett/Presentation/View/WriteLetter/StationerySelectionView.swift b/Kabinett/Presentation/View/WriteLetter/StationerySelectionView.swift index 83895907..88340083 100644 --- a/Kabinett/Presentation/View/WriteLetter/StationerySelectionView.swift +++ b/Kabinett/Presentation/View/WriteLetter/StationerySelectionView.swift @@ -62,8 +62,7 @@ struct StationerySelectionView: View { .toolbar { ToolbarItem(placement: .topBarLeading) { Button(action: { - customViewModel.showOptions = false - dismiss() + customViewModel.hideWriteView() }) { Image(systemName: "chevron.backward") .foregroundColor(Color.primary900) From aec367d50818b0f1b766ca94dbe7dd068a360940 Mon Sep 17 00:00:00 2001 From: ksiomng Date: Tue, 25 Mar 2025 12:26:24 +0900 Subject: [PATCH 06/39] =?UTF-8?q?Fix:=20ImportLetterViewModel=20=EC=97=90?= =?UTF-8?q?=20=ED=95=84=EC=9A=94=EC=97=86=EB=8A=94=20=EC=BD=94=EB=93=9C?= =?UTF-8?q?=EB=93=A4=20=EC=A0=84=EB=B6=80=20=EC=A0=9C=EA=B1=B0,=20?= =?UTF-8?q?=EC=A0=95=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../EnvelopeStampSelectionView.swift | 3 - .../WriteLetter/ImportPhoto/CameraView.swift | 104 +++---- .../ImportLetter/ImagePickerViewModel.swift | 274 +----------------- 3 files changed, 65 insertions(+), 316 deletions(-) diff --git a/Kabinett/Presentation/View/WriteLetter/EnvelopeStampSelectionView.swift b/Kabinett/Presentation/View/WriteLetter/EnvelopeStampSelectionView.swift index c13abf92..b4e6f522 100644 --- a/Kabinett/Presentation/View/WriteLetter/EnvelopeStampSelectionView.swift +++ b/Kabinett/Presentation/View/WriteLetter/EnvelopeStampSelectionView.swift @@ -80,16 +80,13 @@ struct EnvelopeStampSelectionView: View { .task { await viewModel.loadStamps() await viewModel.loadEnvelopes() - await imageViewModel.loadAndUpdateEnvelopeAndStamp() envelopeImageUrl = letterContent.envelopeImageUrlString stampImageUrl = letterContent.stampImageUrlString } .onChange(of: envelopeImageUrl) { _, newValue in - imageViewModel.updateEnvelopeAndStamp(envelope: newValue, stamp: stampImageUrl) letterContent.envelopeImageUrlString = newValue } .onChange(of: stampImageUrl) { _, newValue in - imageViewModel.updateEnvelopeAndStamp(envelope: envelopeImageUrl, stamp: newValue) letterContent.stampImageUrlString = newValue } .navigationBarTitleDisplayMode(.inline) diff --git a/Kabinett/Presentation/View/WriteLetter/ImportPhoto/CameraView.swift b/Kabinett/Presentation/View/WriteLetter/ImportPhoto/CameraView.swift index dc7a92f3..34ffbff1 100644 --- a/Kabinett/Presentation/View/WriteLetter/ImportPhoto/CameraView.swift +++ b/Kabinett/Presentation/View/WriteLetter/ImportPhoto/CameraView.swift @@ -7,55 +7,55 @@ import SwiftUI -struct CameraView: View { - @StateObject private var viewModel = CameraViewModel() - @ObservedObject var imagePickerViewModel: ImagePickerViewModel - @Environment(\.dismiss) private var dismiss - - var body: some View { - CameraViewRepresentable(viewModel: viewModel) - .edgesIgnoringSafeArea(.all) - .onChange(of: viewModel.capturedImage) { _, newImage in - if let image = newImage, - let imageData = image.jpegData(compressionQuality: 0.5) { - imagePickerViewModel.photoContents.append(imageData) - dismiss() - } - } - } -} - -// MARK: - Camera View Representable -private struct CameraViewRepresentable: UIViewControllerRepresentable { - @ObservedObject var viewModel: CameraViewModel - - func makeUIViewController(context: Context) -> UIImagePickerController { - let picker = UIImagePickerController() - picker.sourceType = .camera - picker.delegate = context.coordinator - return picker - } - - func updateUIViewController(_ uiViewController: UIImagePickerController, context: Context) {} - - func makeCoordinator() -> Coordinator { - Coordinator(self) - } - - // MARK: Coordinator (UIImagePickerController Coordinator) - class Coordinator: NSObject, UINavigationControllerDelegate, UIImagePickerControllerDelegate { - let parent: CameraViewRepresentable - - init(_ parent: CameraViewRepresentable) { - self.parent = parent - } - - func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) { - parent.viewModel.captureImage(with: info) - } - - func imagePickerControllerDidCancel(_ picker: UIImagePickerController) { - picker.dismiss(animated: true, completion: nil) - } - } -} +//struct CameraView: View { +// @StateObject private var viewModel = CameraViewModel() +// @ObservedObject var imagePickerViewModel: ImagePickerViewModel +// @Environment(\.dismiss) private var dismiss +// +// var body: some View { +// CameraViewRepresentable(viewModel: viewModel) +// .edgesIgnoringSafeArea(.all) +// .onChange(of: viewModel.capturedImage) { _, newImage in +// if let image = newImage, +// let imageData = image.jpegData(compressionQuality: 0.5) { +// imagePickerViewModel.photoContents.append(imageData) +// dismiss() +// } +// } +// } +//} +// +//// MARK: - Camera View Representable +//private struct CameraViewRepresentable: UIViewControllerRepresentable { +// @ObservedObject var viewModel: CameraViewModel +// +// func makeUIViewController(context: Context) -> UIImagePickerController { +// let picker = UIImagePickerController() +// picker.sourceType = .camera +// picker.delegate = context.coordinator +// return picker +// } +// +// func updateUIViewController(_ uiViewController: UIImagePickerController, context: Context) {} +// +// func makeCoordinator() -> Coordinator { +// Coordinator(self) +// } +// +// // MARK: Coordinator (UIImagePickerController Coordinator) +// class Coordinator: NSObject, UINavigationControllerDelegate, UIImagePickerControllerDelegate { +// let parent: CameraViewRepresentable +// +// init(_ parent: CameraViewRepresentable) { +// self.parent = parent +// } +// +// func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) { +// parent.viewModel.captureImage(with: info) +// } +// +// func imagePickerControllerDidCancel(_ picker: UIImagePickerController) { +// picker.dismiss(animated: true, completion: nil) +// } +// } +//} diff --git a/Kabinett/Presentation/ViewModel/ImportLetter/ImagePickerViewModel.swift b/Kabinett/Presentation/ViewModel/ImportLetter/ImagePickerViewModel.swift index 69434b63..59bc874b 100644 --- a/Kabinett/Presentation/ViewModel/ImportLetter/ImagePickerViewModel.swift +++ b/Kabinett/Presentation/ViewModel/ImportLetter/ImagePickerViewModel.swift @@ -10,166 +10,37 @@ import PhotosUI import Combine final class ImagePickerViewModel: ObservableObject { - - @Published var selectedItems: [PhotosPickerItem] = [] - + @Published var selectedItems: [PhotosPickerItem] = [] //***** @Published var photoContents: [Data] = [] - @Published var date: Date = Date() - @Published var isRead: Bool = false - - @Published var postScript: String? - @Published var envelopeURL: String? - @Published var stampURL: String? - - @Published var fromUserId: String? - @Published var fromUserName: String = "" - @Published var fromUserKabinettNumber: Int? = nil - - @Published var toUserId: String? - @Published var toUserName: String = "" - @Published var toUserKabinettNumber: Int? = nil - - @Published var fromUserSearch: String = "" - @Published var toUserSearch: String = "" - @Published var debouncedSearchText: String = "" - - @Published var fromUser: Writer? = nil - @Published var toUser: Writer? = nil - @Published var usersData: [Writer] = [] - @Published var fromUserSearchResults: [(name: String, kabinettNumber: String)] = [] - @Published var toUserSearchResults: [(name: String, kabinettNumber: String)] = [] - @Published var userKabiNumber: String? - - @Published var checkLogin: Bool = false @Published var isLoading: Bool = false @Published var error: Error? - @Published var isAnonymous: Bool = false private var cancellables = Set() private let componentsUseCase: ImportLetterUseCase init(componentsUseCase: ImportLetterUseCase) { self.componentsUseCase = componentsUseCase - - setupBindings() - Task { - await fetchCurrentWriter() - } } - - @MainActor - func updateDefaultUsers() { - if let fromUser = fromUser { - fromUserName = isAnonymous ? "나" : fromUser.name - fromUserId = fromUser.id - fromUserKabinettNumber = fromUser.kabinettNumber - - if isAnonymous { - toUserName = "나" - toUserId = fromUserId - toUserKabinettNumber = nil - } else { - toUserName = toUserName - toUserId = toUserId - toUserKabinettNumber = toUserKabinettNumber - } - } - } - - private func setupBindings() { - $fromUserSearch - .debounce(for: .seconds(1), scheduler: RunLoop.main) - .removeDuplicates() - .sink { [weak self] text in - Task { [weak self] in - await self?.searchUsers(query: text, isFromUser: true) - } - } - .store(in: &cancellables) - - $toUserSearch - .debounce(for: .seconds(1), scheduler: RunLoop.main) - .removeDuplicates() - .sink { [weak self] text in - Task { [weak self] in - await self?.searchUsers(query: text, isFromUser: false) - } - } - .store(in: &cancellables) - } - - // MARK: 현재 사용자 정보 업데이트 - func updateFromUser() { - if let fromUser = fromUser { - checkLogin = fromUser.kabinettNumber != 0 - isAnonymous = fromUser.kabinettNumber == 0 - fromUserId = fromUser.id - fromUserName = isAnonymous ? "나" : fromUser.name - fromUserKabinettNumber = fromUser.kabinettNumber - userKabiNumber = String(format: "%06d", fromUser.kabinettNumber) - - if checkLogin { - toUser = fromUser - toUserId = fromUser.id - toUserName = fromUser.name - toUserKabinettNumber = fromUser.kabinettNumber - } else { - toUser = nil - toUserId = nil - toUserName = "나" - toUserKabinettNumber = nil - } - } + func resetSelections() { + selectedItems = [] + photoContents = [] } - // MARK: 사용자 검색 기능 @MainActor - func searchUsers(query: String, isFromUser: Bool) async { - guard !query.isEmpty else { - if isFromUser { - self.fromUserSearchResults = [] - } else { - self.toUserSearchResults = [] - } - return - } - - let results = await componentsUseCase.findWriter(by: query) - let formattedResults = results.map { (name: $0.name, kabinettNumber: String(format: "%06d", $0.kabinettNumber)) } + func loadImages() async { + isLoading = true + error = nil - if isFromUser { - self.fromUserSearchResults = formattedResults - } else { - self.toUserSearchResults = formattedResults - } - } - - - func updateSelectedUser(selectedUserName: String) { - if let user = usersData.first(where: { $0.name == selectedUserName }) { - toUser = Writer(id: user.id, name: user.name, kabinettNumber: user.kabinettNumber, profileImage: user.profileImage) - } else { - toUser = Writer(name: selectedUserName, kabinettNumber: 0, profileImage: nil) + do { + let newImageContents = try await loadImagesTask() + self.photoContents = newImageContents + } catch { + self.error = error } - self.toUserId = toUser?.id - self.toUserName = toUser?.name ?? "" - self.toUserKabinettNumber = toUser?.kabinettNumber - } - - - // MARK: 현재 로그인한 사용자 정보 가져오기 - @MainActor - func fetchCurrentWriter() async { - let publisher = componentsUseCase.getCurrentWriter() - - for await writer in publisher.values { - self.fromUser = writer - updateFromUser() - break - } + isLoading = false } // MARK: 선택된 이미지 로드 @@ -197,123 +68,4 @@ final class ImagePickerViewModel: ObservableObject { return results } } - - @MainActor - func loadImages() async { - isLoading = true - error = nil - - do { - let newImageContents = try await loadImagesTask() - self.photoContents = newImageContents - } catch { - self.error = error - } - - isLoading = false - } - - func updatePostScript(_ postScript: String) { - self.postScript = postScript - } - - func updateEnvelopeAndStamp(envelope: String?, stamp: String?) { - if let envelope = envelope { - self.envelopeURL = envelope - } - if let stamp = stamp { - self.stampURL = stamp - } - } - - @MainActor - func loadAndUpdateEnvelopeAndStamp() async { - isLoading = true - error = nil - - do { - let envelopes = try await componentsUseCase.loadEnvelopes().get() - let stamps = try await componentsUseCase.loadStamps().get() - - if self.envelopeURL == nil, let firstEnvelope = envelopes.first { - self.envelopeURL = firstEnvelope - } - if self.stampURL == nil, let firstStamp = stamps.first { - self.stampURL = firstStamp - } - isLoading = false - } catch { - self.error = error - isLoading = false - print("Failed to load envelope and stamp: \(error)") - } - } - - // MARK: 편지저장 - @MainActor - func saveImportingImage() async -> Bool { - isLoading = true - error = nil - - if fromUserId == nil || fromUserKabinettNumber == nil { - await fetchCurrentWriter() - } - - let result = await componentsUseCase.saveLetter( - postScript: postScript, - envelope: envelopeURL ?? "", - stamp: stampURL ?? "", - fromUserId: fromUserId, - fromUserName: fromUserName, - fromUserKabinettNumber: fromUserKabinettNumber ?? 0, - toUserId: toUserId, - toUserName: toUserName, - toUserKabinettNumber: toUserKabinettNumber ?? 0, - photoContents: photoContents, - date: date, - isRead: false - ) - switch result { - case .success: - resetState() - isLoading = false - return true - case .failure(let error): - print("Failed to save letter: \(error)") - self.error = error - isLoading = false - return false - } - } - - // MARK: Methods (편지 저장 후 초기화) - func resetState() { - selectedItems = [] - photoContents = [] - fromUserName = "" - toUserName = "" - date = Date() - postScript = nil - envelopeURL = nil - stampURL = nil - } - - func resetSelections() { - selectedItems = [] - photoContents = [] - postScript = nil - envelopeURL = nil - stampURL = nil - toUserId = nil - toUserName = "" - toUserKabinettNumber = nil - toUserSearch = "" - toUserSearchResults = [] - } - - var formattedDate: String { - let formatter = DateFormatter() - formatter.dateFormat = "yyyy.MM.dd" - return formatter.string(from: date) - } } From 455ac6f78ecd1287e7c4f1f466fa015e9dc284de Mon Sep 17 00:00:00 2001 From: ksiomng Date: Tue, 25 Mar 2025 13:17:31 +0900 Subject: [PATCH 07/39] =?UTF-8?q?Fix:=20ImportLetterUseCase,=20@Injected?= =?UTF-8?q?=20=EC=A3=BC=EC=9E=85=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Kabinett.xcodeproj/project.pbxproj | 4 - .../DIContainer/Keys/UseCaseKeys.swift | 4 - Kabinett/Application/KabinettApp.swift | 8 -- .../DefaultImportLetterUseCase.swift | 117 ------------------ .../ImportLetterUseCase.swift | 29 ----- .../Commons/CustomTabView/CustomTabView.swift | 3 +- .../View/WriteLetter/ContentWriteView.swift | 1 - .../ImportLetter/ImagePickerViewModel.swift | 5 - 8 files changed, 1 insertion(+), 170 deletions(-) delete mode 100644 Kabinett/Data/DefaultUseCases/DefaultImportLetterUseCase.swift diff --git a/Kabinett.xcodeproj/project.pbxproj b/Kabinett.xcodeproj/project.pbxproj index ccb8016c..a7eeba7f 100644 --- a/Kabinett.xcodeproj/project.pbxproj +++ b/Kabinett.xcodeproj/project.pbxproj @@ -120,7 +120,6 @@ 83F0D6872C7072DB001B8733 /* FirestoreWriterManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83F0D6862C7072DB001B8733 /* FirestoreWriterManager.swift */; }; AF738DC42D50B3900081FB96 /* Extension+NotificationName.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF738DC32D50B3900081FB96 /* Extension+NotificationName.swift */; }; AF738DC62D50B3C00081FB96 /* ToastViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF738DC52D50B3C00081FB96 /* ToastViewModel.swift */; }; - AF9B18F82C894B5900F3E446 /* DefaultImportLetterUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF9B18F72C894B5900F3E446 /* DefaultImportLetterUseCase.swift */; }; AF9B18FA2C894B7100F3E446 /* DefaultLetterBoxUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF9B18F92C894B7100F3E446 /* DefaultLetterBoxUseCase.swift */; }; AFA58F222C6A004C00A7C569 /* WriteLetterUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = AFA58F212C6A004C00A7C569 /* WriteLetterUseCase.swift */; }; AFA58F242C6A02BF00A7C569 /* ImportLetterUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = AFA58F232C6A02BF00A7C569 /* ImportLetterUseCase.swift */; }; @@ -263,7 +262,6 @@ 83F0D6862C7072DB001B8733 /* FirestoreWriterManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FirestoreWriterManager.swift; sourceTree = ""; }; AF738DC32D50B3900081FB96 /* Extension+NotificationName.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Extension+NotificationName.swift"; sourceTree = ""; }; AF738DC52D50B3C00081FB96 /* ToastViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ToastViewModel.swift; sourceTree = ""; }; - AF9B18F72C894B5900F3E446 /* DefaultImportLetterUseCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultImportLetterUseCase.swift; sourceTree = ""; }; AF9B18F92C894B7100F3E446 /* DefaultLetterBoxUseCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultLetterBoxUseCase.swift; sourceTree = ""; }; AFA58F172C69DB1300A7C569 /* Writer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Writer.swift; sourceTree = ""; }; AFA58F212C6A004C00A7C569 /* WriteLetterUseCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WriteLetterUseCase.swift; sourceTree = ""; }; @@ -438,7 +436,6 @@ isa = PBXGroup; children = ( AFB88B582C89410600E79F90 /* DefaultWriteLetterUseCase.swift */, - AF9B18F72C894B5900F3E446 /* DefaultImportLetterUseCase.swift */, AF9B18F92C894B7100F3E446 /* DefaultLetterBoxUseCase.swift */, 83949C892C71BC0F0080D72C /* DefaultProfileUseCase.swift */, 83D9C8E42C830C7600EF2684 /* DefaultSignUpUseCase.swift */, @@ -977,7 +974,6 @@ 57ED9CD52C70E4A400A4312C /* OpenSourceLicenseModalView.swift in Sources */, 8356843F2CE0A43600120EC8 /* DIContainer.swift in Sources */, 538150542C8AF04B007B1E5A /* Extension+LetterType.swift in Sources */, - AF9B18F82C894B5900F3E446 /* DefaultImportLetterUseCase.swift in Sources */, 5358E0732CE16E630089C59F /* SearchBarViewModel.swift in Sources */, 83CA92AB2C8160CB00DFB68B /* Publisher+.swift in Sources */, 7F6CE9C42C6B50050074568E /* ImagePickerViewModel.swift in Sources */, diff --git a/Kabinett/Application/DIContainer/Keys/UseCaseKeys.swift b/Kabinett/Application/DIContainer/Keys/UseCaseKeys.swift index 80ed2830..0fa15df0 100644 --- a/Kabinett/Application/DIContainer/Keys/UseCaseKeys.swift +++ b/Kabinett/Application/DIContainer/Keys/UseCaseKeys.swift @@ -24,7 +24,3 @@ struct WriteLetterUseCaseKey: InjectionKey { struct LetterBoxUseCaseKey: InjectionKey { typealias Value = LetterBoxUseCase } - -struct ImportLetterUseCaseKey: InjectionKey { - typealias Value = ImportLetterUseCase -} diff --git a/Kabinett/Application/KabinettApp.swift b/Kabinett/Application/KabinettApp.swift index 72c8a2d4..66ee94b9 100644 --- a/Kabinett/Application/KabinettApp.swift +++ b/Kabinett/Application/KabinettApp.swift @@ -152,14 +152,6 @@ struct KabinettApp: App { authManager: authManager ) } - Module(ImportLetterUseCaseKey.self) { - DefaultImportLetterUseCase( - authManager: authManager, - writerManager: firestoreWriterManager, - letterManager: firestoreLetterWriteManager, - letterStorageManager: firestorageLetterManager - ) - } } } } diff --git a/Kabinett/Data/DefaultUseCases/DefaultImportLetterUseCase.swift b/Kabinett/Data/DefaultUseCases/DefaultImportLetterUseCase.swift deleted file mode 100644 index 8c0c06ca..00000000 --- a/Kabinett/Data/DefaultUseCases/DefaultImportLetterUseCase.swift +++ /dev/null @@ -1,117 +0,0 @@ -// -// DefaultImportLetterUseCase.swift -// Kabinett -// -// Created by JIHYE SEOK on 9/5/24. -// - -import Foundation -import Combine -import os - -final class DefaultImportLetterUseCase { - private let logger: Logger - private let authManager: AuthManager - private let writerManager: FirestoreWriterManager - private let letterManager: FirestoreLetterWriteManager - private let letterStorageManager: FirestorageLetterManager - - init( - authManager: AuthManager, - writerManager: FirestoreWriterManager, - letterManager: FirestoreLetterWriteManager, - letterStorageManager: FirestorageLetterManager - ) { - self.logger = Logger( - subsystem: "co.kr.codegrove.Kabinett", - category: "DefaultImportLetterUseCase" - ) - self.authManager = authManager - self.writerManager = writerManager - self.letterManager = letterManager - self.letterStorageManager = letterStorageManager - } -} - -extension DefaultImportLetterUseCase: ImportLetterUseCase { - func saveLetter(postScript: String?, - envelope: String, - stamp: String, - fromUserId: String?, - fromUserName: String, - fromUserKabinettNumber: Int?, - toUserId: String?, - toUserName: String, - toUserKabinettNumber: Int?, - photoContents: [Data], - date: Date, - isRead: Bool - ) async -> Result { - do { - let photoContentStringUrl = try await letterStorageManager.convertPhotoToUrl(photoContents: photoContents) - - let letter = Letter( - id: nil, - fontString: nil, - postScript: postScript ?? "", - envelopeImageUrlString: envelope, - stampImageUrlString: stamp, - fromUserId: fromUserId ?? "", - fromUserName: fromUserName, - fromUserKabinettNumber: fromUserKabinettNumber ?? 0, - toUserId: toUserId ?? "", - toUserName: toUserName, - toUserKabinettNumber: toUserKabinettNumber ?? 0, - content: [], - photoContents: photoContentStringUrl, - date: date, - stationeryImageUrlString: nil, - isRead: isRead) - - return await letterManager.saveLetterToFireStore(letter: letter, fromUserId: fromUserId, toUserId: toUserId) - } catch { - logger.error("Failed to save Photo Letter: \(error.localizedDescription)") - return .failure(error) - } - } - - // TODO: - Refactor this codes - func findWriter(by query: String) async -> [Writer] { - do { - async let resultByName = letterManager.findDocuments( - by: Query(key: .name, value: query), - as: Writer.self - ) - async let resultByNumber = letterManager.findDocuments( - by: Query(key: .kabinettNumber, value: query), - as: Writer.self - ) - - return try await resultByName + resultByNumber - } catch { - logger.error("Find writer error: \(error.localizedDescription)") - return [] - } - } - - func getCurrentWriter() -> AnyPublisher { - authManager - .getCurrentUser() - .compactMap { $0 } - .asyncMap { [weak self] user in - await self?.writerManager.getWriterDocument(with: user.uid) - } - .compactMap { $0 } - .eraseToAnyPublisher() - } - - // 편지봉투 로딩 - func loadEnvelopes() async -> Result<[String], any Error> { - await letterStorageManager.loadStorage(path: "Envelopes") - } - - // 우표 로딩 - func loadStamps() async -> Result<[String], any Error> { - await letterStorageManager.loadStorage(path: "Stamps") - } -} diff --git a/Kabinett/Domain/UseCase/ImportLetterUseCase/ImportLetterUseCase.swift b/Kabinett/Domain/UseCase/ImportLetterUseCase/ImportLetterUseCase.swift index 6b41a1f6..8b137891 100644 --- a/Kabinett/Domain/UseCase/ImportLetterUseCase/ImportLetterUseCase.swift +++ b/Kabinett/Domain/UseCase/ImportLetterUseCase/ImportLetterUseCase.swift @@ -1,30 +1 @@ -// -// ImportLetterUseCase.swift -// Kabinett -// -// Created by JIHYE SEOK on 8/12/24. -// -import Foundation -import Combine - -protocol ImportLetterUseCase { - func saveLetter(postScript: String?, - envelope: String, - stamp: String, - fromUserId: String?, - fromUserName: String, - fromUserKabinettNumber: Int?, - toUserId: String?, - toUserName: String, - toUserKabinettNumber: Int?, - photoContents: [Data], - date: Date, - isRead: Bool - ) async -> Result - func findWriter(by query: String) async -> [Writer] - func getCurrentWriter() -> AnyPublisher - - func loadEnvelopes() async -> Result<[String], any Error> - func loadStamps() async -> Result<[String], any Error> -} diff --git a/Kabinett/Presentation/Commons/CustomTabView/CustomTabView.swift b/Kabinett/Presentation/Commons/CustomTabView/CustomTabView.swift index 6bd51fde..35885c28 100644 --- a/Kabinett/Presentation/Commons/CustomTabView/CustomTabView.swift +++ b/Kabinett/Presentation/Commons/CustomTabView/CustomTabView.swift @@ -19,12 +19,11 @@ struct CustomTabView: View { @Injected(LetterBoxUseCaseKey.self) var letterBoxUseCase: LetterBoxUseCase @Injected(ProfileUseCaseKey.self) var profileUseCase: ProfileUseCase @Injected(WriteLetterUseCaseKey.self) var writeLetterUseCase: WriteLetterUseCase - @Injected(ImportLetterUseCaseKey.self) var importLetterUseCase: ImportLetterUseCase self._customTabViewModel = StateObject(wrappedValue: CustomTabViewModel()) self._profileViewModel = StateObject(wrappedValue: ProfileViewModel(profileUseCase: profileUseCase)) self._envelopeStampSelectionViewModel = StateObject(wrappedValue: EnvelopeStampSelectionViewModel(useCase: writeLetterUseCase)) - self._imagePickerViewModel = StateObject(wrappedValue: ImagePickerViewModel(componentsUseCase: importLetterUseCase)) + self._imagePickerViewModel = StateObject(wrappedValue: ImagePickerViewModel()) } var body: some View { diff --git a/Kabinett/Presentation/View/WriteLetter/ContentWriteView.swift b/Kabinett/Presentation/View/WriteLetter/ContentWriteView.swift index 70b083dd..b34e5f05 100644 --- a/Kabinett/Presentation/View/WriteLetter/ContentWriteView.swift +++ b/Kabinett/Presentation/View/WriteLetter/ContentWriteView.swift @@ -25,7 +25,6 @@ struct ContentWriteView: View { imageViewModel: ImagePickerViewModel, customTabViewModel: CustomTabViewModel ) { - @Injected(ImportLetterUseCaseKey.self) var importLetterUseCase: ImportLetterUseCase self._letterContent = letterContent self.imageViewModel = imageViewModel self.customTabViewModel = customTabViewModel diff --git a/Kabinett/Presentation/ViewModel/ImportLetter/ImagePickerViewModel.swift b/Kabinett/Presentation/ViewModel/ImportLetter/ImagePickerViewModel.swift index 59bc874b..76bef653 100644 --- a/Kabinett/Presentation/ViewModel/ImportLetter/ImagePickerViewModel.swift +++ b/Kabinett/Presentation/ViewModel/ImportLetter/ImagePickerViewModel.swift @@ -17,11 +17,6 @@ final class ImagePickerViewModel: ObservableObject { @Published var error: Error? private var cancellables = Set() - private let componentsUseCase: ImportLetterUseCase - - init(componentsUseCase: ImportLetterUseCase) { - self.componentsUseCase = componentsUseCase - } func resetSelections() { selectedItems = [] From 8d4d818ed2f7e13004273ef16fd54975a4859a69 Mon Sep 17 00:00:00 2001 From: ksiomng Date: Tue, 25 Mar 2025 13:18:46 +0900 Subject: [PATCH 08/39] =?UTF-8?q?Design:=20=ED=83=AD=EB=B0=94=20=EC=9D=B4?= =?UTF-8?q?=EB=AF=B8=EC=A7=80=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Commons/CustomTabViewModel/CustomTabViewModel.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Kabinett/Presentation/Commons/CustomTabViewModel/CustomTabViewModel.swift b/Kabinett/Presentation/Commons/CustomTabViewModel/CustomTabViewModel.swift index 34da405f..73dc5107 100644 --- a/Kabinett/Presentation/Commons/CustomTabViewModel/CustomTabViewModel.swift +++ b/Kabinett/Presentation/Commons/CustomTabViewModel/CustomTabViewModel.swift @@ -28,7 +28,7 @@ final class CustomTabViewModel: ObservableObject { init() { self.envelopeImage = UIImage(systemName: "envelope")!.applyingSymbolConfiguration(.init(pointSize: 21, weight: .medium))! - self.plusImage = UIImage(systemName: "plus")!.applyingSymbolConfiguration(.init(pointSize: 24, weight: .medium))! + self.plusImage = UIImage(systemName: "pencil.line")!.applyingSymbolConfiguration(.init(pointSize: 24, weight: .medium))! self.profileImage = UIImage(systemName: "circle.fill")!.applyingSymbolConfiguration(.init(pointSize: 21, weight: .medium))! } From 60d9eefaffbf609ff69accd775dd07f5c455bd4c Mon Sep 17 00:00:00 2001 From: ksiomng Date: Tue, 25 Mar 2025 13:19:19 +0900 Subject: [PATCH 09/39] =?UTF-8?q?Design:=20=ED=83=AD=EB=B0=94=20=EC=95=84?= =?UTF-8?q?=EC=9D=B4=EC=BD=98=20=EC=84=A0=ED=83=9D=EB=90=98=EC=97=88?= =?UTF-8?q?=EC=9D=84=20=EB=95=8C=20=EC=83=89=EC=83=81=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Kabinett/Presentation/Commons/CustomTabView/CustomTabBar.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Kabinett/Presentation/Commons/CustomTabView/CustomTabBar.swift b/Kabinett/Presentation/Commons/CustomTabView/CustomTabBar.swift index 8e63715a..037d32b4 100644 --- a/Kabinett/Presentation/Commons/CustomTabView/CustomTabBar.swift +++ b/Kabinett/Presentation/Commons/CustomTabView/CustomTabBar.swift @@ -43,7 +43,7 @@ struct CustomTabBar: View { }) { Image(uiImage: image) .renderingMode(.template) - .foregroundStyle(viewModel.selectedTab == tag ? Color.primary600 : Color.primary300) + .foregroundStyle(viewModel.selectedTab == tag ? Color.primary900 : Color.primary300) } } From bc3b593377b859f37c73c69d6c9000af0a80c57c Mon Sep 17 00:00:00 2001 From: ksiomng Date: Tue, 25 Mar 2025 13:24:46 +0900 Subject: [PATCH 10/39] =?UTF-8?q?Design:=20=EB=AA=A8=EB=8B=AC=EB=A1=9C=20?= =?UTF-8?q?=EC=8B=9C=EC=9E=91=ED=95=98=EB=8A=94=EA=B1=B0=EB=9D=BC=20?= =?UTF-8?q?=EB=B0=B1=EB=B2=84=ED=8A=BC=EC=9D=B4=20=EC=97=86=EC=96=B4?= =?UTF-8?q?=EC=84=9C=20=EB=A7=8C=EB=93=A4=EC=96=B4=EC=A4=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../View/WriteLetter/StationerySelectionView.swift | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Kabinett/Presentation/View/WriteLetter/StationerySelectionView.swift b/Kabinett/Presentation/View/WriteLetter/StationerySelectionView.swift index 88340083..d686a69b 100644 --- a/Kabinett/Presentation/View/WriteLetter/StationerySelectionView.swift +++ b/Kabinett/Presentation/View/WriteLetter/StationerySelectionView.swift @@ -65,9 +65,10 @@ struct StationerySelectionView: View { customViewModel.hideWriteView() }) { Image(systemName: "chevron.backward") + .fontWeight(.semibold) .foregroundColor(Color.primary900) .imageScale(.large) - .padding(.leading, -5) + .padding(.leading, 3) } } ToolbarItem(placement: .topBarTrailing) { From 881211b0536598349e44b3895aa578b21bae2735 Mon Sep 17 00:00:00 2001 From: ksiomng Date: Tue, 25 Mar 2025 13:34:32 +0900 Subject: [PATCH 11/39] =?UTF-8?q?Fix:=20=EA=B8=B0=EC=A1=B4=20=ED=8F=AC?= =?UTF-8?q?=ED=86=A0=ED=94=BC=EC=BB=A4=20=EC=97=86=EC=95=A0=EA=B3=A0?= =?UTF-8?q?=EC=83=88=EB=A1=9C=20=ED=83=AD=EB=B0=94=EC=97=90=EC=84=9C=20?= =?UTF-8?q?=EB=A7=8C=EB=93=A4=EC=96=B4=EC=A4=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Kabinett.xcodeproj/project.pbxproj | 8 --- .../Components/MiniTabBarView.swift | 9 ++- .../View/WriteLetter/ContentWriteView.swift | 5 +- .../WriteLetter/ImportPhoto/CameraView.swift | 61 ------------------- .../ImportPhoto/ImagePickerView.swift | 42 ------------- 5 files changed, 7 insertions(+), 118 deletions(-) delete mode 100644 Kabinett/Presentation/View/WriteLetter/ImportPhoto/CameraView.swift delete mode 100644 Kabinett/Presentation/View/WriteLetter/ImportPhoto/ImagePickerView.swift diff --git a/Kabinett.xcodeproj/project.pbxproj b/Kabinett.xcodeproj/project.pbxproj index a7eeba7f..d5cddc11 100644 --- a/Kabinett.xcodeproj/project.pbxproj +++ b/Kabinett.xcodeproj/project.pbxproj @@ -88,8 +88,6 @@ 7F6CE9C02C6B2FEA0074568E /* CustomTabView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F6CE9BF2C6B2FE90074568E /* CustomTabView.swift */; }; 7F6CE9C42C6B50050074568E /* ImagePickerViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F6CE9C32C6B50050074568E /* ImagePickerViewModel.swift */; }; 7F6CE9E22C6E25500074568E /* CameraViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F6CE9E12C6E25500074568E /* CameraViewModel.swift */; }; - 7F6CE9E62C6E28400074568E /* CameraView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F6CE9E52C6E28400074568E /* CameraView.swift */; }; - 7F78684C2C78B41A0083D204 /* ImagePickerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F78684B2C78B41A0083D204 /* ImagePickerView.swift */; }; 7F9890822C7EF5C30035CB0D /* CustomTabBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F9890812C7EF5C30035CB0D /* CustomTabBar.swift */; }; 7FCAE2BA2C73102900228FA7 /* ImageDetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7FCAE2B92C73102900228FA7 /* ImageDetailView.swift */; }; 8314013F2C69C34500F601FB /* Letter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8314013E2C69C34500F601FB /* Letter.swift */; }; @@ -230,8 +228,6 @@ 7F6CE9BF2C6B2FE90074568E /* CustomTabView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomTabView.swift; sourceTree = ""; }; 7F6CE9C32C6B50050074568E /* ImagePickerViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImagePickerViewModel.swift; sourceTree = ""; }; 7F6CE9E12C6E25500074568E /* CameraViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CameraViewModel.swift; sourceTree = ""; }; - 7F6CE9E52C6E28400074568E /* CameraView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CameraView.swift; sourceTree = ""; }; - 7F78684B2C78B41A0083D204 /* ImagePickerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImagePickerView.swift; sourceTree = ""; }; 7F9890812C7EF5C30035CB0D /* CustomTabBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomTabBar.swift; sourceTree = ""; }; 7FCAE2B92C73102900228FA7 /* ImageDetailView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageDetailView.swift; sourceTree = ""; }; 8314013E2C69C34500F601FB /* Letter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Letter.swift; sourceTree = ""; }; @@ -403,9 +399,7 @@ 57F7A5532D924E8A002E1209 /* ImportPhoto */ = { isa = PBXGroup; children = ( - 7F78684B2C78B41A0083D204 /* ImagePickerView.swift */, 7FCAE2B92C73102900228FA7 /* ImageDetailView.swift */, - 7F6CE9E52C6E28400074568E /* CameraView.swift */, ); path = ImportPhoto; sourceTree = ""; @@ -999,7 +993,6 @@ 5358E07B2CE1F0200089C59F /* ZoomableScrollView.swift in Sources */, 835684422CE0A43600120EC8 /* Module.swift in Sources */, 83A826CD2C6F2D23006FB09B /* ProfileUseCase.swift in Sources */, - 7F6CE9E62C6E28400074568E /* CameraView.swift in Sources */, 57966BA02C7EC452008D650B /* SelectionTabView.swift in Sources */, 04DEC0E32C6B2E1C00D289EA /* SignUpKabinettNumberSelectView.swift in Sources */, 04DEC0E12C6AFA7500D289EA /* SignUpNameInputView.swift in Sources */, @@ -1028,7 +1021,6 @@ 53BA8D212C69E4B60084D5CC /* LetterEnvelopeCell.swift in Sources */, AFDE7D2E2C75797A0019F2DE /* FirestorageLetterManager.swift in Sources */, 57966B9E2C7DB267008D650B /* Extension+TextField.swift in Sources */, - 7F78684C2C78B41A0083D204 /* ImagePickerView.swift in Sources */, AFB88B592C89410600E79F90 /* DefaultWriteLetterUseCase.swift in Sources */, 53FC6B8A2C90221600E7D9A8 /* LetterHelper.swift in Sources */, 57ED94FA2C84AFAC00A6F187 /* LetterWriteModel.swift in Sources */, diff --git a/Kabinett/Presentation/View/WriteLetter/Components/MiniTabBarView.swift b/Kabinett/Presentation/View/WriteLetter/Components/MiniTabBarView.swift index 5f83cd95..e2e6047f 100644 --- a/Kabinett/Presentation/View/WriteLetter/Components/MiniTabBarView.swift +++ b/Kabinett/Presentation/View/WriteLetter/Components/MiniTabBarView.swift @@ -6,11 +6,13 @@ // import SwiftUI +import PhotosUI struct MiniTabBarView: View { @Binding var letterContent: LetterWriteModel @ObservedObject var viewModel: ContentWriteViewModel @ObservedObject var customTabViewModel: CustomTabViewModel + @ObservedObject var imageViewModel: ImagePickerViewModel var body: some View { if viewModel.currentIndex < viewModel.texts.count { @@ -61,9 +63,10 @@ struct MiniTabBarView: View { .font(.system(size: 15)) .frame(width: UIScreen.main.bounds.width * 0.4/4) } - Button { - customTabViewModel.showPhotoLibrary = true - } label: { + PhotosPicker( + selection: $imageViewModel.selectedItems, + maxSelectionCount: 10, + matching: .images) { Image(systemName: "photo.on.rectangle.angled") .font(.system(size: 15)) .frame(width: UIScreen.main.bounds.width * 0.4/4, height: 30) diff --git a/Kabinett/Presentation/View/WriteLetter/ContentWriteView.swift b/Kabinett/Presentation/View/WriteLetter/ContentWriteView.swift index b34e5f05..67afd9a5 100644 --- a/Kabinett/Presentation/View/WriteLetter/ContentWriteView.swift +++ b/Kabinett/Presentation/View/WriteLetter/ContentWriteView.swift @@ -48,7 +48,7 @@ struct ContentWriteView: View { .clipShape(Capsule()) } .padding(.bottom, LayoutHelper.shared.getSize(forSE: 0.03, forOthers: 0.0)) - MiniTabBarView(letterContent: $letterContent, viewModel: viewModel, customTabViewModel: customTabViewModel) + MiniTabBarView(letterContent: $letterContent, viewModel: viewModel, customTabViewModel: customTabViewModel, imageViewModel: imageViewModel) if keyBoard { Button(action:{ @@ -104,9 +104,6 @@ struct ContentWriteView: View { keyBoard = false } } - .sheet(isPresented: $customTabViewModel.showPhotoLibrary) { - ImagePickerView(imageViewModel: imageViewModel, customViewModel: customTabViewModel) - } .analyticsScreen( name: "\(type(of:self))", extraParameters: [ diff --git a/Kabinett/Presentation/View/WriteLetter/ImportPhoto/CameraView.swift b/Kabinett/Presentation/View/WriteLetter/ImportPhoto/CameraView.swift deleted file mode 100644 index 34ffbff1..00000000 --- a/Kabinett/Presentation/View/WriteLetter/ImportPhoto/CameraView.swift +++ /dev/null @@ -1,61 +0,0 @@ -// -// CameraView.swift -// Kabinett -// -// Created by 김정우 on 8/15/24. -// - -import SwiftUI - -//struct CameraView: View { -// @StateObject private var viewModel = CameraViewModel() -// @ObservedObject var imagePickerViewModel: ImagePickerViewModel -// @Environment(\.dismiss) private var dismiss -// -// var body: some View { -// CameraViewRepresentable(viewModel: viewModel) -// .edgesIgnoringSafeArea(.all) -// .onChange(of: viewModel.capturedImage) { _, newImage in -// if let image = newImage, -// let imageData = image.jpegData(compressionQuality: 0.5) { -// imagePickerViewModel.photoContents.append(imageData) -// dismiss() -// } -// } -// } -//} -// -//// MARK: - Camera View Representable -//private struct CameraViewRepresentable: UIViewControllerRepresentable { -// @ObservedObject var viewModel: CameraViewModel -// -// func makeUIViewController(context: Context) -> UIImagePickerController { -// let picker = UIImagePickerController() -// picker.sourceType = .camera -// picker.delegate = context.coordinator -// return picker -// } -// -// func updateUIViewController(_ uiViewController: UIImagePickerController, context: Context) {} -// -// func makeCoordinator() -> Coordinator { -// Coordinator(self) -// } -// -// // MARK: Coordinator (UIImagePickerController Coordinator) -// class Coordinator: NSObject, UINavigationControllerDelegate, UIImagePickerControllerDelegate { -// let parent: CameraViewRepresentable -// -// init(_ parent: CameraViewRepresentable) { -// self.parent = parent -// } -// -// func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) { -// parent.viewModel.captureImage(with: info) -// } -// -// func imagePickerControllerDidCancel(_ picker: UIImagePickerController) { -// picker.dismiss(animated: true, completion: nil) -// } -// } -//} diff --git a/Kabinett/Presentation/View/WriteLetter/ImportPhoto/ImagePickerView.swift b/Kabinett/Presentation/View/WriteLetter/ImportPhoto/ImagePickerView.swift deleted file mode 100644 index 305442da..00000000 --- a/Kabinett/Presentation/View/WriteLetter/ImportPhoto/ImagePickerView.swift +++ /dev/null @@ -1,42 +0,0 @@ -// -// ImagePickerView.swift -// Kabinett -// -// Created by 김정우 on 8/23/24. -// - -import SwiftUI -import _PhotosUI_SwiftUI - -struct ImagePickerView: View { - @ObservedObject var imageViewModel: ImagePickerViewModel - @ObservedObject var customViewModel: CustomTabViewModel - - var body: some View { - EmptyView() - .photosPicker( - isPresented: $customViewModel.showPhotoLibrary, - selection: $imageViewModel.selectedItems, - maxSelectionCount: 10, - matching: .images - ) - .onChange(of: imageViewModel.selectedItems) { _, newValue in - Task { @MainActor in - imageViewModel.selectedItems = newValue - await imageViewModel.loadImages() - } - } - - .onChange(of: imageViewModel.photoContents) { _, newContents in - if !newContents.isEmpty { - customViewModel.showImagePreview = true - } - } -// .fullScreenCover(isPresented: $customViewModel.showImagePreview) { -// ImagePreview( -// imageViewModel: imageViewModel, -// customViewModel: customViewModel -// ) -// } - } -} From c9813eda9b0de295861342e1a1e79fa8f5de4fef Mon Sep 17 00:00:00 2001 From: ksiomng Date: Tue, 25 Mar 2025 14:36:29 +0900 Subject: [PATCH 12/39] =?UTF-8?q?Fix:=20ImagePickerViewModel=20=ED=95=84?= =?UTF-8?q?=EC=9A=94=ED=95=9C=20=EA=B3=B3=EC=97=90=EC=84=9C=EB=A7=8C=20?= =?UTF-8?q?=EC=82=AC=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Kabinett/Application/KabinettApp.swift | 26 +++++++++---------- .../Commons/CustomTabView/CustomTabView.swift | 4 +-- .../Components/MiniTabBarView.swift | 6 ++--- .../View/WriteLetter/ContentWriteView.swift | 8 +++--- .../EnvelopeStampSelectionView.swift | 8 ++---- .../View/WriteLetter/PreviewLetterView.swift | 6 +---- .../WriteLetter/StationerySelectionView.swift | 6 +---- .../View/WriteLetter/UserSelectionView.swift | 8 ++---- 8 files changed, 26 insertions(+), 46 deletions(-) diff --git a/Kabinett/Application/KabinettApp.swift b/Kabinett/Application/KabinettApp.swift index 66ee94b9..61a5511e 100644 --- a/Kabinett/Application/KabinettApp.swift +++ b/Kabinett/Application/KabinettApp.swift @@ -17,19 +17,19 @@ struct KabinettApp: App { // Init Firebase App FirebaseApp.configure() - #if DEBUG - // Firebase Authenticate Emulator - Auth.auth().useEmulator(withHost:"localhost", port:9099) - - // Firebase Storage Emulator - Storage.storage().useEmulator(withHost: "localhost", port: 9199) - - // Firebaes Firestore Emulator - let settings = Firestore.firestore().settings - settings.host = "localhost:8080" - settings.isSSLEnabled = false - Firestore.firestore().settings = settings - #endif +// #if DEBUG +// // Firebase Authenticate Emulator +// Auth.auth().useEmulator(withHost:"localhost", port:9099) +// +// // Firebase Storage Emulator +// Storage.storage().useEmulator(withHost: "localhost", port: 9199) +// +// // Firebaes Firestore Emulator +// let settings = Firestore.firestore().settings +// settings.host = "localhost:8080" +// settings.isSSLEnabled = false +// Firestore.firestore().settings = settings +// #endif // MARK: Register Dependencies KabinettApp.registerServices() diff --git a/Kabinett/Presentation/Commons/CustomTabView/CustomTabView.swift b/Kabinett/Presentation/Commons/CustomTabView/CustomTabView.swift index 35885c28..82e68989 100644 --- a/Kabinett/Presentation/Commons/CustomTabView/CustomTabView.swift +++ b/Kabinett/Presentation/Commons/CustomTabView/CustomTabView.swift @@ -12,7 +12,6 @@ struct CustomTabView: View { @StateObject private var customTabViewModel = CustomTabViewModel() @StateObject private var profileViewModel: ProfileViewModel @StateObject private var envelopeStampSelectionViewModel: EnvelopeStampSelectionViewModel - @StateObject private var imagePickerViewModel: ImagePickerViewModel @State private var letterWriteViewModel = LetterWriteModel() init() { @@ -23,7 +22,6 @@ struct CustomTabView: View { self._customTabViewModel = StateObject(wrappedValue: CustomTabViewModel()) self._profileViewModel = StateObject(wrappedValue: ProfileViewModel(profileUseCase: profileUseCase)) self._envelopeStampSelectionViewModel = StateObject(wrappedValue: EnvelopeStampSelectionViewModel(useCase: writeLetterUseCase)) - self._imagePickerViewModel = StateObject(wrappedValue: ImagePickerViewModel()) } var body: some View { @@ -59,7 +57,7 @@ struct CustomTabView: View { } } .sheet(isPresented: $customTabViewModel.showWriteView) { - UserSelectionView(letterContent: $letterWriteViewModel, customViewModel: customTabViewModel, imageViewModel: imagePickerViewModel) + UserSelectionView(letterContent: $letterWriteViewModel, customViewModel: customTabViewModel) .presentationDetents([.height(300), .large]) } } diff --git a/Kabinett/Presentation/View/WriteLetter/Components/MiniTabBarView.swift b/Kabinett/Presentation/View/WriteLetter/Components/MiniTabBarView.swift index e2e6047f..90540b6b 100644 --- a/Kabinett/Presentation/View/WriteLetter/Components/MiniTabBarView.swift +++ b/Kabinett/Presentation/View/WriteLetter/Components/MiniTabBarView.swift @@ -70,10 +70,10 @@ struct MiniTabBarView: View { Image(systemName: "photo.on.rectangle.angled") .font(.system(size: 15)) .frame(width: UIScreen.main.bounds.width * 0.4/4, height: 30) - .background(letterContent.photoContents.isEmpty ? Color.clear : Color.white) - .foregroundStyle(letterContent.photoContents.isEmpty ? Color("ToolBarIcon") : Color(.primary900)) + .background(imageViewModel.selectedItems.isEmpty ? Color.clear : Color.white) + .foregroundStyle(imageViewModel.selectedItems.isEmpty ? Color("ToolBarIcon") : Color(.primary900)) .clipShape(Capsule()) - .shadow(color: letterContent.photoContents.isEmpty ? Color.clear : Color(.primary300), radius: 7, x: 3, y: 3) + .shadow(color: imageViewModel.selectedItems.isEmpty ? Color.clear : Color(.primary300), radius: 7, x: 3, y: 3) } } .frame(maxWidth: UIScreen.main.bounds.width * 0.5, maxHeight: 40) diff --git a/Kabinett/Presentation/View/WriteLetter/ContentWriteView.swift b/Kabinett/Presentation/View/WriteLetter/ContentWriteView.swift index 67afd9a5..3a3d1b89 100644 --- a/Kabinett/Presentation/View/WriteLetter/ContentWriteView.swift +++ b/Kabinett/Presentation/View/WriteLetter/ContentWriteView.swift @@ -14,7 +14,7 @@ import FirebaseAnalytics struct ContentWriteView: View { @Binding var letterContent: LetterWriteModel @StateObject var viewModel = ContentWriteViewModel() - @ObservedObject var imageViewModel: ImagePickerViewModel + @StateObject var imageViewModel: ImagePickerViewModel @ObservedObject var customTabViewModel: CustomTabViewModel @StateObject var fontViewModel = FontSelectionViewModel() @@ -22,12 +22,11 @@ struct ContentWriteView: View { init( letterContent: Binding, - imageViewModel: ImagePickerViewModel, customTabViewModel: CustomTabViewModel ) { self._letterContent = letterContent - self.imageViewModel = imageViewModel self.customTabViewModel = customTabViewModel + self._imageViewModel = StateObject(wrappedValue: ImagePickerViewModel()) } var body: some View { @@ -76,8 +75,7 @@ struct ContentWriteView: View { ToolbarItem(placement: .topBarTrailing) { NavigationLink(destination: EnvelopeStampSelectionView( letterContent: $letterContent, - customTabViewModel: customTabViewModel, - imageViewModel: imageViewModel + customTabViewModel: customTabViewModel )) { Text("다음") .fontWeight(.medium) diff --git a/Kabinett/Presentation/View/WriteLetter/EnvelopeStampSelectionView.swift b/Kabinett/Presentation/View/WriteLetter/EnvelopeStampSelectionView.swift index b4e6f522..ae82deb6 100644 --- a/Kabinett/Presentation/View/WriteLetter/EnvelopeStampSelectionView.swift +++ b/Kabinett/Presentation/View/WriteLetter/EnvelopeStampSelectionView.swift @@ -12,7 +12,6 @@ import FirebaseAnalytics struct EnvelopeStampSelectionView: View { @Binding var letterContent: LetterWriteModel @StateObject var viewModel: EnvelopeStampSelectionViewModel - @ObservedObject var imageViewModel: ImagePickerViewModel @ObservedObject var customTabViewModel: CustomTabViewModel @State private var postScriptText: String = "" @State private var envelopeImageUrl: String @@ -20,11 +19,9 @@ struct EnvelopeStampSelectionView: View { init( letterContent: Binding, - customTabViewModel: CustomTabViewModel, - imageViewModel: ImagePickerViewModel + customTabViewModel: CustomTabViewModel ) { self._letterContent = letterContent - self.imageViewModel = imageViewModel self.customTabViewModel = customTabViewModel _envelopeImageUrl = State(initialValue: letterContent.wrappedValue.envelopeImageUrlString) @@ -95,8 +92,7 @@ struct EnvelopeStampSelectionView: View { ToolbarItem(placement: .topBarTrailing) { NavigationLink(destination: PreviewLetterView( letterContent: $letterContent, - customTabViewModel: customTabViewModel, - imagePickerViewModel: imageViewModel + customTabViewModel: customTabViewModel )) { Text("다음") .fontWeight(.medium) diff --git a/Kabinett/Presentation/View/WriteLetter/PreviewLetterView.swift b/Kabinett/Presentation/View/WriteLetter/PreviewLetterView.swift index 7b207ac8..7f4e75f5 100644 --- a/Kabinett/Presentation/View/WriteLetter/PreviewLetterView.swift +++ b/Kabinett/Presentation/View/WriteLetter/PreviewLetterView.swift @@ -14,19 +14,16 @@ struct PreviewLetterView: View { @Binding var letterContent: LetterWriteModel @StateObject var viewModel: PreviewLetterViewModel @ObservedObject var customTabViewModel: CustomTabViewModel - @ObservedObject var imagePickerViewModel: ImagePickerViewModel init( letterContent: Binding, - customTabViewModel: CustomTabViewModel, - imagePickerViewModel: ImagePickerViewModel + customTabViewModel: CustomTabViewModel ) { @Injected(WriteLetterUseCaseKey.self) var writeLetterUseCase: WriteLetterUseCase _viewModel = StateObject(wrappedValue: PreviewLetterViewModel(useCase: writeLetterUseCase)) self._letterContent = letterContent self.customTabViewModel = customTabViewModel - self.imagePickerViewModel = imagePickerViewModel } var body: some View { @@ -70,7 +67,6 @@ struct PreviewLetterView: View { stationery: letterContent.stationeryImageUrlString ?? "", isRead: false) customTabViewModel.hideWriteView() - imagePickerViewModel.resetSelections() } label: { Text("편지 보내기") .font(.system(size: 16)) diff --git a/Kabinett/Presentation/View/WriteLetter/StationerySelectionView.swift b/Kabinett/Presentation/View/WriteLetter/StationerySelectionView.swift index d686a69b..e62a1088 100644 --- a/Kabinett/Presentation/View/WriteLetter/StationerySelectionView.swift +++ b/Kabinett/Presentation/View/WriteLetter/StationerySelectionView.swift @@ -14,18 +14,15 @@ struct StationerySelectionView: View { @Binding var letterContent: LetterWriteModel @StateObject var viewModel : StationerySelectionViewModel @ObservedObject var customViewModel: CustomTabViewModel - @ObservedObject var imageViewModel: ImagePickerViewModel init( letterContent: Binding, - customViewModel: CustomTabViewModel, - imageViewModel: ImagePickerViewModel + customViewModel: CustomTabViewModel ) { @Injected(WriteLetterUseCaseKey.self) var writeLetterUseCase: WriteLetterUseCase _viewModel = StateObject(wrappedValue: StationerySelectionViewModel(useCase: writeLetterUseCase)) self._letterContent = letterContent self.customViewModel = customViewModel - self.imageViewModel = imageViewModel } var body: some View { @@ -74,7 +71,6 @@ struct StationerySelectionView: View { ToolbarItem(placement: .topBarTrailing) { NavigationLink(destination: ContentWriteView( letterContent: $letterContent, - imageViewModel: imageViewModel, customTabViewModel: customViewModel )) { Text("다음") diff --git a/Kabinett/Presentation/View/WriteLetter/UserSelectionView.swift b/Kabinett/Presentation/View/WriteLetter/UserSelectionView.swift index a74da960..b928f6a6 100644 --- a/Kabinett/Presentation/View/WriteLetter/UserSelectionView.swift +++ b/Kabinett/Presentation/View/WriteLetter/UserSelectionView.swift @@ -14,19 +14,16 @@ struct UserSelectionView: View { @Environment(\.dismiss) var dismiss @StateObject var viewModel : UserSelectionViewModel @ObservedObject var customViewModel: CustomTabViewModel - @ObservedObject var imageViewModel: ImagePickerViewModel @State private var isFullScreen = false init( letterContent: Binding, - customViewModel: CustomTabViewModel, - imageViewModel: ImagePickerViewModel + customViewModel: CustomTabViewModel ) { @Injected(WriteLetterUseCaseKey.self) var writeLetterUseCase: WriteLetterUseCase _viewModel = StateObject(wrappedValue: UserSelectionViewModel(useCase: writeLetterUseCase)) self._letterContent = letterContent self.customViewModel = customViewModel - self.imageViewModel = imageViewModel } var body: some View { @@ -51,8 +48,7 @@ struct UserSelectionView: View { NavigationStack { StationerySelectionView( letterContent: $letterContent, - customViewModel: customViewModel, - imageViewModel: imageViewModel + customViewModel: customViewModel ) } } From 703634082667e2532fcbe6d1a26f3c7f22fcf551 Mon Sep 17 00:00:00 2001 From: ksiomng Date: Tue, 25 Mar 2025 14:37:27 +0900 Subject: [PATCH 13/39] =?UTF-8?q?Fix:=20=ED=8C=8C=EC=9D=BC=EC=A0=95?= =?UTF-8?q?=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Kabinett.xcodeproj/project.pbxproj | 14 +------------ .../ViewModel/ImportLetter/.gitkeep | 0 .../ImportLetter/CameraViewModel.swift | 21 ------------------- .../ImagePickerViewModel.swift | 12 +++++++++++ 4 files changed, 13 insertions(+), 34 deletions(-) delete mode 100644 Kabinett/Presentation/ViewModel/ImportLetter/.gitkeep delete mode 100644 Kabinett/Presentation/ViewModel/ImportLetter/CameraViewModel.swift rename Kabinett/Presentation/ViewModel/{ImportLetter => WriteLetter}/ImagePickerViewModel.swift (83%) diff --git a/Kabinett.xcodeproj/project.pbxproj b/Kabinett.xcodeproj/project.pbxproj index d5cddc11..c1b5a89d 100644 --- a/Kabinett.xcodeproj/project.pbxproj +++ b/Kabinett.xcodeproj/project.pbxproj @@ -87,7 +87,6 @@ 7F397C4E2C7C0ECE00388645 /* CustomTabViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F397C4D2C7C0ECE00388645 /* CustomTabViewModel.swift */; }; 7F6CE9C02C6B2FEA0074568E /* CustomTabView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F6CE9BF2C6B2FE90074568E /* CustomTabView.swift */; }; 7F6CE9C42C6B50050074568E /* ImagePickerViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F6CE9C32C6B50050074568E /* ImagePickerViewModel.swift */; }; - 7F6CE9E22C6E25500074568E /* CameraViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F6CE9E12C6E25500074568E /* CameraViewModel.swift */; }; 7F9890822C7EF5C30035CB0D /* CustomTabBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F9890812C7EF5C30035CB0D /* CustomTabBar.swift */; }; 7FCAE2BA2C73102900228FA7 /* ImageDetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7FCAE2B92C73102900228FA7 /* ImageDetailView.swift */; }; 8314013F2C69C34500F601FB /* Letter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8314013E2C69C34500F601FB /* Letter.swift */; }; @@ -227,7 +226,6 @@ 7F397C4D2C7C0ECE00388645 /* CustomTabViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomTabViewModel.swift; sourceTree = ""; }; 7F6CE9BF2C6B2FE90074568E /* CustomTabView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomTabView.swift; sourceTree = ""; }; 7F6CE9C32C6B50050074568E /* ImagePickerViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImagePickerViewModel.swift; sourceTree = ""; }; - 7F6CE9E12C6E25500074568E /* CameraViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CameraViewModel.swift; sourceTree = ""; }; 7F9890812C7EF5C30035CB0D /* CustomTabBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomTabBar.swift; sourceTree = ""; }; 7FCAE2B92C73102900228FA7 /* ImageDetailView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageDetailView.swift; sourceTree = ""; }; 8314013E2C69C34500F601FB /* Letter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Letter.swift; sourceTree = ""; }; @@ -572,15 +570,6 @@ path = SignUp; sourceTree = ""; }; - 8366B6F62C65ECFF0021FAE0 /* ImportLetter */ = { - isa = PBXGroup; - children = ( - 7F6CE9C32C6B50050074568E /* ImagePickerViewModel.swift */, - 7F6CE9E12C6E25500074568E /* CameraViewModel.swift */, - ); - path = ImportLetter; - sourceTree = ""; - }; 8366B6F72C65ED080021FAE0 /* LetterBox */ = { isa = PBXGroup; children = ( @@ -597,6 +586,7 @@ 8366B6F82C65ED0F0021FAE0 /* WriteLetter */ = { isa = PBXGroup; children = ( + 7F6CE9C32C6B50050074568E /* ImagePickerViewModel.swift */, 57C35C662CCA02130083A346 /* FontUtility.swift */, 57ED94F92C84AFAC00A6F187 /* LetterWriteModel.swift */, 57ED9CDD2C73698B00A4312C /* StationerySelectionViewModel.swift */, @@ -684,7 +674,6 @@ 8366B6F92C65ED150021FAE0 /* Profile */, 8366B6F82C65ED0F0021FAE0 /* WriteLetter */, 8366B6F72C65ED080021FAE0 /* LetterBox */, - 8366B6F62C65ECFF0021FAE0 /* ImportLetter */, ); path = ViewModel; sourceTree = ""; @@ -1027,7 +1016,6 @@ 839CE0F92C644BEF003635F3 /* ContentView.swift in Sources */, 57966BA42C7FF739008D650B /* PreviewLetterView.swift in Sources */, 04DEC0DD2C6A3AD600D289EA /* SignUpView.swift in Sources */, - 7F6CE9E22C6E25500074568E /* CameraViewModel.swift in Sources */, 573EE1F82D2BA55B00978283 /* CustomTextEditor.swift in Sources */, 57966B9C2C7D8DAF008D650B /* EnvelopeStampSelectionViewModel.swift in Sources */, 7F6CE9C02C6B2FEA0074568E /* CustomTabView.swift in Sources */, diff --git a/Kabinett/Presentation/ViewModel/ImportLetter/.gitkeep b/Kabinett/Presentation/ViewModel/ImportLetter/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/Kabinett/Presentation/ViewModel/ImportLetter/CameraViewModel.swift b/Kabinett/Presentation/ViewModel/ImportLetter/CameraViewModel.swift deleted file mode 100644 index 4c0c554c..00000000 --- a/Kabinett/Presentation/ViewModel/ImportLetter/CameraViewModel.swift +++ /dev/null @@ -1,21 +0,0 @@ -// -// CameraViewModel.swift -// Kabinett -// -// Created by 김정우 on 8/15/24. -// - -import SwiftUI -import AVFoundation - -// MARK: - ViewModel -final class CameraViewModel: ObservableObject { - @Published var capturedImage: UIImage? - - // MARK: Method(캡쳐된 이미지 처리) - func captureImage(with info: [UIImagePickerController.InfoKey : Any]) { - if let image = info[.originalImage] as? UIImage { - capturedImage = image - } - } -} diff --git a/Kabinett/Presentation/ViewModel/ImportLetter/ImagePickerViewModel.swift b/Kabinett/Presentation/ViewModel/WriteLetter/ImagePickerViewModel.swift similarity index 83% rename from Kabinett/Presentation/ViewModel/ImportLetter/ImagePickerViewModel.swift rename to Kabinett/Presentation/ViewModel/WriteLetter/ImagePickerViewModel.swift index 76bef653..1b767169 100644 --- a/Kabinett/Presentation/ViewModel/ImportLetter/ImagePickerViewModel.swift +++ b/Kabinett/Presentation/ViewModel/WriteLetter/ImagePickerViewModel.swift @@ -64,3 +64,15 @@ final class ImagePickerViewModel: ObservableObject { } } } + +// MARK: - ViewModel +final class CameraViewModel: ObservableObject { + @Published var capturedImage: UIImage? + + // MARK: Method(캡쳐된 이미지 처리) + func captureImage(with info: [UIImagePickerController.InfoKey : Any]) { + if let image = info[.originalImage] as? UIImage { + capturedImage = image + } + } +} From d8dae96f894a37833de7e498978ecdf24e9aaa92 Mon Sep 17 00:00:00 2001 From: ksiomng Date: Tue, 25 Mar 2025 14:39:38 +0900 Subject: [PATCH 14/39] =?UTF-8?q?Fix:=20=EC=9E=98=EB=AA=BB=EC=A3=BC?= =?UTF-8?q?=EC=84=9D=EC=B2=98=EB=A6=AC=ED=95=9C=EA=B1=B0=20=E3=85=8E?= =?UTF-8?q?=E3=85=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Kabinett/Application/KabinettApp.swift | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/Kabinett/Application/KabinettApp.swift b/Kabinett/Application/KabinettApp.swift index 61a5511e..66ee94b9 100644 --- a/Kabinett/Application/KabinettApp.swift +++ b/Kabinett/Application/KabinettApp.swift @@ -17,19 +17,19 @@ struct KabinettApp: App { // Init Firebase App FirebaseApp.configure() -// #if DEBUG -// // Firebase Authenticate Emulator -// Auth.auth().useEmulator(withHost:"localhost", port:9099) -// -// // Firebase Storage Emulator -// Storage.storage().useEmulator(withHost: "localhost", port: 9199) -// -// // Firebaes Firestore Emulator -// let settings = Firestore.firestore().settings -// settings.host = "localhost:8080" -// settings.isSSLEnabled = false -// Firestore.firestore().settings = settings -// #endif + #if DEBUG + // Firebase Authenticate Emulator + Auth.auth().useEmulator(withHost:"localhost", port:9099) + + // Firebase Storage Emulator + Storage.storage().useEmulator(withHost: "localhost", port: 9199) + + // Firebaes Firestore Emulator + let settings = Firestore.firestore().settings + settings.host = "localhost:8080" + settings.isSSLEnabled = false + Firestore.firestore().settings = settings + #endif // MARK: Register Dependencies KabinettApp.registerServices() From c8a0a62c2c33105ccd739b10ba54b59b793a6517 Mon Sep 17 00:00:00 2001 From: ksiomng Date: Tue, 25 Mar 2025 16:04:24 +0900 Subject: [PATCH 15/39] =?UTF-8?q?Fix:=20=EB=AA=A8=EB=8D=B8,=20=EB=B7=B0,?= =?UTF-8?q?=20=EB=B7=B0=EB=AA=A8=EB=8D=B8=20=EC=A0=95=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Commons/CustomTabView/CustomTabView.swift | 4 +- .../View/WriteLetter/Cells/EnvelopeCell.swift | 6 +-- .../View/WriteLetter/Cells/StampCell.swift | 6 +-- .../WriteLetter/Cells/StationeryCell.swift | 6 +-- .../Cells/WriteLetterEnvelopeCell.swift | 2 +- .../WriteLetter/Components/FontMenuView.swift | 4 +- .../Components/MiniTabBarView.swift | 1 - .../Components/SelectionTabView.swift | 6 +-- .../View/WriteLetter/ContentWriteView.swift | 38 +++++++-------- .../EnvelopeStampSelectionView.swift | 30 ++++++------ .../View/WriteLetter/PreviewLetterView.swift | 29 +++--------- .../WriteLetter/StationerySelectionView.swift | 10 ++-- .../View/WriteLetter/UserSelectionView.swift | 42 ++++++++--------- .../WriteLetter/LetterWriteModel.swift | 37 +++++++-------- .../WriteLetter/PreviewLetterViewModel.swift | 46 +++++++------------ .../WriteLetter/UserSelectionViewModel.swift | 8 ++-- 16 files changed, 123 insertions(+), 152 deletions(-) diff --git a/Kabinett/Presentation/Commons/CustomTabView/CustomTabView.swift b/Kabinett/Presentation/Commons/CustomTabView/CustomTabView.swift index 82e68989..6c767c5b 100644 --- a/Kabinett/Presentation/Commons/CustomTabView/CustomTabView.swift +++ b/Kabinett/Presentation/Commons/CustomTabView/CustomTabView.swift @@ -12,7 +12,7 @@ struct CustomTabView: View { @StateObject private var customTabViewModel = CustomTabViewModel() @StateObject private var profileViewModel: ProfileViewModel @StateObject private var envelopeStampSelectionViewModel: EnvelopeStampSelectionViewModel - @State private var letterWriteViewModel = LetterWriteModel() + @State var letterWriteModel = LetterWriteModel() init() { @Injected(LetterBoxUseCaseKey.self) var letterBoxUseCase: LetterBoxUseCase @@ -57,7 +57,7 @@ struct CustomTabView: View { } } .sheet(isPresented: $customTabViewModel.showWriteView) { - UserSelectionView(letterContent: $letterWriteViewModel, customViewModel: customTabViewModel) + UserSelectionView(letter: $letterWriteModel.writeLetter, customViewModel: customTabViewModel) .presentationDetents([.height(300), .large]) } } diff --git a/Kabinett/Presentation/View/WriteLetter/Cells/EnvelopeCell.swift b/Kabinett/Presentation/View/WriteLetter/Cells/EnvelopeCell.swift index e1ddc8a1..8f565872 100644 --- a/Kabinett/Presentation/View/WriteLetter/Cells/EnvelopeCell.swift +++ b/Kabinett/Presentation/View/WriteLetter/Cells/EnvelopeCell.swift @@ -9,7 +9,7 @@ import SwiftUI import Kingfisher struct EnvelopeCell: View { - @Binding var letterContent: LetterWriteModel + @Binding var letter: WriteLetter @Binding var envelopeImageUrl: String @ObservedObject var viewModel: EnvelopeStampSelectionViewModel @@ -37,7 +37,7 @@ struct EnvelopeCell: View { .onTapGesture { viewModel.envelopeSelectStationery(coordinates: (rowIndex, columnIndex)) envelopeImageUrl = viewModel.envelopes[index] - letterContent.envelopeImageUrlString = viewModel.envelopes[index] + letter.envelopeImageUrlString = viewModel.envelopes[index] } if viewModel.isEnvelopeSelected(coordinates: (rowIndex, columnIndex)) { @@ -46,7 +46,7 @@ struct EnvelopeCell: View { .frame(width: 27, height: 27) .padding([.top, .trailing], 20) .onAppear { - letterContent.envelopeImageUrlString = viewModel.envelopes[viewModel.envelopeIndex(row: rowIndex, column: columnIndex)] + letter.envelopeImageUrlString = viewModel.envelopes[viewModel.envelopeIndex(row: rowIndex, column: columnIndex)] } } } diff --git a/Kabinett/Presentation/View/WriteLetter/Cells/StampCell.swift b/Kabinett/Presentation/View/WriteLetter/Cells/StampCell.swift index d6a23a29..c3c9efa7 100644 --- a/Kabinett/Presentation/View/WriteLetter/Cells/StampCell.swift +++ b/Kabinett/Presentation/View/WriteLetter/Cells/StampCell.swift @@ -9,7 +9,7 @@ import SwiftUI import Kingfisher struct StampCell: View { - @Binding var letterContent: LetterWriteModel + @Binding var letter: WriteLetter @Binding var stampImageUrl: String @ObservedObject var viewModel: EnvelopeStampSelectionViewModel @@ -37,7 +37,7 @@ struct StampCell: View { .onTapGesture { viewModel.stampSelectStationery(coordinates: (rowIndex, columnIndex)) stampImageUrl = viewModel.stamps[index] - letterContent.stampImageUrlString = viewModel.stamps[index] + letter.stampImageUrlString = viewModel.stamps[index] } if viewModel.isStampSelected(coordinates: (rowIndex, columnIndex)) { @@ -46,7 +46,7 @@ struct StampCell: View { .frame(width: 27, height: 27) .padding([.top, .trailing], 20) .onAppear { - letterContent.stampImageUrlString = viewModel.stamps[viewModel.stampIndex(row: rowIndex, column: columnIndex)] + letter.stampImageUrlString = viewModel.stamps[viewModel.stampIndex(row: rowIndex, column: columnIndex)] } } } diff --git a/Kabinett/Presentation/View/WriteLetter/Cells/StationeryCell.swift b/Kabinett/Presentation/View/WriteLetter/Cells/StationeryCell.swift index d18b9f59..d3181c32 100644 --- a/Kabinett/Presentation/View/WriteLetter/Cells/StationeryCell.swift +++ b/Kabinett/Presentation/View/WriteLetter/Cells/StationeryCell.swift @@ -12,7 +12,7 @@ struct StationeryCell: View { let index: Int let rowIndex: Int let columnIndex: Int - @Binding var letterContent: LetterWriteModel + @Binding var letter: WriteLetter @ObservedObject var stationerySelectionViewModel: StationerySelectionViewModel var body: some View { @@ -28,7 +28,7 @@ struct StationeryCell: View { .shadow(color: Color(.primary300), radius: 5, x: 3, y: 3) .onTapGesture { stationerySelectionViewModel.selectStationery(coordinates: (rowIndex, columnIndex)) - letterContent.stationeryImageUrlString = stationerySelectionViewModel.stationerys[index] + letter.stationeryImageUrlString = stationerySelectionViewModel.stationerys[index] } } else { EmptyView() @@ -40,7 +40,7 @@ struct StationeryCell: View { .frame(width: 32, height: 32) .padding([.top, .trailing], 20) .onAppear { - letterContent.stationeryImageUrlString = stationerySelectionViewModel.stationerys[index] + letter.stationeryImageUrlString = stationerySelectionViewModel.stationerys[index] } } } diff --git a/Kabinett/Presentation/View/WriteLetter/Cells/WriteLetterEnvelopeCell.swift b/Kabinett/Presentation/View/WriteLetter/Cells/WriteLetterEnvelopeCell.swift index e63b1a37..5d1a100e 100644 --- a/Kabinett/Presentation/View/WriteLetter/Cells/WriteLetterEnvelopeCell.swift +++ b/Kabinett/Presentation/View/WriteLetter/Cells/WriteLetterEnvelopeCell.swift @@ -9,7 +9,7 @@ import SwiftUI import Kingfisher struct WriteLetterEnvelopeCell: View { - var letter: Letter + var letter: WriteLetter var body: some View { ZStack { diff --git a/Kabinett/Presentation/View/WriteLetter/Components/FontMenuView.swift b/Kabinett/Presentation/View/WriteLetter/Components/FontMenuView.swift index e5edccbe..7b5ca984 100644 --- a/Kabinett/Presentation/View/WriteLetter/Components/FontMenuView.swift +++ b/Kabinett/Presentation/View/WriteLetter/Components/FontMenuView.swift @@ -8,7 +8,7 @@ import SwiftUI struct FontMenuView: View { - @Binding var letterContent: LetterWriteModel + @Binding var letter: WriteLetter @Binding var showFontMenu: Bool @ObservedObject var fontViewModel: FontSelectionViewModel @@ -24,7 +24,7 @@ struct FontMenuView: View { ForEach(0.., + letter: Binding, customTabViewModel: CustomTabViewModel ) { - self._letterContent = letterContent self.customTabViewModel = customTabViewModel self._imageViewModel = StateObject(wrappedValue: ImagePickerViewModel()) + self._letter = letter } var body: some View { @@ -37,8 +37,8 @@ struct ContentWriteView: View { } ZStack(alignment: .top) { VStack { - ScrollableLetterView(letterContent: $letterContent, viewModel: viewModel, imageViewModel: imageViewModel, currentIndex: $viewModel.currentIndex) - .font(FontUtility.selectedFont(font: letterContent.fontString ?? "", size: 13)) + ScrollableLetterView(letter: $letter, viewModel: viewModel, imageViewModel: imageViewModel, currentIndex: $viewModel.currentIndex) + .font(FontUtility.selectedFont(font: letter.fontString ?? "", size: 13)) Text("\(viewModel.currentIndex+1) / \(viewModel.texts.count+imageViewModel.photoContents.count)") .padding(5) @@ -47,7 +47,7 @@ struct ContentWriteView: View { .clipShape(Capsule()) } .padding(.bottom, LayoutHelper.shared.getSize(forSE: 0.03, forOthers: 0.0)) - MiniTabBarView(letterContent: $letterContent, viewModel: viewModel, customTabViewModel: customTabViewModel, imageViewModel: imageViewModel) + MiniTabBarView(viewModel: viewModel, customTabViewModel: customTabViewModel, imageViewModel: imageViewModel) if keyBoard { Button(action:{ @@ -68,13 +68,13 @@ struct ContentWriteView: View { } .overlay { if viewModel.showFontMenu { - FontMenuView(letterContent: $letterContent, showFontMenu: $viewModel.showFontMenu, fontViewModel: fontViewModel) + FontMenuView(letter: $letter, showFontMenu: $viewModel.showFontMenu, fontViewModel: fontViewModel) } } .toolbar { ToolbarItem(placement: .topBarTrailing) { NavigationLink(destination: EnvelopeStampSelectionView( - letterContent: $letterContent, + letter: $letter, customTabViewModel: customTabViewModel )) { Text("다음") @@ -89,7 +89,7 @@ struct ContentWriteView: View { Task { @MainActor in imageViewModel.selectedItems = newValue await imageViewModel.loadImages() - letterContent.photoContents = imageViewModel.photoContents + letter.photoContents = imageViewModel.photoContents } } .onAppear{ @@ -117,7 +117,7 @@ struct ScrollableLetterView: View { let screenWidth = UIScreen.main.bounds.width let screenHeight = UIScreen.main.bounds.height - @Binding var letterContent: LetterWriteModel + @Binding var letter: WriteLetter @ObservedObject var viewModel: ContentWriteViewModel @ObservedObject var imageViewModel: ImagePickerViewModel @Binding var currentIndex: Int @@ -130,7 +130,7 @@ struct ScrollableLetterView: View { LazyHStack(alignment: .top, spacing: UIScreen.main.bounds.width * 0.04) { ForEach(0.., + letter: Binding, customTabViewModel: CustomTabViewModel ) { - self._letterContent = letterContent self.customTabViewModel = customTabViewModel + self._letter = letter - _envelopeImageUrl = State(initialValue: letterContent.wrappedValue.envelopeImageUrlString) - _stampImageUrl = State(initialValue: letterContent.wrappedValue.stampImageUrlString) + _envelopeImageUrl = State(initialValue: letter.wrappedValue.envelopeImageUrlString) + _stampImageUrl = State(initialValue: letter.wrappedValue.stampImageUrlString) @Injected(WriteLetterUseCaseKey.self) var writeLetterUseCase: WriteLetterUseCase _viewModel = StateObject(wrappedValue: EnvelopeStampSelectionViewModel(useCase: writeLetterUseCase)) @@ -39,16 +39,16 @@ struct EnvelopeStampSelectionView: View { } VStack { - WriteLetterEnvelopeCell(letter: Letter(fontString: letterContent.fontString, postScript: postScriptText, envelopeImageUrlString: letterContent.envelopeImageUrlString, stampImageUrlString: letterContent.stampImageUrlString, fromUserId: letterContent.fromUserId, fromUserName: letterContent.fromUserName, fromUserKabinettNumber: letterContent.fromUserKabinettNumber, toUserId: letterContent.toUserId, toUserName: letterContent.toUserName, toUserKabinettNumber: letterContent.toUserKabinettNumber, content: letterContent.content, photoContents: [""], date: letterContent.date, stationeryImageUrlString: letterContent.stationeryImageUrlString, isRead: true)) + WriteLetterEnvelopeCell(letter: letter) .padding(.top, 10) .padding(.bottom, 50) .onChange(of: viewModel.envelopes) { - if letterContent.envelopeImageUrlString.isEmpty { + if letter.envelopeImageUrlString.isEmpty { envelopeImageUrl = viewModel.envelopes[0] } } .onChange(of: viewModel.stamps) { - if letterContent.stampImageUrlString.isEmpty { + if letter.stampImageUrlString.isEmpty { stampImageUrl = viewModel.stamps[0] } } @@ -65,33 +65,33 @@ struct EnvelopeStampSelectionView: View { .background(Color.white) .clipShape(RoundedRectangle(cornerRadius: 5)) .onChange(of: postScriptText) { - letterContent.postScript = postScriptText + letter.postScript = postScriptText } } .padding(.bottom, 30) - SelectionTabView(envelopeStampSelectionViewModel: viewModel, letterContent: $letterContent, envelopeImageUrl: $envelopeImageUrl, stampImageUrl: $stampImageUrl) + SelectionTabView(envelopeStampSelectionViewModel: viewModel, letter: $letter, envelopeImageUrl: $envelopeImageUrl, stampImageUrl: $stampImageUrl) } .padding(.horizontal, UIScreen.main.bounds.width * 0.06) } .task { await viewModel.loadStamps() await viewModel.loadEnvelopes() - envelopeImageUrl = letterContent.envelopeImageUrlString - stampImageUrl = letterContent.stampImageUrlString + envelopeImageUrl = letter.envelopeImageUrlString + stampImageUrl = letter.stampImageUrlString } .onChange(of: envelopeImageUrl) { _, newValue in - letterContent.envelopeImageUrlString = newValue + letter.envelopeImageUrlString = newValue } .onChange(of: stampImageUrl) { _, newValue in - letterContent.stampImageUrlString = newValue + letter.stampImageUrlString = newValue } .navigationBarTitleDisplayMode(.inline) .navigationTitle("봉투와 우표 고르기") .toolbar { ToolbarItem(placement: .topBarTrailing) { NavigationLink(destination: PreviewLetterView( - letterContent: $letterContent, + letter: $letter, customTabViewModel: customTabViewModel )) { Text("다음") diff --git a/Kabinett/Presentation/View/WriteLetter/PreviewLetterView.swift b/Kabinett/Presentation/View/WriteLetter/PreviewLetterView.swift index 7f4e75f5..2b77fa77 100644 --- a/Kabinett/Presentation/View/WriteLetter/PreviewLetterView.swift +++ b/Kabinett/Presentation/View/WriteLetter/PreviewLetterView.swift @@ -11,19 +11,18 @@ import UIKit import FirebaseAnalytics struct PreviewLetterView: View { - @Binding var letterContent: LetterWriteModel + @Binding var letter: WriteLetter @StateObject var viewModel: PreviewLetterViewModel @ObservedObject var customTabViewModel: CustomTabViewModel init( - letterContent: Binding, + letter: Binding, customTabViewModel: CustomTabViewModel ) { + self.customTabViewModel = customTabViewModel + self._letter = letter @Injected(WriteLetterUseCaseKey.self) var writeLetterUseCase: WriteLetterUseCase - _viewModel = StateObject(wrappedValue: PreviewLetterViewModel(useCase: writeLetterUseCase)) - self._letterContent = letterContent - self.customTabViewModel = customTabViewModel } var body: some View { @@ -32,14 +31,14 @@ struct PreviewLetterView: View { VStack { Spacer() - WriteLetterEnvelopeCell(letter: Letter(fontString: letterContent.fontString, postScript: letterContent.postScript, envelopeImageUrlString: letterContent.envelopeImageUrlString, stampImageUrlString: letterContent.stampImageUrlString, fromUserId: letterContent.fromUserId, fromUserName: letterContent.fromUserName, fromUserKabinettNumber: letterContent.fromUserKabinettNumber, toUserId: letterContent.toUserId, toUserName: letterContent.toUserName, toUserKabinettNumber: letterContent.toUserKabinettNumber, content: letterContent.content, photoContents: [""], date: letterContent.date, stationeryImageUrlString: letterContent.stationeryImageUrlString, isRead: true)) + WriteLetterEnvelopeCell(letter: letter) .padding(.bottom,30) VStack { Text("편지가 완성되었어요.") .font(.system(size: 18, weight: .semibold)) HStack { - Text("\(letterContent.toUserName == letterContent.fromUserName ? "나" : letterContent.toUserName)") + Text("\(letter.toUserName == letter.fromUserName ? "나" : letter.toUserName)") .font(.system(size: 22, weight: .bold)) .padding(.trailing, -3) Text("에게 편지를 보낼까요?") @@ -51,21 +50,7 @@ struct PreviewLetterView: View { Spacer() Button { - viewModel.saveLetter(font: letterContent.fontString ?? "", - postScript: letterContent.postScript, - envelope: letterContent.envelopeImageUrlString, - stamp: letterContent.stampImageUrlString, - fromUserId: letterContent.fromUserId, - fromUserName: letterContent.fromUserName, - fromUserKabinettNumber: letterContent.fromUserKabinettNumber, - toUserId: letterContent.toUserId, - toUserName: letterContent.toUserName, - toUserKabinettNumber: letterContent.toUserKabinettNumber, - content: letterContent.content, - photoContents: letterContent.photoContents, - date: letterContent.date, - stationery: letterContent.stationeryImageUrlString ?? "", - isRead: false) + viewModel.saveLetter(letter: letter) customTabViewModel.hideWriteView() } label: { Text("편지 보내기") diff --git a/Kabinett/Presentation/View/WriteLetter/StationerySelectionView.swift b/Kabinett/Presentation/View/WriteLetter/StationerySelectionView.swift index e62a1088..d4babae3 100644 --- a/Kabinett/Presentation/View/WriteLetter/StationerySelectionView.swift +++ b/Kabinett/Presentation/View/WriteLetter/StationerySelectionView.swift @@ -11,18 +11,18 @@ import FirebaseAnalytics struct StationerySelectionView: View { @Environment(\.dismiss) var dismiss - @Binding var letterContent: LetterWriteModel + @Binding var letter: WriteLetter @StateObject var viewModel : StationerySelectionViewModel @ObservedObject var customViewModel: CustomTabViewModel init( - letterContent: Binding, + letter: Binding, customViewModel: CustomTabViewModel ) { @Injected(WriteLetterUseCaseKey.self) var writeLetterUseCase: WriteLetterUseCase _viewModel = StateObject(wrappedValue: StationerySelectionViewModel(useCase: writeLetterUseCase)) - self._letterContent = letterContent self.customViewModel = customViewModel + self._letter = letter } var body: some View { @@ -39,7 +39,7 @@ struct StationerySelectionView: View { index: index, rowIndex: rowIndex, columnIndex: columnIndex, - letterContent: $letterContent, + letter: $letter, stationerySelectionViewModel: viewModel ) } @@ -70,7 +70,7 @@ struct StationerySelectionView: View { } ToolbarItem(placement: .topBarTrailing) { NavigationLink(destination: ContentWriteView( - letterContent: $letterContent, + letter: $letter, customTabViewModel: customViewModel )) { Text("다음") diff --git a/Kabinett/Presentation/View/WriteLetter/UserSelectionView.swift b/Kabinett/Presentation/View/WriteLetter/UserSelectionView.swift index b928f6a6..4169291b 100644 --- a/Kabinett/Presentation/View/WriteLetter/UserSelectionView.swift +++ b/Kabinett/Presentation/View/WriteLetter/UserSelectionView.swift @@ -10,20 +10,20 @@ import Kingfisher import FirebaseAnalytics struct UserSelectionView: View { - @Binding var letterContent: LetterWriteModel + @Binding var letter: WriteLetter @Environment(\.dismiss) var dismiss @StateObject var viewModel : UserSelectionViewModel @ObservedObject var customViewModel: CustomTabViewModel @State private var isFullScreen = false init( - letterContent: Binding, + letter: Binding, customViewModel: CustomTabViewModel ) { @Injected(WriteLetterUseCaseKey.self) var writeLetterUseCase: WriteLetterUseCase _viewModel = StateObject(wrappedValue: UserSelectionViewModel(useCase: writeLetterUseCase)) - self._letterContent = letterContent self.customViewModel = customViewModel + self._letter = letter } var body: some View { @@ -47,19 +47,19 @@ struct UserSelectionView: View { .fullScreenCover(isPresented: $isFullScreen) { NavigationStack { StationerySelectionView( - letterContent: $letterContent, + letter: $letter, customViewModel: customViewModel ) } } - FormToUser(letterContent: $letterContent, viewModel: viewModel) + FormToUser(letter: $letter, viewModel: viewModel) HStack { if viewModel.checkLogin { Spacer(minLength: 95) VStack { - SearchBar(letterContent: $letterContent, searchText: $viewModel.searchText, viewModel: viewModel) + SearchBar(letter: $letter, searchText: $viewModel.searchText, viewModel: viewModel) Group { Text("정확한 닉네임") .bold() + @@ -119,7 +119,7 @@ struct UserSelectionView: View { // MARK: - FormToUserView struct FormToUser: View { - @Binding var letterContent: LetterWriteModel + @Binding var letter: WriteLetter @ObservedObject var viewModel : UserSelectionViewModel var body: some View { @@ -138,17 +138,17 @@ struct FormToUser: View { } .padding(.top, 15) .onChange(of: viewModel.fromUser?.kabinettNumber) { - letterContent.fromUserId = viewModel.fromUser?.id - letterContent.fromUserKabinettNumber = viewModel.fromUser?.kabinettNumber - letterContent.toUserId = viewModel.toUser?.id - letterContent.toUserKabinettNumber = viewModel.toUser?.kabinettNumber - letterContent.date = Date() + letter.fromUserId = viewModel.fromUser?.id + letter.fromUserKabinettNumber = viewModel.fromUser?.kabinettNumber + letter.toUserId = viewModel.toUser?.id + letter.toUserKabinettNumber = viewModel.toUser?.kabinettNumber + letter.date = Date() if viewModel.checkLogin { - letterContent.fromUserName = viewModel.fromUser?.name ?? "" - letterContent.toUserName = viewModel.toUser?.name ?? "" + letter.fromUserName = viewModel.fromUser?.name ?? "" + letter.toUserName = viewModel.toUser?.name ?? "" } else { - letterContent.fromUserName = "나" - letterContent.toUserName = "나" + letter.fromUserName = "나" + letter.toUserName = "나" } } @@ -158,8 +158,8 @@ struct FormToUser: View { .font(.system(size: 16)) .bold() Spacer(minLength: 37) - let toName = letterContent.toUserName.isEmpty ? viewModel.toUser?.name ?? "" : letterContent.toUserName - let toKabi = letterContent.toUserName.isEmpty ? viewModel.fromUser?.kabinettNumber ?? 0 : letterContent.toUserKabinettNumber + let toName = letter.toUserName.isEmpty ? viewModel.toUser?.name ?? "" : letter.toUserName + let toKabi = letter.toUserName.isEmpty ? viewModel.fromUser?.kabinettNumber ?? 0 : letter.toUserKabinettNumber Text(viewModel.checkLogin ? "\(toName) \(viewModel.checkMe(kabiNumber: toKabi ?? 0))" : "나") .foregroundStyle(viewModel.checkLogin ? Color.black : Color("ContentSecondary")) .font(.system(size: 15)) @@ -174,7 +174,7 @@ struct FormToUser: View { // MARK: - SearchBarView struct SearchBar: View { - @Binding var letterContent: LetterWriteModel + @Binding var letter: WriteLetter @Binding var searchText: String @ObservedObject var viewModel: UserSelectionViewModel @State var isSearchBar: Bool = true @@ -213,7 +213,7 @@ struct SearchBar: View { List { Text("\(viewModel.debouncedSearchText) 입력") .onTapGesture { - viewModel.updateToUser(&letterContent, toUserName: viewModel.debouncedSearchText) + viewModel.updateToUser(&letter, toUserName: viewModel.debouncedSearchText) searchText = "" UIApplication.shared.endEditing() isSearchBar = false @@ -248,7 +248,7 @@ struct SearchBar: View { } .listRowSeparator(.hidden) .onTapGesture { - viewModel.updateToUser(&letterContent, toUserName: user.name) + viewModel.updateToUser(&letter, toUserName: user.name) searchText = "" UIApplication.shared.endEditing() isSearchBar = false diff --git a/Kabinett/Presentation/ViewModel/WriteLetter/LetterWriteModel.swift b/Kabinett/Presentation/ViewModel/WriteLetter/LetterWriteModel.swift index 2dcb0721..bfd71b18 100644 --- a/Kabinett/Presentation/ViewModel/WriteLetter/LetterWriteModel.swift +++ b/Kabinett/Presentation/ViewModel/WriteLetter/LetterWriteModel.swift @@ -9,22 +9,23 @@ import Foundation import SwiftUI class LetterWriteModel: ObservableObject { - @Published var fontString: String? = nil - @Published var postScript: String? = nil - @Published var envelopeImageUrlString: String = "" - @Published var stampImageUrlString: String = "" - - @Published var fromUserId: String? = nil - @Published var fromUserName: String = "" - @Published var fromUserKabinettNumber: Int? = nil - - @Published var toUserId: String? = nil - @Published var toUserName: String = "" - @Published var toUserKabinettNumber: Int? = nil - - @Published var content: [String] = [] - @Published var photoContents: [Data] = [] - @Published var date: Date = Date() - @Published var stationeryImageUrlString: String? = nil - @Published var isRead: Bool = false + @Published var writeLetter: WriteLetter = WriteLetter(envelopeImageUrlString: "", stampImageUrlString: "", fromUserName: "", toUserName: "", content: [], date: Date(), stationeryImageUrlString: "", isRead: false) +} + +struct WriteLetter { + var fontString: String? + var postScript: String? + var envelopeImageUrlString: String + var stampImageUrlString: String + var fromUserId: String? + var fromUserName: String + var fromUserKabinettNumber: Int? + var toUserId: String? + var toUserName: String + var toUserKabinettNumber: Int? + var content: [String] + var photoContents: [Data]? + var date: Date + var stationeryImageUrlString: String + var isRead: Bool } diff --git a/Kabinett/Presentation/ViewModel/WriteLetter/PreviewLetterViewModel.swift b/Kabinett/Presentation/ViewModel/WriteLetter/PreviewLetterViewModel.swift index 125eb2dd..72297da9 100644 --- a/Kabinett/Presentation/ViewModel/WriteLetter/PreviewLetterViewModel.swift +++ b/Kabinett/Presentation/ViewModel/WriteLetter/PreviewLetterViewModel.swift @@ -18,38 +18,24 @@ class PreviewLetterViewModel: ObservableObject { self.useCase = useCase } - func saveLetter(font: String, - postScript: String?, - envelope: String, - stamp: String, - fromUserId: String?, - fromUserName: String, - fromUserKabinettNumber: Int?, - toUserId: String?, - toUserName: String, - toUserKabinettNumber: Int?, - content: [String], - photoContents: [Data], - date: Date, - stationery: String, - isRead: Bool) { + func saveLetter(letter: WriteLetter) { Task { - let result = await useCase.saveLetter(font: font, - postScript: postScript, - envelope: envelope, - stamp: stamp, - fromUserId: fromUserId, - fromUserName: fromUserName, - fromUserKabinettNumber: fromUserKabinettNumber, - toUserId: toUserId, - toUserName: toUserName, - toUserKabinettNumber: toUserKabinettNumber, - content: content, - photoContents: photoContents, - date: date, - stationery: stationery, - isRead: isRead) + let result = await useCase.saveLetter(font: letter.fontString ?? "", + postScript: letter.postScript, + envelope: letter.envelopeImageUrlString, + stamp: letter.stampImageUrlString, + fromUserId: letter.fromUserId, + fromUserName: letter.fromUserName, + fromUserKabinettNumber: letter.fromUserKabinettNumber, + toUserId: letter.toUserId, + toUserName: letter.toUserName, + toUserKabinettNumber: letter.toUserKabinettNumber, + content: letter.content, + photoContents: letter.photoContents ?? [], + date: letter.date, + stationery: letter.stationeryImageUrlString, + isRead: letter.isRead) await MainActor.run { switch result { case .success(let success): diff --git a/Kabinett/Presentation/ViewModel/WriteLetter/UserSelectionViewModel.swift b/Kabinett/Presentation/ViewModel/WriteLetter/UserSelectionViewModel.swift index 0929e86a..1197b3d9 100644 --- a/Kabinett/Presentation/ViewModel/WriteLetter/UserSelectionViewModel.swift +++ b/Kabinett/Presentation/ViewModel/WriteLetter/UserSelectionViewModel.swift @@ -52,15 +52,15 @@ class UserSelectionViewModel: ObservableObject { } } - func updateToUser(_ letterContent: inout LetterWriteModel, toUserName: String) { + func updateToUser(_ letter: inout WriteLetter, toUserName: String) { if let user = usersData.first(where: { $0.name == toUserName }) { toUser = Writer(id: user.id, name: user.name, kabinettNumber: user.kabinettNumber, profileImage: user.profileImage) } else { toUser = Writer(name: toUserName, kabinettNumber: 0, profileImage: nil) } - letterContent.toUserId = toUser?.id - letterContent.toUserName = toUser?.name ?? "" - letterContent.toUserKabinettNumber = toUser?.kabinettNumber + letter.toUserId = toUser?.id + letter.toUserName = toUser?.name ?? "" + letter.toUserKabinettNumber = toUser?.kabinettNumber } func checkMe(kabiNumber: Int) -> String { From 1c3a5bbbb09a8578a41fe59bf51d4e95f03e5626 Mon Sep 17 00:00:00 2001 From: ksiomng Date: Tue, 25 Mar 2025 16:07:45 +0900 Subject: [PATCH 16/39] =?UTF-8?q?Fix:=20private=EB=A1=9C=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Kabinett/Presentation/Commons/CustomTabView/CustomTabView.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Kabinett/Presentation/Commons/CustomTabView/CustomTabView.swift b/Kabinett/Presentation/Commons/CustomTabView/CustomTabView.swift index 6c767c5b..be3216ba 100644 --- a/Kabinett/Presentation/Commons/CustomTabView/CustomTabView.swift +++ b/Kabinett/Presentation/Commons/CustomTabView/CustomTabView.swift @@ -12,7 +12,7 @@ struct CustomTabView: View { @StateObject private var customTabViewModel = CustomTabViewModel() @StateObject private var profileViewModel: ProfileViewModel @StateObject private var envelopeStampSelectionViewModel: EnvelopeStampSelectionViewModel - @State var letterWriteModel = LetterWriteModel() + @State private var letterWriteModel = LetterWriteModel() init() { @Injected(LetterBoxUseCaseKey.self) var letterBoxUseCase: LetterBoxUseCase From 06d6b6a3fb272ba3ac5827d5dceec4046b14ee56 Mon Sep 17 00:00:00 2001 From: ksiomng Date: Wed, 26 Mar 2025 11:58:51 +0900 Subject: [PATCH 17/39] =?UTF-8?q?Fix:=20=EB=AF=B8=EB=A6=AC=EB=B3=B4?= =?UTF-8?q?=EA=B8=B0=EC=97=90=EC=84=9C=20postScript=20=EC=93=B8=20?= =?UTF-8?q?=EB=95=8C=20=EB=AF=B8=EB=A6=AC=EB=B3=B4=EA=B8=B0=EA=B0=80=20?= =?UTF-8?q?=EB=94=9C=EB=A0=88=EC=9D=B4=20=EB=90=98=EB=8A=94=EB=AC=B8?= =?UTF-8?q?=EC=A0=9C=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../View/WriteLetter/Cells/WriteLetterEnvelopeCell.swift | 3 ++- .../View/WriteLetter/EnvelopeStampSelectionView.swift | 2 +- Kabinett/Presentation/View/WriteLetter/PreviewLetterView.swift | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Kabinett/Presentation/View/WriteLetter/Cells/WriteLetterEnvelopeCell.swift b/Kabinett/Presentation/View/WriteLetter/Cells/WriteLetterEnvelopeCell.swift index 5d1a100e..53830182 100644 --- a/Kabinett/Presentation/View/WriteLetter/Cells/WriteLetterEnvelopeCell.swift +++ b/Kabinett/Presentation/View/WriteLetter/Cells/WriteLetterEnvelopeCell.swift @@ -10,6 +10,7 @@ import Kingfisher struct WriteLetterEnvelopeCell: View { var letter: WriteLetter + var postScript: String var body: some View { ZStack { @@ -40,7 +41,7 @@ struct WriteLetterEnvelopeCell: View { .padding(.bottom, LayoutHelper.shared.getSize(forSE: 0.035 * 1.1, forOthers: 0.03 * 1.1)) HStack(alignment: .top) { - Text(letter.postScript ?? "") + Text(postScript ?? "") .font(FontUtility.selectedFont(font: letter.fontString ?? "SFDisplay", size: LayoutHelper.shared.getSize(forSE: 0.012 * 1.1, forOthers: 0.012 * 1.1))) .foregroundStyle(.contentPrimary) .frame(width: LayoutHelper.shared.getWidth(forSE: 0.4 * 1.1, forOthers: 0.4 * 1.1), alignment: .leading) diff --git a/Kabinett/Presentation/View/WriteLetter/EnvelopeStampSelectionView.swift b/Kabinett/Presentation/View/WriteLetter/EnvelopeStampSelectionView.swift index 379532b5..f2078bdb 100644 --- a/Kabinett/Presentation/View/WriteLetter/EnvelopeStampSelectionView.swift +++ b/Kabinett/Presentation/View/WriteLetter/EnvelopeStampSelectionView.swift @@ -39,7 +39,7 @@ struct EnvelopeStampSelectionView: View { } VStack { - WriteLetterEnvelopeCell(letter: letter) + WriteLetterEnvelopeCell(letter: letter, postScript: postScriptText) .padding(.top, 10) .padding(.bottom, 50) .onChange(of: viewModel.envelopes) { diff --git a/Kabinett/Presentation/View/WriteLetter/PreviewLetterView.swift b/Kabinett/Presentation/View/WriteLetter/PreviewLetterView.swift index 2b77fa77..6892c6e4 100644 --- a/Kabinett/Presentation/View/WriteLetter/PreviewLetterView.swift +++ b/Kabinett/Presentation/View/WriteLetter/PreviewLetterView.swift @@ -31,7 +31,7 @@ struct PreviewLetterView: View { VStack { Spacer() - WriteLetterEnvelopeCell(letter: letter) + WriteLetterEnvelopeCell(letter: letter, postScript: letter.postScript ?? "") .padding(.bottom,30) VStack { From 1423f409396444e61ee5b6a467860f0434054e15 Mon Sep 17 00:00:00 2001 From: ksiomng Date: Wed, 26 Mar 2025 12:27:08 +0900 Subject: [PATCH 18/39] =?UTF-8?q?Fix:=20=EC=98=B5=EC=85=94=EB=84=90=20?= =?UTF-8?q?=EC=95=84=EB=8B=88=EB=9D=BC=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../View/WriteLetter/Cells/WriteLetterEnvelopeCell.swift | 2 +- Kabinett/Presentation/View/WriteLetter/ContentWriteView.swift | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Kabinett/Presentation/View/WriteLetter/Cells/WriteLetterEnvelopeCell.swift b/Kabinett/Presentation/View/WriteLetter/Cells/WriteLetterEnvelopeCell.swift index 53830182..b4873b84 100644 --- a/Kabinett/Presentation/View/WriteLetter/Cells/WriteLetterEnvelopeCell.swift +++ b/Kabinett/Presentation/View/WriteLetter/Cells/WriteLetterEnvelopeCell.swift @@ -41,7 +41,7 @@ struct WriteLetterEnvelopeCell: View { .padding(.bottom, LayoutHelper.shared.getSize(forSE: 0.035 * 1.1, forOthers: 0.03 * 1.1)) HStack(alignment: .top) { - Text(postScript ?? "") + Text(postScript) .font(FontUtility.selectedFont(font: letter.fontString ?? "SFDisplay", size: LayoutHelper.shared.getSize(forSE: 0.012 * 1.1, forOthers: 0.012 * 1.1))) .foregroundStyle(.contentPrimary) .frame(width: LayoutHelper.shared.getWidth(forSE: 0.4 * 1.1, forOthers: 0.4 * 1.1), alignment: .leading) diff --git a/Kabinett/Presentation/View/WriteLetter/ContentWriteView.swift b/Kabinett/Presentation/View/WriteLetter/ContentWriteView.swift index 313ff3e2..a5740bb9 100644 --- a/Kabinett/Presentation/View/WriteLetter/ContentWriteView.swift +++ b/Kabinett/Presentation/View/WriteLetter/ContentWriteView.swift @@ -130,7 +130,7 @@ struct ScrollableLetterView: View { LazyHStack(alignment: .top, spacing: UIScreen.main.bounds.width * 0.04) { ForEach(0.. Date: Wed, 26 Mar 2025 15:22:34 +0900 Subject: [PATCH 19/39] =?UTF-8?q?Fix:=20=EC=82=AC=EC=A7=84=20=EC=82=AD?= =?UTF-8?q?=EC=A0=9C=EB=90=98=EB=8A=94=20=EB=A1=9C=EC=A7=81=EC=9D=B4=20?= =?UTF-8?q?=EC=9D=B4=EC=83=81=ED=95=B4=EC=84=9C=20=EC=83=9D=EA=B8=B0?= =?UTF-8?q?=EB=8A=94=20=EB=AC=B8=EC=A0=9C=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Presentation/View/WriteLetter/ContentWriteView.swift | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/Kabinett/Presentation/View/WriteLetter/ContentWriteView.swift b/Kabinett/Presentation/View/WriteLetter/ContentWriteView.swift index a5740bb9..2beb8277 100644 --- a/Kabinett/Presentation/View/WriteLetter/ContentWriteView.swift +++ b/Kabinett/Presentation/View/WriteLetter/ContentWriteView.swift @@ -85,9 +85,8 @@ struct ContentWriteView: View { } } .ignoresSafeArea(.keyboard) - .onChange(of: imageViewModel.selectedItems) { _, newValue in + .onChange(of: imageViewModel.selectedItems) { Task { @MainActor in - imageViewModel.selectedItems = newValue await imageViewModel.loadImages() letter.photoContents = imageViewModel.photoContents } @@ -152,8 +151,6 @@ struct ScrollableLetterView: View { maxWidth: geo.size.width, maxHeight: geo.size.height, font: FontUtility.selectedUIFont(font: letter.fontString ?? "", size: FontUtility.fontSize(font: letter.fontString ?? "")) - //lineSpacing: FontUtility.lineSpacing(font: letter.fontString ?? ""), - //kerning: FontUtility.kerning(font: letter.fontString ?? "") ) } .onChange(of: viewModel.texts[i]) { @@ -198,7 +195,6 @@ struct ScrollableLetterView: View { .anchorPreference(key: AnchorsKey.self, value: .trailing, transform: { [imageIndex: $0] }) Button(action: { - imageViewModel.photoContents.remove(at: index) imageViewModel.selectedItems.remove(at: index) }) { Image(systemName: "xmark.circle.fill") From b0746b7b0ccd6eb9a1043ea05c58f36df09150df Mon Sep 17 00:00:00 2001 From: ksiomng Date: Wed, 26 Mar 2025 15:32:20 +0900 Subject: [PATCH 20/39] =?UTF-8?q?Feat:=20=EC=A3=BC=EC=84=9D=EC=B6=94?= =?UTF-8?q?=EA=B0=80,=20=EC=BD=94=EB=93=9C=20=EC=A0=95=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../View/WriteLetter/ContentWriteView.swift | 36 +++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/Kabinett/Presentation/View/WriteLetter/ContentWriteView.swift b/Kabinett/Presentation/View/WriteLetter/ContentWriteView.swift index 2beb8277..0293f63b 100644 --- a/Kabinett/Presentation/View/WriteLetter/ContentWriteView.swift +++ b/Kabinett/Presentation/View/WriteLetter/ContentWriteView.swift @@ -37,7 +37,7 @@ struct ContentWriteView: View { } ZStack(alignment: .top) { VStack { - ScrollableLetterView(letter: $letter, viewModel: viewModel, imageViewModel: imageViewModel, currentIndex: $viewModel.currentIndex) + ScrollableLetterView(letter: $letter, viewModel: viewModel, imageViewModel: imageViewModel) .font(FontUtility.selectedFont(font: letter.fontString ?? "", size: 13)) Text("\(viewModel.currentIndex+1) / \(viewModel.texts.count+imageViewModel.photoContents.count)") @@ -66,32 +66,19 @@ struct ContentWriteView: View { } } } - .overlay { + .overlay { // 폰트 선택뷰 if viewModel.showFontMenu { FontMenuView(letter: $letter, showFontMenu: $viewModel.showFontMenu, fontViewModel: fontViewModel) } } - .toolbar { - ToolbarItem(placement: .topBarTrailing) { - NavigationLink(destination: EnvelopeStampSelectionView( - letter: $letter, - customTabViewModel: customTabViewModel - )) { - Text("다음") - .fontWeight(.medium) - .font(.system(size: 19)) - .foregroundStyle(.contentPrimary) - } - } - } .ignoresSafeArea(.keyboard) - .onChange(of: imageViewModel.selectedItems) { + .onChange(of: imageViewModel.selectedItems) { // 이미지가 변경될 때 Task { @MainActor in await imageViewModel.loadImages() letter.photoContents = imageViewModel.photoContents } } - .onAppear{ + .onAppear{ // 키보드 감지 NotificationCenter.default.addObserver( forName: UIResponder.keyboardWillShowNotification, object: nil, queue: .main) { _ in keyBoard = true @@ -101,7 +88,20 @@ struct ContentWriteView: View { keyBoard = false } } - .analyticsScreen( + .toolbar { + ToolbarItem(placement: .topBarTrailing) { + NavigationLink(destination: EnvelopeStampSelectionView( + letter: $letter, + customTabViewModel: customTabViewModel + )) { + Text("다음") + .fontWeight(.medium) + .font(.system(size: 19)) + .foregroundStyle(.contentPrimary) + } + } + } + .analyticsScreen( // 화면 추적 name: "\(type(of:self))", extraParameters: [ AnalyticsParameterScreenName: "\(type(of:self))", From 74ddc92acef3b3eb4c4852301d7718a8f37fcf18 Mon Sep 17 00:00:00 2001 From: ksiomng Date: Wed, 26 Mar 2025 15:34:46 +0900 Subject: [PATCH 21/39] =?UTF-8?q?Fix:=20ViewModel=20index=EB=A5=BC=20?= =?UTF-8?q?=EC=82=AC=EC=9A=A9=ED=95=98=EB=A9=B4=20=EB=90=98=EC=84=9C=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Presentation/View/WriteLetter/ContentWriteView.swift | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/Kabinett/Presentation/View/WriteLetter/ContentWriteView.swift b/Kabinett/Presentation/View/WriteLetter/ContentWriteView.swift index 0293f63b..ae9ef3b1 100644 --- a/Kabinett/Presentation/View/WriteLetter/ContentWriteView.swift +++ b/Kabinett/Presentation/View/WriteLetter/ContentWriteView.swift @@ -119,7 +119,6 @@ struct ScrollableLetterView: View { @Binding var letter: WriteLetter @ObservedObject var viewModel: ContentWriteViewModel @ObservedObject var imageViewModel: ImagePickerViewModel - @Binding var currentIndex: Int var body: some View { GeometryReader { geometry in @@ -216,7 +215,7 @@ struct ScrollableLetterView: View { .scrollTargetBehavior(.viewAligned) .onChange(of: viewModel.texts.count) { withAnimation { - scrollViewProxy.scrollTo((currentIndex+1), anchor: .center) + scrollViewProxy.scrollTo((viewModel.currentIndex+1), anchor: .center) } } .onPreferenceChange(AnchorsKey.self) { anchors in @@ -226,8 +225,8 @@ struct ScrollableLetterView: View { .sorted { geometry[$0.value].x < geometry[$1.value].x } .first - if let leadingAnchor = leadingAnchor, currentIndex != leadingAnchor.key { - currentIndex = leadingAnchor.key + if let leadingAnchor = leadingAnchor, viewModel.currentIndex != leadingAnchor.key { + viewModel.currentIndex = leadingAnchor.key } } From ca832aeba4aa02b0acfbadfc843b7e2e304ce6ba Mon Sep 17 00:00:00 2001 From: ksiomng Date: Wed, 26 Mar 2025 17:48:43 +0900 Subject: [PATCH 22/39] =?UTF-8?q?Fix:=20=EB=B7=B0=20=EB=B6=84=EB=A6=AC?= =?UTF-8?q?=EC=A4=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../View/WriteLetter/ContentWriteView.swift | 159 ++++++++++-------- 1 file changed, 86 insertions(+), 73 deletions(-) diff --git a/Kabinett/Presentation/View/WriteLetter/ContentWriteView.swift b/Kabinett/Presentation/View/WriteLetter/ContentWriteView.swift index ae9ef3b1..3471cb48 100644 --- a/Kabinett/Presentation/View/WriteLetter/ContentWriteView.swift +++ b/Kabinett/Presentation/View/WriteLetter/ContentWriteView.swift @@ -126,87 +126,61 @@ struct ScrollableLetterView: View { ZStack(alignment: .top) { ScrollView(.horizontal, showsIndicators: false) { LazyHStack(alignment: .top, spacing: UIScreen.main.bounds.width * 0.04) { - ForEach(0..] static var defaultValue: Value { [ : ] } From 2d7304486c1f037baa69986fce12c1b1aa110929 Mon Sep 17 00:00:00 2001 From: ksiomng Date: Thu, 27 Mar 2025 09:02:15 +0900 Subject: [PATCH 23/39] =?UTF-8?q?Revert=20"Fix:=20=EB=B7=B0=20=EB=B6=84?= =?UTF-8?q?=EB=A6=AC=EC=A4=91"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit ca832aeba4aa02b0acfbadfc843b7e2e304ce6ba. --- .../View/WriteLetter/ContentWriteView.swift | 159 ++++++++---------- 1 file changed, 73 insertions(+), 86 deletions(-) diff --git a/Kabinett/Presentation/View/WriteLetter/ContentWriteView.swift b/Kabinett/Presentation/View/WriteLetter/ContentWriteView.swift index 3471cb48..ae9ef3b1 100644 --- a/Kabinett/Presentation/View/WriteLetter/ContentWriteView.swift +++ b/Kabinett/Presentation/View/WriteLetter/ContentWriteView.swift @@ -126,61 +126,87 @@ struct ScrollableLetterView: View { ZStack(alignment: .top) { ScrollView(.horizontal, showsIndicators: false) { LazyHStack(alignment: .top, spacing: UIScreen.main.bounds.width * 0.04) { - - ForEach(0..] static var defaultValue: Value { [ : ] } From 5d3d8f1bd53cf8dd68902af374196dfff192fbf3 Mon Sep 17 00:00:00 2001 From: ksiomng Date: Thu, 27 Mar 2025 10:00:35 +0900 Subject: [PATCH 24/39] =?UTF-8?q?Fix:=20=EB=B7=B0=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../View/WriteLetter/ContentWriteView.swift | 178 ++++++++++-------- 1 file changed, 101 insertions(+), 77 deletions(-) diff --git a/Kabinett/Presentation/View/WriteLetter/ContentWriteView.swift b/Kabinett/Presentation/View/WriteLetter/ContentWriteView.swift index ae9ef3b1..56296f1c 100644 --- a/Kabinett/Presentation/View/WriteLetter/ContentWriteView.swift +++ b/Kabinett/Presentation/View/WriteLetter/ContentWriteView.swift @@ -11,6 +11,9 @@ import Kingfisher import PhotosUI import FirebaseAnalytics +let screenWidth = UIScreen.main.bounds.width +let screenHeight = UIScreen.main.bounds.height + struct ContentWriteView: View { @Binding var letter: WriteLetter @StateObject var viewModel = ContentWriteViewModel() @@ -113,9 +116,6 @@ struct ContentWriteView: View { // MARK: ScrollableLetterView struct ScrollableLetterView: View { - let screenWidth = UIScreen.main.bounds.width - let screenHeight = UIScreen.main.bounds.height - @Binding var letter: WriteLetter @ObservedObject var viewModel: ContentWriteViewModel @ObservedObject var imageViewModel: ImagePickerViewModel @@ -126,84 +126,21 @@ struct ScrollableLetterView: View { ZStack(alignment: .top) { ScrollView(.horizontal, showsIndicators: false) { LazyHStack(alignment: .top, spacing: UIScreen.main.bounds.width * 0.04) { - ForEach(0..] static var defaultValue: Value { [ : ] } From 24bd71f8607d7355d34226808b15477e7c6c367a Mon Sep 17 00:00:00 2001 From: ksiomng Date: Thu, 27 Mar 2025 10:06:37 +0900 Subject: [PATCH 25/39] =?UTF-8?q?Fix:=20=EB=B7=B0=EB=AA=A8=EB=8D=B8=20?= =?UTF-8?q?=ED=95=98=EB=82=98=EB=A1=9C=20=ED=95=A9=EC=B9=98=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Kabinett.xcodeproj/project.pbxproj | 4 - .../Components/MiniTabBarView.swift | 9 +-- .../View/WriteLetter/ContentWriteView.swift | 24 +++--- .../WriteLetter/ContentWriteViewModel.swift | 56 +++++++++++++ .../WriteLetter/ImagePickerViewModel.swift | 78 ------------------- 5 files changed, 70 insertions(+), 101 deletions(-) delete mode 100644 Kabinett/Presentation/ViewModel/WriteLetter/ImagePickerViewModel.swift diff --git a/Kabinett.xcodeproj/project.pbxproj b/Kabinett.xcodeproj/project.pbxproj index c1b5a89d..a4d245b8 100644 --- a/Kabinett.xcodeproj/project.pbxproj +++ b/Kabinett.xcodeproj/project.pbxproj @@ -86,7 +86,6 @@ 57ED9CE92C74262500A4312C /* SourceHanSerifK-Regular.otf in Resources */ = {isa = PBXBuildFile; fileRef = 57ED9CE82C74262400A4312C /* SourceHanSerifK-Regular.otf */; }; 7F397C4E2C7C0ECE00388645 /* CustomTabViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F397C4D2C7C0ECE00388645 /* CustomTabViewModel.swift */; }; 7F6CE9C02C6B2FEA0074568E /* CustomTabView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F6CE9BF2C6B2FE90074568E /* CustomTabView.swift */; }; - 7F6CE9C42C6B50050074568E /* ImagePickerViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F6CE9C32C6B50050074568E /* ImagePickerViewModel.swift */; }; 7F9890822C7EF5C30035CB0D /* CustomTabBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F9890812C7EF5C30035CB0D /* CustomTabBar.swift */; }; 7FCAE2BA2C73102900228FA7 /* ImageDetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7FCAE2B92C73102900228FA7 /* ImageDetailView.swift */; }; 8314013F2C69C34500F601FB /* Letter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8314013E2C69C34500F601FB /* Letter.swift */; }; @@ -225,7 +224,6 @@ 57ED9CE82C74262400A4312C /* SourceHanSerifK-Regular.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "SourceHanSerifK-Regular.otf"; sourceTree = ""; }; 7F397C4D2C7C0ECE00388645 /* CustomTabViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomTabViewModel.swift; sourceTree = ""; }; 7F6CE9BF2C6B2FE90074568E /* CustomTabView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomTabView.swift; sourceTree = ""; }; - 7F6CE9C32C6B50050074568E /* ImagePickerViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImagePickerViewModel.swift; sourceTree = ""; }; 7F9890812C7EF5C30035CB0D /* CustomTabBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomTabBar.swift; sourceTree = ""; }; 7FCAE2B92C73102900228FA7 /* ImageDetailView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageDetailView.swift; sourceTree = ""; }; 8314013E2C69C34500F601FB /* Letter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Letter.swift; sourceTree = ""; }; @@ -586,7 +584,6 @@ 8366B6F82C65ED0F0021FAE0 /* WriteLetter */ = { isa = PBXGroup; children = ( - 7F6CE9C32C6B50050074568E /* ImagePickerViewModel.swift */, 57C35C662CCA02130083A346 /* FontUtility.swift */, 57ED94F92C84AFAC00A6F187 /* LetterWriteModel.swift */, 57ED9CDD2C73698B00A4312C /* StationerySelectionViewModel.swift */, @@ -959,7 +956,6 @@ 538150542C8AF04B007B1E5A /* Extension+LetterType.swift in Sources */, 5358E0732CE16E630089C59F /* SearchBarViewModel.swift in Sources */, 83CA92AB2C8160CB00DFB68B /* Publisher+.swift in Sources */, - 7F6CE9C42C6B50050074568E /* ImagePickerViewModel.swift in Sources */, 534C67B72C7FF85700F0C175 /* LetterContentView.swift in Sources */, 7FCAE2BA2C73102900228FA7 /* ImageDetailView.swift in Sources */, 04DEC0E72C6C6C7300D289EA /* ProfileView.swift in Sources */, diff --git a/Kabinett/Presentation/View/WriteLetter/Components/MiniTabBarView.swift b/Kabinett/Presentation/View/WriteLetter/Components/MiniTabBarView.swift index 2f9ce185..b0aea3b4 100644 --- a/Kabinett/Presentation/View/WriteLetter/Components/MiniTabBarView.swift +++ b/Kabinett/Presentation/View/WriteLetter/Components/MiniTabBarView.swift @@ -11,7 +11,6 @@ import PhotosUI struct MiniTabBarView: View { @ObservedObject var viewModel: ContentWriteViewModel @ObservedObject var customTabViewModel: CustomTabViewModel - @ObservedObject var imageViewModel: ImagePickerViewModel var body: some View { if viewModel.currentIndex < viewModel.texts.count { @@ -63,16 +62,16 @@ struct MiniTabBarView: View { .frame(width: UIScreen.main.bounds.width * 0.4/4) } PhotosPicker( - selection: $imageViewModel.selectedItems, + selection: $viewModel.selectedItems, maxSelectionCount: 10, matching: .images) { Image(systemName: "photo.on.rectangle.angled") .font(.system(size: 15)) .frame(width: UIScreen.main.bounds.width * 0.4/4, height: 30) - .background(imageViewModel.selectedItems.isEmpty ? Color.clear : Color.white) - .foregroundStyle(imageViewModel.selectedItems.isEmpty ? Color("ToolBarIcon") : Color(.primary900)) + .background(viewModel.selectedItems.isEmpty ? Color.clear : Color.white) + .foregroundStyle(viewModel.selectedItems.isEmpty ? Color("ToolBarIcon") : Color(.primary900)) .clipShape(Capsule()) - .shadow(color: imageViewModel.selectedItems.isEmpty ? Color.clear : Color(.primary300), radius: 7, x: 3, y: 3) + .shadow(color: viewModel.selectedItems.isEmpty ? Color.clear : Color(.primary300), radius: 7, x: 3, y: 3) } } .frame(maxWidth: UIScreen.main.bounds.width * 0.5, maxHeight: 40) diff --git a/Kabinett/Presentation/View/WriteLetter/ContentWriteView.swift b/Kabinett/Presentation/View/WriteLetter/ContentWriteView.swift index 56296f1c..352100f6 100644 --- a/Kabinett/Presentation/View/WriteLetter/ContentWriteView.swift +++ b/Kabinett/Presentation/View/WriteLetter/ContentWriteView.swift @@ -17,7 +17,6 @@ let screenHeight = UIScreen.main.bounds.height struct ContentWriteView: View { @Binding var letter: WriteLetter @StateObject var viewModel = ContentWriteViewModel() - @StateObject var imageViewModel: ImagePickerViewModel @ObservedObject var customTabViewModel: CustomTabViewModel @StateObject var fontViewModel = FontSelectionViewModel() @@ -28,7 +27,6 @@ struct ContentWriteView: View { customTabViewModel: CustomTabViewModel ) { self.customTabViewModel = customTabViewModel - self._imageViewModel = StateObject(wrappedValue: ImagePickerViewModel()) self._letter = letter } @@ -40,17 +38,17 @@ struct ContentWriteView: View { } ZStack(alignment: .top) { VStack { - ScrollableLetterView(letter: $letter, viewModel: viewModel, imageViewModel: imageViewModel) + ScrollableLetterView(letter: $letter, viewModel: viewModel) .font(FontUtility.selectedFont(font: letter.fontString ?? "", size: 13)) - Text("\(viewModel.currentIndex+1) / \(viewModel.texts.count+imageViewModel.photoContents.count)") + Text("\(viewModel.currentIndex+1) / \(viewModel.texts.count+viewModel.photoContents.count)") .padding(5) .padding(.horizontal, 8) .background(Color(.primary900).opacity(0.3)) .clipShape(Capsule()) } .padding(.bottom, LayoutHelper.shared.getSize(forSE: 0.03, forOthers: 0.0)) - MiniTabBarView(viewModel: viewModel, customTabViewModel: customTabViewModel, imageViewModel: imageViewModel) + MiniTabBarView(viewModel: viewModel, customTabViewModel: customTabViewModel) if keyBoard { Button(action:{ @@ -75,10 +73,10 @@ struct ContentWriteView: View { } } .ignoresSafeArea(.keyboard) - .onChange(of: imageViewModel.selectedItems) { // 이미지가 변경될 때 + .onChange(of: viewModel.selectedItems) { // 이미지가 변경될 때 Task { @MainActor in - await imageViewModel.loadImages() - letter.photoContents = imageViewModel.photoContents + await viewModel.loadImages() + letter.photoContents = viewModel.photoContents } } .onAppear{ // 키보드 감지 @@ -118,7 +116,6 @@ struct ContentWriteView: View { struct ScrollableLetterView: View { @Binding var letter: WriteLetter @ObservedObject var viewModel: ContentWriteViewModel - @ObservedObject var imageViewModel: ImagePickerViewModel var body: some View { GeometryReader { geometry in @@ -138,9 +135,9 @@ struct ScrollableLetterView: View { .anchorPreference(key: AnchorsKey.self, value: .trailing, transform: { [i: $0] }) } - ForEach(imageViewModel.photoContents.indices, id: \.self) { index in - if let uiImage = UIImage(data: imageViewModel.photoContents[index]) { - PolaroidView(index: index, uiImage: uiImage, letter: $letter, viewModel: viewModel, imageViewModel: imageViewModel) + ForEach(viewModel.photoContents.indices, id: \.self) { index in + if let uiImage = UIImage(data: viewModel.photoContents[index]) { + PolaroidView(index: index, uiImage: uiImage, letter: $letter, viewModel: viewModel) } } @@ -227,7 +224,6 @@ struct PolaroidView: View { let uiImage: UIImage @Binding var letter: WriteLetter @ObservedObject var viewModel: ContentWriteViewModel - @ObservedObject var imageViewModel: ImagePickerViewModel var body: some View { let imageIndex = index + viewModel.texts.count @@ -246,7 +242,7 @@ struct PolaroidView: View { .anchorPreference(key: AnchorsKey.self, value: .trailing, transform: { [imageIndex: $0] }) Button(action: { - imageViewModel.selectedItems.remove(at: index) + viewModel.selectedItems.remove(at: index) }) { Image(systemName: "xmark.circle.fill") .resizable() diff --git a/Kabinett/Presentation/ViewModel/WriteLetter/ContentWriteViewModel.swift b/Kabinett/Presentation/ViewModel/WriteLetter/ContentWriteViewModel.swift index ab647ac2..b8cb6306 100644 --- a/Kabinett/Presentation/ViewModel/WriteLetter/ContentWriteViewModel.swift +++ b/Kabinett/Presentation/ViewModel/WriteLetter/ContentWriteViewModel.swift @@ -7,8 +7,64 @@ import Foundation import SwiftUI +import PhotosUI +import Combine class ContentWriteViewModel: ObservableObject { + @Published var selectedItems: [PhotosPickerItem] = [] //***** + @Published var photoContents: [Data] = [] + + @Published var isLoading: Bool = false + @Published var error: Error? + + private var cancellables = Set() + + func resetSelections() { + selectedItems = [] + photoContents = [] + } + + @MainActor + func loadImages() async { + isLoading = true + error = nil + + do { + let newImageContents = try await loadImagesTask() + self.photoContents = newImageContents + } catch { + self.error = error + } + + isLoading = false + } + + // MARK: 선택된 이미지 로드 + private func loadImagesTask() async throws -> [Data] { + try await withThrowingTaskGroup(of: Data?.self) { group -> [Data] in + for item in selectedItems { + group.addTask { + do { + if let data = try await item.loadTransferable(type: Data.self) { + return data + } + } catch { + print("Failed to load image: \(error)") + } + return nil + } + } + + var results: [Data] = [] + for try await result in group { + if let result = result { + results.append(result) + } + } + return results + } + } + @Published var texts: [String] = [""] @Published var currentIndex: Int = 0 @Published var isDeleteAlertPresented = false diff --git a/Kabinett/Presentation/ViewModel/WriteLetter/ImagePickerViewModel.swift b/Kabinett/Presentation/ViewModel/WriteLetter/ImagePickerViewModel.swift deleted file mode 100644 index 1b767169..00000000 --- a/Kabinett/Presentation/ViewModel/WriteLetter/ImagePickerViewModel.swift +++ /dev/null @@ -1,78 +0,0 @@ -// -// ImagePickerViewModel.swift -// Kabinett -// -// Created by 김정우 on 8/13/24. -// - -import SwiftUI -import PhotosUI -import Combine - -final class ImagePickerViewModel: ObservableObject { - @Published var selectedItems: [PhotosPickerItem] = [] //***** - @Published var photoContents: [Data] = [] - - @Published var isLoading: Bool = false - @Published var error: Error? - - private var cancellables = Set() - - func resetSelections() { - selectedItems = [] - photoContents = [] - } - - @MainActor - func loadImages() async { - isLoading = true - error = nil - - do { - let newImageContents = try await loadImagesTask() - self.photoContents = newImageContents - } catch { - self.error = error - } - - isLoading = false - } - - // MARK: 선택된 이미지 로드 - private func loadImagesTask() async throws -> [Data] { - try await withThrowingTaskGroup(of: Data?.self) { group -> [Data] in - for item in selectedItems { - group.addTask { - do { - if let data = try await item.loadTransferable(type: Data.self) { - return data - } - } catch { - print("Failed to load image: \(error)") - } - return nil - } - } - - var results: [Data] = [] - for try await result in group { - if let result = result { - results.append(result) - } - } - return results - } - } -} - -// MARK: - ViewModel -final class CameraViewModel: ObservableObject { - @Published var capturedImage: UIImage? - - // MARK: Method(캡쳐된 이미지 처리) - func captureImage(with info: [UIImagePickerController.InfoKey : Any]) { - if let image = info[.originalImage] as? UIImage { - capturedImage = image - } - } -} From d567657ec95f7d469c7d797f54f007592c0b3904 Mon Sep 17 00:00:00 2001 From: ksiomng Date: Thu, 27 Mar 2025 10:11:18 +0900 Subject: [PATCH 26/39] =?UTF-8?q?Fix:=20=EB=B7=B0=EC=99=80=20=EB=B7=B0?= =?UTF-8?q?=EB=AA=A8=EB=8D=B8=20=ED=95=9C=EB=B2=88=20=EB=8D=94=20=EC=A0=95?= =?UTF-8?q?=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../View/WriteLetter/ContentWriteView.swift | 8 ++-- .../WriteLetter/ContentWriteViewModel.swift | 44 +++++++++---------- 2 files changed, 25 insertions(+), 27 deletions(-) diff --git a/Kabinett/Presentation/View/WriteLetter/ContentWriteView.swift b/Kabinett/Presentation/View/WriteLetter/ContentWriteView.swift index 352100f6..0935703c 100644 --- a/Kabinett/Presentation/View/WriteLetter/ContentWriteView.swift +++ b/Kabinett/Presentation/View/WriteLetter/ContentWriteView.swift @@ -20,8 +20,6 @@ struct ContentWriteView: View { @ObservedObject var customTabViewModel: CustomTabViewModel @StateObject var fontViewModel = FontSelectionViewModel() - @State var keyBoard: Bool = false - init( letter: Binding, customTabViewModel: CustomTabViewModel @@ -50,7 +48,7 @@ struct ContentWriteView: View { .padding(.bottom, LayoutHelper.shared.getSize(forSE: 0.03, forOthers: 0.0)) MiniTabBarView(viewModel: viewModel, customTabViewModel: customTabViewModel) - if keyBoard { + if viewModel.isKeyboard { Button(action:{ UIApplication.shared.sendAction( #selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil @@ -82,11 +80,11 @@ struct ContentWriteView: View { .onAppear{ // 키보드 감지 NotificationCenter.default.addObserver( forName: UIResponder.keyboardWillShowNotification, object: nil, queue: .main) { _ in - keyBoard = true + viewModel.isKeyboard = true } NotificationCenter.default.addObserver( forName: UIResponder.keyboardWillHideNotification, object: nil, queue: .main) { _ in - keyBoard = false + viewModel.isKeyboard = false } } .toolbar { diff --git a/Kabinett/Presentation/ViewModel/WriteLetter/ContentWriteViewModel.swift b/Kabinett/Presentation/ViewModel/WriteLetter/ContentWriteViewModel.swift index b8cb6306..5735fd58 100644 --- a/Kabinett/Presentation/ViewModel/WriteLetter/ContentWriteViewModel.swift +++ b/Kabinett/Presentation/ViewModel/WriteLetter/ContentWriteViewModel.swift @@ -5,12 +5,19 @@ // Created by Song Kim on 8/22/24. // -import Foundation import SwiftUI import PhotosUI import Combine class ContentWriteViewModel: ObservableObject { + @Published var texts: [String] = [""] + @Published var currentIndex: Int = 0 + @Published var isDeleteAlertPresented = false + + @Published var showFontMenu: Bool = false + @Published var isFontEdit: Bool = true + @Published var isKeyboard: Bool = false + @Published var selectedItems: [PhotosPickerItem] = [] //***** @Published var photoContents: [Data] = [] @@ -18,6 +25,20 @@ class ContentWriteViewModel: ObservableObject { @Published var error: Error? private var cancellables = Set() + + func toggleFontView() { + showFontMenu.toggle() + } + + func createNewLetter(idx: Int) { + texts.insert("", at: idx+1) + } + + func deleteLetter(idx: Int) { + if texts.count > 1 { + texts.remove(at: idx) + } + } func resetSelections() { selectedItems = [] @@ -64,25 +85,4 @@ class ContentWriteViewModel: ObservableObject { return results } } - - @Published var texts: [String] = [""] - @Published var currentIndex: Int = 0 - @Published var isDeleteAlertPresented = false - - @Published var showFontMenu: Bool = false - @Published var isFontEdit: Bool = true - - func toggleFontView() { - showFontMenu.toggle() - } - - func createNewLetter(idx: Int) { - texts.insert("", at: idx+1) - } - - func deleteLetter(idx: Int) { - if texts.count > 1 { - texts.remove(at: idx) - } - } } From 993b4d741f802c68e9f66e27cf65ff0978856c8c Mon Sep 17 00:00:00 2001 From: ksiomng Date: Thu, 27 Mar 2025 10:16:27 +0900 Subject: [PATCH 27/39] =?UTF-8?q?Fix:=20geometry=20=EA=B2=BD=EA=B3=A0?= =?UTF-8?q?=EB=AC=B8=EC=9D=84=20=EA=B3=A0=EC=B9=98=EA=B8=B0=EC=9C=84?= =?UTF-8?q?=ED=95=B4=20=EA=B0=99=EC=9D=B4=20=EC=82=AC=EC=9A=A9=ED=95=B4?= =?UTF-8?q?=EC=95=BC=ED=95=A0=20=EC=BD=94=EB=93=9C=EB=A5=BC=20=EC=98=AE?= =?UTF-8?q?=EA=B2=A8=EC=A4=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../View/WriteLetter/ContentWriteView.swift | 48 +++++++++---------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/Kabinett/Presentation/View/WriteLetter/ContentWriteView.swift b/Kabinett/Presentation/View/WriteLetter/ContentWriteView.swift index 0935703c..51cc0185 100644 --- a/Kabinett/Presentation/View/WriteLetter/ContentWriteView.swift +++ b/Kabinett/Presentation/View/WriteLetter/ContentWriteView.swift @@ -134,8 +134,11 @@ struct ScrollableLetterView: View { } ForEach(viewModel.photoContents.indices, id: \.self) { index in + let imageIndex = index + viewModel.texts.count if let uiImage = UIImage(data: viewModel.photoContents[index]) { PolaroidView(index: index, uiImage: uiImage, letter: $letter, viewModel: viewModel) + .tag(imageIndex) + .anchorPreference(key: AnchorsKey.self, value: .trailing, transform: { [imageIndex: $0] }) } } @@ -224,32 +227,29 @@ struct PolaroidView: View { @ObservedObject var viewModel: ContentWriteViewModel var body: some View { - let imageIndex = index + viewModel.texts.count - ZStack(alignment: .topTrailing) { - Image(uiImage: uiImage) + ZStack(alignment: .topTrailing) { + Image(uiImage: uiImage) + .resizable() + .clipShape(RoundedRectangle(cornerRadius: 5)) + .aspectRatio(contentMode: .fit) + .padding([.horizontal, .top], 10) + .padding(.bottom, UIScreen.main.bounds.width * 0.12) + .background(Color.white) + .clipShape(RoundedRectangle(cornerRadius: 5)) + .shadow(color: .primary300, radius: 5, x: 3, y: 3) + .padding([.top, .bottom], 10) + + Button(action: { + viewModel.selectedItems.remove(at: index) + }) { + Image(systemName: "xmark.circle.fill") .resizable() - .clipShape(RoundedRectangle(cornerRadius: 5)) - .aspectRatio(contentMode: .fit) - .padding([.horizontal, .top], 10) - .padding(.bottom, UIScreen.main.bounds.width * 0.12) - .background(Color.white) - .clipShape(RoundedRectangle(cornerRadius: 5)) - .shadow(color: .primary300, radius: 5, x: 3, y: 3) - .padding([.top, .bottom], 10) - .tag(imageIndex) - .anchorPreference(key: AnchorsKey.self, value: .trailing, transform: { [imageIndex: $0] }) - - Button(action: { - viewModel.selectedItems.remove(at: index) - }) { - Image(systemName: "xmark.circle.fill") - .resizable() - .frame(width: 25, height: 25) - .padding(.trailing, -10) - .foregroundColor(Color(.primary900)) - } + .frame(width: 25, height: 25) + .padding(.trailing, -10) + .foregroundColor(Color(.primary900)) } - .frame(width: UIScreen.main.bounds.width * 0.88) + } + .frame(width: UIScreen.main.bounds.width * 0.88) } } From 4d7470b689ca0d662166c01c98f7e0ffd51f5971 Mon Sep 17 00:00:00 2001 From: ksiomng Date: Thu, 27 Mar 2025 14:45:06 +0900 Subject: [PATCH 28/39] =?UTF-8?q?Fix:=20=ED=8E=98=EC=9D=B4=EC=A7=80=20?= =?UTF-8?q?=EA=B3=84=EC=82=B0=EC=9D=84=20=EC=8A=A4=ED=81=AC=EB=A1=A4=20off?= =?UTF-8?q?set=EC=9C=BC=EB=A1=9C=20=ED=95=B4=EC=84=9C=20=EA=B0=80=EA=B9=8C?= =?UTF-8?q?=EC=9A=B4=20=ED=8E=98=EC=9D=B4=EC=A7=80=EC=9D=98=20=EC=9D=B8?= =?UTF-8?q?=EB=8D=B1=EC=8A=A4=EB=A5=BC=20=EA=B5=AC=ED=95=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../View/WriteLetter/ContentWriteView.swift | 37 +++++++++++++++---- .../WriteLetter/ContentWriteViewModel.swift | 16 ++++++++ 2 files changed, 46 insertions(+), 7 deletions(-) diff --git a/Kabinett/Presentation/View/WriteLetter/ContentWriteView.swift b/Kabinett/Presentation/View/WriteLetter/ContentWriteView.swift index 51cc0185..44728c6d 100644 --- a/Kabinett/Presentation/View/WriteLetter/ContentWriteView.swift +++ b/Kabinett/Presentation/View/WriteLetter/ContentWriteView.swift @@ -114,12 +114,27 @@ struct ContentWriteView: View { struct ScrollableLetterView: View { @Binding var letter: WriteLetter @ObservedObject var viewModel: ContentWriteViewModel + private var scrollObservableView: some View { + GeometryReader { proxy in + let offsetX = proxy.frame(in: .global).origin.x + Color.clear + .preference( + key: ScrollOffsetKey.self, + value: offsetX + ) + .onAppear { + viewModel.setOriginOffset(offsetX) + } + } + .frame(height: 0) + } var body: some View { GeometryReader { geometry in ScrollViewReader { scrollViewProxy in ZStack(alignment: .top) { ScrollView(.horizontal, showsIndicators: false) { + scrollObservableView LazyHStack(alignment: .top, spacing: UIScreen.main.bounds.width * 0.04) { ForEach(viewModel.texts.indices, id: \.self) { i in TypingView(index: i, letter: $letter, viewModel: viewModel) @@ -130,7 +145,6 @@ struct ScrollableLetterView: View { .aspectRatio(9/13, contentMode: .fit) .frame(width: UIScreen.main.bounds.width * 0.88) .id(i) - .anchorPreference(key: AnchorsKey.self, value: .trailing, transform: { [i: $0] }) } ForEach(viewModel.photoContents.indices, id: \.self) { index in @@ -138,7 +152,6 @@ struct ScrollableLetterView: View { if let uiImage = UIImage(data: viewModel.photoContents[index]) { PolaroidView(index: index, uiImage: uiImage, letter: $letter, viewModel: viewModel) .tag(imageIndex) - .anchorPreference(key: AnchorsKey.self, value: .trailing, transform: { [imageIndex: $0] }) } } @@ -146,6 +159,17 @@ struct ScrollableLetterView: View { .padding(.horizontal, UIScreen.main.bounds.width * 0.06) } .scrollTargetLayout() + .onPreferenceChange(ScrollOffsetKey.self) { newOffset in + viewModel.offset = newOffset + + let pageWidth = screenWidth * 0.9204 + let rawIndex = -viewModel.offset / pageWidth + let nearestIndex = Int(round(rawIndex)) + + if viewModel.currentIndex != nearestIndex { + viewModel.currentIndex = nearestIndex + } + } } .scrollTargetBehavior(.viewAligned) .onChange(of: viewModel.texts.count) { @@ -253,10 +277,9 @@ struct PolaroidView: View { } } -struct AnchorsKey: PreferenceKey { - typealias Value = [Int: Anchor] - static var defaultValue: Value { [ : ] } - static func reduce(value: inout Value, nextValue: () -> Value) { - value.merge(nextValue()) { $1 } +struct ScrollOffsetKey: PreferenceKey { + static var defaultValue: CGFloat = .zero + static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) { + value += nextValue() } } diff --git a/Kabinett/Presentation/ViewModel/WriteLetter/ContentWriteViewModel.swift b/Kabinett/Presentation/ViewModel/WriteLetter/ContentWriteViewModel.swift index 5735fd58..e79d2a81 100644 --- a/Kabinett/Presentation/ViewModel/WriteLetter/ContentWriteViewModel.swift +++ b/Kabinett/Presentation/ViewModel/WriteLetter/ContentWriteViewModel.swift @@ -10,6 +10,22 @@ import PhotosUI import Combine class ContentWriteViewModel: ObservableObject { + @Published var offset: CGFloat = 0 + private var originOffset: CGFloat = 0 + private var isCheckedOriginOffset: Bool = false + + func setOriginOffset(_ offset: CGFloat) { + guard !isCheckedOriginOffset else { return } + self.originOffset = offset + self.offset = offset + isCheckedOriginOffset = true + } + + func setOffset(_ offset: CGFloat) { + guard isCheckedOriginOffset else { return } + self.offset = offset + } + @Published var texts: [String] = [""] @Published var currentIndex: Int = 0 @Published var isDeleteAlertPresented = false From 70ac8e861ee0f1ec9bced530f2d0b950e13ac08a Mon Sep 17 00:00:00 2001 From: ksiomng Date: Thu, 27 Mar 2025 14:45:56 +0900 Subject: [PATCH 29/39] =?UTF-8?q?Fix:=20offset=EC=9D=B4=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD=EB=90=A0=EB=95=8C=20=ED=8E=98=EC=9D=B4=EC=A7=80?= =?UTF-8?q?=EA=B0=80=20center=EB=A1=9C=20=EC=98=AC=EC=88=98=EC=9E=88?= =?UTF-8?q?=EA=B2=8C=20=EC=BD=94=EB=93=9C=EB=A5=BC=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../View/WriteLetter/ContentWriteView.swift | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/Kabinett/Presentation/View/WriteLetter/ContentWriteView.swift b/Kabinett/Presentation/View/WriteLetter/ContentWriteView.swift index 44728c6d..70603b16 100644 --- a/Kabinett/Presentation/View/WriteLetter/ContentWriteView.swift +++ b/Kabinett/Presentation/View/WriteLetter/ContentWriteView.swift @@ -114,6 +114,8 @@ struct ContentWriteView: View { struct ScrollableLetterView: View { @Binding var letter: WriteLetter @ObservedObject var viewModel: ContentWriteViewModel + @State private var scrollWorkItem: DispatchWorkItem? + private var scrollObservableView: some View { GeometryReader { proxy in let offsetX = proxy.frame(in: .global).origin.x @@ -177,18 +179,16 @@ struct ScrollableLetterView: View { scrollViewProxy.scrollTo((viewModel.currentIndex+1), anchor: .center) } } - .onPreferenceChange(AnchorsKey.self) { anchors in - let horizontalPadding = UIScreen.main.bounds.width * 0.06 - let leadingAnchor = anchors - .filter { geometry[$0.value].x >= horizontalPadding } - .sorted { geometry[$0.value].x < geometry[$1.value].x } - .first - - if let leadingAnchor = leadingAnchor, viewModel.currentIndex != leadingAnchor.key { - viewModel.currentIndex = leadingAnchor.key + .onChange(of: viewModel.offset) { + scrollWorkItem?.cancel() + let workItem = DispatchWorkItem { + withAnimation { + scrollViewProxy.scrollTo(viewModel.currentIndex, anchor: .center) + } } + DispatchQueue.main.asyncAfter(deadline: .now() + 0.02, execute: workItem) + scrollWorkItem = workItem } - } } } From 8a32122e05707816ecfc96aa0af642d0747d79aa Mon Sep 17 00:00:00 2001 From: ksiomng Date: Thu, 27 Mar 2025 16:21:42 +0900 Subject: [PATCH 30/39] =?UTF-8?q?Fix:=20=ED=8E=98=EC=9D=B4=EC=A7=80=20?= =?UTF-8?q?=EC=9D=B4=EB=8F=99=EC=9D=B4=20=EB=B6=80=EC=9E=90=EC=97=B0?= =?UTF-8?q?=EC=8A=A4=EB=9F=AC=EC=9B=8C=EC=84=9C=20=EB=8B=A4=EB=A5=B8?= =?UTF-8?q?=EB=B0=A9=EB=B2=95=EC=9C=BC=EB=A1=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../View/WriteLetter/ContentWriteView.swift | 54 ++++++++----------- 1 file changed, 21 insertions(+), 33 deletions(-) diff --git a/Kabinett/Presentation/View/WriteLetter/ContentWriteView.swift b/Kabinett/Presentation/View/WriteLetter/ContentWriteView.swift index 70603b16..64ceabd6 100644 --- a/Kabinett/Presentation/View/WriteLetter/ContentWriteView.swift +++ b/Kabinett/Presentation/View/WriteLetter/ContentWriteView.swift @@ -116,28 +116,20 @@ struct ScrollableLetterView: View { @ObservedObject var viewModel: ContentWriteViewModel @State private var scrollWorkItem: DispatchWorkItem? - private var scrollObservableView: some View { - GeometryReader { proxy in - let offsetX = proxy.frame(in: .global).origin.x - Color.clear - .preference( - key: ScrollOffsetKey.self, - value: offsetX - ) - .onAppear { - viewModel.setOriginOffset(offsetX) - } - } - .frame(height: 0) - } - var body: some View { GeometryReader { geometry in ScrollViewReader { scrollViewProxy in ZStack(alignment: .top) { ScrollView(.horizontal, showsIndicators: false) { - scrollObservableView - LazyHStack(alignment: .top, spacing: UIScreen.main.bounds.width * 0.04) { + GeometryReader { proxy in + Color.clear + .preference( + key: ScrollOffsetKey.self, + value: proxy.frame(in: .global).origin.x + ) + } + .frame(height: 0) + LazyHStack(alignment: .top, spacing: geometry.size.width * 0.04) { ForEach(viewModel.texts.indices, id: \.self) { i in TypingView(index: i, letter: $letter, viewModel: viewModel) .onChange(of: viewModel.texts[i]) { @@ -145,22 +137,23 @@ struct ScrollableLetterView: View { } .padding(.top, 10) .aspectRatio(9/13, contentMode: .fit) - .frame(width: UIScreen.main.bounds.width * 0.88) + .frame(width: geometry.size.width * 0.88) .id(i) } ForEach(viewModel.photoContents.indices, id: \.self) { index in let imageIndex = index + viewModel.texts.count if let uiImage = UIImage(data: viewModel.photoContents[index]) { - PolaroidView(index: index, uiImage: uiImage, letter: $letter, viewModel: viewModel) - .tag(imageIndex) + PolaroidView(index: imageIndex, uiImage: uiImage, letter: $letter, viewModel: viewModel) + .frame(width: geometry.size.width * 0.88) + .id(imageIndex) } } - } - .padding(.horizontal, UIScreen.main.bounds.width * 0.06) + .padding(.horizontal, geometry.size.width * 0.06) } .scrollTargetLayout() + .scrollTargetBehavior(.viewAligned) .onPreferenceChange(ScrollOffsetKey.self) { newOffset in viewModel.offset = newOffset @@ -173,27 +166,22 @@ struct ScrollableLetterView: View { } } } - .scrollTargetBehavior(.viewAligned) .onChange(of: viewModel.texts.count) { - withAnimation { - scrollViewProxy.scrollTo((viewModel.currentIndex+1), anchor: .center) + withAnimation(.spring()) { + scrollViewProxy.scrollTo(viewModel.currentIndex+1, anchor: .center) } } - .onChange(of: viewModel.offset) { - scrollWorkItem?.cancel() - let workItem = DispatchWorkItem { - withAnimation { - scrollViewProxy.scrollTo(viewModel.currentIndex, anchor: .center) - } + .onAppear { + DispatchQueue.main.async { + scrollViewProxy.scrollTo(viewModel.currentIndex, anchor: .center) } - DispatchQueue.main.asyncAfter(deadline: .now() + 0.02, execute: workItem) - scrollWorkItem = workItem } } } } } + struct TypingView: View { let index: Int @Binding var letter: WriteLetter From a450142dcd903063c88363a29f554a51a4bf1cc6 Mon Sep 17 00:00:00 2001 From: ksiomng Date: Thu, 27 Mar 2025 16:53:18 +0900 Subject: [PATCH 31/39] =?UTF-8?q?Fix:=20index=20out=20of=20range=20?= =?UTF-8?q?=EB=9C=A8=EB=8A=94=EA=B1=B0=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Kabinett/Presentation/View/WriteLetter/ContentWriteView.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Kabinett/Presentation/View/WriteLetter/ContentWriteView.swift b/Kabinett/Presentation/View/WriteLetter/ContentWriteView.swift index 64ceabd6..5c449484 100644 --- a/Kabinett/Presentation/View/WriteLetter/ContentWriteView.swift +++ b/Kabinett/Presentation/View/WriteLetter/ContentWriteView.swift @@ -252,7 +252,7 @@ struct PolaroidView: View { .padding([.top, .bottom], 10) Button(action: { - viewModel.selectedItems.remove(at: index) + viewModel.selectedItems.remove(at: viewModel.currentIndex - viewModel.texts.count) }) { Image(systemName: "xmark.circle.fill") .resizable() From fea478ccc503bbc75d0033574f46230e832ba159 Mon Sep 17 00:00:00 2001 From: ksiomng Date: Thu, 27 Mar 2025 17:05:47 +0900 Subject: [PATCH 32/39] =?UTF-8?q?Fix:=20=EB=AF=B8=EB=A6=AC=20=EC=84=A0?= =?UTF-8?q?=EC=96=B8=ED=95=B4=EB=86=93=EC=9D=80=20=EC=88=98=20=EC=82=AC?= =?UTF-8?q?=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../View/WriteLetter/ContentWriteView.swift | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Kabinett/Presentation/View/WriteLetter/ContentWriteView.swift b/Kabinett/Presentation/View/WriteLetter/ContentWriteView.swift index 5c449484..118407af 100644 --- a/Kabinett/Presentation/View/WriteLetter/ContentWriteView.swift +++ b/Kabinett/Presentation/View/WriteLetter/ContentWriteView.swift @@ -60,8 +60,8 @@ struct ContentWriteView: View { .background(Color.primary900) .clipShape(Circle()) } - .padding(.top, UIScreen.main.bounds.height * 0.488) - .padding(.leading, UIScreen.main.bounds.width * 0.85) + .padding(.top, screenHeight * 0.488) + .padding(.leading, screenWidth * 0.85) } } } @@ -137,7 +137,7 @@ struct ScrollableLetterView: View { } .padding(.top, 10) .aspectRatio(9/13, contentMode: .fit) - .frame(width: geometry.size.width * 0.88) + .frame(width: screenWidth * 0.88) .id(i) } @@ -145,7 +145,7 @@ struct ScrollableLetterView: View { let imageIndex = index + viewModel.texts.count if let uiImage = UIImage(data: viewModel.photoContents[index]) { PolaroidView(index: imageIndex, uiImage: uiImage, letter: $letter, viewModel: viewModel) - .frame(width: geometry.size.width * 0.88) + .frame(width: screenWidth * 0.88) .id(imageIndex) } } @@ -227,7 +227,7 @@ struct TypingView: View { .padding(.bottom, screenHeight * 0.05) .frame(maxWidth: .infinity, alignment: .trailing) } - .padding(.horizontal, UIScreen.main.bounds.width * 0.08) + .padding(.horizontal, screenWidth * 0.08) } } } @@ -245,7 +245,7 @@ struct PolaroidView: View { .clipShape(RoundedRectangle(cornerRadius: 5)) .aspectRatio(contentMode: .fit) .padding([.horizontal, .top], 10) - .padding(.bottom, UIScreen.main.bounds.width * 0.12) + .padding(.bottom, screenWidth * 0.12) .background(Color.white) .clipShape(RoundedRectangle(cornerRadius: 5)) .shadow(color: .primary300, radius: 5, x: 3, y: 3) @@ -261,7 +261,7 @@ struct PolaroidView: View { .foregroundColor(Color(.primary900)) } } - .frame(width: UIScreen.main.bounds.width * 0.88) + .frame(width: screenWidth * 0.88) } } From 358f86125594c33eb58de6218c2f6ac5e70066c9 Mon Sep 17 00:00:00 2001 From: ksiomng Date: Thu, 27 Mar 2025 17:16:49 +0900 Subject: [PATCH 33/39] =?UTF-8?q?Refactor:=20=EC=BD=94=EB=93=9C=20?= =?UTF-8?q?=EB=B0=8F=20=ED=8C=8C=EC=9D=BC=20=EC=A0=95=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Kabinett.xcodeproj/project.pbxproj | 4 + .../WriteLetter/Cells/ContentWriteCell.swift | 92 +++++++++ .../View/WriteLetter/ContentWriteView.swift | 178 +++++------------- .../WriteLetter/ContentWriteViewModel.swift | 17 +- 4 files changed, 143 insertions(+), 148 deletions(-) create mode 100644 Kabinett/Presentation/View/WriteLetter/Cells/ContentWriteCell.swift diff --git a/Kabinett.xcodeproj/project.pbxproj b/Kabinett.xcodeproj/project.pbxproj index a4d245b8..83a72499 100644 --- a/Kabinett.xcodeproj/project.pbxproj +++ b/Kabinett.xcodeproj/project.pbxproj @@ -84,6 +84,7 @@ 57ED9CE52C73760800A4312C /* goormSansOTF4.otf in Resources */ = {isa = PBXBuildFile; fileRef = 57ED9CE42C73760800A4312C /* goormSansOTF4.otf */; }; 57ED9CE72C73780100A4312C /* Pecita.otf in Resources */ = {isa = PBXBuildFile; fileRef = 57ED9CE62C73780100A4312C /* Pecita.otf */; }; 57ED9CE92C74262500A4312C /* SourceHanSerifK-Regular.otf in Resources */ = {isa = PBXBuildFile; fileRef = 57ED9CE82C74262400A4312C /* SourceHanSerifK-Regular.otf */; }; + 57F7A5AB2D954061002E1209 /* ContentWriteCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57F7A5AA2D954061002E1209 /* ContentWriteCell.swift */; }; 7F397C4E2C7C0ECE00388645 /* CustomTabViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F397C4D2C7C0ECE00388645 /* CustomTabViewModel.swift */; }; 7F6CE9C02C6B2FEA0074568E /* CustomTabView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F6CE9BF2C6B2FE90074568E /* CustomTabView.swift */; }; 7F9890822C7EF5C30035CB0D /* CustomTabBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F9890812C7EF5C30035CB0D /* CustomTabBar.swift */; }; @@ -222,6 +223,7 @@ 57ED9CE42C73760800A4312C /* goormSansOTF4.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = goormSansOTF4.otf; sourceTree = ""; }; 57ED9CE62C73780100A4312C /* Pecita.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = Pecita.otf; sourceTree = ""; }; 57ED9CE82C74262400A4312C /* SourceHanSerifK-Regular.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "SourceHanSerifK-Regular.otf"; sourceTree = ""; }; + 57F7A5AA2D954061002E1209 /* ContentWriteCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentWriteCell.swift; sourceTree = ""; }; 7F397C4D2C7C0ECE00388645 /* CustomTabViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomTabViewModel.swift; sourceTree = ""; }; 7F6CE9BF2C6B2FE90074568E /* CustomTabView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomTabView.swift; sourceTree = ""; }; 7F9890812C7EF5C30035CB0D /* CustomTabBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomTabBar.swift; sourceTree = ""; }; @@ -373,6 +375,7 @@ 579E35FA2D2BB0B300F92A87 /* StationeryCell.swift */, 579E35FC2D2BB0FA00F92A87 /* EnvelopeCell.swift */, 579E35FE2D2BB11400F92A87 /* StampCell.swift */, + 57F7A5AA2D954061002E1209 /* ContentWriteCell.swift */, ); path = Cells; sourceTree = ""; @@ -1014,6 +1017,7 @@ 04DEC0DD2C6A3AD600D289EA /* SignUpView.swift in Sources */, 573EE1F82D2BA55B00978283 /* CustomTextEditor.swift in Sources */, 57966B9C2C7D8DAF008D650B /* EnvelopeStampSelectionViewModel.swift in Sources */, + 57F7A5AB2D954061002E1209 /* ContentWriteCell.swift in Sources */, 7F6CE9C02C6B2FEA0074568E /* CustomTabView.swift in Sources */, 53FC6B822C901F7700E7D9A8 /* Extension+Collection.swift in Sources */, 53DC1A2F2C7F0FC000575ACC /* LetterViewModel.swift in Sources */, diff --git a/Kabinett/Presentation/View/WriteLetter/Cells/ContentWriteCell.swift b/Kabinett/Presentation/View/WriteLetter/Cells/ContentWriteCell.swift new file mode 100644 index 00000000..4dd60e20 --- /dev/null +++ b/Kabinett/Presentation/View/WriteLetter/Cells/ContentWriteCell.swift @@ -0,0 +1,92 @@ +// +// ContentWriteCell.swift +// Kabinett +// +// Created by Song Kim on 3/27/25. +// + +import SwiftUI +import Kingfisher + +struct TypingView: View { + let index: Int + @Binding var letter: WriteLetter + @ObservedObject var viewModel: ContentWriteViewModel + + var body: some View { + ZStack { + KFImage(URL(string: letter.stationeryImageUrlString)) + .placeholder { + ProgressView() + } + .resizable() + .shadow(color: Color(.primary300), radius: 5, x: 3, y: 3) + + VStack { + Text(index == 0 ? letter.toUserName : "") + .frame(maxWidth: .infinity, alignment: .leading) + .padding(.top, screenHeight * 0.05) + .padding(.bottom, screenHeight * 0.01) + .onTapGesture { + UIApplication.shared.endEditing() + } + + GeometryReader { geo in + if index < viewModel.texts.count { + CustomTextEditor( + text: $viewModel.texts[index], + maxWidth: geo.size.width, + maxHeight: geo.size.height, + font: FontUtility.selectedUIFont(font: letter.fontString ?? "", size: FontUtility.fontSize(font: letter.fontString ?? "")) + ) + } + } + .onChange(of: viewModel.texts.count) { + letter.content = viewModel.texts + } + + Text(index == (viewModel.texts.count-1) ? (letter.date).formattedString() : "") + .padding(.bottom, screenHeight * 0.00001) + .frame(maxWidth: .infinity, alignment: .trailing) + + Text(index == (viewModel.texts.count-1) ? letter.fromUserName : "") + .padding(.bottom, screenHeight * 0.05) + .frame(maxWidth: .infinity, alignment: .trailing) + } + .padding(.horizontal, screenWidth * 0.08) + } + } +} + +struct PolaroidView: View { + let index: Int + let uiImage: UIImage + @Binding var letter: WriteLetter + @ObservedObject var viewModel: ContentWriteViewModel + + var body: some View { + ZStack(alignment: .topTrailing) { + Image(uiImage: uiImage) + .resizable() + .clipShape(RoundedRectangle(cornerRadius: 5)) + .aspectRatio(contentMode: .fit) + .padding([.horizontal, .top], 10) + .padding(.bottom, screenWidth * 0.12) + .background(Color.white) + .clipShape(RoundedRectangle(cornerRadius: 5)) + .shadow(color: .primary300, radius: 5, x: 3, y: 3) + .padding([.top, .bottom], 10) + + Button(action: { + viewModel.selectedItems.remove(at: viewModel.currentIndex - viewModel.texts.count) + }) { + Image(systemName: "xmark.circle.fill") + .resizable() + .frame(width: 25, height: 25) + .padding(.trailing, -10) + .foregroundColor(Color(.primary900)) + } + } + .frame(width: screenWidth * 0.88) + } +} diff --git a/Kabinett/Presentation/View/WriteLetter/ContentWriteView.swift b/Kabinett/Presentation/View/WriteLetter/ContentWriteView.swift index 118407af..adf81aaa 100644 --- a/Kabinett/Presentation/View/WriteLetter/ContentWriteView.swift +++ b/Kabinett/Presentation/View/WriteLetter/ContentWriteView.swift @@ -117,151 +117,65 @@ struct ScrollableLetterView: View { @State private var scrollWorkItem: DispatchWorkItem? var body: some View { - GeometryReader { geometry in - ScrollViewReader { scrollViewProxy in - ZStack(alignment: .top) { - ScrollView(.horizontal, showsIndicators: false) { - GeometryReader { proxy in - Color.clear - .preference( - key: ScrollOffsetKey.self, - value: proxy.frame(in: .global).origin.x - ) - } - .frame(height: 0) - LazyHStack(alignment: .top, spacing: geometry.size.width * 0.04) { - ForEach(viewModel.texts.indices, id: \.self) { i in - TypingView(index: i, letter: $letter, viewModel: viewModel) - .onChange(of: viewModel.texts[i]) { - letter.content = viewModel.texts - } - .padding(.top, 10) - .aspectRatio(9/13, contentMode: .fit) - .frame(width: screenWidth * 0.88) - .id(i) - } - - ForEach(viewModel.photoContents.indices, id: \.self) { index in - let imageIndex = index + viewModel.texts.count - if let uiImage = UIImage(data: viewModel.photoContents[index]) { - PolaroidView(index: imageIndex, uiImage: uiImage, letter: $letter, viewModel: viewModel) - .frame(width: screenWidth * 0.88) - .id(imageIndex) + ScrollViewReader { scrollViewProxy in + ZStack(alignment: .top) { + ScrollView(.horizontal, showsIndicators: false) { + GeometryReader { proxy in + Color.clear + .preference( + key: ScrollOffsetKey.self, + value: proxy.frame(in: .global).origin.x + ) + } + .frame(height: 0) + LazyHStack(alignment: .top, spacing: screenWidth * 0.04) { + ForEach(viewModel.texts.indices, id: \.self) { index in + TypingView(index: index, letter: $letter, viewModel: viewModel) + .onChange(of: viewModel.texts[index]) { + letter.content = viewModel.texts } - } + .padding(.top, 10) + .aspectRatio(9/13, contentMode: .fit) + .frame(width: screenWidth * 0.88) + .id(index) } - .padding(.horizontal, geometry.size.width * 0.06) - } - .scrollTargetLayout() - .scrollTargetBehavior(.viewAligned) - .onPreferenceChange(ScrollOffsetKey.self) { newOffset in - viewModel.offset = newOffset - - let pageWidth = screenWidth * 0.9204 - let rawIndex = -viewModel.offset / pageWidth - let nearestIndex = Int(round(rawIndex)) - if viewModel.currentIndex != nearestIndex { - viewModel.currentIndex = nearestIndex + ForEach(viewModel.photoContents.indices, id: \.self) { index in + let imageIndex = index + viewModel.texts.count + if let uiImage = UIImage(data: viewModel.photoContents[index]) { + PolaroidView(index: imageIndex, uiImage: uiImage, letter: $letter, viewModel: viewModel) + .frame(width: screenWidth * 0.88) + .id(imageIndex) + } } } + .padding(.horizontal, screenWidth * 0.06) } - .onChange(of: viewModel.texts.count) { - withAnimation(.spring()) { - scrollViewProxy.scrollTo(viewModel.currentIndex+1, anchor: .center) - } - } - .onAppear { - DispatchQueue.main.async { - scrollViewProxy.scrollTo(viewModel.currentIndex, anchor: .center) + .scrollTargetLayout() + .scrollTargetBehavior(.viewAligned) + .onPreferenceChange(ScrollOffsetKey.self) { newOffset in + viewModel.offset = newOffset + + let pageWidth = screenWidth * 0.9204 + let rawIndex = -viewModel.offset / pageWidth + let nearestIndex = Int(round(rawIndex)) + + if viewModel.currentIndex != nearestIndex { + viewModel.currentIndex = nearestIndex } } } - } - } -} - - -struct TypingView: View { - let index: Int - @Binding var letter: WriteLetter - @ObservedObject var viewModel: ContentWriteViewModel - - var body: some View { - ZStack { - KFImage(URL(string: letter.stationeryImageUrlString)) - .placeholder { - ProgressView() - } - .resizable() - .shadow(color: Color(.primary300), radius: 5, x: 3, y: 3) - - VStack { - Text(index == 0 ? letter.toUserName : "") - .frame(maxWidth: .infinity, alignment: .leading) - .padding(.top, screenHeight * 0.05) - .padding(.bottom, screenHeight * 0.01) - .onTapGesture { - UIApplication.shared.endEditing() - } - - GeometryReader { geo in - if index < viewModel.texts.count { - CustomTextEditor( - text: $viewModel.texts[index], - maxWidth: geo.size.width, - maxHeight: geo.size.height, - font: FontUtility.selectedUIFont(font: letter.fontString ?? "", size: FontUtility.fontSize(font: letter.fontString ?? "")) - ) - } + .onChange(of: viewModel.texts.count) { + withAnimation(.spring()) { + scrollViewProxy.scrollTo(viewModel.currentIndex+1, anchor: .center) } - .onChange(of: viewModel.texts.count) { - letter.content = viewModel.texts - } - - Text(index == (viewModel.texts.count-1) ? (letter.date).formattedString() : "") - .padding(.bottom, screenHeight * 0.00001) - .frame(maxWidth: .infinity, alignment: .trailing) - - Text(index == (viewModel.texts.count-1) ? letter.fromUserName : "") - .padding(.bottom, screenHeight * 0.05) - .frame(maxWidth: .infinity, alignment: .trailing) } - .padding(.horizontal, screenWidth * 0.08) - } - } -} - -struct PolaroidView: View { - let index: Int - let uiImage: UIImage - @Binding var letter: WriteLetter - @ObservedObject var viewModel: ContentWriteViewModel - - var body: some View { - ZStack(alignment: .topTrailing) { - Image(uiImage: uiImage) - .resizable() - .clipShape(RoundedRectangle(cornerRadius: 5)) - .aspectRatio(contentMode: .fit) - .padding([.horizontal, .top], 10) - .padding(.bottom, screenWidth * 0.12) - .background(Color.white) - .clipShape(RoundedRectangle(cornerRadius: 5)) - .shadow(color: .primary300, radius: 5, x: 3, y: 3) - .padding([.top, .bottom], 10) - - Button(action: { - viewModel.selectedItems.remove(at: viewModel.currentIndex - viewModel.texts.count) - }) { - Image(systemName: "xmark.circle.fill") - .resizable() - .frame(width: 25, height: 25) - .padding(.trailing, -10) - .foregroundColor(Color(.primary900)) + .onAppear { + DispatchQueue.main.async { + scrollViewProxy.scrollTo(viewModel.currentIndex, anchor: .center) + } } } - .frame(width: screenWidth * 0.88) } } diff --git a/Kabinett/Presentation/ViewModel/WriteLetter/ContentWriteViewModel.swift b/Kabinett/Presentation/ViewModel/WriteLetter/ContentWriteViewModel.swift index e79d2a81..9611231c 100644 --- a/Kabinett/Presentation/ViewModel/WriteLetter/ContentWriteViewModel.swift +++ b/Kabinett/Presentation/ViewModel/WriteLetter/ContentWriteViewModel.swift @@ -11,20 +11,6 @@ import Combine class ContentWriteViewModel: ObservableObject { @Published var offset: CGFloat = 0 - private var originOffset: CGFloat = 0 - private var isCheckedOriginOffset: Bool = false - - func setOriginOffset(_ offset: CGFloat) { - guard !isCheckedOriginOffset else { return } - self.originOffset = offset - self.offset = offset - isCheckedOriginOffset = true - } - - func setOffset(_ offset: CGFloat) { - guard isCheckedOriginOffset else { return } - self.offset = offset - } @Published var texts: [String] = [""] @Published var currentIndex: Int = 0 @@ -34,7 +20,7 @@ class ContentWriteViewModel: ObservableObject { @Published var isFontEdit: Bool = true @Published var isKeyboard: Bool = false - @Published var selectedItems: [PhotosPickerItem] = [] //***** + @Published var selectedItems: [PhotosPickerItem] = [] @Published var photoContents: [Data] = [] @Published var isLoading: Bool = false @@ -76,7 +62,6 @@ class ContentWriteViewModel: ObservableObject { isLoading = false } - // MARK: 선택된 이미지 로드 private func loadImagesTask() async throws -> [Data] { try await withThrowingTaskGroup(of: Data?.self) { group -> [Data] in for item in selectedItems { From 25c1ce6c83f8662c49f2431db7b202f1831c64d5 Mon Sep 17 00:00:00 2001 From: ksiomng Date: Thu, 27 Mar 2025 17:26:56 +0900 Subject: [PATCH 34/39] =?UTF-8?q?Refactor:=20=EC=A4=84=EB=B0=94=EA=BF=88?= =?UTF-8?q?=20=EB=B0=8F=20=EC=BD=94=EB=93=9C=20=EC=88=9C=EC=84=9C=20?= =?UTF-8?q?=EC=A0=95=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/CustomTextEditor.swift | 2 +- .../WriteLetter/Components/MiniTabBarView.swift | 16 ++++++++-------- .../Components/SelectionTabView.swift | 6 +++--- .../View/WriteLetter/ContentWriteView.swift | 12 ++++++------ .../WriteLetter/EnvelopeStampSelectionView.swift | 4 ++-- .../View/WriteLetter/UserSelectionView.swift | 4 ++-- .../WriteLetter/ContentWriteViewModel.swift | 2 +- .../WriteLetter/FontSelectionViewModel.swift | 2 +- .../WriteLetter/PreviewLetterViewModel.swift | 4 ++-- 9 files changed, 26 insertions(+), 26 deletions(-) diff --git a/Kabinett/Presentation/View/WriteLetter/Components/CustomTextEditor.swift b/Kabinett/Presentation/View/WriteLetter/Components/CustomTextEditor.swift index 33b5ebc4..0b3240fe 100644 --- a/Kabinett/Presentation/View/WriteLetter/Components/CustomTextEditor.swift +++ b/Kabinett/Presentation/View/WriteLetter/Components/CustomTextEditor.swift @@ -9,10 +9,10 @@ import UIKit import SwiftUI struct CustomTextEditor: UIViewRepresentable { - @Binding var text: String var maxWidth: CGFloat var maxHeight: CGFloat var font: UIFont + @Binding var text: String class Coordinator: NSObject, UITextViewDelegate { var parent: CustomTextEditor diff --git a/Kabinett/Presentation/View/WriteLetter/Components/MiniTabBarView.swift b/Kabinett/Presentation/View/WriteLetter/Components/MiniTabBarView.swift index b0aea3b4..815f37d0 100644 --- a/Kabinett/Presentation/View/WriteLetter/Components/MiniTabBarView.swift +++ b/Kabinett/Presentation/View/WriteLetter/Components/MiniTabBarView.swift @@ -65,14 +65,14 @@ struct MiniTabBarView: View { selection: $viewModel.selectedItems, maxSelectionCount: 10, matching: .images) { - Image(systemName: "photo.on.rectangle.angled") - .font(.system(size: 15)) - .frame(width: UIScreen.main.bounds.width * 0.4/4, height: 30) - .background(viewModel.selectedItems.isEmpty ? Color.clear : Color.white) - .foregroundStyle(viewModel.selectedItems.isEmpty ? Color("ToolBarIcon") : Color(.primary900)) - .clipShape(Capsule()) - .shadow(color: viewModel.selectedItems.isEmpty ? Color.clear : Color(.primary300), radius: 7, x: 3, y: 3) - } + Image(systemName: "photo.on.rectangle.angled") + .font(.system(size: 15)) + .frame(width: UIScreen.main.bounds.width * 0.4/4, height: 30) + .background(viewModel.selectedItems.isEmpty ? Color.clear : Color.white) + .foregroundStyle(viewModel.selectedItems.isEmpty ? Color("ToolBarIcon") : Color(.primary900)) + .clipShape(Capsule()) + .shadow(color: viewModel.selectedItems.isEmpty ? Color.clear : Color(.primary300), radius: 7, x: 3, y: 3) + } } .frame(maxWidth: UIScreen.main.bounds.width * 0.5, maxHeight: 40) .foregroundStyle(Color("ToolBarIcon")) diff --git a/Kabinett/Presentation/View/WriteLetter/Components/SelectionTabView.swift b/Kabinett/Presentation/View/WriteLetter/Components/SelectionTabView.swift index 75c8c0bc..f7b29726 100644 --- a/Kabinett/Presentation/View/WriteLetter/Components/SelectionTabView.swift +++ b/Kabinett/Presentation/View/WriteLetter/Components/SelectionTabView.swift @@ -8,11 +8,11 @@ import SwiftUI struct SelectionTabView: View { - @State private var selectedTab: Int = 0 - @ObservedObject var envelopeStampSelectionViewModel: EnvelopeStampSelectionViewModel @Binding var letter: WriteLetter - @Binding var envelopeImageUrl: String @Binding var stampImageUrl: String + @Binding var envelopeImageUrl: String + @State private var selectedTab: Int = 0 + @ObservedObject var envelopeStampSelectionViewModel: EnvelopeStampSelectionViewModel let tabs: [String] = [ "봉투", diff --git a/Kabinett/Presentation/View/WriteLetter/ContentWriteView.swift b/Kabinett/Presentation/View/WriteLetter/ContentWriteView.swift index adf81aaa..676bb4cc 100644 --- a/Kabinett/Presentation/View/WriteLetter/ContentWriteView.swift +++ b/Kabinett/Presentation/View/WriteLetter/ContentWriteView.swift @@ -17,8 +17,8 @@ let screenHeight = UIScreen.main.bounds.height struct ContentWriteView: View { @Binding var letter: WriteLetter @StateObject var viewModel = ContentWriteViewModel() - @ObservedObject var customTabViewModel: CustomTabViewModel @StateObject var fontViewModel = FontSelectionViewModel() + @ObservedObject var customTabViewModel: CustomTabViewModel init( letter: Binding, @@ -65,19 +65,19 @@ struct ContentWriteView: View { } } } - .overlay { // 폰트 선택뷰 + .overlay { if viewModel.showFontMenu { FontMenuView(letter: $letter, showFontMenu: $viewModel.showFontMenu, fontViewModel: fontViewModel) } } .ignoresSafeArea(.keyboard) - .onChange(of: viewModel.selectedItems) { // 이미지가 변경될 때 + .onChange(of: viewModel.selectedItems) { Task { @MainActor in await viewModel.loadImages() letter.photoContents = viewModel.photoContents } } - .onAppear{ // 키보드 감지 + .onAppear { NotificationCenter.default.addObserver( forName: UIResponder.keyboardWillShowNotification, object: nil, queue: .main) { _ in viewModel.isKeyboard = true @@ -110,11 +110,11 @@ struct ContentWriteView: View { } } -// MARK: ScrollableLetterView +// MARK: - ScrollableLetterView struct ScrollableLetterView: View { @Binding var letter: WriteLetter - @ObservedObject var viewModel: ContentWriteViewModel @State private var scrollWorkItem: DispatchWorkItem? + @ObservedObject var viewModel: ContentWriteViewModel var body: some View { ScrollViewReader { scrollViewProxy in diff --git a/Kabinett/Presentation/View/WriteLetter/EnvelopeStampSelectionView.swift b/Kabinett/Presentation/View/WriteLetter/EnvelopeStampSelectionView.swift index f2078bdb..b540c9b8 100644 --- a/Kabinett/Presentation/View/WriteLetter/EnvelopeStampSelectionView.swift +++ b/Kabinett/Presentation/View/WriteLetter/EnvelopeStampSelectionView.swift @@ -11,11 +11,11 @@ import FirebaseAnalytics struct EnvelopeStampSelectionView: View { @Binding var letter: WriteLetter - @StateObject var viewModel: EnvelopeStampSelectionViewModel - @ObservedObject var customTabViewModel: CustomTabViewModel @State private var postScriptText: String = "" @State private var envelopeImageUrl: String @State private var stampImageUrl: String + @StateObject var viewModel: EnvelopeStampSelectionViewModel + @ObservedObject var customTabViewModel: CustomTabViewModel init( letter: Binding, diff --git a/Kabinett/Presentation/View/WriteLetter/UserSelectionView.swift b/Kabinett/Presentation/View/WriteLetter/UserSelectionView.swift index 4169291b..9e5fe6b9 100644 --- a/Kabinett/Presentation/View/WriteLetter/UserSelectionView.swift +++ b/Kabinett/Presentation/View/WriteLetter/UserSelectionView.swift @@ -10,11 +10,11 @@ import Kingfisher import FirebaseAnalytics struct UserSelectionView: View { - @Binding var letter: WriteLetter @Environment(\.dismiss) var dismiss + @Binding var letter: WriteLetter + @State private var isFullScreen = false @StateObject var viewModel : UserSelectionViewModel @ObservedObject var customViewModel: CustomTabViewModel - @State private var isFullScreen = false init( letter: Binding, diff --git a/Kabinett/Presentation/ViewModel/WriteLetter/ContentWriteViewModel.swift b/Kabinett/Presentation/ViewModel/WriteLetter/ContentWriteViewModel.swift index 9611231c..8a028f19 100644 --- a/Kabinett/Presentation/ViewModel/WriteLetter/ContentWriteViewModel.swift +++ b/Kabinett/Presentation/ViewModel/WriteLetter/ContentWriteViewModel.swift @@ -27,7 +27,7 @@ class ContentWriteViewModel: ObservableObject { @Published var error: Error? private var cancellables = Set() - + func toggleFontView() { showFontMenu.toggle() } diff --git a/Kabinett/Presentation/ViewModel/WriteLetter/FontSelectionViewModel.swift b/Kabinett/Presentation/ViewModel/WriteLetter/FontSelectionViewModel.swift index b36338b8..7bc876fb 100644 --- a/Kabinett/Presentation/ViewModel/WriteLetter/FontSelectionViewModel.swift +++ b/Kabinett/Presentation/ViewModel/WriteLetter/FontSelectionViewModel.swift @@ -32,7 +32,7 @@ class FontSelectionViewModel: ObservableObject { init() { updateText() } - + private func updateText() { for _ in 0.. Date: Thu, 27 Mar 2025 17:44:15 +0900 Subject: [PATCH 35/39] =?UTF-8?q?Fix:=20=EC=88=9C=EC=84=9C=EB=A5=BC=20?= =?UTF-8?q?=EB=B0=94=EA=BF=94=EB=86=93=EA=B3=A0=20=EC=A0=81=EC=9A=A9?= =?UTF-8?q?=EC=9D=84=20=EC=95=88=EC=8B=9C=EC=BC=9C=EC=84=9C=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../View/WriteLetter/Cells/ContentWriteCell.swift | 4 ++-- .../View/WriteLetter/EnvelopeStampSelectionView.swift | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Kabinett/Presentation/View/WriteLetter/Cells/ContentWriteCell.swift b/Kabinett/Presentation/View/WriteLetter/Cells/ContentWriteCell.swift index 4dd60e20..1257706b 100644 --- a/Kabinett/Presentation/View/WriteLetter/Cells/ContentWriteCell.swift +++ b/Kabinett/Presentation/View/WriteLetter/Cells/ContentWriteCell.swift @@ -34,10 +34,10 @@ struct TypingView: View { GeometryReader { geo in if index < viewModel.texts.count { CustomTextEditor( - text: $viewModel.texts[index], maxWidth: geo.size.width, maxHeight: geo.size.height, - font: FontUtility.selectedUIFont(font: letter.fontString ?? "", size: FontUtility.fontSize(font: letter.fontString ?? "")) + font: FontUtility.selectedUIFont(font: letter.fontString ?? "", size: FontUtility.fontSize(font: letter.fontString ?? "")), + text: $viewModel.texts[index] ) } } diff --git a/Kabinett/Presentation/View/WriteLetter/EnvelopeStampSelectionView.swift b/Kabinett/Presentation/View/WriteLetter/EnvelopeStampSelectionView.swift index b540c9b8..6897b46e 100644 --- a/Kabinett/Presentation/View/WriteLetter/EnvelopeStampSelectionView.swift +++ b/Kabinett/Presentation/View/WriteLetter/EnvelopeStampSelectionView.swift @@ -70,7 +70,7 @@ struct EnvelopeStampSelectionView: View { } .padding(.bottom, 30) - SelectionTabView(envelopeStampSelectionViewModel: viewModel, letter: $letter, envelopeImageUrl: $envelopeImageUrl, stampImageUrl: $stampImageUrl) + SelectionTabView(letter: $letter, stampImageUrl: $stampImageUrl, envelopeImageUrl: $envelopeImageUrl, envelopeStampSelectionViewModel: viewModel) } .padding(.horizontal, UIScreen.main.bounds.width * 0.06) } From e538df077e93d24fae2d3e117169c64fa34d0ef2 Mon Sep 17 00:00:00 2001 From: ksiomng Date: Mon, 7 Apr 2025 11:33:33 +0900 Subject: [PATCH 36/39] =?UTF-8?q?Fix:=20=ED=95=84=EC=9A=94=EC=97=86?= =?UTF-8?q?=EB=8A=94=20=EB=B7=B0=20=EC=82=AD=EC=A0=9C,=20=EC=9D=B4?= =?UTF-8?q?=EB=AF=B8=EC=A7=80=20=EC=82=AD=EC=A0=9C=ED=95=A0=20=EB=95=8C=20?= =?UTF-8?q?=EC=95=8C=EB=9F=BF=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Kabinett.xcodeproj/project.pbxproj | 12 ---- .../WriteLetter/Cells/ContentWriteCell.swift | 14 ++++- .../ImportPhoto/ImageDetailView.swift | 60 ------------------- .../WriteLetter/ContentWriteViewModel.swift | 2 + 4 files changed, 15 insertions(+), 73 deletions(-) delete mode 100644 Kabinett/Presentation/View/WriteLetter/ImportPhoto/ImageDetailView.swift diff --git a/Kabinett.xcodeproj/project.pbxproj b/Kabinett.xcodeproj/project.pbxproj index 83a72499..ce76a1dc 100644 --- a/Kabinett.xcodeproj/project.pbxproj +++ b/Kabinett.xcodeproj/project.pbxproj @@ -88,7 +88,6 @@ 7F397C4E2C7C0ECE00388645 /* CustomTabViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F397C4D2C7C0ECE00388645 /* CustomTabViewModel.swift */; }; 7F6CE9C02C6B2FEA0074568E /* CustomTabView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F6CE9BF2C6B2FE90074568E /* CustomTabView.swift */; }; 7F9890822C7EF5C30035CB0D /* CustomTabBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F9890812C7EF5C30035CB0D /* CustomTabBar.swift */; }; - 7FCAE2BA2C73102900228FA7 /* ImageDetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7FCAE2B92C73102900228FA7 /* ImageDetailView.swift */; }; 8314013F2C69C34500F601FB /* Letter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8314013E2C69C34500F601FB /* Letter.swift */; }; 832C72672C71CF7B0071E8D0 /* SignUpUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 832C72662C71CF7B0071E8D0 /* SignUpUseCase.swift */; }; 8356843D2CE0A43600120EC8 /* ServiceKeys.swift in Sources */ = {isa = PBXBuildFile; fileRef = 835684352CE0A43600120EC8 /* ServiceKeys.swift */; }; @@ -227,7 +226,6 @@ 7F397C4D2C7C0ECE00388645 /* CustomTabViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomTabViewModel.swift; sourceTree = ""; }; 7F6CE9BF2C6B2FE90074568E /* CustomTabView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomTabView.swift; sourceTree = ""; }; 7F9890812C7EF5C30035CB0D /* CustomTabBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomTabBar.swift; sourceTree = ""; }; - 7FCAE2B92C73102900228FA7 /* ImageDetailView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageDetailView.swift; sourceTree = ""; }; 8314013E2C69C34500F601FB /* Letter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Letter.swift; sourceTree = ""; }; 832C72662C71CF7B0071E8D0 /* SignUpUseCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignUpUseCase.swift; sourceTree = ""; }; 835684352CE0A43600120EC8 /* ServiceKeys.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ServiceKeys.swift; sourceTree = ""; }; @@ -395,14 +393,6 @@ path = Font; sourceTree = ""; }; - 57F7A5532D924E8A002E1209 /* ImportPhoto */ = { - isa = PBXGroup; - children = ( - 7FCAE2B92C73102900228FA7 /* ImageDetailView.swift */, - ); - path = ImportPhoto; - sourceTree = ""; - }; 7F397C502C7C382A00388645 /* CustomTabView */ = { isa = PBXGroup; children = ( @@ -535,7 +525,6 @@ 8366B6F32C65ECE60021FAE0 /* WriteLetter */ = { isa = PBXGroup; children = ( - 57F7A5532D924E8A002E1209 /* ImportPhoto */, 579E35F92D2BB09700F92A87 /* Cells */, 579E35F82D2BAE0300F92A87 /* Components */, 57EBE5AF2C69E5F2003ECD7F /* UserSelectionView.swift */, @@ -960,7 +949,6 @@ 5358E0732CE16E630089C59F /* SearchBarViewModel.swift in Sources */, 83CA92AB2C8160CB00DFB68B /* Publisher+.swift in Sources */, 534C67B72C7FF85700F0C175 /* LetterContentView.swift in Sources */, - 7FCAE2BA2C73102900228FA7 /* ImageDetailView.swift in Sources */, 04DEC0E72C6C6C7300D289EA /* ProfileView.swift in Sources */, 573EE1F62D2BA50300978283 /* MiniTabBarView.swift in Sources */, 53A482DA2C6C6F2D00F00A9A /* LetterBoxCell.swift in Sources */, diff --git a/Kabinett/Presentation/View/WriteLetter/Cells/ContentWriteCell.swift b/Kabinett/Presentation/View/WriteLetter/Cells/ContentWriteCell.swift index 1257706b..3533a348 100644 --- a/Kabinett/Presentation/View/WriteLetter/Cells/ContentWriteCell.swift +++ b/Kabinett/Presentation/View/WriteLetter/Cells/ContentWriteCell.swift @@ -78,7 +78,7 @@ struct PolaroidView: View { .padding([.top, .bottom], 10) Button(action: { - viewModel.selectedItems.remove(at: viewModel.currentIndex - viewModel.texts.count) + viewModel.isDeletePhoto = true }) { Image(systemName: "xmark.circle.fill") .resizable() @@ -86,6 +86,18 @@ struct PolaroidView: View { .padding(.trailing, -10) .foregroundColor(Color(.primary900)) } + .alert(isPresented: $viewModel.isDeletePhoto) { + Alert( + title: Text("Delete Page"), + message: Text("이 사진을 삭제하시겠어요?"), + primaryButton: .destructive(Text("삭제")) { + viewModel.selectedItems.remove(at: viewModel.currentIndex - viewModel.texts.count) + }, + secondaryButton: .cancel(Text("취소")) { + viewModel.isDeletePhoto = false + } + ) + } } .frame(width: screenWidth * 0.88) } diff --git a/Kabinett/Presentation/View/WriteLetter/ImportPhoto/ImageDetailView.swift b/Kabinett/Presentation/View/WriteLetter/ImportPhoto/ImageDetailView.swift deleted file mode 100644 index 4b055a29..00000000 --- a/Kabinett/Presentation/View/WriteLetter/ImportPhoto/ImageDetailView.swift +++ /dev/null @@ -1,60 +0,0 @@ -// -// ImageDetailView.swift -// Kabinett -// -// Created by 김정우 on 8/19/24. -// - -import FirebaseAnalytics -import SwiftUI - -struct ImageDetailView: View { - let images: [Data] - @State private var currentIndex = 0 - @Binding var showDetailView: Bool - - var body: some View { - NavigationStack { - ZStack { - TabView(selection: $currentIndex) { - ForEach(images.indices, id: \.self) { index in - if let uiImage = UIImage(data: images[index]) { - Image(uiImage: uiImage) - .resizable() - .aspectRatio(contentMode: .fit) - .tag(index) - } - } - } - .tabViewStyle(PageTabViewStyle(indexDisplayMode: .never)) - - HStack { - Button(action: { currentIndex = max(currentIndex - 1, 0) }) { - Image(systemName: "chevron.left") - .foregroundColor(.white) - } - .opacity(currentIndex > 0 ? 1 : 0) - - Spacer() - - Button(action: { currentIndex = min(currentIndex + 1, images.count - 1) }) { - Image(systemName: "chevron.right") - .foregroundColor(.white) - } - .opacity(currentIndex < images.count - 1 ? 1 : 0) - } - .padding() - } - .background(Color.background.edgesIgnoringSafeArea(.all)) - .navigationTitle("") - .navigationBarTitleDisplayMode(.inline) - } - .analyticsScreen( - name: "\(type(of:self))", - extraParameters: [ - AnalyticsParameterScreenName: "\(type(of:self))", - AnalyticsParameterScreenClass: "\(type(of:self))", - ] - ) - } -} diff --git a/Kabinett/Presentation/ViewModel/WriteLetter/ContentWriteViewModel.swift b/Kabinett/Presentation/ViewModel/WriteLetter/ContentWriteViewModel.swift index 8a028f19..86ed59c9 100644 --- a/Kabinett/Presentation/ViewModel/WriteLetter/ContentWriteViewModel.swift +++ b/Kabinett/Presentation/ViewModel/WriteLetter/ContentWriteViewModel.swift @@ -26,6 +26,8 @@ class ContentWriteViewModel: ObservableObject { @Published var isLoading: Bool = false @Published var error: Error? + @Published var isDeletePhoto: Bool = false + private var cancellables = Set() func toggleFontView() { From d0b48cd4d6c29c13772b0ab4e371b6e3d84fdf4e Mon Sep 17 00:00:00 2001 From: ksiomng Date: Mon, 7 Apr 2025 12:24:09 +0900 Subject: [PATCH 37/39] =?UTF-8?q?Feat:=20=EC=82=AC=EC=A7=84=20=EB=8F=99?= =?UTF-8?q?=EB=B4=89=20+=20=EC=82=AD=EC=A0=9C=EA=B0=80=20=EC=84=B1?= =?UTF-8?q?=EA=B3=B5=ED=96=88=EC=9D=84=20=EB=95=8C=20=EC=B2=B4=ED=81=AC?= =?UTF-8?q?=ED=91=9C=EC=8B=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../View/WriteLetter/ContentWriteView.swift | 14 ++++++++++++++ .../WriteLetter/ContentWriteViewModel.swift | 1 + 2 files changed, 15 insertions(+) diff --git a/Kabinett/Presentation/View/WriteLetter/ContentWriteView.swift b/Kabinett/Presentation/View/WriteLetter/ContentWriteView.swift index 676bb4cc..fa8e6a9c 100644 --- a/Kabinett/Presentation/View/WriteLetter/ContentWriteView.swift +++ b/Kabinett/Presentation/View/WriteLetter/ContentWriteView.swift @@ -64,6 +64,15 @@ struct ContentWriteView: View { .padding(.leading, screenWidth * 0.85) } } + if viewModel.showCheckmark { + Image(systemName: "checkmark.circle.fill") + .resizable() + .frame(width: 50, height: 50) + .foregroundColor(.green) + .transition(.scale.combined(with: .opacity)) + .animation(.easeInOut(duration: 0.3), value: viewModel.showCheckmark) + .position(x: screenWidth / 2, y: screenHeight * 0.5) + } } .overlay { if viewModel.showFontMenu { @@ -75,6 +84,11 @@ struct ContentWriteView: View { Task { @MainActor in await viewModel.loadImages() letter.photoContents = viewModel.photoContents + + viewModel.showCheckmark = true + DispatchQueue.main.asyncAfter(deadline: .now() + 1.5) { + viewModel.showCheckmark = false + } } } .onAppear { diff --git a/Kabinett/Presentation/ViewModel/WriteLetter/ContentWriteViewModel.swift b/Kabinett/Presentation/ViewModel/WriteLetter/ContentWriteViewModel.swift index 86ed59c9..a172f4fb 100644 --- a/Kabinett/Presentation/ViewModel/WriteLetter/ContentWriteViewModel.swift +++ b/Kabinett/Presentation/ViewModel/WriteLetter/ContentWriteViewModel.swift @@ -27,6 +27,7 @@ class ContentWriteViewModel: ObservableObject { @Published var error: Error? @Published var isDeletePhoto: Bool = false + @Published var showCheckmark: Bool = false private var cancellables = Set() From 49060c4bc621987eb35f6923941782768f7cb328 Mon Sep 17 00:00:00 2001 From: ksiomng Date: Mon, 7 Apr 2025 13:12:06 +0900 Subject: [PATCH 38/39] =?UTF-8?q?Fix:=20=ED=82=A4=EB=B3=B4=EB=93=9C=20?= =?UTF-8?q?=EC=9C=84=EC=97=90=EC=9E=88=EB=8A=94=20=EB=B2=84=ED=8A=BC?= =?UTF-8?q?=EC=9D=B4=20=EC=9C=84=EC=B9=98=EA=B0=80=20=ED=82=A4=EB=B3=B4?= =?UTF-8?q?=EB=93=9C=20=EC=82=AC=EC=9D=B4=EC=A6=88=EB=A7=88=EB=8B=A4=20?= =?UTF-8?q?=EB=8B=AC=EB=9D=BC=EC=A0=B8=EC=95=BC=ED=95=B4=EC=84=9C=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Presentation/View/WriteLetter/ContentWriteView.swift | 8 +++++++- .../ViewModel/WriteLetter/ContentWriteViewModel.swift | 2 ++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/Kabinett/Presentation/View/WriteLetter/ContentWriteView.swift b/Kabinett/Presentation/View/WriteLetter/ContentWriteView.swift index fa8e6a9c..c2c3bbb2 100644 --- a/Kabinett/Presentation/View/WriteLetter/ContentWriteView.swift +++ b/Kabinett/Presentation/View/WriteLetter/ContentWriteView.swift @@ -60,7 +60,7 @@ struct ContentWriteView: View { .background(Color.primary900) .clipShape(Circle()) } - .padding(.top, screenHeight * 0.488) + .padding(.top, (screenHeight*0.82857)-viewModel.keyboardHeight) .padding(.leading, screenWidth * 0.85) } } @@ -100,6 +100,12 @@ struct ContentWriteView: View { forName: UIResponder.keyboardWillHideNotification, object: nil, queue: .main) { _ in viewModel.isKeyboard = false } + + NotificationCenter.default.addObserver(forName: UIResponder.keyboardWillShowNotification, object: nil, queue: .main) { notification in + if let keyboardFrame = notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect { + viewModel.keyboardHeight = keyboardFrame.height + } + } } .toolbar { ToolbarItem(placement: .topBarTrailing) { diff --git a/Kabinett/Presentation/ViewModel/WriteLetter/ContentWriteViewModel.swift b/Kabinett/Presentation/ViewModel/WriteLetter/ContentWriteViewModel.swift index a172f4fb..6411cc0c 100644 --- a/Kabinett/Presentation/ViewModel/WriteLetter/ContentWriteViewModel.swift +++ b/Kabinett/Presentation/ViewModel/WriteLetter/ContentWriteViewModel.swift @@ -29,6 +29,8 @@ class ContentWriteViewModel: ObservableObject { @Published var isDeletePhoto: Bool = false @Published var showCheckmark: Bool = false + @Published var keyboardHeight: CGFloat = 0 + private var cancellables = Set() func toggleFontView() { From 478096787609c07b26a643f7d21f534431068b09 Mon Sep 17 00:00:00 2001 From: ksiomng Date: Mon, 7 Apr 2025 13:15:38 +0900 Subject: [PATCH 39/39] =?UTF-8?q?Design:=20=EB=B2=84=ED=8A=BC=202=EA=B0=9C?= =?UTF-8?q?=20=EC=83=89=EC=83=81=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Kabinett/Presentation/View/WriteLetter/ContentWriteView.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Kabinett/Presentation/View/WriteLetter/ContentWriteView.swift b/Kabinett/Presentation/View/WriteLetter/ContentWriteView.swift index c2c3bbb2..93b994c8 100644 --- a/Kabinett/Presentation/View/WriteLetter/ContentWriteView.swift +++ b/Kabinett/Presentation/View/WriteLetter/ContentWriteView.swift @@ -57,7 +57,7 @@ struct ContentWriteView: View { Image(systemName: "keyboard.chevron.compact.down") .padding(12) .foregroundStyle(Color.white) - .background(Color.primary900) + .background(Color.secondary) .clipShape(Circle()) } .padding(.top, (screenHeight*0.82857)-viewModel.keyboardHeight) @@ -68,7 +68,7 @@ struct ContentWriteView: View { Image(systemName: "checkmark.circle.fill") .resizable() .frame(width: 50, height: 50) - .foregroundColor(.green) + .foregroundColor(Color(UIColor(red: 0x13/255, green: 0xA4/255, blue: 0x50/255, alpha: 1))) .transition(.scale.combined(with: .opacity)) .animation(.easeInOut(duration: 0.3), value: viewModel.showCheckmark) .position(x: screenWidth / 2, y: screenHeight * 0.5)