Skip to content

Commit e43976f

Browse files
committed
Refactoring: welcome to Composable
1 parent 56de1f1 commit e43976f

20 files changed

Lines changed: 180 additions & 106 deletions

LocalPackage/Sources/DataSource/Entities/ShiftPattern.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
import SpiceKey
2222
import SwiftUI
2323

24-
public struct ShiftPattern: Codable, Identifiable, Sendable {
24+
public struct ShiftPattern: Sendable, Codable, Identifiable {
2525
enum CodingKeys: String, CodingKey {
2626
case shiftType
2727
case spiceKeyData

LocalPackage/Sources/DataSource/Entities/ShiftType.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020

2121
import Foundation
2222

23-
public enum ShiftType: Int, Codable, Identifiable, Sendable, CaseIterable {
23+
public enum ShiftType: Int, Sendable, Codable, Identifiable, CaseIterable {
2424
case topHalf
2525
case bottomHalf
2626
case leftHalf
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/*
2+
Composable.swift
3+
Model
4+
5+
Created by Takuto Nakamura on 2025/08/13.
6+
Copyright 2022 Takuto Nakamura (Kyome22)
7+
8+
Licensed under the Apache License, Version 2.0 (the "License");
9+
you may not use this file except in compliance with the License.
10+
You may obtain a copy of the License at
11+
12+
http://www.apache.org/licenses/LICENSE-2.0
13+
14+
Unless required by applicable law or agreed to in writing, software
15+
distributed under the License is distributed on an "AS IS" BASIS,
16+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17+
See the License for the specific language governing permissions and
18+
limitations under the License.
19+
*/
20+
21+
import Observation
22+
23+
@MainActor
24+
public protocol Composable: AnyObject {
25+
associatedtype Action: Sendable
26+
27+
var action: (Action) async -> Void { get }
28+
29+
func reduce(_ action: Action) async
30+
}
31+
32+
public extension Composable {
33+
func reduce(_ action: Action) async {}
34+
35+
func send(_ action: Action) async {
36+
await self.action(action)
37+
await reduce(action)
38+
}
39+
}

LocalPackage/Sources/Model/Extensions/String+Extension.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ import Foundation
2222

2323
extension String {
2424
static let screenNumber = "NSScreenNumber"
25+
static let kAXFullScreen = "AXFullScreen"
2526
public static let shortcutPanel = "shortcutPanel"
26-
public static let kAXFullScreen = "AXFullScreen"
2727
public static let keyEquivalent = "keyEquivalent"
2828
}

LocalPackage/Sources/Model/Services/LogService.swift

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,16 +22,16 @@ import Foundation
2222
import DataSource
2323
import Logging
2424

25-
public struct LogService {
25+
struct LogService {
2626
private let appStateClient: AppStateClient
2727
private let loggingSystemClient: LoggingSystemClient
2828

29-
public init(_ appDependencies: AppDependencies) {
29+
init(_ appDependencies: AppDependencies) {
3030
self.appStateClient = appDependencies.appStateClient
3131
self.loggingSystemClient = appDependencies.loggingSystemClient
3232
}
3333

34-
public func bootstrap() {
34+
func bootstrap() {
3535
guard !appStateClient.withLock(\.hasAlreadyBootstrap) else {
3636
return
3737
}
@@ -43,7 +43,7 @@ public struct LogService {
4343
appStateClient.withLock { $0.hasAlreadyBootstrap = true }
4444
}
4545

46-
public nonisolated func notice(
46+
nonisolated func notice(
4747
_ event: NoticeEvent,
4848
source: @autoclosure () -> String? = nil,
4949
file: String = #fileID,
@@ -60,7 +60,7 @@ public struct LogService {
6060
)
6161
}
6262

63-
public nonisolated func error(
63+
nonisolated func error(
6464
_ event: ErrorEvent,
6565
source: @autoclosure () -> String? = nil,
6666
file: String = #fileID,
@@ -77,7 +77,7 @@ public struct LogService {
7777
)
7878
}
7979

80-
public nonisolated func critical(
80+
nonisolated func critical(
8181
_ event: CriticalEvent,
8282
source: @autoclosure () -> String? = nil,
8383
file: String = #fileID,

LocalPackage/Sources/Model/Services/ShiftService.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,14 @@ import AppKit
2222
import Foundation
2323
import DataSource
2424

25-
public struct ShiftService {
25+
actor ShiftService {
2626
private let cgDirectDisplayClient: CGDirectDisplayClient
2727
private let hiServicesClient: HIServicesClient
2828
private let nsAppClient: NSAppClient
2929
private let nsScreenClient: NSScreenClient
3030
private let nsWorkspaceClient: NSWorkspaceClient
3131

32-
public init(_ appDependencies: AppDependencies) {
32+
init(_ appDependencies: AppDependencies) {
3333
self.cgDirectDisplayClient = appDependencies.cgDirectDisplayClient
3434
self.hiServicesClient = appDependencies.hiServicesClient
3535
self.nsAppClient = appDependencies.nsAppClient

LocalPackage/Sources/Model/Services/ShortcutService.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,13 @@ import Foundation
2222
import DataSource
2323
import SpiceKey
2424

25-
public struct ShortcutService {
25+
struct ShortcutService {
2626
private let appStateClient: AppStateClient
2727
private let spiceKeyClient: SpiceKeyClient
2828
private let windowSceneMessengerClient: WindowSceneMessengerClient
2929
private let userDefaultsRepository: UserDefaultsRepository
3030

31-
public init(_ appDependencies: AppDependencies) {
31+
init(_ appDependencies: AppDependencies) {
3232
self.appStateClient = appDependencies.appStateClient
3333
self.spiceKeyClient = appDependencies.spiceKeyClient
3434
self.windowSceneMessengerClient = appDependencies.windowSceneMessengerClient

LocalPackage/Sources/Model/Services/UpdateService.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,14 @@
2121
import Combine
2222
import DataSource
2323

24-
public struct UpdateService {
24+
struct UpdateService {
2525
private let spuUpdaterClient: SPUUpdaterClient
2626

2727
var canChecksForUpdates: AsyncPublisher<AnyPublisher<Bool, Never>> {
2828
spuUpdaterClient.canCheckForUpdatesPublisher().values
2929
}
3030

31-
public init(_ appDependencies: AppDependencies) {
31+
init(_ appDependencies: AppDependencies) {
3232
self.spuUpdaterClient = appDependencies.spuUpdaterClient
3333
}
3434

LocalPackage/Sources/Model/Stores/ExtraMenu.swift

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ import Foundation
2222
import DataSource
2323
import Observation
2424

25-
@MainActor @Observable public final class ExtraMenu {
25+
@MainActor @Observable public final class ExtraMenu: Composable {
2626
private let appStateClient: AppStateClient
2727
private let executeClient: ExecuteClient
2828
private let nsAppClient: NSAppClient
@@ -36,12 +36,14 @@ import Observation
3636
public var shiftPatterns: [ShiftPattern]
3737
public var hideIcons: Bool
3838
public var canChecksForUpdates: Bool
39+
public let action: (Action) async -> Void
3940

4041
public init(
4142
_ appDependencies: AppDependencies,
4243
shiftPatterns: [ShiftPattern] = [],
4344
hideIcons: Bool = false,
44-
canChecksForUpdates: Bool = false
45+
canChecksForUpdates: Bool = false,
46+
action: @escaping (Action) async -> Void = { _ in }
4547
) {
4648
self.appStateClient = appDependencies.appStateClient
4749
self.executeClient = appDependencies.executeClient
@@ -53,9 +55,10 @@ import Observation
5355
self.shiftPatterns = shiftPatterns
5456
self.hideIcons = (try? executeClient.checkIconsVisible()) ?? hideIcons
5557
self.canChecksForUpdates = canChecksForUpdates
58+
self.action = action
5659
}
5760

58-
public func send(_ action: Action) async {
61+
public func reduce(_ action: Action) async {
5962
switch action {
6063
case let .task(screenName):
6164
logService.notice(.screenView(name: screenName))
@@ -77,9 +80,7 @@ import Observation
7780
}
7881

7982
case let .shiftPatternButtonTapped(shiftType):
80-
await Task { @MainActor [shiftService] in
81-
await shiftService.shiftWindow(shiftType: shiftType)
82-
}.value
83+
await shiftService.shiftWindow(shiftType: shiftType)
8384

8485
case let .hideDesktopIconsButtonTapped(isOn):
8586
do {
@@ -112,7 +113,7 @@ import Observation
112113
self.canChecksForUpdates = canChecksForUpdates
113114
}
114115

115-
public enum Action {
116+
public enum Action: Sendable {
116117
case task(String)
117118
case shiftPatternButtonTapped(ShiftType)
118119
case hideDesktopIconsButtonTapped(Bool)

LocalPackage/Sources/Model/Stores/GeneralSettings.swift

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,31 +22,34 @@ import Foundation
2222
import DataSource
2323
import Observation
2424

25-
@MainActor @Observable public final class GeneralSettings {
25+
@MainActor @Observable public final class GeneralSettings: Composable {
2626
private let nsWorkspaceClient: NSWorkspaceClient
2727
private let checkForUpdatesRepository: CheckForUpdatesRepository
2828
private let launchAtLoginRepository: LaunchAtLoginRepository
2929
private let logService: LogService
3030

3131
public var launchAtLogin: Bool
3232
public var checkForUpdates: Bool
33+
public let action: (Action) async -> Void
3334

3435
public init(
3536
_ appDependencies: AppDependencies,
3637
launchAtLogin: Bool? = nil,
37-
checkForUpdates: Bool? = nil
38+
checkForUpdates: Bool? = nil,
39+
action: @escaping (Action) async -> Void = { _ in }
3840
) {
3941
self.nsWorkspaceClient = appDependencies.nsWorkspaceClient
4042
self.checkForUpdatesRepository = .init(appDependencies.spuUpdaterClient)
4143
self.launchAtLoginRepository = .init(appDependencies.smAppServiceClient)
4244
self.logService = .init(appDependencies)
4345
self.launchAtLogin = launchAtLogin ?? launchAtLoginRepository.isEnabled
4446
self.checkForUpdates = checkForUpdates ?? checkForUpdatesRepository.isEnabled
47+
self.action = action
4548
}
4649

47-
public func send(_ action: Action) {
50+
public func reduce(_ action: Action) async {
4851
switch action {
49-
case let .onAppear(screenName):
52+
case let .task(screenName):
5053
logService.notice(.screenView(name: screenName))
5154

5255
case .openSystemSettingsButtonTapped:
@@ -67,8 +70,8 @@ import Observation
6770
}
6871
}
6972

70-
public enum Action {
71-
case onAppear(String)
73+
public enum Action: Sendable {
74+
case task(String)
7275
case openSystemSettingsButtonTapped
7376
case launchAtLoginToggleSwitched(Bool)
7477
case checkForUpdatesToggleSwitched(Bool)

0 commit comments

Comments
 (0)