Skip to content

Commit 42bf49a

Browse files
authoredApr 29, 2024
🔀 :: (#10) 비밀번호 찾기 퍼블리싱
2 parents 583857c + 42f064c commit 42bf49a

27 files changed

+484
-13
lines changed
 

‎Plugin/DependencyPlugin/ProjectDescriptionHelpers/ModulePaths.swift

+1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ extension ModulePaths: MicroTargetPathConvertable {
2424

2525
public extension ModulePaths {
2626
enum Feature: String, MicroTargetPathConvertable {
27+
case FindPasswordFeature
2728
case SignupFeature
2829
case SigninFeature
2930
case SplashFeature

‎Projects/App/Sources/Application/DI/AppComponent.swift

+13
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ import SigninFeature
88
import SigninFeatureInterface
99
import SignupFeature
1010
import SignupFeatureInterface
11+
import FindPasswordFeature
12+
import FindPasswordFeatureInterface
1113

1214
public final class AppComponent: BootstrapComponent {
1315
// private let _keychain: any Keychain
@@ -63,4 +65,15 @@ public extension AppComponent {
6365
var signupCheckLevelFactory: any SignupCheckLevelFactory {
6466
SignupCheckLevelComponent(parent: self)
6567
}
68+
69+
// Find Password
70+
var inputEmailFactory: any InputEmailFactory {
71+
InputEmailComponent(parent: self)
72+
}
73+
var verifyAuthCodeFactory: any VerifyAuthCodeFactory {
74+
VerifyAuthCodeComponent(parent: self)
75+
}
76+
var inputNewPasswordFactory: any InputNewPasswordFactory {
77+
InputNewPasswordComponent(parent: self)
78+
}
6679
}

‎Projects/App/Sources/Application/NeedleGenerated.swift

+64
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11

22

3+
import FindPasswordFeature
4+
import FindPasswordFeatureInterface
35
import NeedleFoundation
46
import RootFeature
57
import RootFeatureInterface
@@ -162,6 +164,9 @@ private class SigninDependencyde06a9d0b22764487733Provider: SigninDependency {
162164
var signupEmailFactory: any SignupEmailFactory {
163165
return appComponent.signupEmailFactory
164166
}
167+
var inputEmailFactory: any InputEmailFactory {
168+
return appComponent.inputEmailFactory
169+
}
165170
private let appComponent: AppComponent
166171
init(appComponent: AppComponent) {
167172
self.appComponent = appComponent
@@ -171,6 +176,43 @@ private class SigninDependencyde06a9d0b22764487733Provider: SigninDependency {
171176
private func factory2882a056d84a613debccf47b58f8f304c97af4d5(_ component: NeedleFoundation.Scope) -> AnyObject {
172177
return SigninDependencyde06a9d0b22764487733Provider(appComponent: parent1(component) as! AppComponent)
173178
}
179+
private class VerifyAuthCodeDependencya16ab19f97e0892b555bProvider: VerifyAuthCodeDependency {
180+
var inputNewPasswordFactory: any InputNewPasswordFactory {
181+
return appComponent.inputNewPasswordFactory
182+
}
183+
private let appComponent: AppComponent
184+
init(appComponent: AppComponent) {
185+
self.appComponent = appComponent
186+
}
187+
}
188+
/// ^->AppComponent->VerifyAuthCodeComponent
189+
private func factoryed5ce75de1bf576b84adf47b58f8f304c97af4d5(_ component: NeedleFoundation.Scope) -> AnyObject {
190+
return VerifyAuthCodeDependencya16ab19f97e0892b555bProvider(appComponent: parent1(component) as! AppComponent)
191+
}
192+
private class InputNewPasswordDependency1149e32e41e1cfce6f6dProvider: InputNewPasswordDependency {
193+
194+
195+
init() {
196+
197+
}
198+
}
199+
/// ^->AppComponent->InputNewPasswordComponent
200+
private func factory27615059458a0576f404e3b0c44298fc1c149afb(_ component: NeedleFoundation.Scope) -> AnyObject {
201+
return InputNewPasswordDependency1149e32e41e1cfce6f6dProvider()
202+
}
203+
private class InputEmailDependency4102766a436592066e97Provider: InputEmailDependency {
204+
var verifyAuthCodeFactory: any VerifyAuthCodeFactory {
205+
return appComponent.verifyAuthCodeFactory
206+
}
207+
private let appComponent: AppComponent
208+
init(appComponent: AppComponent) {
209+
self.appComponent = appComponent
210+
}
211+
}
212+
/// ^->AppComponent->InputEmailComponent
213+
private func factoryf939e41ba3a1151e88f8f47b58f8f304c97af4d5(_ component: NeedleFoundation.Scope) -> AnyObject {
214+
return InputEmailDependency4102766a436592066e97Provider(appComponent: parent1(component) as! AppComponent)
215+
}
174216

175217
#else
176218
extension AppComponent: Registration {
@@ -186,6 +228,9 @@ extension AppComponent: Registration {
186228
localTable["signupStudentIDFactory-any SignupStudentIDFactory"] = { [unowned self] in self.signupStudentIDFactory as Any }
187229
localTable["signupGenderFactory-any SignupGenderFactory"] = { [unowned self] in self.signupGenderFactory as Any }
188230
localTable["signupCheckLevelFactory-any SignupCheckLevelFactory"] = { [unowned self] in self.signupCheckLevelFactory as Any }
231+
localTable["inputEmailFactory-any InputEmailFactory"] = { [unowned self] in self.inputEmailFactory as Any }
232+
localTable["verifyAuthCodeFactory-any VerifyAuthCodeFactory"] = { [unowned self] in self.verifyAuthCodeFactory as Any }
233+
localTable["inputNewPasswordFactory-any InputNewPasswordFactory"] = { [unowned self] in self.inputNewPasswordFactory as Any }
189234
}
190235
}
191236
extension SplashComponent: Registration {
@@ -245,6 +290,22 @@ extension RootComponent: Registration {
245290
extension SigninComponent: Registration {
246291
public func registerItems() {
247292
keyPathToName[\SigninDependency.signupEmailFactory] = "signupEmailFactory-any SignupEmailFactory"
293+
keyPathToName[\SigninDependency.inputEmailFactory] = "inputEmailFactory-any InputEmailFactory"
294+
}
295+
}
296+
extension VerifyAuthCodeComponent: Registration {
297+
public func registerItems() {
298+
keyPathToName[\VerifyAuthCodeDependency.inputNewPasswordFactory] = "inputNewPasswordFactory-any InputNewPasswordFactory"
299+
}
300+
}
301+
extension InputNewPasswordComponent: Registration {
302+
public func registerItems() {
303+
304+
}
305+
}
306+
extension InputEmailComponent: Registration {
307+
public func registerItems() {
308+
keyPathToName[\InputEmailDependency.verifyAuthCodeFactory] = "verifyAuthCodeFactory-any VerifyAuthCodeFactory"
248309
}
249310
}
250311

@@ -275,6 +336,9 @@ private func registerProviderFactory(_ componentPath: String, _ factory: @escapi
275336
registerProviderFactory("^->AppComponent->SignupEmailComponent", factory4d1ddf658c5970ef6b47f47b58f8f304c97af4d5)
276337
registerProviderFactory("^->AppComponent->RootComponent", factory264bfc4d4cb6b0629b40f47b58f8f304c97af4d5)
277338
registerProviderFactory("^->AppComponent->SigninComponent", factory2882a056d84a613debccf47b58f8f304c97af4d5)
339+
registerProviderFactory("^->AppComponent->VerifyAuthCodeComponent", factoryed5ce75de1bf576b84adf47b58f8f304c97af4d5)
340+
registerProviderFactory("^->AppComponent->InputNewPasswordComponent", factory27615059458a0576f404e3b0c44298fc1c149afb)
341+
registerProviderFactory("^->AppComponent->InputEmailComponent", factoryf939e41ba3a1151e88f8f47b58f8f304c97af4d5)
278342
}
279343
#endif
280344

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import SwiftUI
2+
3+
public struct RootPresentationModeKey: EnvironmentKey {
4+
public static let defaultValue: Binding<RootPresentationMode> = .constant(RootPresentationMode())
5+
}
6+
7+
public extension EnvironmentValues {
8+
var rootPresentationMode: Binding<RootPresentationMode> {
9+
get { return self[RootPresentationModeKey.self] }
10+
set { self[RootPresentationModeKey.self] = newValue }
11+
}
12+
}
13+
14+
public typealias RootPresentationMode = Bool
15+
16+
public extension Binding<RootPresentationMode> {
17+
func popToRootView() {
18+
self.wrappedValue.toggle()
19+
}
20+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import SwiftUI
2+
3+
public protocol InputEmailFactory {
4+
associatedtype SomeView: View
5+
func makeView() -> SomeView
6+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import SwiftUI
2+
3+
public protocol InputNewPasswordFactory {
4+
associatedtype SomeView: View
5+
func makeView() -> SomeView
6+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import SwiftUI
2+
3+
public protocol VerifyAuthCodeFactory {
4+
associatedtype SomeView: View
5+
func makeView() -> SomeView
6+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import DependencyPlugin
2+
import ProjectDescription
3+
import ProjectDescriptionHelpers
4+
5+
let project = Project.module(
6+
name: ModulePaths.Feature.FindPasswordFeature.rawValue,
7+
targets: [
8+
.interface(module: .feature(.FindPasswordFeature)),
9+
.implements(module: .feature(.FindPasswordFeature), dependencies: [
10+
.feature(target: .FindPasswordFeature, type: .interface),
11+
.feature(target: .BaseFeature)
12+
]),
13+
.tests(module: .feature(.FindPasswordFeature), dependencies: [
14+
.feature(target: .FindPasswordFeature)
15+
])
16+
]
17+
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import SwiftUI
2+
import NeedleFoundation
3+
import FindPasswordFeatureInterface
4+
5+
public protocol InputEmailDependency: Dependency {
6+
var verifyAuthCodeFactory: any VerifyAuthCodeFactory { get }
7+
}
8+
9+
public final class InputEmailComponent: Component<InputEmailDependency>, InputEmailFactory {
10+
public func makeView() -> some View {
11+
InputEmailView(
12+
viewModel: .init(),
13+
verifyAuthCodeFactory: dependency.verifyAuthCodeFactory
14+
)
15+
}
16+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import BaseFeature
2+
import Combine
3+
4+
final class InputEmailViewModel: BaseViewModel {
5+
@Published var email: String = ""
6+
7+
@Published var isNavigatedToVerifyAuthCode: Bool = false
8+
9+
func nextButtonDidTap() {
10+
self.isNavigatedToVerifyAuthCode = true
11+
}
12+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
import DesignSystem
2+
import SwiftUI
3+
import BaseFeature
4+
import ViewUtil
5+
import FindPasswordFeatureInterface
6+
7+
struct InputEmailView: View {
8+
private enum FocusField {
9+
case email
10+
}
11+
@FocusState private var focusField: FocusField?
12+
@StateObject var viewModel: InputEmailViewModel
13+
@Environment(\.rootPresentationMode) var rootPresentationMode
14+
15+
private let verifyAuthCodeFactory: any VerifyAuthCodeFactory
16+
17+
init(
18+
viewModel: InputEmailViewModel,
19+
verifyAuthCodeFactory: any VerifyAuthCodeFactory
20+
) {
21+
_viewModel = StateObject(wrappedValue: viewModel)
22+
self.verifyAuthCodeFactory = verifyAuthCodeFactory
23+
}
24+
25+
var body: some View {
26+
VStack(spacing: 0) {
27+
NavigationTitleView(
28+
title: "이메일을 입력해 주세요",
29+
description: "이메일로 인증번호를 전송해 드릴게요"
30+
)
31+
32+
KGTextField(
33+
"이메일을 입력해주세요",
34+
text: $viewModel.email,
35+
title: "이메일",
36+
isError: viewModel.isErrorOccurred,
37+
errorMessage: viewModel.errorMessage,
38+
onCommit: viewModel.nextButtonDidTap
39+
)
40+
.textContentType(.emailAddress)
41+
.keyboardType(.emailAddress)
42+
.focused($focusField, equals: .email)
43+
44+
Spacer()
45+
}
46+
.bottomButton(
47+
text: "다음",
48+
isEditing: focusField != nil,
49+
isDisabled: viewModel.email.isEmpty,
50+
action: viewModel.nextButtonDidTap
51+
)
52+
.navigationBackButton()
53+
.kgBackground()
54+
.hideKeyboardWhenTap()
55+
.navigate(
56+
to: verifyAuthCodeFactory.makeView().eraseToAnyView()
57+
.environment(\.rootPresentationMode, rootPresentationMode),
58+
when: $viewModel.isNavigatedToVerifyAuthCode
59+
)
60+
}
61+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import SwiftUI
2+
import NeedleFoundation
3+
import FindPasswordFeatureInterface
4+
5+
public protocol InputNewPasswordDependency: Dependency {}
6+
7+
public final class InputNewPasswordComponent: Component<InputNewPasswordDependency>, InputNewPasswordFactory {
8+
public func makeView() -> some View {
9+
InputNewPasswordView(
10+
viewModel: .init()
11+
)
12+
}
13+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import DesignSystem
2+
import SwiftUI
3+
import BaseFeature
4+
import SignupFeatureInterface
5+
import ViewUtil
6+
7+
struct InputNewPasswordView: View {
8+
private enum FocusField {
9+
case password
10+
case checkPassword
11+
}
12+
@FocusState private var focusField: FocusField?
13+
@StateObject var viewModel: InputNewPasswordViewModel
14+
@Environment(\.rootPresentationMode) var rootPresentationMode
15+
16+
init(
17+
viewModel: InputNewPasswordViewModel
18+
) {
19+
_viewModel = StateObject(wrappedValue: viewModel)
20+
}
21+
22+
var body: some View {
23+
VStack(spacing: 0) {
24+
NavigationTitleView(
25+
title: "새 비밀번호를 입력해주세요",
26+
description: "비밀번호는 영어와 숫자를 조합해 만들어 주세요"
27+
)
28+
29+
KGTextField(
30+
"비밀번호(8~12자)를 입력해 주세요",
31+
text: $viewModel.password,
32+
title: "비밀번호",
33+
isError: viewModel.isErrorOccurred,
34+
errorMessage: viewModel.errorMessage,
35+
isSecure: true
36+
) {
37+
self.focusField = .checkPassword
38+
}
39+
.textContentType(.password)
40+
.focused($focusField, equals: .password)
41+
42+
KGTextField(
43+
"비밀번호 다시 입력해 주세요",
44+
text: $viewModel.checkPassword,
45+
title: "비밀번호 확인",
46+
isError: viewModel.isErrorOccurred,
47+
errorMessage: viewModel.errorMessage,
48+
isSecure: true,
49+
onCommit: viewModel.nextButtonDidTap
50+
)
51+
.textContentType(.password)
52+
.focused($focusField, equals: .checkPassword)
53+
54+
Spacer()
55+
}
56+
.bottomButton(
57+
text: "다음",
58+
isEditing: focusField != nil,
59+
isDisabled: viewModel.password.isEmpty || viewModel.checkPassword.isEmpty,
60+
action: viewModel.nextButtonDidTap
61+
)
62+
.navigationBar()
63+
.kgBackground()
64+
.hideKeyboardWhenTap()
65+
.onSuccess(of: viewModel.isSuccessToChangePassword) {
66+
DispatchQueue.main.async {
67+
self.rootPresentationMode.popToRootView()
68+
}
69+
}
70+
}
71+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import BaseFeature
2+
import Combine
3+
4+
final class InputNewPasswordViewModel: BaseViewModel {
5+
@Published var password: String = ""
6+
@Published var checkPassword: String = ""
7+
8+
@Published var isSuccessToChangePassword: Bool = false
9+
10+
func nextButtonDidTap() {
11+
self.isSuccessToChangePassword = true
12+
}
13+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import SwiftUI
2+
import NeedleFoundation
3+
import FindPasswordFeatureInterface
4+
5+
public protocol VerifyAuthCodeDependency: Dependency {
6+
var inputNewPasswordFactory: any InputNewPasswordFactory { get }
7+
}
8+
9+
public final class VerifyAuthCodeComponent: Component<VerifyAuthCodeDependency>,
10+
VerifyAuthCodeFactory {
11+
public func makeView() -> some View {
12+
VerifyAuthCodeView(
13+
viewModel: .init(),
14+
inputNewPasswordFactory: dependency.inputNewPasswordFactory
15+
)
16+
}
17+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
import DesignSystem
2+
import SwiftUI
3+
import BaseFeature
4+
import ViewUtil
5+
import FindPasswordFeatureInterface
6+
7+
struct VerifyAuthCodeView: View {
8+
private enum FocusField {
9+
case authCode
10+
}
11+
@FocusState private var focusField: FocusField?
12+
@StateObject var viewModel: VerifyAuthCodeViewModel
13+
@Environment(\.rootPresentationMode) var rootPresentationMode
14+
15+
private let inputNewPasswordFactory: any InputNewPasswordFactory
16+
17+
init(
18+
viewModel: VerifyAuthCodeViewModel,
19+
inputNewPasswordFactory: any InputNewPasswordFactory
20+
) {
21+
_viewModel = StateObject(wrappedValue: viewModel)
22+
self.inputNewPasswordFactory = inputNewPasswordFactory
23+
}
24+
25+
var body: some View {
26+
VStack(spacing: 0) {
27+
NavigationTitleView(
28+
title: "인증번호를 입력해 주세요",
29+
description: "입력해주신 이메일로 인증번호를 전송해 드렸어요"
30+
)
31+
32+
VerifyCodeTextField(
33+
$viewModel.authCode,
34+
isError: viewModel.isErrorOccurred,
35+
errorMessage: viewModel.errorMessage,
36+
onCommit: viewModel.nextButtonDidTap
37+
)
38+
.focused($focusField, equals: .authCode)
39+
40+
HStack {
41+
Text("5:00")
42+
.kgFont(.label, weight: .regular, color: .Greens.main)
43+
44+
Spacer()
45+
46+
Text("인증번호 재전송")
47+
.kgFont(.label, weight: .regular, color: .Grays.gray400)
48+
.underlineText(color: .Grays.gray400)
49+
}
50+
.padding(.vertical, 16)
51+
.padding(.horizontal, 24)
52+
53+
Spacer()
54+
}
55+
.bottomButton(
56+
text: "인증",
57+
isEditing: focusField != nil,
58+
isDisabled: viewModel.authCode.count < 4,
59+
action: viewModel.nextButtonDidTap
60+
)
61+
.navigationBackButton()
62+
.kgBackground()
63+
.hideKeyboardWhenTap()
64+
.navigate(
65+
to: inputNewPasswordFactory.makeView().eraseToAnyView()
66+
.environment(\.rootPresentationMode, rootPresentationMode),
67+
when: $viewModel.isNavigatedToNewPassword
68+
)
69+
}
70+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import BaseFeature
2+
import Foundation
3+
import Combine
4+
5+
final class VerifyAuthCodeViewModel: BaseViewModel {
6+
@Published var authCode: String = ""
7+
8+
@Published var isNavigatedToNewPassword: Bool = false
9+
10+
func nextButtonDidTap() {
11+
self.isNavigatedToNewPassword = true
12+
}
13+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import XCTest
2+
3+
final class FindPasswordFeatureTests: XCTestCase {
4+
override func setUpWithError() throws {}
5+
6+
override func tearDownWithError() throws {}
7+
8+
func testExample() {
9+
XCTAssertEqual(1, 1)
10+
}
11+
}

‎Projects/Feature/SigninFeature/Project.swift

+2-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ let project = Project.module(
99
.implements(module: .feature(.SigninFeature), dependencies: [
1010
.feature(target: .SigninFeature, type: .interface),
1111
.feature(target: .BaseFeature),
12-
.feature(target: .SignupFeature, type: .interface)
12+
.feature(target: .SignupFeature, type: .interface),
13+
.feature(target: .FindPasswordFeature, type: .interface)
1314
]),
1415
.tests(module: .feature(.SigninFeature), dependencies: [
1516
.feature(target: .SigninFeature)

‎Projects/Feature/SigninFeature/Sources/SigninComponent.swift

+4-1
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,19 @@ import SwiftUI
22
import NeedleFoundation
33
import SigninFeatureInterface
44
import SignupFeatureInterface
5+
import FindPasswordFeatureInterface
56

67
public protocol SigninDependency: Dependency {
78
var signupEmailFactory: any SignupEmailFactory { get }
9+
var inputEmailFactory: any InputEmailFactory { get }
810
}
911

1012
public final class SigninComponent: Component<SigninDependency>, SigninFactory {
1113
public func makeView() -> some View {
1214
SigninView(
1315
viewModel: .init(),
14-
signupEmailFactory: dependency.signupEmailFactory
16+
signupEmailFactory: dependency.signupEmailFactory,
17+
inputEmailFactory: dependency.inputEmailFactory
1518
)
1619
}
1720
}

‎Projects/Feature/SigninFeature/Sources/SigninView.swift

+19-4
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import SwiftUI
33
import BaseFeature
44
import ViewUtil
55
import SignupFeatureInterface
6+
import FindPasswordFeatureInterface
67

78
struct SigninView: View {
89
private enum FocusField {
@@ -13,13 +14,16 @@ struct SigninView: View {
1314
@StateObject var viewModel: SigninViewModel
1415

1516
private let signupEmailFactory: any SignupEmailFactory
17+
private let inputEmailFactory: any InputEmailFactory
1618

1719
init(
1820
viewModel: SigninViewModel,
19-
signupEmailFactory: any SignupEmailFactory
21+
signupEmailFactory: any SignupEmailFactory,
22+
inputEmailFactory: any InputEmailFactory
2023
) {
2124
_viewModel = StateObject(wrappedValue: viewModel)
2225
self.signupEmailFactory = signupEmailFactory
26+
self.inputEmailFactory = inputEmailFactory
2327
}
2428

2529
var body: some View {
@@ -63,13 +67,24 @@ struct SigninView: View {
6367
Color.Grays.gray700
6468
.frame(width: 1, height: 16)
6569

66-
Text("비밀번호 찾기")
67-
.kgFont(.label, weight: .regular, color: .Grays.gray700)
70+
Button(action: viewModel.findPasswordButtonDidTap) {
71+
Text("비밀번호 찾기")
72+
.kgFont(.label, weight: .regular, color: .Grays.gray700)
73+
}
6874
}
6975
}
7076

7177
Spacer()
7278
}
73-
.navigate(to: signupEmailFactory.makeView().eraseToAnyView(), when: $viewModel.isNavigatedToSignup)
79+
.hideKeyboardWhenTap()
80+
.navigate(
81+
to: signupEmailFactory.makeView().eraseToAnyView(),
82+
when: $viewModel.isNavigatedToSignup
83+
)
84+
.navigate(
85+
to: inputEmailFactory.makeView().eraseToAnyView()
86+
.environment(\.rootPresentationMode, $viewModel.isNavigatedToFindPassword),
87+
when: $viewModel.isNavigatedToFindPassword
88+
)
7489
}
7590
}

‎Projects/Feature/SigninFeature/Sources/SigninViewModel.swift

+5
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ final class SigninViewModel: BaseViewModel {
66
@Published var password: String = ""
77

88
@Published var isNavigatedToSignup: Bool = false
9+
@Published var isNavigatedToFindPassword: Bool = false
910

1011
func signinButtonDidTap() {
1112
print("Signin")
@@ -14,4 +15,8 @@ final class SigninViewModel: BaseViewModel {
1415
func signupButtonDidTap() {
1516
self.isNavigatedToSignup = true
1617
}
18+
19+
func findPasswordButtonDidTap() {
20+
self.isNavigatedToFindPassword = true
21+
}
1722
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import SwiftUI
2+
3+
public extension View {
4+
func onSuccess(of value: Bool, _ action: @escaping () -> Void) -> some View {
5+
self.onChange(of: value) { changedValue in
6+
if changedValue {
7+
action()
8+
}
9+
}
10+
}
11+
}

‎Projects/Feature/SignupFeature/Sources/Components/BottomButton.swift ‎Projects/UserInterface/DesignSystem/Sources/Extension/View+bottomButton.swift

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
import SwiftUI
2-
import DesignSystem
32

43
/// Vstack으로 할 경우 버튼이 잘리는 문제가 발생
54
/// ZStack을 사용해 SuperView의 상단으로 띄움
65

7-
struct BottomButton: ViewModifier {
6+
private struct BottomButton: ViewModifier {
87
let text: String
98
let isEditing: Bool
109
let isDisabled: Bool

‎Projects/UserInterface/DesignSystem/Sources/TextField/KGTextField.swift

+3
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,9 @@ public struct KGTextField: View {
6969
lineWidth: 1
7070
)
7171
}
72+
.onTapGesture {
73+
self.isFocused = true
74+
}
7275

7376
if !description.isEmpty || isErrorAndNotEmpty {
7477
Text(isErrorAndNotEmpty ? errorMessage : description)

‎Projects/Feature/SignupFeature/Sources/Components/NavigationTitleView.swift ‎Projects/UserInterface/DesignSystem/Sources/View/NavigationTitleView.swift

+9-5
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
11
import SwiftUI
2-
import DesignSystem
32

4-
struct NavigationTitleView: View {
5-
let title: String
6-
let description: String
3+
public struct NavigationTitleView: View {
4+
private let title: String
5+
private let description: String
76

8-
var body: some View {
7+
public init(title: String, description: String) {
8+
self.title = title
9+
self.description = description
10+
}
11+
12+
public var body: some View {
913
VStack(alignment: .leading, spacing: 8) {
1014
Text(title)
1115
.kgFont(.h3, weight: .semiBold, color: .white)

0 commit comments

Comments
 (0)
Please sign in to comment.