Skip to content

Commit 60b5188

Browse files
authored
Merge pull request #15 from nativeapptemplate/add_other_viewModels5
Add other view models5
2 parents 97b8b61 + cb81821 commit 60b5188

34 files changed

Lines changed: 2394 additions & 611 deletions

NativeAppTemplate.xcodeproj/project.pbxproj

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,14 @@
126126
0199CD2B2E07512100109DC6 /* SignUpRepositoryProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0199CD292E07512100109DC6 /* SignUpRepositoryProtocol.swift */; };
127127
0199CD2C2E07512100109DC6 /* LoginRepositoryProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0199CD272E07512100109DC6 /* LoginRepositoryProtocol.swift */; };
128128
0199CD3E2E075CBB00109DC6 /* SessionControllerProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0199CD3D2E075CBB00109DC6 /* SessionControllerProtocol.swift */; };
129+
01A133992E08B052000AD24A /* AcceptPrivacyViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01A133982E08B052000AD24A /* AcceptPrivacyViewModel.swift */; };
130+
01A1339B2E08B0DF000AD24A /* MainViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01A1339A2E08B0DF000AD24A /* MainViewModel.swift */; };
131+
01A1339D2E08B2BB000AD24A /* OnboardingViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01A1339C2E08B2BB000AD24A /* OnboardingViewModel.swift */; };
132+
01A1339F2E08B2FD000AD24A /* AcceptTermsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01A1339E2E08B2FD000AD24A /* AcceptTermsViewModel.swift */; };
133+
01A133A12E08B4A5000AD24A /* ForgotPasswordViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01A133A02E08B4A5000AD24A /* ForgotPasswordViewModel.swift */; };
134+
01A133A32E08B4DA000AD24A /* ResendConfirmationInstructionsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01A133A22E08B4DA000AD24A /* ResendConfirmationInstructionsViewModel.swift */; };
135+
01A133A52E08BB1B000AD24A /* SignInEmailAndPasswordViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01A133A42E08BB1B000AD24A /* SignInEmailAndPasswordViewModel.swift */; };
136+
01A133A72E08BB66000AD24A /* SignUpViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01A133A62E08BB66000AD24A /* SignUpViewModel.swift */; };
129137
01B37C7629B0960700BF5B2D /* ForgotPasswordView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01B37C7529B0960700BF5B2D /* ForgotPasswordView.swift */; };
130138
01B526542AF4E36400655131 /* MainTab.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01B526532AF4E36400655131 /* MainTab.swift */; };
131139
01B526562AF4E82A00655131 /* ScrollToTopID.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01B526552AF4E82A00655131 /* ScrollToTopID.swift */; };
@@ -294,6 +302,14 @@
294302
0199CD282E07512100109DC6 /* OnboardingRepositoryProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingRepositoryProtocol.swift; sourceTree = "<group>"; };
295303
0199CD292E07512100109DC6 /* SignUpRepositoryProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignUpRepositoryProtocol.swift; sourceTree = "<group>"; };
296304
0199CD3D2E075CBB00109DC6 /* SessionControllerProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionControllerProtocol.swift; sourceTree = "<group>"; };
305+
01A133982E08B052000AD24A /* AcceptPrivacyViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AcceptPrivacyViewModel.swift; sourceTree = "<group>"; };
306+
01A1339A2E08B0DF000AD24A /* MainViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainViewModel.swift; sourceTree = "<group>"; };
307+
01A1339C2E08B2BB000AD24A /* OnboardingViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingViewModel.swift; sourceTree = "<group>"; };
308+
01A1339E2E08B2FD000AD24A /* AcceptTermsViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AcceptTermsViewModel.swift; sourceTree = "<group>"; };
309+
01A133A02E08B4A5000AD24A /* ForgotPasswordViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ForgotPasswordViewModel.swift; sourceTree = "<group>"; };
310+
01A133A22E08B4DA000AD24A /* ResendConfirmationInstructionsViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResendConfirmationInstructionsViewModel.swift; sourceTree = "<group>"; };
311+
01A133A42E08BB1B000AD24A /* SignInEmailAndPasswordViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignInEmailAndPasswordViewModel.swift; sourceTree = "<group>"; };
312+
01A133A62E08BB66000AD24A /* SignUpViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignUpViewModel.swift; sourceTree = "<group>"; };
297313
01B37C7529B0960700BF5B2D /* ForgotPasswordView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ForgotPasswordView.swift; sourceTree = "<group>"; };
298314
01B526532AF4E36400655131 /* MainTab.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainTab.swift; sourceTree = "<group>"; };
299315
01B526552AF4E82A00655131 /* ScrollToTopID.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScrollToTopID.swift; sourceTree = "<group>"; };
@@ -671,16 +687,24 @@
671687
isa = PBXGroup;
672688
children = (
673689
01482FA32B351E4100A56D43 /* AcceptPrivacyView.swift */,
690+
01A133982E08B052000AD24A /* AcceptPrivacyViewModel.swift */,
674691
012643362B3554AD00D4E9BD /* AcceptTermsView.swift */,
692+
01A1339E2E08B2FD000AD24A /* AcceptTermsViewModel.swift */,
675693
01B37C7529B0960700BF5B2D /* ForgotPasswordView.swift */,
694+
01A133A02E08B4A5000AD24A /* ForgotPasswordViewModel.swift */,
676695
0172045725AA82B4008FD63B /* MainView.swift */,
696+
01A1339A2E08B0DF000AD24A /* MainViewModel.swift */,
677697
0172045925AA82B4008FD63B /* MessageBarView.swift */,
678698
0172045825AA82B4008FD63B /* OnboardingView.swift */,
699+
01A1339C2E08B2BB000AD24A /* OnboardingViewModel.swift */,
679700
0172045D25AA82B4008FD63B /* PermissionsLoadingView.swift */,
680701
0110A1602AC81978003EDCBA /* ResendConfirmationInstructionsView.swift */,
702+
01A133A22E08B4DA000AD24A /* ResendConfirmationInstructionsViewModel.swift */,
681703
01E0A60B25BD440300298D35 /* SignInEmailAndPasswordView.swift */,
704+
01A133A42E08BB1B000AD24A /* SignInEmailAndPasswordViewModel.swift */,
682705
011586112B567363005E8E8F /* SignUpOrSignInView.swift */,
683706
01E1CECB287787A700E724FC /* SignUpView.swift */,
707+
01A133A62E08BB66000AD24A /* SignUpViewModel.swift */,
684708
0172045C25AA82B4008FD63B /* SnackbarView.swift */,
685709
01ED197A2A037B9E00CD4735 /* AppTabView.swift */,
686710
);
@@ -962,6 +986,8 @@
962986
"",
963987
"",
964988
"",
989+
"",
990+
"",
965991
);
966992
};
967993
/* End PBXShellScriptBuildPhase section */
@@ -979,6 +1005,7 @@
9791005
0172052F25AC41A7008FD63B /* SessionRequest.swift in Sources */,
9801006
017278772D7D8FF100CE424F /* ItemTagsService.swift in Sources */,
9811007
017204C025AA846D008FD63B /* TabViewModel.swift in Sources */,
1008+
01A1339D2E08B2BB000AD24A /* OnboardingViewModel.swift in Sources */,
9821009
01B9E45228A5070D00CAC681 /* ShopkeeperSignInAdapter.swift in Sources */,
9831010
0172040025AA6775008FD63B /* LoginRepository.swift in Sources */,
9841011
0172034B25A9642E008FD63B /* EntityAdapter.swift in Sources */,
@@ -989,6 +1016,8 @@
9891016
01B526562AF4E82A00655131 /* ScrollToTopID.swift in Sources */,
9901017
0172033C25A9642E008FD63B /* NativeAppTemplateAPI.swift in Sources */,
9911018
017203B325A96FD6008FD63B /* UIApplication+DismissKeyboard.swift in Sources */,
1019+
01A133A72E08BB66000AD24A /* SignUpViewModel.swift in Sources */,
1020+
01A1339B2E08B0DF000AD24A /* MainViewModel.swift in Sources */,
9921021
0182D37825B277FA001E881D /* KeychainStore.swift in Sources */,
9931022
01FC03E22B3329B700E6CD8E /* NeedAppUpdatesView.swift in Sources */,
9941023
0172033725A9642E008FD63B /* JSONAPIResource.swift in Sources */,
@@ -1006,7 +1035,9 @@
10061035
0182D38225B296B9001E881D /* ShopkeeperAdapter.swift in Sources */,
10071036
01BE4F1D29CA6F8C002008BE /* TimeZoneData.swift in Sources */,
10081037
010F86BE2622F9C900B6C62A /* ShopListView.swift in Sources */,
1038+
01A133A12E08B4A5000AD24A /* ForgotPasswordViewModel.swift in Sources */,
10091039
011586122B567363005E8E8F /* SignUpOrSignInView.swift in Sources */,
1040+
01A133992E08B052000AD24A /* AcceptPrivacyViewModel.swift in Sources */,
10101041
01E727212B020ECC004AC043 /* Bundle+Extensions.swift in Sources */,
10111042
0172046925AA82BF008FD63B /* PermissionsLoadingView.swift in Sources */,
10121043
01B6F5A82601F83400397E66 /* PermissionsService.swift in Sources */,
@@ -1043,6 +1074,7 @@
10431074
0172035625A9642E008FD63B /* ShopAdapter.swift in Sources */,
10441075
0172788B2D7D936E00CE424F /* CompletedTag.swift in Sources */,
10451076
0172788C2D7D936E00CE424F /* IdlingTagView.swift in Sources */,
1077+
01A1339F2E08B2FD000AD24A /* AcceptTermsViewModel.swift in Sources */,
10461078
0172788D2D7D936E00CE424F /* CustomerScannedTag.swift in Sources */,
10471079
017278902D7D936E00CE424F /* TagView.swift in Sources */,
10481080
0106414429AA061100B46FED /* PasswordEditView.swift in Sources */,
@@ -1080,6 +1112,7 @@
10801112
01B526542AF4E36400655131 /* MainTab.swift in Sources */,
10811113
01D85B442E07ED8700A95798 /* ShopDetailViewModel.swift in Sources */,
10821114
017203CB25A97090008FD63B /* SessionController.swift in Sources */,
1115+
01A133A32E08B4DA000AD24A /* ResendConfirmationInstructionsViewModel.swift in Sources */,
10831116
0106413E29A9F1C300B46FED /* UpdatePassword.swift in Sources */,
10841117
0172787B2D7D903500CE424F /* ItemTagAdapter.swift in Sources */,
10851118
010F86AE2621A2A900B6C62A /* ShopDetailView.swift in Sources */,
@@ -1095,6 +1128,7 @@
10951128
018E21CB2B36367F00FFD1F6 /* MeRequest.swift in Sources */,
10961129
01E0A5B825BD0FCD00298D35 /* ErrorView.swift in Sources */,
10971130
0172789A2D7D99D100CE424F /* ItemTagListCardView.swift in Sources */,
1131+
01A133A52E08BB1B000AD24A /* SignInEmailAndPasswordViewModel.swift in Sources */,
10981132
0172789B2D7D99D100CE424F /* ItemTagListView.swift in Sources */,
10991133
0172789C2D7D99D100CE424F /* ItemTagDetailView.swift in Sources */,
11001134
01D85AEB2E07CF3600A95798 /* ItemTagEditViewModel.swift in Sources */,

