diff --git a/desktop/Desktop/Sources/AppState.swift b/desktop/Desktop/Sources/AppState.swift index 3798696a75..9c16ca8027 100644 --- a/desktop/Desktop/Sources/AppState.swift +++ b/desktop/Desktop/Sources/AppState.swift @@ -2466,6 +2466,12 @@ class AppState: ObservableObject { nonisolated func resetOnboardingAndRestart() { log("Resetting onboarding state for current app...") + // Update live @AppStorage state in the current app instance before touching + // raw UserDefaults so SwiftUI doesn't write stale onboarding values back. + DispatchQueue.main.async { + NotificationCenter.default.post(name: .resetOnboardingRequested, object: nil) + } + // Clear onboarding-related UserDefaults keys (thread-safe, do first) let onboardingKeys = [ "hasCompletedOnboarding", @@ -2503,6 +2509,7 @@ class AppState: ObservableObject { // Restart off the main thread to avoid blocking the menu action path. DispatchQueue.global(qos: .utility).async { [self] in + Thread.sleep(forTimeInterval: 0.15) // Keep onboarding reset scoped to the current app instance. // It must not mutate production defaults, shared local data, or TCC permissions. self.restartApp() @@ -2773,6 +2780,8 @@ class AppState: ObservableObject { // MARK: - System Event Notification Names extension Notification.Name { + /// Posted when the current app instance should fully clear its own onboarding state. + static let resetOnboardingRequested = Notification.Name("resetOnboardingRequested") /// Posted when the system wakes from sleep static let systemDidWake = Notification.Name("systemDidWake") /// Posted when the screen is locked diff --git a/desktop/Desktop/Sources/MainWindow/DesktopHomeView.swift b/desktop/Desktop/Sources/MainWindow/DesktopHomeView.swift index 4c92071e47..dc869544a6 100644 --- a/desktop/Desktop/Sources/MainWindow/DesktopHomeView.swift +++ b/desktop/Desktop/Sources/MainWindow/DesktopHomeView.swift @@ -22,6 +22,8 @@ struct DesktopHomeView: View { }() @State private var isSidebarCollapsed: Bool = false @AppStorage("currentTierLevel") private var currentTierLevel = 0 + @AppStorage("onboardingStep") private var onboardingStep = 0 + @AppStorage("onboardingJustCompleted") private var onboardingJustCompleted = false // Settings sidebar state @State private var selectedSettingsSection: SettingsContentView.SettingsSection = .general @@ -201,6 +203,13 @@ struct DesktopHomeView: View { appState.hasCompletedOnboarding = false appState.stopTranscription() } + .onReceive(NotificationCenter.default.publisher(for: .resetOnboardingRequested)) { _ in + log("DesktopHomeView: resetOnboardingRequested — clearing live onboarding state for current app") + appState.hasCompletedOnboarding = false + onboardingStep = 0 + onboardingJustCompleted = false + appState.stopTranscription() + } // Handle transcription toggle from menu bar .onReceive(NotificationCenter.default.publisher(for: .toggleTranscriptionRequested)) { notification in if let enabled = notification.userInfo?["enabled"] as? Bool { diff --git a/desktop/Desktop/Sources/MainWindow/Pages/SettingsPage.swift b/desktop/Desktop/Sources/MainWindow/Pages/SettingsPage.swift index 9f5677914d..e39c73f6ab 100644 --- a/desktop/Desktop/Sources/MainWindow/Pages/SettingsPage.swift +++ b/desktop/Desktop/Sources/MainWindow/Pages/SettingsPage.swift @@ -3801,7 +3801,7 @@ struct SettingsContentView: View { .scaledFont(size: 16, weight: .semibold) .foregroundColor(OmiColors.textPrimary) - Text("Restart setup wizard and reset permissions") + Text("Restart setup wizard for this app build only") .scaledFont(size: 13) .foregroundColor(OmiColors.textTertiary) } @@ -3828,7 +3828,7 @@ struct SettingsContentView: View { appState.resetOnboardingAndRestart() } } message: { - Text("This will reset all permissions, clear chat history, and restart the app. You'll need to grant permissions again during setup.") + Text("This will reset onboarding for this app build only, clear onboarding chat history, and restart the app without affecting the other installed build.") } } } diff --git a/desktop/Desktop/Sources/OnboardingView.swift b/desktop/Desktop/Sources/OnboardingView.swift index c93c4cc22d..2842a467ec 100644 --- a/desktop/Desktop/Sources/OnboardingView.swift +++ b/desktop/Desktop/Sources/OnboardingView.swift @@ -63,6 +63,10 @@ struct OnboardingView: View { // Pre-warm the ACP bridge before the chat step starts. await chatProvider.warmupBridge() } + .onReceive(NotificationCenter.default.publisher(for: .resetOnboardingRequested)) { _ in + log("OnboardingView: resetOnboardingRequested — returning to chat step for current app") + currentStep = 0 + } } private var onboardingContent: some View {