Skip to content

Commit 84417c2

Browse files
authored
Create new settings page with debug view and trackpad selector (#26)
* Update OpenMultitouchSupport dependency and enhance OMSManager with device management features * add settings page * less cluttered * better settings design
1 parent 14560cf commit 84417c2

File tree

7 files changed

+229
-9
lines changed

7 files changed

+229
-9
lines changed

Package.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ let package = Package(
2020
targets: [
2121
.binaryTarget(
2222
name: "OpenMultitouchSupportXCF",
23-
url: "https://github.com/Kyome22/OpenMultitouchSupport/releases/download/3.0.3/OpenMultitouchSupportXCF.xcframework.zip",
24-
checksum: "9ffe72a65f0107e87a003485ab9530e772a6b45953af2f7d0cc41665d1873dea"
23+
url: "https://github.com/KrishKrosh/OpenMultitouchSupport/releases/download/v1.0.0/OpenMultitouchSupportXCF.xcframework.zip",
24+
checksum: "dbee657fea27f427e5b05c89cfa923f9c1c733b1ac6a6cb71360cd77c93f08ca"
2525
),
2626
.target(
2727
name: "OpenMultitouchSupport",

Sources/OpenMultitouchSupport/OMSManager.swift

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,23 @@
55
*/
66

77
import Combine
8-
import OpenMultitouchSupportXCF
8+
@preconcurrency import OpenMultitouchSupportXCF
99
import os
1010

11+
public struct OMSDeviceInfo: Sendable, Hashable {
12+
public let deviceName: String
13+
public let deviceID: String
14+
public let isBuiltIn: Bool
15+
internal nonisolated(unsafe) let deviceInfo: OpenMTDeviceInfo
16+
17+
internal init(_ deviceInfo: OpenMTDeviceInfo) {
18+
self.deviceInfo = deviceInfo
19+
self.deviceName = deviceInfo.deviceName
20+
self.deviceID = deviceInfo.deviceID
21+
self.isBuiltIn = deviceInfo.isBuiltIn
22+
}
23+
}
24+
1125
public final class OMSManager: Sendable {
1226
public static let shared = OMSManager()
1327

@@ -30,6 +44,17 @@ public final class OMSManager: Sendable {
3044
public var isListening: Bool {
3145
protectedListener.withLockUnchecked { $0 != nil }
3246
}
47+
48+
public var availableDevices: [OMSDeviceInfo] {
49+
guard let xcfManager = protectedManager.withLockUnchecked(\.self) else { return [] }
50+
return xcfManager.availableDevices().map { OMSDeviceInfo($0) }
51+
}
52+
53+
public var currentDevice: OMSDeviceInfo? {
54+
guard let xcfManager = protectedManager.withLockUnchecked(\.self),
55+
let current = xcfManager.currentDevice() else { return nil }
56+
return OMSDeviceInfo(current)
57+
}
3358

3459
private init() {
3560
protectedManager = .init(uncheckedState: OpenMTManager.shared())
@@ -60,6 +85,12 @@ public final class OMSManager: Sendable {
6085
protectedListener.withLockUnchecked { $0 = nil }
6186
return true
6287
}
88+
89+
@discardableResult
90+
public func selectDevice(_ device: OMSDeviceInfo) -> Bool {
91+
guard let xcfManager = protectedManager.withLockUnchecked(\.self) else { return false }
92+
return xcfManager.selectDevice(device.deviceInfo)
93+
}
6394

6495
@objc func listen(_ event: OpenMTEvent) {
6596
guard let touches = (event.touches as NSArray) as? [OpenMTTouch] else { return }

TrackWeight.xcodeproj/project.pbxproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
77292AA22B931E04001CA3F6 /* DebugView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77292AA32B931E04001CA3F6 /* DebugView.swift */; };
2020
77292AA42B931E05001CA3F6 /* ScaleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77292AA52B931E05001CA3F6 /* ScaleView.swift */; };
2121
77292AA62B931E06001CA3F6 /* ScaleViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77292AA72B931E06001CA3F6 /* ScaleViewModel.swift */; };
22+
93A095122E33359600E1E1D1 /* SettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 93A095112E33359600E1E1D1 /* SettingsView.swift */; };
2223
93ABD0212E2E01E200668D4F /* HomeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 93ABD0202E2E01E200668D4F /* HomeView.swift */; };
2324
/* End PBXBuildFile section */
2425

@@ -37,6 +38,7 @@
3738
77292AA32B931E04001CA3F6 /* DebugView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DebugView.swift; sourceTree = "<group>"; };
3839
77292AA52B931E05001CA3F6 /* ScaleView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScaleView.swift; sourceTree = "<group>"; };
3940
77292AA72B931E06001CA3F6 /* ScaleViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScaleViewModel.swift; sourceTree = "<group>"; };
41+
93A095112E33359600E1E1D1 /* SettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsView.swift; sourceTree = "<group>"; };
4042
93ABD0202E2E01E200668D4F /* HomeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeView.swift; sourceTree = "<group>"; };
4143
/* End PBXFileReference section */
4244

@@ -81,6 +83,7 @@
8183
77292A9D2B931E01001CA3F6 /* WeighingState.swift */,
8284
93ABD0202E2E01E200668D4F /* HomeView.swift */,
8385
77292A9F2B931E02001CA3F6 /* WeighingViewModel.swift */,
86+
93A095112E33359600E1E1D1 /* SettingsView.swift */,
8487
77292AA12B931E03001CA3F6 /* TrackWeightView.swift */,
8588
77292AA32B931E04001CA3F6 /* DebugView.swift */,
8689
77292AA52B931E05001CA3F6 /* ScaleView.swift */,
@@ -188,6 +191,7 @@
188191
77292AA22B931E04001CA3F6 /* DebugView.swift in Sources */,
189192
77292AA42B931E05001CA3F6 /* ScaleView.swift in Sources */,
190193
77292AA62B931E06001CA3F6 /* ScaleViewModel.swift in Sources */,
194+
93A095122E33359600E1E1D1 /* SettingsView.swift in Sources */,
191195
);
192196
runOnlyForDeploymentPostprocessing = 0;
193197
};

TrackWeight/ContentView.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,10 @@ struct ContentView: View {
3131
}
3232
.tag(1)
3333

34-
DebugView()
34+
SettingsView()
3535
.tabItem {
36-
Image(systemName: "hand.point.up.left")
37-
Text("Debug")
36+
Image(systemName: "gearshape")
37+
Text("Settings")
3838
}
3939
.tag(2)
4040
}

