Skip to content

Commit a4a09e0

Browse files
committed
add SessionControllerProtocol
1 parent e74d897 commit a4a09e0

26 files changed

Lines changed: 142 additions & 103 deletions

NativeAppTemplate.xcodeproj/project.pbxproj

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,6 @@
5555
017203A325A96F7B008FD63B /* Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 017203A225A96F7A008FD63B /* Constants.swift */; };
5656
017203B325A96FD6008FD63B /* UIApplication+DismissKeyboard.swift in Sources */ = {isa = PBXBuildFile; fileRef = 017203A825A96FBF008FD63B /* UIApplication+DismissKeyboard.swift */; };
5757
017203B625A96FD6008FD63B /* View+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 017203AB25A96FBF008FD63B /* View+Extensions.swift */; };
58-
017203CA25A97090008FD63B /* SessionController+States.swift in Sources */ = {isa = PBXBuildFile; fileRef = 017203C825A9708A008FD63B /* SessionController+States.swift */; };
5958
017203CB25A97090008FD63B /* SessionController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 017203C725A9708A008FD63B /* SessionController.swift */; };
6059
017203EB25AA6606008FD63B /* Logger.swift in Sources */ = {isa = PBXBuildFile; fileRef = 017203EA25AA6601008FD63B /* Logger.swift */; };
6160
0172040025AA6775008FD63B /* LoginRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = 017203F525AA675E008FD63B /* LoginRepository.swift */; };
@@ -124,6 +123,7 @@
124123
0199CD2A2E07512100109DC6 /* OnboardingRepositoryProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0199CD282E07512100109DC6 /* OnboardingRepositoryProtocol.swift */; };
125124
0199CD2B2E07512100109DC6 /* SignUpRepositoryProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0199CD292E07512100109DC6 /* SignUpRepositoryProtocol.swift */; };
126125
0199CD2C2E07512100109DC6 /* LoginRepositoryProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0199CD272E07512100109DC6 /* LoginRepositoryProtocol.swift */; };
126+
0199CD3E2E075CBB00109DC6 /* SessionControllerProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0199CD3D2E075CBB00109DC6 /* SessionControllerProtocol.swift */; };
127127
01B37C7629B0960700BF5B2D /* ForgotPasswordView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01B37C7529B0960700BF5B2D /* ForgotPasswordView.swift */; };
128128
01B526542AF4E36400655131 /* MainTab.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01B526532AF4E36400655131 /* MainTab.swift */; };
129129
01B526562AF4E82A00655131 /* ScrollToTopID.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01B526552AF4E82A00655131 /* ScrollToTopID.swift */; };
@@ -210,7 +210,6 @@
210210
017203A825A96FBF008FD63B /* UIApplication+DismissKeyboard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIApplication+DismissKeyboard.swift"; sourceTree = "<group>"; };
211211
017203AB25A96FBF008FD63B /* View+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "View+Extensions.swift"; sourceTree = "<group>"; };
212212
017203C725A9708A008FD63B /* SessionController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionController.swift; sourceTree = "<group>"; };
213-
017203C825A9708A008FD63B /* SessionController+States.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SessionController+States.swift"; sourceTree = "<group>"; };
214213
017203EA25AA6601008FD63B /* Logger.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Logger.swift; sourceTree = "<group>"; };
215214
017203F525AA675E008FD63B /* LoginRepository.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginRepository.swift; sourceTree = "<group>"; };
216215
0172045725AA82B4008FD63B /* MainView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainView.swift; sourceTree = "<group>"; };
@@ -278,6 +277,7 @@
278277
0199CD272E07512100109DC6 /* LoginRepositoryProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginRepositoryProtocol.swift; sourceTree = "<group>"; };
279278
0199CD282E07512100109DC6 /* OnboardingRepositoryProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingRepositoryProtocol.swift; sourceTree = "<group>"; };
280279
0199CD292E07512100109DC6 /* SignUpRepositoryProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SignUpRepositoryProtocol.swift; sourceTree = "<group>"; };
280+
0199CD3D2E075CBB00109DC6 /* SessionControllerProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionControllerProtocol.swift; sourceTree = "<group>"; };
281281
01B37C7529B0960700BF5B2D /* ForgotPasswordView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ForgotPasswordView.swift; sourceTree = "<group>"; };
282282
01B526532AF4E36400655131 /* MainTab.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainTab.swift; sourceTree = "<group>"; };
283283
01B526552AF4E82A00655131 /* ScrollToTopID.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScrollToTopID.swift; sourceTree = "<group>"; };
@@ -576,9 +576,9 @@
576576
017203C525A9708A008FD63B /* Sessions */ = {
577577
isa = PBXGroup;
578578
children = (
579-
01E0A62125BD4A7800298D35 /* Shopkeeper+Backdoor.swift */,
580579
017203C725A9708A008FD63B /* SessionController.swift */,
581-
017203C825A9708A008FD63B /* SessionController+States.swift */,
580+
0199CD3D2E075CBB00109DC6 /* SessionControllerProtocol.swift */,
581+
01E0A62125BD4A7800298D35 /* Shopkeeper+Backdoor.swift */,
582582
);
583583
path = Sessions;
584584
sourceTree = "<group>";
@@ -913,6 +913,7 @@
913913
"fi",
914914
"",
915915
"",
916+
"",
916917
);
917918
};
918919
/* End PBXShellScriptBuildPhase section */
@@ -950,6 +951,7 @@
950951
0199CD2C2E07512100109DC6 /* LoginRepositoryProtocol.swift in Sources */,
951952
0172033D25A9642E008FD63B /* NativeAppTemplateEnvironment.swift in Sources */,
952953
0172787F2D7D933000CE424F /* ShopDetailCardView.swift in Sources */,
954+
0199CD3E2E075CBB00109DC6 /* SessionControllerProtocol.swift in Sources */,
953955
01EE363E29A6DCEB009BCD9D /* ShopkeeperEditView.swift in Sources */,
954956
0182D38225B296B9001E881D /* ShopkeeperAdapter.swift in Sources */,
955957
01BE4F1D29CA6F8C002008BE /* TimeZoneData.swift in Sources */,
@@ -970,7 +972,6 @@
970972
0172051A25AAF6C0008FD63B /* SessionsService.swift in Sources */,
971973
017204D125AA8479008FD63B /* DataState.swift in Sources */,
972974
012643372B3554AD00D4E9BD /* AcceptTermsView.swift in Sources */,
973-
017203CA25A97090008FD63B /* SessionController+States.swift in Sources */,
974975
0172033E25A9642E008FD63B /* Parameters.swift in Sources */,
975976
0150A36629B14BB300907F96 /* SendResetPassword.swift in Sources */,
976977
017204B625AA8467008FD63B /* DataManager.swift in Sources */,

