From 926938690f69f99c77e25220facb990de3f3cea2 Mon Sep 17 00:00:00 2001 From: baegteun Date: Thu, 27 Oct 2022 13:42:16 +0900 Subject: [PATCH 1/5] feat :: SignupProfileImage FIles --- .../SignupProfileImageComponent.swift | 12 ++++++++++++ .../SignupProfileImageView.swift | 15 +++++++++++++++ .../SignupProfileImageViewModel.swift | 5 +++++ 3 files changed, 32 insertions(+) create mode 100644 Projects/Features/SignupFeature/Sources/SignupProfileImage/SignupProfileImageComponent.swift create mode 100644 Projects/Features/SignupFeature/Sources/SignupProfileImage/SignupProfileImageView.swift create mode 100644 Projects/Features/SignupFeature/Sources/SignupProfileImage/SignupProfileImageViewModel.swift diff --git a/Projects/Features/SignupFeature/Sources/SignupProfileImage/SignupProfileImageComponent.swift b/Projects/Features/SignupFeature/Sources/SignupProfileImage/SignupProfileImageComponent.swift new file mode 100644 index 00000000..b435d87a --- /dev/null +++ b/Projects/Features/SignupFeature/Sources/SignupProfileImage/SignupProfileImageComponent.swift @@ -0,0 +1,12 @@ +import SwiftUI +import NeedleFoundation + +public protocol SignupProfileImageDependency: Dependency {} + +public final class SignupProfileImageComponent: Component { + public func makeView() -> some View { + SignupProfileImageView( + viewModel: .init() + ) + } +} diff --git a/Projects/Features/SignupFeature/Sources/SignupProfileImage/SignupProfileImageView.swift b/Projects/Features/SignupFeature/Sources/SignupProfileImage/SignupProfileImageView.swift new file mode 100644 index 00000000..52f1aaf4 --- /dev/null +++ b/Projects/Features/SignupFeature/Sources/SignupProfileImage/SignupProfileImageView.swift @@ -0,0 +1,15 @@ +import SwiftUI + +struct SignupProfileImageView: View { + @StateObject var viewModel: SignupProfileImageViewModel + + public init(viewModel: SignupProfileImageViewModel) { + _viewModel = StateObject(wrappedValue: viewModel) + } + + var body: some View { + VStack { + + } + } +} diff --git a/Projects/Features/SignupFeature/Sources/SignupProfileImage/SignupProfileImageViewModel.swift b/Projects/Features/SignupFeature/Sources/SignupProfileImage/SignupProfileImageViewModel.swift new file mode 100644 index 00000000..cb1446c7 --- /dev/null +++ b/Projects/Features/SignupFeature/Sources/SignupProfileImage/SignupProfileImageViewModel.swift @@ -0,0 +1,5 @@ +import BaseFeature +import Combine + +final class SignupProfileImageViewModel: BaseViewModel { +} From 12bd631261b5eea94572e8150f0f5f2e5f581169 Mon Sep 17 00:00:00 2001 From: baegteun Date: Thu, 27 Oct 2022 14:03:25 +0900 Subject: [PATCH 2/5] feat :: SignupProfileImageParam --- .../SignupProfileImageComponent.swift | 6 ++-- .../SignupProfileImageParam.swift | 32 +++++++++++++++++++ .../SignupProfileImageViewModel.swift | 5 +++ 3 files changed, 41 insertions(+), 2 deletions(-) create mode 100644 Projects/Features/SignupFeature/Sources/SignupProfileImage/SignupProfileImageParam.swift diff --git a/Projects/Features/SignupFeature/Sources/SignupProfileImage/SignupProfileImageComponent.swift b/Projects/Features/SignupFeature/Sources/SignupProfileImage/SignupProfileImageComponent.swift index b435d87a..779ca743 100644 --- a/Projects/Features/SignupFeature/Sources/SignupProfileImage/SignupProfileImageComponent.swift +++ b/Projects/Features/SignupFeature/Sources/SignupProfileImage/SignupProfileImageComponent.swift @@ -4,9 +4,11 @@ import NeedleFoundation public protocol SignupProfileImageDependency: Dependency {} public final class SignupProfileImageComponent: Component { - public func makeView() -> some View { + public func makeView(signupProfileImageParam: SignupProfileImageParam) -> some View { SignupProfileImageView( - viewModel: .init() + viewModel: .init( + signupProfileImageParam: signupProfileImageParam + ), ) } } diff --git a/Projects/Features/SignupFeature/Sources/SignupProfileImage/SignupProfileImageParam.swift b/Projects/Features/SignupFeature/Sources/SignupProfileImage/SignupProfileImageParam.swift new file mode 100644 index 00000000..24307e79 --- /dev/null +++ b/Projects/Features/SignupFeature/Sources/SignupProfileImage/SignupProfileImageParam.swift @@ -0,0 +1,32 @@ +import Foundation + +public struct SignupProfileImageParam: Equatable { + public init( + schoolCode: String, + schoolAnswer: String, + email: String, + grade: Int, + classRoom: Int, + number: Int, + accountID: String, + password: String + ) { + self.schoolCode = schoolCode + self.schoolAnswer = schoolAnswer + self.email = email + self.grade = grade + self.classRoom = classRoom + self.number = number + self.accountID = accountID + self.password = password + } + + public let schoolCode: String + public let schoolAnswer: String + public let email: String + public let grade: Int + public let classRoom: Int + public let number: Int + public let accountID: String + public let password: String +} diff --git a/Projects/Features/SignupFeature/Sources/SignupProfileImage/SignupProfileImageViewModel.swift b/Projects/Features/SignupFeature/Sources/SignupProfileImage/SignupProfileImageViewModel.swift index cb1446c7..5b79e2d8 100644 --- a/Projects/Features/SignupFeature/Sources/SignupProfileImage/SignupProfileImageViewModel.swift +++ b/Projects/Features/SignupFeature/Sources/SignupProfileImage/SignupProfileImageViewModel.swift @@ -2,4 +2,9 @@ import BaseFeature import Combine final class SignupProfileImageViewModel: BaseViewModel { + let signupProfileImageParam: SignupProfileImageParam + + init(signupProfileImageParam: SignupProfileImageParam) { + self.signupProfileImageParam = signupProfileImageParam + } } From b4ec61206f5051fd540790dd1e2f09df5adbee15 Mon Sep 17 00:00:00 2001 From: baegteun Date: Thu, 27 Oct 2022 14:21:51 +0900 Subject: [PATCH 3/5] =?UTF-8?q?feat=20::=20=ED=9A=8C=EC=9B=90=EA=B0=80?= =?UTF-8?q?=EC=9E=85=20=ED=94=84=EB=A1=9C=ED=95=84=20=EC=9D=B4=EB=AF=B8?= =?UTF-8?q?=EC=A7=80=20=EC=84=A4=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Sources/Application/DI/AppComponent.swift | 3 + Projects/App/Sources/Application/DMSApp.swift | 13 ++++- .../Sources/Application/NeedleGenerated.swift | 18 ++++++ .../SignupProfileImageComponent.swift | 2 +- .../SignupProfileImageView.swift | 56 ++++++++++++++++++- .../SignupProfileImageViewModel.swift | 10 ++++ .../Sources/ImagePicker/ImagePicker.swift | 52 +++++++++++++++++ 7 files changed, 151 insertions(+), 3 deletions(-) create mode 100644 Projects/UsertInterfaces/DesignSystem/Sources/ImagePicker/ImagePicker.swift diff --git a/Projects/App/Sources/Application/DI/AppComponent.swift b/Projects/App/Sources/Application/DI/AppComponent.swift index e6499773..ac8be636 100644 --- a/Projects/App/Sources/Application/DI/AppComponent.swift +++ b/Projects/App/Sources/Application/DI/AppComponent.swift @@ -30,6 +30,9 @@ public extension AppComponent { var signinComponent: SigninComponent { SigninComponent(parent: self) } + var signupProfileImageComponent: SignupProfileImageComponent { + SignupProfileImageComponent(parent: self) + } } // MARK: - Main diff --git a/Projects/App/Sources/Application/DMSApp.swift b/Projects/App/Sources/Application/DMSApp.swift index 14074981..7f194f2b 100644 --- a/Projects/App/Sources/Application/DMSApp.swift +++ b/Projects/App/Sources/Application/DMSApp.swift @@ -12,7 +12,18 @@ struct DMSApp: App { var body: some Scene { WindowGroup { - AppComponent().mainTabComponent.makeView() + AppComponent().signupProfileImageComponent.makeView( + signupProfileImageParam: .init( + schoolCode: "", + schoolAnswer: "", + email: "", + grade: 1, + classRoom: 1, + number: 1, + accountID: "", + password: "" + ) + ) } } } diff --git a/Projects/App/Sources/Application/NeedleGenerated.swift b/Projects/App/Sources/Application/NeedleGenerated.swift index 9db8dc3f..de496b7b 100644 --- a/Projects/App/Sources/Application/NeedleGenerated.swift +++ b/Projects/App/Sources/Application/NeedleGenerated.swift @@ -38,6 +38,17 @@ private class SchoolCodeDependencyc0114744c1c8c7843672Provider: SchoolCodeDepend private func factoryb65c1efbf06b87162473f47b58f8f304c97af4d5(_ component: NeedleFoundation.Scope) -> AnyObject { return SchoolCodeDependencyc0114744c1c8c7843672Provider(appComponent: parent1(component) as! AppComponent) } +private class SignupProfileImageDependency4203088ab57581d9f871Provider: SignupProfileImageDependency { + + + init() { + + } +} +/// ^->AppComponent->SignupProfileImageComponent +private func factory6792674212c15df7e9cfe3b0c44298fc1c149afb(_ component: NeedleFoundation.Scope) -> AnyObject { + return SignupProfileImageDependency4203088ab57581d9f871Provider() +} private class MainTabDependency2826cdb310ed0b17a725Provider: MainTabDependency { var homeComponent: HomeComponent { return appComponent.homeComponent @@ -110,6 +121,7 @@ extension AppComponent: Registration { localTable["schoolCodeComponent-SchoolCodeComponent"] = { self.schoolCodeComponent as Any } localTable["findIDComponent-FindIDComponent"] = { self.findIDComponent as Any } localTable["signinComponent-SigninComponent"] = { self.signinComponent as Any } + localTable["signupProfileImageComponent-SignupProfileImageComponent"] = { self.signupProfileImageComponent as Any } localTable["mainTabComponent-MainTabComponent"] = { self.mainTabComponent as Any } localTable["homeComponent-HomeComponent"] = { self.homeComponent as Any } localTable["remoteStudentsDataSource-any RemoteStudentsDataSource"] = { self.remoteStudentsDataSource as Any } @@ -136,6 +148,11 @@ extension SchoolCodeComponent: Registration { keyPathToName[\SchoolCodeDependency.checkSchoolCodeUseCase] = "checkSchoolCodeUseCase-any CheckSchoolCodeUseCase" } } +extension SignupProfileImageComponent: Registration { + public func registerItems() { + + } +} extension MainTabComponent: Registration { public func registerItems() { keyPathToName[\MainTabDependency.homeComponent] = "homeComponent-HomeComponent" @@ -175,6 +192,7 @@ private func registerProviderFactory(_ componentPath: String, _ factory: @escapi private func register1() { registerProviderFactory("^->AppComponent", factoryEmptyDependencyProvider) registerProviderFactory("^->AppComponent->SchoolCodeComponent", factoryb65c1efbf06b87162473f47b58f8f304c97af4d5) + registerProviderFactory("^->AppComponent->SignupProfileImageComponent", factory6792674212c15df7e9cfe3b0c44298fc1c149afb) registerProviderFactory("^->AppComponent->MainTabComponent", factory1ab5a747ddf21e1393f9f47b58f8f304c97af4d5) registerProviderFactory("^->AppComponent->SigninComponent", factory2882a056d84a613debccf47b58f8f304c97af4d5) registerProviderFactory("^->AppComponent->HomeComponent", factory67229cdf0f755562b2b1f47b58f8f304c97af4d5) diff --git a/Projects/Features/SignupFeature/Sources/SignupProfileImage/SignupProfileImageComponent.swift b/Projects/Features/SignupFeature/Sources/SignupProfileImage/SignupProfileImageComponent.swift index 779ca743..afd1bcfc 100644 --- a/Projects/Features/SignupFeature/Sources/SignupProfileImage/SignupProfileImageComponent.swift +++ b/Projects/Features/SignupFeature/Sources/SignupProfileImage/SignupProfileImageComponent.swift @@ -8,7 +8,7 @@ public final class SignupProfileImageComponent: Component, uiImage: Binding) -> some View { + self + .fullScreenCover(isPresented: isShow) { + ImagePicker(configuration: .init(photoLibrary: .shared()), requests: uiImage) + } + } +} + +struct ImagePicker: UIViewControllerRepresentable { + let configuration: PHPickerConfiguration + @Binding var requests: UIImage? + + func makeUIViewController(context: Context) -> PHPickerViewController { + let controller = PHPickerViewController(configuration: configuration) + controller.delegate = context.coordinator + return controller + } + + func updateUIViewController(_ uiViewController: PHPickerViewController, context: Context) { } + + func makeCoordinator() -> Coordinator { + Coordinator(self) + } + + class Coordinator: PHPickerViewControllerDelegate { + var parent: ImagePicker + + init(_ parent: ImagePicker) { + self.parent = parent + } + + func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) { + for result in results { + let provider = result.itemProvider + if provider.canLoadObject(ofClass: UIImage.self) { + provider.loadObject(ofClass: UIImage.self) { [weak self] image, _ in + if let image = image as? UIImage { + DispatchQueue.main.async { + self?.parent.requests = image + } + } + } + } + } + picker.dismiss(animated: true) + } + } +} From 210e9d841d66d3f0ca17955575c9d5d6bb77b6e6 Mon Sep 17 00:00:00 2001 From: baegteun Date: Thu, 27 Oct 2022 14:52:54 +0900 Subject: [PATCH 4/5] =?UTF-8?q?feat=20::=20=EC=B9=B4=EB=A9=94=EB=9D=BC?= =?UTF-8?q?=EB=A1=9C=20=EC=B4=AC=EC=98=81=20=EA=B8=B0=EB=8A=A5=20+?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Projects/App/Support/Info.plist | 2 + .../SignupProfileImageView.swift | 25 ++++++++- .../Sources/ActionSheet/DMSActionSheet.swift | 53 ++++++++++++++++++ .../Sources/CameraPicker/CameraPicker.swift | 55 +++++++++++++++++++ 4 files changed, 134 insertions(+), 1 deletion(-) create mode 100644 Projects/UsertInterfaces/DesignSystem/Sources/ActionSheet/DMSActionSheet.swift create mode 100644 Projects/UsertInterfaces/DesignSystem/Sources/CameraPicker/CameraPicker.swift diff --git a/Projects/App/Support/Info.plist b/Projects/App/Support/Info.plist index 434881ab..a23b8dbb 100644 --- a/Projects/App/Support/Info.plist +++ b/Projects/App/Support/Info.plist @@ -2,6 +2,8 @@ + NSCameraUsageDescription + 사진을 촬영하기 위해서는 권한이 필요합니다! CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) CFBundleDisplayName diff --git a/Projects/Features/SignupFeature/Sources/SignupProfileImage/SignupProfileImageView.swift b/Projects/Features/SignupFeature/Sources/SignupProfileImage/SignupProfileImageView.swift index 1d06a254..e05f1369 100644 --- a/Projects/Features/SignupFeature/Sources/SignupProfileImage/SignupProfileImageView.swift +++ b/Projects/Features/SignupFeature/Sources/SignupProfileImage/SignupProfileImageView.swift @@ -4,6 +4,8 @@ import SwiftUI struct SignupProfileImageView: View { @StateObject var viewModel: SignupProfileImageViewModel @State var isShowingImagePicker = false + @State var isShowingCameraPicker = false + @State var isPresentedImageActionSheet = false public init(viewModel: SignupProfileImageViewModel) { _viewModel = StateObject(wrappedValue: viewModel) @@ -25,7 +27,7 @@ struct SignupProfileImageView: View { .padding(.top, 24) Button { - isShowingImagePicker.toggle() + isPresentedImageActionSheet.toggle() } label: { ZStack(alignment: .bottomTrailing) { Group { @@ -64,6 +66,27 @@ struct SignupProfileImageView: View { .padding(.bottom, 40) } .imagePicker(isShow: $isShowingImagePicker, uiImage: $viewModel.selectedImage) + .cameraPicker(isShow: $isShowingCameraPicker, uiImage: $viewModel.selectedImage) .padding(.horizontal, 24) + .dmsActionSheet(isPresented: $isPresentedImageActionSheet) { + Button(role: nil) { + isPresentedImageActionSheet = false + isShowingCameraPicker.toggle() + } label: { + Label("사진 촬영", systemImage: "camera.fill") + } + .foregroundColor(.GrayScale.gray6) + + Divider() + .foregroundColor(.GrayScale.gray4) + + Button(role: nil) { + isPresentedImageActionSheet = false + isShowingImagePicker.toggle() + } label: { + Label("사진 선택", systemImage: "photo.tv") + } + .foregroundColor(.GrayScale.gray6) + } } } diff --git a/Projects/UsertInterfaces/DesignSystem/Sources/ActionSheet/DMSActionSheet.swift b/Projects/UsertInterfaces/DesignSystem/Sources/ActionSheet/DMSActionSheet.swift new file mode 100644 index 00000000..ffb46999 --- /dev/null +++ b/Projects/UsertInterfaces/DesignSystem/Sources/ActionSheet/DMSActionSheet.swift @@ -0,0 +1,53 @@ +import SwiftUI + +public extension View { + func dmsActionSheet( + isPresented: Binding, + @ViewBuilder actions: @escaping () -> Actions + ) -> some View { + modifier(DMSActionSheet(isPresented: isPresented, actions: actions)) + } +} +struct DMSActionSheet: ViewModifier { + @Binding var isPresented: Bool + @ViewBuilder let actions: () -> Actions + + func body(content: Content) -> some View { + ZStack { + content + .frame(maxWidth: .infinity, maxHeight: .infinity) + + ZStack(alignment: .bottom) { + if isPresented { + Color.GrayScale.gray9.opacity(0.16) + .ignoresSafeArea() + .onTapGesture { + isPresented = false + } + .transition(.opacity) + } + + if isPresented { + VStack { + GroupBox { + actions() + .frame(maxWidth: .infinity, alignment: .leading) + } + + GroupBox { + Button("취소", role: .cancel) { + isPresented = false + } + .foregroundColor(.GrayScale.gray6) + .frame(maxWidth: .infinity, alignment: .center) + } + } + .font(.title3) + .padding(8) + .transition(.move(edge: .bottom)) + } + } + } + .animation(.easeInOut, value: isPresented) + } +} diff --git a/Projects/UsertInterfaces/DesignSystem/Sources/CameraPicker/CameraPicker.swift b/Projects/UsertInterfaces/DesignSystem/Sources/CameraPicker/CameraPicker.swift new file mode 100644 index 00000000..ed0e33f4 --- /dev/null +++ b/Projects/UsertInterfaces/DesignSystem/Sources/CameraPicker/CameraPicker.swift @@ -0,0 +1,55 @@ +import SwiftUI +import UIKit + +public extension View { + func cameraPicker(isShow: Binding, uiImage: Binding) -> some View { + self + .fullScreenCover(isPresented: isShow) { + CameraPicker(sourceType: .camera, image: uiImage, isPresented: isShow) + } + } +} + +struct CameraPicker: UIViewControllerRepresentable { + var sourceType: UIImagePickerController.SourceType + @Binding var image: UIImage? + @Binding var isPresented: Bool + + func makeCoordinator() -> ImagePickerViewCoordinator { + return ImagePickerViewCoordinator(image: $image, isPresented: $isPresented) + } + + func makeUIViewController(context: Context) -> UIImagePickerController { + let pickerController = UIImagePickerController() + pickerController.sourceType = sourceType + pickerController.delegate = context.coordinator + return pickerController + } + + func updateUIViewController(_ uiViewController: UIImagePickerController, context: Context) {} + +} + +final class ImagePickerViewCoordinator: NSObject, UINavigationControllerDelegate, UIImagePickerControllerDelegate { + @Binding var image: UIImage? + @Binding var isPresented: Bool + + init(image: Binding, isPresented: Binding) { + self._image = image + self._isPresented = isPresented + } + + func imagePickerController( + _ picker: UIImagePickerController, + didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey: Any] + ) { + if let image = info[UIImagePickerController.InfoKey.originalImage] as? UIImage { + self.image = image + } + self.isPresented = false + } + + func imagePickerControllerDidCancel(_ picker: UIImagePickerController) { + self.isPresented = false + } +} From 7478c81db49317a2909e5a9972c48914b480cc3d Mon Sep 17 00:00:00 2001 From: baegteun Date: Thu, 27 Oct 2022 15:03:03 +0900 Subject: [PATCH 5/5] =?UTF-8?q?feat=20::=20DMSApp=20=EC=A0=95=EC=83=81?= =?UTF-8?q?=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Projects/App/Sources/Application/DMSApp.swift | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/Projects/App/Sources/Application/DMSApp.swift b/Projects/App/Sources/Application/DMSApp.swift index 7f194f2b..14074981 100644 --- a/Projects/App/Sources/Application/DMSApp.swift +++ b/Projects/App/Sources/Application/DMSApp.swift @@ -12,18 +12,7 @@ struct DMSApp: App { var body: some Scene { WindowGroup { - AppComponent().signupProfileImageComponent.makeView( - signupProfileImageParam: .init( - schoolCode: "", - schoolAnswer: "", - email: "", - grade: 1, - classRoom: 1, - number: 1, - accountID: "", - password: "" - ) - ) + AppComponent().mainTabComponent.makeView() } } }