TrackWeight/ContentViewModel.swift

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//
22
// ContentViewModel.swift
3-
// TrackWeight
3+
// OMSDemo
44
//
55
// Created by Takuto Nakamura on 2024/03/02.
66
//
@@ -12,16 +12,19 @@ import SwiftUI
1212
final class ContentViewModel: ObservableObject {
1313
@Published var touchData = [OMSTouchData]()
1414
@Published var isListening: Bool = false
15+
@Published var availableDevices = [OMSDeviceInfo]()
16+
@Published var selectedDevice: OMSDeviceInfo?
1517

1618
private let manager = OMSManager.shared
1719
private var task: Task<Void, Never>?
1820

19-
init() {}
21+
init() {
22+
loadDevices()
23+
}
2024

2125
func onAppear() {
2226
task = Task { [weak self, manager] in
2327
for await touchData in manager.touchDataStream {
24-
print(touchData)
2528
await MainActor.run {
2629
self?.touchData = touchData
2730
}
@@ -45,4 +48,15 @@ final class ContentViewModel: ObservableObject {
4548
isListening = false
4649
}
4750
}
51+
52+
func loadDevices() {
53+
availableDevices = manager.availableDevices
54+
selectedDevice = manager.currentDevice
55+
}
56+
57+
func selectDevice(_ device: OMSDeviceInfo) {
58+
if manager.selectDevice(device) {
59+
selectedDevice = device
60+
}
61+
}
4862
}

TrackWeight/DebugView.swift

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,30 @@ struct DebugView: View {
1313

1414
var body: some View {
1515
VStack {
16+
17+
// Device Selector
18+
if !viewModel.availableDevices.isEmpty {
19+
VStack(alignment: .leading) {
20+
Text("Trackpad Device:")
21+
.font(.headline)
22+
Picker("Select Device", selection: Binding(
23+
get: { viewModel.selectedDevice },
24+
set: { device in
25+
if let device = device {
26+
viewModel.selectDevice(device)
27+
}
28+
}
29+
)) {
30+
ForEach(viewModel.availableDevices, id: \.self) { device in
31+
Text("\(device.deviceName) (ID: \(device.deviceID))")
32+
.tag(device as OMSDeviceInfo?)
33+
}
34+
}
35+
.pickerStyle(MenuPickerStyle())
36+
}
37+
.padding(.bottom)
38+
}
39+
1640
if viewModel.isListening {
1741
Button {
1842
viewModel.stop()

TrackWeight/SettingsView.swift

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
//
2+
// SettingsView.swift
3+
// TrackWeight
4+
//
5+
6+
import OpenMultitouchSupport
7+
import SwiftUI
8+
9+
struct SettingsView: View {
10+
@StateObject private var viewModel = ContentViewModel()
11+
@State private var showDebugView = false
12+
13+
var body: some View {
14+
VStack(spacing: 0) {
15+
// Minimal Header
16+
Text("Settings")
17+
.font(.title)
18+
.fontWeight(.medium)
19+
.padding(.top, 32)
20+
.padding(.bottom, 32)
21+
22+
// Settings Cards
23+
VStack(spacing: 20) {
24+
// Device Card
25+
SettingsCard {
26+
VStack(spacing: 20) {
27+
// Status Row
28+
HStack {
29+
HStack(spacing: 12) {
30+
Text("Trackpad")
31+
.font(.headline)
32+
.fontWeight(.medium)
33+
}
34+
35+
Spacer()
36+
37+
if !viewModel.availableDevices.isEmpty {
38+
Text("\(viewModel.availableDevices.count) device\(viewModel.availableDevices.count == 1 ? "" : "s")")
39+
.font(.caption)
40+
.foregroundColor(.secondary)
41+
}
42+
}
43+
44+
// Device Selector
45+
if !viewModel.availableDevices.isEmpty {
46+
HStack {
47+
Picker("", selection: Binding(
48+
get: { viewModel.selectedDevice },
49+
set: { device in
50+
if let device = device {
51+
viewModel.selectDevice(device)
52+
}
53+
}
54+
)) {
55+
ForEach(viewModel.availableDevices, id: \.self) { device in
56+
Text(device.deviceName)
57+
.tag(device as OMSDeviceInfo?)
58+
}
59+
}
60+
.pickerStyle(MenuPickerStyle())
61+
62+
Spacer()
63+
}
64+
} else {
65+
HStack {
66+
Text("No devices available")
67+
.foregroundColor(.secondary)
68+
Spacer()
69+
}
70+
}
71+
}
72+
}
73+
74+
// Debug Card
75+
SettingsCard {
76+
Button(action: { showDebugView = true }) {
77+
HStack(spacing: 16) {
78+
VStack(alignment: .leading, spacing: 4) {
79+
Text("Debug Console")
80+
.font(.headline)
81+
.fontWeight(.medium)
82+
.foregroundColor(.primary)
83+
84+
Text("Raw touch data & diagnostics")
85+
.font(.caption)
86+
.foregroundColor(.secondary)
87+
}
88+
89+
Spacer()
90+
91+
Image(systemName: "chevron.right")
92+
.font(.caption)
93+
.fontWeight(.medium)
94+
.foregroundColor(.secondary.opacity(0.6))
95+
}
96+
.contentShape(Rectangle())
97+
}
98+
.buttonStyle(CardButtonStyle())
99+
}
100+
}
101+
.frame(maxWidth: 480)
102+
.padding(.horizontal, 40)
103+
104+
Spacer()
105+
}
106+
.frame(maxWidth: .infinity, maxHeight: .infinity)
107+
.background(Color(NSColor.windowBackgroundColor))
108+
.sheet(isPresented: $showDebugView) {
109+
DebugView()
110+
.frame(minWidth: 700, minHeight: 500)
111+
}
112+
.onAppear {
113+
viewModel.loadDevices()
114+
}
115+
}
116+
}
117+
118+
struct SettingsCard<Content: View>: View {
119+
let content: Content
120+
121+
init(@ViewBuilder content: () -> Content) {
122+
self.content = content()
123+
}
124+
125+
var body: some View {
126+
VStack {
127+
content
128+
}
129+
.padding(24)
130+
.background(Color(NSColor.controlBackgroundColor))
131+
.cornerRadius(16)
132+
.shadow(color: Color.black.opacity(0.03), radius: 1, x: 0, y: 1)
133+
.shadow(color: Color.black.opacity(0.05), radius: 8, x: 0, y: 4)
134+
}
135+
}
136+
137+
struct CardButtonStyle: ButtonStyle {
138+
func makeBody(configuration: Configuration) -> some View {
139+
configuration.label
140+
.scaleEffect(configuration.isPressed ? 0.98 : 1.0)
141+
.animation(.easeInOut(duration: 0.1), value: configuration.isPressed)
142+
}
143+
}
144+
145+
#Preview {
146+
SettingsView()
147+
}

0 commit comments

Comments
 (0)