ReviewOS

also looking at this

craft-native/craft

fix(ios): let native screens choose interface appearance

#398
Closed glennmichael123 wants to merge codex/issue-389-appearance into main
8 files +218 -5

Review threads live on the whole diff, not on one commit, so none are shown here - a thread's line means something in the branch's final form, and painting it into an intermediate step would put it on code it is not about.

packages/ios/src/index.test.tsmodified+3-1
Changes to packages/ios/src/index.test.ts
@@ -790,7 +790,7 @@ describe('Craft iOS builder', () => {
790790 const launch = JSON.parse(readFileSync(join(output, 'Assets.xcassets', 'LaunchBackground.colorset', 'Contents.json'), 'utf8'))
791791 expect(plist).toContain('<key>UIUserInterfaceStyle</key>\n <string>Automatic</string>')
792792 expect(plist).toContain('<string>UIStatusBarStyleDefault</string>')
793 expect(swift).toContain('.preferredColorScheme(appState.config.colorScheme)')
793 expect(swift).toContain('.preferredColorScheme(appState.appearanceScheme)')
794794 expect(launch.colors).toHaveLength(2)
795795 expect(launch.colors[1].appearances).toEqual([{ appearance: 'luminosity', value: 'dark' }])
796796 expect(launch.colors[1].color.components.red).toBe('0.008')
@@ -834,6 +834,8 @@ describe('Craft iOS builder', () => {
834834 const screen = readFileSync(join(output, 'Sources', 'CraftNativeScreen.swift'), 'utf8')
835835 expect(swift).toContain('CraftInterfaceStyleController.configure(config)')
836836 expect(swift).toContain('CraftInterfaceStyleController.set(appearance)')
837 expect(swift).toContain('.preferredColorScheme(appState.appearanceScheme)')
838 expect(swift).toContain('CraftInterfaceStyleController.colorScheme(for: self.config)')
837839 expect(swift).toContain('case "getAppearance":')
838840 expect(screen).toContain('CraftInterfaceStyleController.apply(to: self, config: config)')
839841 expect(screen).toContain('craftNativeSetAppearance')
packages/ios/templates/CraftApp.swiftmodified+26-1
Changes to packages/ios/templates/CraftApp.swift
@@ -134,6 +134,14 @@ enum CraftInterfaceStyleController {
134134 runtimeSelection ?? configuredStyle(for: config)
135135 }
136136
137 static func colorScheme(for config: CraftConfig) -> ColorScheme? {
138 switch style(for: config) {
139 case .light: return .light
140 case .dark: return .dark
141 default: return nil
142 }
143 }
144
137145 /// Returns false rather than silently accepting a typo from JavaScript.
138146 @discardableResult
139147 static func set(_ value: String) -> Bool {
@@ -689,7 +697,7 @@ struct CraftApp: App {
689697 .ignoresSafeArea(.keyboard, edges: .bottom)
690698 }
691699 }
692 .preferredColorScheme(appState.config.colorScheme)
700 .preferredColorScheme(appState.appearanceScheme)
693701 .environmentObject(appState)
694702 .onOpenURL { url in
695703 // Handle deep links and universal links
@@ -1601,6 +1609,8 @@ class DeepLinkManager {
16011609// MARK: - App State
16021610class AppState: ObservableObject {
16031611 @Published var config: CraftConfig
1612 @Published private(set) var appearanceScheme: ColorScheme?
1613 private var appearanceObserver: NSObjectProtocol?
16041614
16051615 init() {
16061616 if let configURL = Bundle.main.url(forResource: "craft.config", withExtension: "json"),
@@ -1609,11 +1619,26 @@ class AppState: ObservableObject {
16091619 } else {
16101620 self.config = CraftConfig()
16111621 }
1622 self.appearanceScheme = CraftInterfaceStyleController.colorScheme(for: config)
1623 appearanceObserver = NotificationCenter.default.addObserver(
1624 forName: .craftColorSchemeChanged,
1625 object: nil,
1626 queue: .main,
1627 ) { [weak self] _ in
1628 guard let self else { return }
1629 self.appearanceScheme = CraftInterfaceStyleController.colorScheme(for: self.config)
1630 }
16121631 // Before the first frame: the hybrid start screen, and the tab bar
16131632 // from the config, are decided here, if the app delegate has not
16141633 // already (it does at launch; the first call decides).
16151634 CraftHybrid.shared.configure(config)
16161635 }
1636
1637 deinit {
1638 if let appearanceObserver {
1639 NotificationCenter.default.removeObserver(appearanceObserver)
1640 }
1641 }
16171642}
16181643
16191644extension CraftConfig {