NativeAppTemplate/Data/DataManager.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ import SwiftUI
1414
var sessionController: SessionControllerProtocol
1515

1616
// Repositories
17+
private(set) var onboardingRepository: OnboardingRepositoryProtocol!
18+
private(set) var signUpRepository: SignUpRepositoryProtocol!
1719
private(set) var accountPasswordRepository: AccountPasswordRepositoryProtocol!
1820
private(set) var shopRepository: ShopRepositoryProtocol!
1921
private(set) var itemTagRepository: ItemTagRepositoryProtocol!
@@ -40,6 +42,8 @@ import SwiftUI
4042
let shopsService = ShopsService(networkClient: sessionController.client)
4143
let itemTagsService = ItemTagsService(networkClient: sessionController.client)
4244

45+
onboardingRepository = OnboardingRepository()
46+
signUpRepository = SignUpRepository()
4347
accountPasswordRepository = AccountPasswordRepository(accountPasswordService: accountPasswordService)
4448
shopRepository = ShopRepository(shopsService: shopsService)
4549
itemTagRepository = ItemTagRepository(itemTagsService: itemTagsService)

NativeAppTemplate/UI/App Root/AcceptPrivacyView.swift

Lines changed: 17 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -9,66 +9,53 @@ import SwiftUI
99

