diff --git a/xcode/Catnip.xcodeproj/project.pbxproj b/xcode/Catnip.xcodeproj/project.pbxproj index 9fc20ef8..f4376703 100644 --- a/xcode/Catnip.xcodeproj/project.pbxproj +++ b/xcode/Catnip.xcodeproj/project.pbxproj @@ -423,9 +423,10 @@ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground; CODE_SIGN_ENTITLEMENTS = CatnipWidgetsExtension.entitlements; + CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = QCUUU7QVF7; + DEVELOPMENT_TEAM = 5DTHBP38WM; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = CatnipWidgets/Info.plist; INFOPLIST_KEY_CFBundleDisplayName = CatnipWidgets; @@ -437,8 +438,9 @@ "@executable_path/../../Frameworks", ); MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = wandb.catnip.CatnipWidgets; + PRODUCT_BUNDLE_IDENTIFIER = com.wandb.catnip.CatnipWidgets; PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = ""; SKIP_INSTALL = YES; STRING_CATALOG_GENERATE_SYMBOLS = YES; "SWIFT_ACTIVE_COMPILATION_CONDITIONS[arch=*]" = WIDGET_EXTENSION; @@ -456,9 +458,10 @@ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground; CODE_SIGN_ENTITLEMENTS = CatnipWidgetsExtension.entitlements; + CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = QCUUU7QVF7; + DEVELOPMENT_TEAM = 5DTHBP38WM; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = CatnipWidgets/Info.plist; INFOPLIST_KEY_CFBundleDisplayName = CatnipWidgets; @@ -470,8 +473,9 @@ "@executable_path/../../Frameworks", ); MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = wandb.catnip.CatnipWidgets; + PRODUCT_BUNDLE_IDENTIFIER = com.wandb.catnip.CatnipWidgets; PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = ""; SKIP_INSTALL = YES; STRING_CATALOG_GENERATE_SYMBOLS = YES; "SWIFT_ACTIVE_COMPILATION_CONDITIONS[arch=*]" = WIDGET_EXTENSION; @@ -490,12 +494,15 @@ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = YES; CODE_SIGN_ENTITLEMENTS = catnip/catnip.entitlements; + CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 2; - DEVELOPMENT_TEAM = QCUUU7QVF7; + DEVELOPMENT_TEAM = 5DTHBP38WM; ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = catnip/Info.plist; + INFOPLIST_KEY_ITSAppUsesNonExemptEncryption = NO; + INFOPLIST_KEY_NSSupportsLiveActivities = YES; INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; INFOPLIST_KEY_UILaunchScreen_Generation = YES; @@ -506,8 +513,9 @@ "@executable_path/Frameworks", ); MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = wandb.catnip; + PRODUCT_BUNDLE_IDENTIFIER = com.wandb.catnip; PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = ""; STRING_CATALOG_GENERATE_SYMBOLS = YES; SWIFT_DEFAULT_ACTOR_ISOLATION = MainActor; SWIFT_EMIT_LOC_STRINGS = YES; @@ -524,12 +532,15 @@ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = YES; CODE_SIGN_ENTITLEMENTS = catnip/catnip.entitlements; + CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 2; - DEVELOPMENT_TEAM = QCUUU7QVF7; + DEVELOPMENT_TEAM = 5DTHBP38WM; ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = catnip/Info.plist; + INFOPLIST_KEY_ITSAppUsesNonExemptEncryption = NO; + INFOPLIST_KEY_NSSupportsLiveActivities = YES; INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; INFOPLIST_KEY_UILaunchScreen_Generation = YES; @@ -540,8 +551,9 @@ "@executable_path/Frameworks", ); MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = wandb.catnip; + PRODUCT_BUNDLE_IDENTIFIER = com.wandb.catnip; PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = ""; STRING_CATALOG_GENERATE_SYMBOLS = YES; SWIFT_DEFAULT_ACTOR_ISOLATION = MainActor; SWIFT_EMIT_LOC_STRINGS = YES; @@ -678,7 +690,7 @@ BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = QCUUU7QVF7; + DEVELOPMENT_TEAM = 5DTHBP38WM; GENERATE_INFOPLIST_FILE = YES; IPHONEOS_DEPLOYMENT_TARGET = 17.0; MARKETING_VERSION = 1.0; @@ -699,7 +711,7 @@ BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = QCUUU7QVF7; + DEVELOPMENT_TEAM = 5DTHBP38WM; GENERATE_INFOPLIST_FILE = YES; IPHONEOS_DEPLOYMENT_TARGET = 17.0; MARKETING_VERSION = 1.0; @@ -719,7 +731,7 @@ buildSettings = { CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = QCUUU7QVF7; + DEVELOPMENT_TEAM = 5DTHBP38WM; GENERATE_INFOPLIST_FILE = YES; MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = wandb.catnipUITests; @@ -738,7 +750,7 @@ buildSettings = { CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = QCUUU7QVF7; + DEVELOPMENT_TEAM = 5DTHBP38WM; GENERATE_INFOPLIST_FILE = YES; MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = wandb.catnipUITests; diff --git a/xcode/CatnipWidgetsExtension.entitlements b/xcode/CatnipWidgetsExtension.entitlements index aa653443..18ed62bc 100644 --- a/xcode/CatnipWidgetsExtension.entitlements +++ b/xcode/CatnipWidgetsExtension.entitlements @@ -4,7 +4,7 @@ com.apple.security.application-groups - group.com.wandb.catnip + group.com.wandb.catnip.widgets diff --git a/xcode/catnip/Info.plist b/xcode/catnip/Info.plist index b88ea579..cf03a97a 100644 --- a/xcode/catnip/Info.plist +++ b/xcode/catnip/Info.plist @@ -2,15 +2,6 @@ - ITSAppUsesNonExemptEncryption - - NSSupportsLiveActivities - - UIBackgroundModes - - remote-notification - fetch - CFBundleURLTypes @@ -24,5 +15,14 @@ NSUserNotificationsUsageDescription Catnip sends notifications when your codespace is ready. Creating a codespace can take up to 10 minutes. + ITSAppUsesNonExemptEncryption + + NSSupportsLiveActivities + + UIBackgroundModes + + remote-notification + fetch + diff --git a/xcode/catnip/Views/CodespaceView.swift b/xcode/catnip/Views/CodespaceView.swift index 7d51f99e..4f4c0720 100644 --- a/xcode/catnip/Views/CodespaceView.swift +++ b/xcode/catnip/Views/CodespaceView.swift @@ -26,6 +26,7 @@ enum RepositoryListMode { } struct CodespaceView: View { + @Environment(\.scenePhase) private var scenePhase @EnvironmentObject var authManager: AuthManager @StateObject private var installer = CatnipInstaller.shared @StateObject private var tracker = CodespaceCreationTracker.shared @@ -40,6 +41,8 @@ struct CodespaceView: View { @State private var createdCodespace: CodespaceCreationResult.CodespaceInfo? @State private var repositoryListMode: RepositoryListMode = .installation @State private var pendingRepository: String? + @State private var pendingCodespaceName: String? + @State private var wasConnectingBeforeBackground = false private let catFacts = [ "Cats can rotate their ears 180 degrees.", @@ -227,6 +230,10 @@ struct CodespaceView: View { NSLog("🐱 [CodespaceView] Failed to preload repositories: \(error)") } } + + } + .onChange(of: scenePhase) { oldPhase, newPhase in + handleScenePhaseChange(oldPhase: oldPhase, newPhase: newPhase) } } @@ -510,6 +517,9 @@ struct CodespaceView: View { statusMessage = "" statusMessage = "Finding your codespace..." + // Store codespace name for potential reconnection after backgrounding + pendingCodespaceName = codespaceName + // Mock connection for UI tests if UITestingHelper.isUITesting { UserDefaults.standard.set("mock-codespace", forKey: "codespace_name") @@ -1115,6 +1125,31 @@ struct CodespaceView: View { .background(Color(uiColor: .systemGroupedBackground)) } + // MARK: - App Lifecycle Handling + + private func handleScenePhaseChange(oldPhase: ScenePhase, newPhase: ScenePhase) { + // Track when app goes to background during SSE connection + if newPhase == .background && phase == .connecting { + wasConnectingBeforeBackground = true + NSLog("🐱 [CodespaceView] App backgrounded during SSE connection, will reconnect on foreground") + } + + // Reconnect when app returns to foreground if we were connecting + if newPhase == .active && oldPhase == .background && wasConnectingBeforeBackground && phase == .connecting { + NSLog("🐱 [CodespaceView] App foregrounded, reconnecting SSE...") + + // Disconnect the old stale connection + sseService?.disconnect() + sseService = nil + + // Restart the connection with the same codespace name + handleConnect(codespaceName: pendingCodespaceName) + + // Reset the flag + wasConnectingBeforeBackground = false + } + } + private var createRepositoryView: some View { ScrollView { VStack(spacing: 24) { diff --git a/xcode/catnip/catnip.entitlements b/xcode/catnip/catnip.entitlements index 3e80a236..5d5f9b30 100644 --- a/xcode/catnip/catnip.entitlements +++ b/xcode/catnip/catnip.entitlements @@ -6,7 +6,7 @@ development com.apple.security.application-groups - group.com.wandb.catnip + group.com.wandb.catnip.widgets