Skip to content

Commit 555a2e6

Browse files
committed
Adjust host app to use store
1 parent f8c565a commit 555a2e6

File tree

9 files changed

+329
-178
lines changed

9 files changed

+329
-178
lines changed

Core/Sources/HostApp/CustomCommandSettings/CustomCommand.swift

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ struct CustomCommandFeature: ReducerProtocol {
99
}
1010

1111
let settings: CustomCommandView.Settings
12-
let toast: (Text, ToastType) -> Void
1312

1413
enum Action: Equatable {
1514
case createNewCommand
@@ -18,6 +17,8 @@ struct CustomCommandFeature: ReducerProtocol {
1817
case deleteCommand(CustomCommand)
1918
}
2019

20+
@Dependency(\.toastController) var toastController
21+
2122
var body: some ReducerProtocol<State, Action> {
2223
Reduce { state, action in
2324
switch action {
@@ -43,7 +44,7 @@ struct CustomCommandFeature: ReducerProtocol {
4344

4445
}
4546
}.ifLet(\.editCustomCommand, action: /Action.editCustomCommand) {
46-
EditCustomCommand(settings: settings, toast: toast)
47+
EditCustomCommand(settings: settings)
4748
}
4849
}
4950
}

Core/Sources/HostApp/CustomCommandSettings/CustomCommandView.swift

Lines changed: 3 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,7 @@ extension List {
1717
let customCommandStore = StoreOf<CustomCommandFeature>(
1818
initialState: .init(),
1919
reducer: CustomCommandFeature(
20-
settings: .init(),
21-
toast: { content, type in
22-
Task { @MainActor in
23-
globalToastController.toast(content: content, type: type)
24-
}
25-
}
20+
settings: .init()
2621
)
2722
)
2823

@@ -247,10 +242,7 @@ struct CustomCommandView_Preview: PreviewProvider {
247242
)
248243
)))
249244
),
250-
reducer: CustomCommandFeature(
251-
settings: settings,
252-
toast: { _, _ in }
253-
)
245+
reducer: CustomCommandFeature(settings: settings)
254246
),
255247
settings: settings
256248
)
@@ -286,10 +278,7 @@ struct CustomCommandView_NoEditing_Preview: PreviewProvider {
286278
initialState: .init(
287279
editCustomCommand: nil
288280
),
289-
reducer: CustomCommandFeature(
290-
settings: settings,
291-
toast: { _, _ in }
292-
)
281+
reducer: CustomCommandFeature(settings: settings)
293282
),
294283
settings: settings
295284
)

Core/Sources/HostApp/CustomCommandSettings/EditCustomCommand.swift

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,8 @@ struct EditCustomCommand: ReducerProtocol {
8484
}
8585

8686
let settings: CustomCommandView.Settings
87-
let toast: (Text, ToastType) -> Void
87+
88+
@Dependency(\.toastController) var toastController
8889

