Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions DasherApp/Sources/ContentView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
36 changes: 36 additions & 0 deletions DasherApp/Sources/DasherBridge.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
99 changes: 66 additions & 33 deletions DasherApp/Sources/DasherSettingsView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -169,41 +169,31 @@ struct DasherSettingsView: View {

private func customizationSection(_ params: [DasherParameterInfo]) -> some View {
Section {
Picker("Appearance", selection: Binding<Int>(
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..<palettes.count, id: \.self) { i in
let palette = palettes[i]
let isSelected = viewModel.bridge.currentPalette == palette.name
Button(action: { viewModel.bridge.setPalette(palette.name) }) {
VStack(spacing: 4) {
HStack(spacing: 2) {
ForEach(0..<min(palette.previewColors.count, 4), id: \.self) { ci in
RoundedRectangle(cornerRadius: 2)
.fill(Color(cgColor: palette.previewColors[ci]))
.frame(width: 16, height: 24)
}
}
.overlay(
RoundedRectangle(cornerRadius: 4)
.stroke(isSelected ? Color.accentColor : Color.gray.opacity(0.3), lineWidth: isSelected ? 2 : 1)
)
Text(palette.name)
.font(.system(size: 9))
.lineLimit(1)
.foregroundColor(isSelected ? .primary : .secondary)
}
.frame(width: 72)
}
.buttonStyle(.plain)
}
}
.padding(.vertical, 2)
}
palettePickerRow(
label: "Light Palette",
palettes: palettes,
selectedName: viewModel.bridge.getLightPalette()
) { name in
viewModel.bridge.setLightPalette(name)
}
palettePickerRow(
label: "Dark Palette",
palettes: palettes,
selectedName: viewModel.bridge.getDarkPalette()
) { name in
viewModel.bridge.setDarkPalette(name)
}
}
ForEach(params.filter { $0.name != "Color Palette" }) { param in
Expand All @@ -214,6 +204,49 @@ struct DasherSettingsView: View {
}
}

@ViewBuilder
private func palettePickerRow(
label: String,
palettes: [DasherPalette],
selectedName: String,
onSelect: @escaping (String) -> Void
) -> some View {
VStack(alignment: .leading, spacing: 8) {
Text(label)
.font(.subheadline)
ScrollView(.horizontal, showsIndicators: false) {
HStack(spacing: 10) {
ForEach(0..<palettes.count, id: \.self) { i in
let palette = palettes[i]
let isSelected = selectedName == palette.name
Button(action: { onSelect(palette.name) }) {
VStack(spacing: 4) {
HStack(spacing: 2) {
ForEach(0..<min(palette.previewColors.count, 4), id: \.self) { ci in
RoundedRectangle(cornerRadius: 2)
.fill(Color(cgColor: palette.previewColors[ci]))
.frame(width: 16, height: 24)
}
}
.overlay(
RoundedRectangle(cornerRadius: 4)
.stroke(isSelected ? Color.accentColor : Color.gray.opacity(0.3), lineWidth: isSelected ? 2 : 1)
)
Text(palette.name)
.font(.system(size: 9))
.lineLimit(1)
.foregroundColor(isSelected ? .primary : .secondary)
}
.frame(width: 72)
}
.buttonStyle(.plain)
}
}
.padding(.vertical, 2)
}
}
}

// MARK: - Input

private func inputSection(_ params: [DasherParameterInfo]) -> some View {
Expand Down
36 changes: 36 additions & 0 deletions DasherKeyboard/Sources/DasherBridge.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
7 changes: 7 additions & 0 deletions DasherKeyboard/Sources/KeyboardViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ class KeyboardViewController: UIInputViewController {
}

@objc private func resetTapped() {
viewModel?.bridge.setSystemAppearance(dark: traitCollection.userInterfaceStyle == .dark)
viewModel?.bridge.reset()
}

Expand All @@ -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)
Expand Down
36 changes: 36 additions & 0 deletions DasherMac/Sources/DasherBridge.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
5 changes: 5 additions & 0 deletions DasherMac/Sources/MacContentView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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 {
Expand Down
36 changes: 36 additions & 0 deletions DasherVision/Sources/DasherBridge.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
1 change: 1 addition & 0 deletions DasherVision/Sources/VisionContentView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
Loading