Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

merge :: 회원가입 - 프로필 이미지 설정 페이지 #101

Merged
merged 7 commits into from
Oct 27, 2022
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Projects/App/Sources/Application/DI/AppComponent.swift
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ public extension AppComponent {
var signupEmailAuthCodeVerifyComponent: SignupEmailAuthCodeVerifyComponent {
SignupEmailAuthCodeVerifyComponent(parent: self)
}
var signupProfileImageComponent: SignupProfileImageComponent {
SignupProfileImageComponent(parent: self)
}
}

// MARK: - Main
Expand Down
12 changes: 12 additions & 0 deletions Projects/App/Sources/Application/NeedleGenerated.swift
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,17 @@ private class SignupEmailVerifyDependencyf9d372ac752ee19b78caProvider: SignupEma
private func factory3b1904c76335d70151ebf47b58f8f304c97af4d5(_ component: NeedleFoundation.Scope) -> AnyObject {
return SignupEmailVerifyDependencyf9d372ac752ee19b78caProvider(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
Expand Down Expand Up @@ -223,6 +234,7 @@ private func register1() {
registerProviderFactory("^->AppComponent->SchoolCodeComponent", factoryb65c1efbf06b87162473f47b58f8f304c97af4d5)
registerProviderFactory("^->AppComponent->SignupEmailAuthCodeVerifyComponent", factoryb06be35aa893adde971bf47b58f8f304c97af4d5)
registerProviderFactory("^->AppComponent->SignupEmailVerifyComponent", factory3b1904c76335d70151ebf47b58f8f304c97af4d5)
registerProviderFactory("^->AppComponent->SignupProfileImageComponent", factory6792674212c15df7e9cfe3b0c44298fc1c149afb)
registerProviderFactory("^->AppComponent->MainTabComponent", factory1ab5a747ddf21e1393f9f47b58f8f304c97af4d5)
registerProviderFactory("^->AppComponent->SigninComponent", factory2882a056d84a613debccf47b58f8f304c97af4d5)
registerProviderFactory("^->AppComponent->HomeComponent", factory67229cdf0f755562b2b1f47b58f8f304c97af4d5)
Expand Down
2 changes: 2 additions & 0 deletions Projects/App/Support/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>NSCameraUsageDescription</key>
<string>사진을 촬영하기 위해서는 권한이 필요합니다!</string>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleDisplayName</key>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import SwiftUI
import NeedleFoundation

public protocol SignupProfileImageDependency: Dependency {}

public final class SignupProfileImageComponent: Component<SignupProfileImageDependency> {
public func makeView(signupProfileImageParam: SignupProfileImageParam) -> some View {
SignupProfileImageView(
viewModel: .init(
signupProfileImageParam: signupProfileImageParam
)
)
}
}
Original file line number Diff line number Diff line change
@@ -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
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import DesignSystem
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)
}

var body: some View {
VStack {
HStack {
VStack(alignment: .leading, spacing: 8) {
Text("DMS")
.dmsFont(.title(.extraLarge), color: .PrimaryVariant.primary)

Text("프로필 사진")
.dmsFont(.text(.medium), color: .GrayScale.gray6)
}

Spacer()
}
.padding(.top, 24)

Button {
isPresentedImageActionSheet.toggle()
} label: {
ZStack(alignment: .bottomTrailing) {
Group {
if let image = viewModel.selectedImage {
Image(uiImage: image)
.resizable()
} else {
Image(systemName: "person.crop.circle.fill")
.resizable()
}
}
.foregroundColor(.GrayScale.gray4)
.frame(width: 150, height: 150)
.clipShape(Circle())

Image(systemName: "plus.circle.fill")
.resizable()
.frame(width: 46, height: 46)
.clipShape(Circle())
.foregroundColor(.PrimaryVariant.primary)
}
.padding(.top, 80)
}

Spacer()

DMSButton(text: "다음에 설정하기", style: .underline, color: .GrayScale.gray6) {
viewModel.skipButtonDidTap()
}

DMSWideButton(text: "다음", color: .PrimaryVariant.primary) {
viewModel.nextButtonDidTap()
}
.disabled(viewModel.selectedImage == nil)
.padding(.top, 32)
.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)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import BaseFeature
import Combine
import UIKit

final class SignupProfileImageViewModel: BaseViewModel {
@Published var selectedImage: UIImage?
let signupProfileImageParam: SignupProfileImageParam

init(signupProfileImageParam: SignupProfileImageParam) {
self.signupProfileImageParam = signupProfileImageParam
}

func skipButtonDidTap() {

}

func nextButtonDidTap() {

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import SwiftUI

public extension View {
func dmsActionSheet<Actions: View>(
isPresented: Binding<Bool>,
@ViewBuilder actions: @escaping () -> Actions
) -> some View {
modifier(DMSActionSheet(isPresented: isPresented, actions: actions))
}
}
struct DMSActionSheet<Actions: View>: 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)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import SwiftUI
import UIKit

public extension View {
func cameraPicker(isShow: Binding<Bool>, uiImage: Binding<UIImage?>) -> 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<UIImage?>, isPresented: Binding<Bool>) {
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
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import SwiftUI
import PhotosUI

public extension View {
func imagePicker(isShow: Binding<Bool>, uiImage: Binding<UIImage?>) -> 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)
}
}
}