-
Notifications
You must be signed in to change notification settings - Fork 48
Fix: Enable real-time theme switching without app restart #17
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
- Changed onChange to onReceive with proper publisher for reactive theme updates - Added immediate window interface style updates when theme is changed - Wrapped UIKit updates in DispatchQueue.main.async for thread safety - Force window tint color refresh for navigation bar appearance - Added direct updateAppearance call in settings for instant feedback 🤖 Generated with Claude Code (https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
- Added notification-based immediate UI updates for theme changes - Modified WindowGroup to properly apply preferredColorScheme at root level - Added ZStack with ID to force view redraw on theme change - Implemented applyAppearance method in RootHostingController - Added debug logging to track theme changes - Synchronized UserDefaults to ensure persistence - Updated both window and hosting controller interface styles - Added notification observer for cross-component communication 🤖 Generated with Claude Code (https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
- Removed AppearanceMode type dependency in RootHostingController - Simplified WindowGroup structure removing ZStack wrapper - Use string-based appearance handling to avoid type issues - Restored stable app launch while keeping theme functionality 🤖 Generated with Claude Code (https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
- Fixed settings UI to use store state directly instead of local @State - Added comprehensive debug logging throughout theme change flow - Enhanced window interface style updates to cover all scenes and windows - Added startup theme application with slight delay for proper initialization - Improved UserDefaults loading with debug output - Force window redraw after theme changes - Ensure all UI elements properly reflect saved theme preference 🤖 Generated with Claude Code (https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
- Created static methods for appearance updates to avoid self capture in init - Replaced instance method calls with static versions in closures - Simplified updateAppearance in AppearanceSettingView to use static method - Maintains all functionality while fixing Swift compilation issue 🤖 Generated with Claude Code (https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
- Added notification observer in RootHostingController to listen for theme changes - Moved preferredColorScheme modifier to the correct view hierarchy level - Removed duplicate notification handling in V2erApp - Added force redraw on theme change to ensure immediate UI update - Cleaned up redundant theme update calls in AppearanceSettingView The app now switches themes immediately when selecting Light/Dark/System modes in settings without requiring an app restart.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR fixes theme switching functionality to apply immediately without requiring an app restart. The implementation adds real-time theme change support through notification-based architecture and proper view hierarchy modifications.
- Added notification observer in
RootHostingControllerto listen for theme changes and apply them immediately - Simplified theme state management by removing local state variables and using the global store directly
- Enhanced UI update mechanisms with forced redraws and proper interface style propagation
Reviewed Changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 17 comments.
Show a summary per file
| File | Description |
|---|---|
| AppearanceSettingView.swift | Removed local state and simplified UI to use store state directly |
| SettingState.swift | Added debug logging for appearance loading and initialization |
| SettingReducer.swift | Added notification posting and debug logging for theme changes |
| V2erApp.swift | Enhanced appearance update methods with static variants and improved UI refresh logic |
| RootView.swift | Added notification observer and appearance handling in RootHostingController |
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
| ForEach(AppearanceMode.allCases, id: \.self) { mode in | ||
| Button(action: { | ||
| selectedAppearance = mode | ||
| print("🎨 User selected: \(mode.rawValue)") |
Copilot
AI
Sep 14, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Debug print statements should be removed from production code. Consider using a proper logging framework or removing this before merging to production.
| print("🎨 User selected: \(mode.rawValue)") |
| print("📱 Loaded saved appearance: \(mode.rawValue)") | ||
| } else { | ||
| print("📱 No saved appearance, using default: system") |
Copilot
AI
Sep 14, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Debug print statements should be removed from production code. Consider using a proper logging framework or removing these before merging to production.
| print("📱 Loaded saved appearance: \(mode.rawValue)") | |
| } else { | |
| print("📱 No saved appearance, using default: system") | |
| } else { | |
|
|
||
| switch action { | ||
| case let action as SettingActions.ChangeAppearanceAction: | ||
| print("🎨 Changing appearance to: \(action.appearance.rawValue)") |
Copilot
AI
Sep 14, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Debug print statements should be removed from production code. Consider using a proper logging framework or removing this before merging to production.
V2er/General/V2erApp.swift
Outdated
| setupNotifications() | ||
| // Apply saved theme on app launch | ||
| let savedAppearance = Store.shared.appState.settingState.appearance | ||
| print("🚀 Saved appearance on launch: \(savedAppearance.rawValue)") |
Copilot
AI
Sep 14, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Debug print statements should be removed from production code. Consider using a proper logging framework or removing this before merging to production.
| print("🚀 Saved appearance on launch: \(savedAppearance.rawValue)") | |
| // Debug print removed for production |
V2er/General/V2erApp.swift
Outdated
| } | ||
|
|
||
| private func updateAppearance(_ appearance: AppearanceMode) { | ||
| print("🔄 Updating appearance to: \(appearance.rawValue)") |
Copilot
AI
Sep 14, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Multiple debug print statements should be removed from production code. Consider using a proper logging framework or removing these before merging to production.
V2er/General/V2erApp.swift
Outdated
| // Also update the stored window if available | ||
| if let window = V2erApp.window { | ||
| window.overrideUserInterfaceStyle = style | ||
| print(" ✓ Updated stored window") |
Copilot
AI
Sep 14, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Multiple debug print statements should be removed from production code. Consider using a proper logging framework or removing these before merging to production.
V2er/General/V2erApp.swift
Outdated
| // Update the root hosting controller | ||
| if let rootHostingController = V2erApp.rootViewController as? RootHostingController<RootHostView> { | ||
| rootHostingController.applyAppearanceFromString(appearance.rawValue) | ||
| print(" ✓ Updated root hosting controller") |
Copilot
AI
Sep 14, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Multiple debug print statements should be removed from production code. Consider using a proper logging framework or removing these before merging to production.
V2er/General/V2erApp.swift
Outdated
| setupNotifications() | ||
| // Apply saved theme on app launch | ||
| let savedAppearance = Store.shared.appState.settingState.appearance | ||
| print("🚀 Saved appearance on launch: \(savedAppearance.rawValue)") | ||
| } | ||
|
|
||
| private func setupNotifications() { | ||
| // Notifications are now handled in RootHostingController | ||
| } | ||
|
|
Copilot
AI
Sep 14, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Empty method with only a comment should be removed entirely since it serves no purpose. If this is a placeholder for future functionality, consider adding a TODO comment or removing it completely.
| setupNotifications() | |
| // Apply saved theme on app launch | |
| let savedAppearance = Store.shared.appState.settingState.appearance | |
| print("🚀 Saved appearance on launch: \(savedAppearance.rawValue)") | |
| } | |
| private func setupNotifications() { | |
| // Notifications are now handled in RootHostingController | |
| } | |
| // Apply saved theme on app launch | |
| let savedAppearance = Store.shared.appState.settingState.appearance | |
| print("🚀 Saved appearance on launch: \(savedAppearance.rawValue)") | |
| } |
V2er/General/V2erApp.swift
Outdated
| } | ||
|
|
||
| // Force a redraw | ||
| UIApplication.shared.windows.forEach { $0.setNeedsDisplay() } |
Copilot
AI
Sep 14, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
UIApplication.shared.windows is deprecated in iOS 15+. Consider using UIApplication.shared.connectedScenes approach consistently as done elsewhere in the same methods.
V2er/General/V2erApp.swift
Outdated
| } | ||
|
|
||
| // Force a redraw | ||
| UIApplication.shared.windows.forEach { $0.setNeedsDisplay() } |
Copilot
AI
Sep 14, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
UIApplication.shared.windows is deprecated in iOS 15+. Consider using UIApplication.shared.connectedScenes approach consistently as done elsewhere in the same methods.
| UIApplication.shared.windows.forEach { $0.setNeedsDisplay() } | |
| UIApplication.shared.connectedScenes.forEach { scene in | |
| if let windowScene = scene as? UIWindowScene { | |
| windowScene.windows.forEach { $0.setNeedsDisplay() } | |
| } | |
| } |
- Removed all debug print statements from production code - Fixed deprecated UIApplication.shared.windows usage - Removed empty setupNotifications method - Cleaned up code formatting and unnecessary blank lines All CI checks should now pass.
Summary
Changes
RootHostingControllerto listen for theme changespreferredColorSchememodifier to the correct view hierarchy levelV2erAppAppearanceSettingViewTest Plan
🤖 Generated with Claude Code