diff --git a/DasherApp/Sources/ContentView.swift b/DasherApp/Sources/ContentView.swift index 40abbdc..a5276c4 100644 --- a/DasherApp/Sources/ContentView.swift +++ b/DasherApp/Sources/ContentView.swift @@ -11,6 +11,7 @@ struct ContentView: View { @State private var showOpenFile = false @State private var outputPaneFraction: CGFloat = 2.0 / 9.0 @State private var showAlphabetPopover = false + @Environment(\.colorScheme) private var colorScheme var body: some View { GeometryReader { geometry in @@ -67,6 +68,10 @@ struct ContentView: View { .padding(.top, 8) } } + .onAppear { viewModel.bridge.setSystemAppearance(dark: colorScheme == .dark) } + .onChange(of: colorScheme) { _, newScheme in + viewModel.bridge.setSystemAppearance(dark: newScheme == .dark) + } } // MARK: - Layouts diff --git a/DasherApp/Sources/DasherBridge.swift b/DasherApp/Sources/DasherBridge.swift index ce768b2..850b517 100644 --- a/DasherApp/Sources/DasherBridge.swift +++ b/DasherApp/Sources/DasherBridge.swift @@ -350,6 +350,42 @@ class DasherBridge: InputMethodBridge { return String(cString: cStr) } + + // MARK: - Appearance / dark mode (RFC 0007) + + func setSystemAppearance(dark: Bool) { + guard let ctx = ctx else { return } + dasher_set_system_appearance(ctx, dark ? 2 : 1) + } + func setAppearanceMode(_ mode: Int) { + guard let ctx = ctx else { return } + dasher_set_appearance_mode(ctx, Int32(mode)) + } + func getAppearanceMode() -> Int { + guard let ctx = ctx else { return 0 } + return Int(dasher_get_appearance_mode(ctx)) + } + func setUserPalette(_ name: String) { + guard let ctx = ctx else { return } + dasher_set_user_palette(ctx, name) + } + func setLightPalette(_ name: String) { + guard let ctx = ctx else { return } + dasher_set_light_palette(ctx, name) + } + func setDarkPalette(_ name: String) { + guard let ctx = ctx else { return } + dasher_set_dark_palette(ctx, name) + } + func getLightPalette() -> String { + guard let ctx = ctx, let cStr = dasher_get_light_palette(ctx) else { return "" } + return String(cString: cStr) + } + func getDarkPalette() -> String { + guard let ctx = ctx, let cStr = dasher_get_dark_palette(ctx) else { return "" } + return String(cString: cStr) + } + // MARK: - Alphabets var alphabetCount: Int { diff --git a/DasherApp/Sources/DasherSettingsView.swift b/DasherApp/Sources/DasherSettingsView.swift index 8a629c7..a4b48a5 100644 --- a/DasherApp/Sources/DasherSettingsView.swift +++ b/DasherApp/Sources/DasherSettingsView.swift @@ -169,41 +169,31 @@ struct DasherSettingsView: View { private func customizationSection(_ params: [DasherParameterInfo]) -> some View { Section { + Picker("Appearance", selection: Binding( + get: { viewModel.bridge.getAppearanceMode() }, + set: { viewModel.bridge.setAppearanceMode($0) } + )) { + Text("System").tag(0) + Text("Light").tag(1) + Text("Dark").tag(2) + } + .pickerStyle(.segmented) + let palettes = viewModel.bridge.allPalettes if !palettes.isEmpty { - VStack(alignment: .leading, spacing: 8) { - Text("Colour Theme") - .font(.subheadline) - ScrollView(.horizontal, showsIndicators: false) { - HStack(spacing: 10) { - ForEach(0.. Void + ) -> some View { + VStack(alignment: .leading, spacing: 8) { + Text(label) + .font(.subheadline) + ScrollView(.horizontal, showsIndicators: false) { + HStack(spacing: 10) { + ForEach(0.. some View { diff --git a/DasherCore b/DasherCore index 581093e..5d6cfa0 160000 --- a/DasherCore +++ b/DasherCore @@ -1 +1 @@ -Subproject commit 581093ef2ed90456a0dbd70f5aba8d2950b075bd +Subproject commit 5d6cfa0d4a65becda69af14eec9d679f42717456 diff --git a/DasherKeyboard/Sources/DasherBridge.swift b/DasherKeyboard/Sources/DasherBridge.swift index f206060..02f389e 100644 --- a/DasherKeyboard/Sources/DasherBridge.swift +++ b/DasherKeyboard/Sources/DasherBridge.swift @@ -341,6 +341,42 @@ class DasherBridge: InputMethodBridge { return String(cString: cStr) } + + // MARK: - Appearance / dark mode (RFC 0007) + + func setSystemAppearance(dark: Bool) { + guard let ctx = ctx else { return } + dasher_set_system_appearance(ctx, dark ? 2 : 1) + } + func setAppearanceMode(_ mode: Int) { + guard let ctx = ctx else { return } + dasher_set_appearance_mode(ctx, Int32(mode)) + } + func getAppearanceMode() -> Int { + guard let ctx = ctx else { return 0 } + return Int(dasher_get_appearance_mode(ctx)) + } + func setUserPalette(_ name: String) { + guard let ctx = ctx else { return } + dasher_set_user_palette(ctx, name) + } + func setLightPalette(_ name: String) { + guard let ctx = ctx else { return } + dasher_set_light_palette(ctx, name) + } + func setDarkPalette(_ name: String) { + guard let ctx = ctx else { return } + dasher_set_dark_palette(ctx, name) + } + func getLightPalette() -> String { + guard let ctx = ctx, let cStr = dasher_get_light_palette(ctx) else { return "" } + return String(cString: cStr) + } + func getDarkPalette() -> String { + guard let ctx = ctx, let cStr = dasher_get_dark_palette(ctx) else { return "" } + return String(cString: cStr) + } + // MARK: - Alphabets var alphabetCount: Int { diff --git a/DasherKeyboard/Sources/KeyboardViewController.swift b/DasherKeyboard/Sources/KeyboardViewController.swift index f0c1a36..95bfe9b 100644 --- a/DasherKeyboard/Sources/KeyboardViewController.swift +++ b/DasherKeyboard/Sources/KeyboardViewController.swift @@ -118,6 +118,7 @@ class KeyboardViewController: UIInputViewController { } @objc private func resetTapped() { + viewModel?.bridge.setSystemAppearance(dark: traitCollection.userInterfaceStyle == .dark) viewModel?.bridge.reset() } @@ -133,10 +134,16 @@ class KeyboardViewController: UIInputViewController { super.viewWillAppear(animated) // The bridge is a singleton so its model state survives across open/close // cycles. Reset to the root so each keyboard session starts fresh. + viewModel?.bridge.setSystemAppearance(dark: traitCollection.userInterfaceStyle == .dark) viewModel?.bridge.reset() canvas?.requestRedraw() } + override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { + super.traitCollectionDidChange(previousTraitCollection) + viewModel?.bridge.setSystemAppearance(dark: traitCollection.userInterfaceStyle == .dark) + } + override func viewDidLayoutSubviews() { super.viewDidLayoutSubviews() viewModel?.setCanvasSize(canvas?.bounds.size ?? view.bounds.size) diff --git a/DasherMac/Sources/DasherBridge.swift b/DasherMac/Sources/DasherBridge.swift index 64c914a..04a9712 100644 --- a/DasherMac/Sources/DasherBridge.swift +++ b/DasherMac/Sources/DasherBridge.swift @@ -353,6 +353,42 @@ class DasherBridge: InputMethodBridge, DasherBridgeProtocol { return String(cString: cStr) } + + // MARK: - Appearance / dark mode (RFC 0007) + + func setSystemAppearance(dark: Bool) { + guard let ctx = ctx else { return } + dasher_set_system_appearance(ctx, dark ? 2 : 1) + } + func setAppearanceMode(_ mode: Int) { + guard let ctx = ctx else { return } + dasher_set_appearance_mode(ctx, Int32(mode)) + } + func getAppearanceMode() -> Int { + guard let ctx = ctx else { return 0 } + return Int(dasher_get_appearance_mode(ctx)) + } + func setUserPalette(_ name: String) { + guard let ctx = ctx else { return } + dasher_set_user_palette(ctx, name) + } + func setLightPalette(_ name: String) { + guard let ctx = ctx else { return } + dasher_set_light_palette(ctx, name) + } + func setDarkPalette(_ name: String) { + guard let ctx = ctx else { return } + dasher_set_dark_palette(ctx, name) + } + func getLightPalette() -> String { + guard let ctx = ctx, let cStr = dasher_get_light_palette(ctx) else { return "" } + return String(cString: cStr) + } + func getDarkPalette() -> String { + guard let ctx = ctx, let cStr = dasher_get_dark_palette(ctx) else { return "" } + return String(cString: cStr) + } + // MARK: - Alphabets var alphabetCount: Int { diff --git a/DasherMac/Sources/MacContentView.swift b/DasherMac/Sources/MacContentView.swift index 20633a0..7b7e027 100644 --- a/DasherMac/Sources/MacContentView.swift +++ b/DasherMac/Sources/MacContentView.swift @@ -8,6 +8,7 @@ struct MacContentView: View { @State private var showSettings = false @State private var currentLayoutPosition = "Right" @State private var outputPaneFraction: CGFloat = 2.0 / 9.0 + @Environment(\.colorScheme) private var colorScheme var body: some View { VStack(spacing: 0) { @@ -69,6 +70,10 @@ struct MacContentView: View { } } } + .onAppear { viewModel.bridge.setSystemAppearance(dark: colorScheme == .dark) } + .onChange(of: colorScheme) { _, newScheme in + viewModel.bridge.setSystemAppearance(dark: newScheme == .dark) + } } private var layoutPickerMenu: some View { diff --git a/DasherVision/Sources/DasherBridge.swift b/DasherVision/Sources/DasherBridge.swift index 1fe7438..e0d72fd 100644 --- a/DasherVision/Sources/DasherBridge.swift +++ b/DasherVision/Sources/DasherBridge.swift @@ -315,6 +315,42 @@ class DasherBridge: InputMethodBridge { return String(cString: cStr) } + + // MARK: - Appearance / dark mode (RFC 0007) + + func setSystemAppearance(dark: Bool) { + guard let ctx = ctx else { return } + dasher_set_system_appearance(ctx, dark ? 2 : 1) + } + func setAppearanceMode(_ mode: Int) { + guard let ctx = ctx else { return } + dasher_set_appearance_mode(ctx, Int32(mode)) + } + func getAppearanceMode() -> Int { + guard let ctx = ctx else { return 0 } + return Int(dasher_get_appearance_mode(ctx)) + } + func setUserPalette(_ name: String) { + guard let ctx = ctx else { return } + dasher_set_user_palette(ctx, name) + } + func setLightPalette(_ name: String) { + guard let ctx = ctx else { return } + dasher_set_light_palette(ctx, name) + } + func setDarkPalette(_ name: String) { + guard let ctx = ctx else { return } + dasher_set_dark_palette(ctx, name) + } + func getLightPalette() -> String { + guard let ctx = ctx, let cStr = dasher_get_light_palette(ctx) else { return "" } + return String(cString: cStr) + } + func getDarkPalette() -> String { + guard let ctx = ctx, let cStr = dasher_get_dark_palette(ctx) else { return "" } + return String(cString: cStr) + } + // MARK: - Alphabets var alphabetCount: Int { diff --git a/DasherVision/Sources/VisionContentView.swift b/DasherVision/Sources/VisionContentView.swift index 3ee94ea..0c43136 100644 --- a/DasherVision/Sources/VisionContentView.swift +++ b/DasherVision/Sources/VisionContentView.swift @@ -73,6 +73,7 @@ struct VisionContentView: View { .sheet(isPresented: $showSettings) { VisionSettingsView(viewModel: viewModel) } + .onAppear { viewModel.bridge.setSystemAppearance(dark: true) } } private func toolbarButton(_ icon: String, isAccent: Bool = false, _ action: @escaping () -> Void) -> some View {