8990
var body: some ReducerProtocol<State, Action> {
9091
Scope(state: \.sendMessage, action: /Action.sendMessage) {
@@ -109,7 +110,10 @@ struct EditCustomCommand: ReducerProtocol {
109110
switch action {
110111
case .saveCommand:
111112
guard !state.name.isEmpty else {
112-
toast(Text("Command name cannot be empty."), .error)
113+
toastController.toast(
114+
content: Text("Command name cannot be empty."),
115+
type: .error
116+
)
113117
return .none
114118
}
115119

@@ -154,7 +158,7 @@ struct EditCustomCommand: ReducerProtocol {
154158
if state.isNewCommand {
155159
settings.customCommands.append(newCommand)
156160
state.isNewCommand = false
157-
toast(Text("The command is created."), .info)
161+
toastController.toast(content: Text("The command is created."), type: .info)
158162
} else {
159163
if let index = settings.customCommands.firstIndex(where: {
160164
$0.id == newCommand.id
@@ -163,7 +167,7 @@ struct EditCustomCommand: ReducerProtocol {
163167
} else {
164168
settings.customCommands.append(newCommand)
165169
}
166-
toast(Text("The command is updated."), .info)
170+
toastController.toast(content: Text("The command is updated."), type: .info)
167171
}
168172

169173
return .none

Core/Sources/HostApp/CustomCommandSettings/EditCustomCommandView.swift

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -243,8 +243,7 @@ struct EditCustomCommandView_Preview: PreviewProvider {
243243
settings: .init(customCommands: .init(
244244
wrappedValue: [],
245245
"CustomCommandView_Preview"
246-
)),
247-
toast: { _, _ in }
246+
))
248247
)
249248
)
250249
)

Core/Sources/HostApp/General.swift

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
import Client
2+
import ComposableArchitecture
3+
import Foundation
4+
import LaunchAgentManager
5+
import SwiftUI
6+
7+
struct General: ReducerProtocol {
8+
struct State: Equatable {
9+
var xpcServiceVersion: String?
10+
var isAccessibilityPermissionGranted: Bool?
11+
var isReloading = false
12+
}
13+
14+
enum Action: Equatable {
15+
case appear
16+
case setupLaunchAgentIfNeeded
17+
case reloadStatus
18+
case finishReloading(xpcServiceVersion: String, permissionGranted: Bool)
19+
case failedReloading
20+
}
21+
22+
@Dependency(\.toastController) var toastController
23+
24+
var body: some ReducerProtocol<State, Action> {
25+
Reduce { state, action in
26+
switch action {
27+
case .appear:
28+
return .run { send in
29+
await send(.setupLaunchAgentIfNeeded)
30+
}
31+
case .setupLaunchAgentIfNeeded:
32+
return .run { send in
33+
#if DEBUG
34+
// do not auto install on debug build
35+
#else
36+
Task {
37+
do {
38+
try await LaunchAgentManager()
39+
.setupLaunchAgentForTheFirstTimeIfNeeded()
40+
} catch {
41+
toastController.toast(
42+
content: Text(error.localizedDescription),
43+
type: .error
44+
)
45+
}
46+
}
47+
#endif
48+
await send(.reloadStatus)
49+
}
50+
case .reloadStatus:
51+
state.isReloading = true
52+
return .run { send in
53+
let service = try getService()
54+
do {
55+
let xpcServiceVersion = try await service.getXPCServiceVersion().version
56+
let isAccessibilityPermissionGranted = try await service
57+
.getXPCServiceAccessibilityPermission()
58+
await send(.finishReloading(
59+
xpcServiceVersion: xpcServiceVersion,
60+
permissionGranted: isAccessibilityPermissionGranted
61+
))
62+
} catch {
63+
toastController.toast(
64+
content: Text(error.localizedDescription),
65+
type: .error
66+
)
67+
await send(.failedReloading)
68+
}
69+
}
70+
71+
case let .finishReloading(version, granted):
72+
state.xpcServiceVersion = version
73+
state.isAccessibilityPermissionGranted = granted
74+
state.isReloading = false
75+
return .none
76+
77+
case .failedReloading:
78+
state.isReloading = false
79+
return .none
80+
}
81+
}
82+
}
83+
}
84+

Core/Sources/HostApp/GeneralView.swift

Lines changed: 25 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,27 @@
11
import Client
2+
import ComposableArchitecture
23
import LaunchAgentManager
34
import Preferences
45
import SwiftUI
56

67
struct GeneralView: View {
8+
let store: StoreOf<General>
9+
710
var body: some View {
811
ScrollView {
912
VStack(alignment: .leading, spacing: 0) {
1013
AppInfoView()
1114
Divider()
12-
ExtensionServiceView()
15+
ExtensionServiceView(store: store)
1316
Divider()
1417
LaunchAgentView()
1518
Divider()
1619
GeneralSettingsView()
1720
}
1821
}
22+
.onAppear {
23+
store.send(.appear)
24+
}
1925
}
2026
}
2127

@@ -74,24 +80,28 @@ struct AppInfoView: View {
7480
}
7581

7682
struct ExtensionServiceView: View {
77-
@Environment(\.toast) var toast
78-
@State var xpcServiceVersion: String?
79-
@State var isAccessibilityPermissionGranted: Bool?
80-
@State var isRunningAction = false
83+
let store: StoreOf<General>
8184

8285
var body: some View {
8386
VStack(alignment: .leading) {
84-
Text("Extension Service Version: \(xpcServiceVersion ?? "Loading..")")
85-
let grantedStatus: String = {
86-
guard let isAccessibilityPermissionGranted else { return "Loading.." }
87-
return isAccessibilityPermissionGranted ? "Granted" : "Not Granted"
88-
}()
89-
Text("Accessibility Permission: \(grantedStatus)")
87+
WithViewStore(store, observe: { $0.xpcServiceVersion }) { viewStore in
88+
Text("Extension Service Version: \(viewStore.state ?? "Loading..")")
89+
}
90+
91+
WithViewStore(store, observe: { $0.isAccessibilityPermissionGranted }) { viewStore in
92+
let grantedStatus: String = {
93+
guard let granted = viewStore.state else { return "Loading.." }
94+
return granted ? "Granted" : "Not Granted"
95+
}()
96+
Text("Accessibility Permission: \(grantedStatus)")
97+
}
9098

9199
HStack {
92-
Button(action: { checkStatus() }) {
93-
Text("Refresh")
94-
}.disabled(isRunningAction)
100+
WithViewStore(store, observe: { $0.isReloading }) { viewStore in
101+
Button(action: { viewStore.send(.reloadStatus) }) {
102+
Text("Refresh")
103+
}.disabled(viewStore.state)
104+
}
95105

96106
Button(action: {
97107
Task {
@@ -126,25 +136,6 @@ struct ExtensionServiceView: View {
126136
}
127137
}
128138
.padding()
129-
.onAppear {
130-
checkStatus()
131-
}
132-
}
133-
134-
func checkStatus() {
135-
Task {
136-
try await Task.sleep(nanoseconds: 2_000_000_000)
137-
isRunningAction = true
138-
defer { isRunningAction = false }
139-
do {
140-
let service = try getService()
141-
xpcServiceVersion = try await service.getXPCServiceVersion().version
142-
isAccessibilityPermissionGranted = try await service
143-
.getXPCServiceAccessibilityPermission()
144-
} catch {
145-
toast(Text(error.localizedDescription), .error)
146-
}
147-
}
148139
}
149140
}
150141

@@ -298,7 +289,7 @@ struct GeneralSettingsView: View {
298289

299290
struct GeneralView_Previews: PreviewProvider {
300291
static var previews: some View {
301-
GeneralView()
292+
GeneralView(store: .init(initialState: .init(), reducer: General()))
302293
}
303294
}
304295

Core/Sources/HostApp/HostApp.swift

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import Foundation
2+
import ComposableArchitecture
3+
4+
struct HostApp: ReducerProtocol {
5+
struct State: Equatable {
6+
var general = General.State()
7+
}
8+
9+
enum Action: Equatable {
10+
case appear
11+
case general(General.Action)
12+
}
13+
14+
var body: some ReducerProtocol<State, Action> {
15+
Scope(state: \.general, action: /Action.general) {
16+
General()
17+
}
18+
19+
Reduce { _, action in
20+
switch action {
21+
case .appear:
22+
return .none
23+
case .general:
24+
return .none
25+
}
26+
}
27+
}
28+
}

0 commit comments

Comments
 (0)