NativeAppTemplate/App.swift

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,48 @@ import Foundation
99
import SwiftUI
1010
import TipKit
1111

12+
private struct SessionControllerKey: EnvironmentKey {
13+
static let defaultValue: any SessionControllerProtocol = MainActor.assumeIsolated {
14+
NullSessionController()
15+
}
16+
}
17+
18+
extension EnvironmentValues {
19+
var sessionController: any SessionControllerProtocol {
20+
get { self[SessionControllerKey.self] }
21+
set { self[SessionControllerKey.self] = newValue }
22+
}
23+
}
24+
25+
// Null object pattern for default value
26+
@MainActor
27+
private final class NullSessionController: SessionControllerProtocol {
28+
var sessionState: SessionState { .unknown }
29+
var userState: UserState { .notLoggedIn }
30+
var permissionState: PermissionState { .notLoaded }
31+
var didFetchPermissions: Bool { false }
32+
var shouldPopToRootView: Bool = false
33+
var didBackgroundTagReading: Bool = false
34+
var completeScanResult = CompleteScanResult()
35+
var showTagInfoScanResult = ShowTagInfoScanResult()
36+
var shouldUpdateApp: Bool = false
37+
var shouldUpdatePrivacy: Bool = false
38+
var shouldUpdateTerms: Bool = false
39+
var maximumQueueNumberLength: Int = 0
40+
var shopLimitCount: Int = 0
41+
var shopkeeper: Shopkeeper?
42+
var hasPermissions: Bool { false }
43+
var isLoggedIn: Bool { false }
44+
var client: NativeAppTemplateAPI { NativeAppTemplateAPI() }
45+
func login(email: String, password: String) async throws {}
46+
func logout() async throws {}
47+
func fetchPermissionsIfNeeded() {}
48+
func fetchPermissions() {}
49+
func updateShopkeeper(shopkeeper: Shopkeeper?) throws {}
50+
func updateConfirmedPrivacyVersion() async throws {}
51+
func updateConfirmedTermsVersion() async throws {}
52+
}
53+
1254
@main
1355
struct App {
1456
typealias Objects = ( // swiftlint:disable:this large_tuple
@@ -48,7 +90,7 @@ extension App: SwiftUI.App {
4890
MainView()
4991
.preferredColorScheme(.dark) // Dark mode only
5092
.environment(loginRepository)
51-
.environment(sessionController)
93+
.environment(\.sessionController, sessionController)
5294
.environment(dataManager)
5395
.environment(messageBus)
5496
}

NativeAppTemplate/Data/DataManager.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import SwiftUI
1111

1212
// MARK: - Properties
1313
// Initialiser Arguments
14-
var sessionController: SessionController
14+
var sessionController: SessionControllerProtocol
1515

1616
// Repositories
1717
private(set) var accountPasswordRepository: AccountPasswordRepositoryProtocol!
@@ -20,7 +20,7 @@ import SwiftUI
2020
private(set) var isRebuildingRepositories = false
2121

2222
// MARK: - Initializers
23-
init(sessionController: SessionController) {
23+
init(sessionController: SessionControllerProtocol) {
2424
self.sessionController = sessionController
2525
rebuildRepositories()
2626
}

NativeAppTemplate/Networking/Network/NativeAppTemplateAPI.swift

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,8 +86,12 @@ public struct NativeAppTemplateAPI: Equatable {
8686
let contentTypeHeader: HTTPHeader = ("Content-Type", "application/vnd.api+json; charset=utf-8")
8787
var additionalHeaders: HTTPHeaders = [:]
8888

89+
nonisolated init() {
90+
self.init(authToken: "", client: "", expiry: "", uid: "", accountId: "")
91+
}
92+
8993
// MARK: - Initializers
90-
init(
94+
nonisolated init(
9195
session: URLSession = .init(configuration: .default),
9296
environment: NativeAppTemplateEnvironment = .prod,
9397
authToken: String,

NativeAppTemplate/Sessions/SessionController+States.swift

Lines changed: 0 additions & 50 deletions
This file was deleted.

NativeAppTemplate/Sessions/SessionController.swift

Lines changed: 4 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,15 @@
1-
// Copyright (c) 2019 Razeware LLC
21
//
3-
// Permission is hereby granted, free of charge, to any person obtaining a copy
4-
// of this software and associated documentation files (the "Software"), to deal
5-
// in the Software without restriction, including without limitation the rights
6-
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7-
// copies of the Software, and to permit persons to whom the Software is
8-
// furnished to do so, subject to the following conditions:
2+
// SessionController.swift
3+
// NativeAppTemplate
94
//
10-
// The above copyright notice and this permission notice shall be included in
11-
// all copies or substantial portions of the Software.
5+
// Created by Daisuke Adachi on 2023/12/23.
126
//
13-
// Notwithstanding the foregoing, you may not use, copy, modify, merge, publish,
14-
// distribute, sublicense, create a derivative work, and/or sell copies of the
15-
// Software in any work that is designed, intended, or marketed for pedagogical or
16-
// instructional purposes related to programming, coding, application development,
17-
// or information technology. Permission for such use, copying, modification,
18-
// merger, publication, distribution, sublicensing, creation of derivative works,
19-
// or sale is expressly withheld.
20-
//
21-
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22-
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23-
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24-
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25-
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26-
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
27-
// THE SOFTWARE.
287

298
import Foundation
309
import Network
3110
import Observation
3211

33-
@MainActor @Observable class SessionController {
12+
@MainActor @Observable class SessionController: SessionControllerProtocol {
3413
// Managing the state of the current session
3514
private(set) var sessionState: SessionState = .unknown
3615
private(set) var userState: UserState = .notLoggedIn
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
//
2+
// SessionControllerProtocol.swift
3+
// NativeAppTemplate
4+
//
5+
// Created by Daisuke Adachi on 2025/04/25.
6+
//
7+
8+
import Foundation
9+
10+
public enum UserState: Sendable {
11+
case loggedIn
12+
case loggingIn
13+
case notLoggedIn
14+
}
15+
16+
public enum SessionState: Sendable {
17+
case unknown
18+
case online
19+
case offline
20+
}
21+
22+
public enum PermissionState: Equatable, Sendable {
23+
case notLoaded
24+
case loading
25+
case loaded
26+
case error
27+
}
28+
29+
@MainActor
30+
protocol SessionControllerProtocol: AnyObject, Observable, Sendable {
31+
// MARK: - Properties
32+
var sessionState: SessionState { get }
33+
var userState: UserState { get }
34+
var permissionState: PermissionState { get }
35+
var didFetchPermissions: Bool { get }
36+
37+
var shouldPopToRootView: Bool { get set }
38+
var didBackgroundTagReading: Bool { get set }
39+
40+
var completeScanResult: CompleteScanResult { get set }
41+
var showTagInfoScanResult: ShowTagInfoScanResult { get set }
42+
43+
var shouldUpdateApp: Bool { get set }
44+
var shouldUpdatePrivacy: Bool { get set }
45+
var shouldUpdateTerms: Bool { get set }
46+
var maximumQueueNumberLength: Int { get set }
47+
var shopLimitCount: Int { get set }
48+
49+
var shopkeeper: Shopkeeper? { get set }
50+
var hasPermissions: Bool { get }
51+
52+
var isLoggedIn: Bool { get }
53+
var client: NativeAppTemplateAPI { get }
54+
55+
// MARK: - Methods
56+
func login(email: String, password: String) async throws
57+
func logout() async throws
58+
func fetchPermissionsIfNeeded()
59+
func fetchPermissions()
60+
func updateShopkeeper(shopkeeper: Shopkeeper?) throws
61+
func updateConfirmedPrivacyVersion() async throws
62+
func updateConfirmedTermsVersion() async throws
63+
}

NativeAppTemplate/UI/App Root/AcceptPrivacyView.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import SwiftUI
1010
struct AcceptPrivacyView: View {
1111
@Environment(\.dismiss) private var dismiss
1212
@Environment(MessageBus.self) private var messageBus
13-
@Environment(SessionController.self) private var sessionController
13+
@Environment(\.sessionController) private var sessionController
1414
@Binding var arePrivacyAccepted: Bool
1515
@State private var isUpdating = false
1616

NativeAppTemplate/UI/App Root/AcceptTermsView.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import SwiftUI
1010
struct AcceptTermsView: View {
1111
@Environment(\.dismiss) private var dismiss
1212
@Environment(MessageBus.self) private var messageBus
13-
@Environment(SessionController.self) private var sessionController
13+
@Environment(\.sessionController) private var sessionController
1414
@Binding var areTermsAccepted: Bool
1515
@State private var isUpdating = false
1616

NativeAppTemplate/UI/App Root/AppTabView.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ struct AppTabView<
1313
SettingsView: View
1414
> {
1515

16-
@Environment(SessionController.self) private var sessionController
16+
@Environment(\.sessionController) private var sessionController
1717
@Environment(DataManager.self) private var dataManager
1818
@Environment(TabViewModel.self) private var model
1919
@State var navigationPathShops = NavigationPath()

0 commit comments

Comments
 (0)