1010
struct AcceptPrivacyView: View {
1111
@Environment(\.dismiss) private var dismiss
12-
@Environment(MessageBus.self) private var messageBus
13-
@Environment(\.sessionController) private var sessionController
1412
@Binding var arePrivacyAccepted: Bool
15-
@State private var isUpdating = false
13+
let viewModel: AcceptPrivacyViewModel
1614

1715
var body: some View {
1816
contentView
17+
.onChange(of: viewModel.arePrivacyAccepted) { _, arePrivacyAccepted in
18+
if arePrivacyAccepted {
19+
self.arePrivacyAccepted = true
20+
}
21+
}
22+
.onChange(of: viewModel.shouldDismiss) { _, shouldDismiss in
23+
if shouldDismiss {
24+
dismiss()
25+
}
26+
}
1927
}
2028
}
2129

2230
// MARK: - private
2331
private extension AcceptPrivacyView {
2432
var contentView: some View {
25-
33+
2634
@ViewBuilder var contentView: some View {
27-
if isUpdating {
35+
if viewModel.isUpdating {
2836
LoadingView()
2937
} else {
3038
acceptPrivacyView
3139
}
3240
}
33-
41+
3442
return contentView
3543
}
36-
44+
3745
var acceptPrivacyView: some View {
3846
VStack {
3947
let agreement = "Please accept updated [\(String.privacyPolicy)](\(String.privacyPolicyUrl))."
4048
Text(.init(agreement))
4149
.padding(.top, 48)
4250

4351
MainButtonView(title: String.accept, type: .primary(withArrow: false)) {
44-
updateConfirmedPrivacyVersion()
52+
viewModel.updateConfirmedPrivacyVersion()
4553
}
4654
.padding(24)
47-
55+
4856
Spacer()
4957
}
5058
.navigationTitle(String.privacyPolicyUpdated)
5159
.navigationBarTitleDisplayMode(.inline)
5260
}
53-
54-
private func updateConfirmedPrivacyVersion() {
55-
Task { @MainActor in
56-
do {
57-
isUpdating = true
58-
try await sessionController.updateConfirmedPrivacyVersion()
59-
messageBus.post(message: Message(level: .success, message: .confirmedPrivacyVersionUpdated))
60-
} catch {
61-
messageBus.post(message: Message(level: .error, message: "\(String.confirmedPrivacyVersionUpdatedError) \(error.localizedDescription)", autoDismiss: false))
62-
}
63-
64-
arePrivacyAccepted = true
65-
dismiss()
66-
}
67-
}
68-
}
69-
70-
#Preview {
71-
@Previewable @State var arePrivacyAccepted = true
72-
73-
return AcceptPrivacyView(arePrivacyAccepted: $arePrivacyAccepted)
7461
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
//
2+
// AcceptPrivacyViewModel.swift
3+
// NativeAppTemplate
4+
//
5+
// Created by Daisuke Adachi on 2025/06/16.
6+
//
7+
8+
import SwiftUI
9+
import Observation
10+
11+
@Observable
12+
@MainActor
13+
final class AcceptPrivacyViewModel {
14+
var isUpdating = false
15+
var shouldDismiss = false
16+
var arePrivacyAccepted = false
17+
18+
private let sessionController: SessionControllerProtocol
19+
private let messageBus: MessageBus
20+
21+
init(
22+
sessionController: SessionControllerProtocol,
23+
messageBus: MessageBus
24+
) {
25+
self.sessionController = sessionController
26+
self.messageBus = messageBus
27+
}
28+
29+
func updateConfirmedPrivacyVersion() {
30+
Task { @MainActor in
31+
do {
32+
isUpdating = true
33+
try await sessionController.updateConfirmedPrivacyVersion()
34+
messageBus.post(message: Message(level: .success, message: .confirmedPrivacyVersionUpdated))
35+
} catch {
36+
messageBus.post(message: Message(level: .error, message: "\(String.confirmedPrivacyVersionUpdatedError) \(error.localizedDescription)", autoDismiss: false))
37+
}
38+
39+
arePrivacyAccepted = true
40+
shouldDismiss = true
41+
isUpdating = false
42+
}
43+
}
44+
}

NativeAppTemplate/UI/App Root/AcceptTermsView.swift

Lines changed: 17 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -9,66 +9,53 @@ import SwiftUI
99

1010
struct AcceptTermsView: View {
1111
@Environment(\.dismiss) private var dismiss
12-
@Environment(MessageBus.self) private var messageBus
13-
@Environment(\.sessionController) private var sessionController
1412
@Binding var areTermsAccepted: Bool
15-
@State private var isUpdating = false
13+
let viewModel: AcceptTermsViewModel
1614

1715
var body: some View {
1816
contentView
17+
.onChange(of: viewModel.areTermsAccepted) { _, areTermsAccepted in
18+
if areTermsAccepted {
19+
self.areTermsAccepted = true
20+
}
21+
}
22+
.onChange(of: viewModel.shouldDismiss) { _, shouldDismiss in
23+
if shouldDismiss {
24+
dismiss()
25+
}
26+
}
1927
}
2028
}
2129

2230
// MARK: - private
2331
private extension AcceptTermsView {
2432
var contentView: some View {
25-
33+
2634
@ViewBuilder var contentView: some View {
27-
if isUpdating {
35+
if viewModel.isUpdating {
2836
LoadingView()
2937
} else {
3038
acceptTermsView
3139
}
3240
}
33-
41+
3442
return contentView
3543
}
36-
44+
3745
var acceptTermsView: some View {
3846
VStack {
3947
let agreement = "Please accept updated [\(String.termsOfUse)](\(String.termsOfUseUrl))."
4048
Text(.init(agreement))
4149
.padding(.top, 48)
4250

4351
MainButtonView(title: String.accept, type: .primary(withArrow: false)) {
44-
updateConfirmedTermsVersion()
52+
viewModel.updateConfirmedTermsVersion()
4553
}
4654
.padding(24)
47-
55+
4856
Spacer()
4957
}
5058
.navigationTitle(String.termsOfUseUpdated)
5159
.navigationBarTitleDisplayMode(.inline)
5260
}
53-
54-
private func updateConfirmedTermsVersion() {
55-
Task { @MainActor in
56-
do {
57-
isUpdating = true
58-
try await sessionController.updateConfirmedTermsVersion()
59-
messageBus.post(message: Message(level: .success, message: .confirmedTermsVersionUpdated))
60-
} catch {
61-
messageBus.post(message: Message(level: .error, message: "\(String.confirmedTermsVersionUpdatedError) \(error.localizedDescription)", autoDismiss: false))
62-
}
63-
64-
areTermsAccepted = true
65-
dismiss()
66-
}
67-
}
68-
}
69-
70-
#Preview {
71-
@Previewable @State var areTermsAccepted = true
72-
73-
return AcceptTermsView(areTermsAccepted: $areTermsAccepted)
7461
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
//
2+
// AcceptTermsViewModel.swift
3+
// NativeAppTemplate
4+
//
5+
// Created by Daisuke Adachi on 2025/06/16.
6+
//
7+
8+
import SwiftUI
9+
import Observation
10+
11+
@Observable
12+
@MainActor
13+
final class AcceptTermsViewModel {
14+
var isUpdating = false
15+
var shouldDismiss = false
16+
var areTermsAccepted = false
17+
18+
private let sessionController: SessionControllerProtocol
19+
private let messageBus: MessageBus
20+
21+
init(
22+
sessionController: SessionControllerProtocol,
23+
messageBus: MessageBus
24+
) {
25+
self.sessionController = sessionController
26+
self.messageBus = messageBus
27+
}
28+
29+
func updateConfirmedTermsVersion() {
30+
Task { @MainActor in
31+
do {
32+
isUpdating = true
33+
try await sessionController.updateConfirmedTermsVersion()
34+
messageBus.post(message: Message(level: .success, message: .confirmedTermsVersionUpdated))
35+
} catch {
36+
messageBus.post(message: Message(level: .error, message: "\(String.confirmedTermsVersionUpdatedError) \(error.localizedDescription)", autoDismiss: false))
37+
}
38+
39+
areTermsAccepted = true
40+
shouldDismiss = true
41+
isUpdating = false
42+
}
43+
}
44+
}

0 commit comments

Comments
 (0)