feat: added deep links
ac62b6de
4 file(s) · +47 −2
| 29 | 29 | 0C5424A32EF79293001BB2ED /* TitanUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = TitanUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; |
|
| 30 | 30 | /* End PBXFileReference section */ |
|
| 31 | 31 | ||
| 32 | + | /* Begin PBXFileSystemSynchronizedBuildFileExceptionSet section */ |
|
| 33 | + | 0C10957F2F04AB0D00120458 /* Exceptions for "Titan" folder in "Titan" target */ = { |
|
| 34 | + | isa = PBXFileSystemSynchronizedBuildFileExceptionSet; |
|
| 35 | + | membershipExceptions = ( |
|
| 36 | + | Info.plist, |
|
| 37 | + | ); |
|
| 38 | + | target = 0C54248B2EF79292001BB2ED /* Titan */; |
|
| 39 | + | }; |
|
| 40 | + | /* End PBXFileSystemSynchronizedBuildFileExceptionSet section */ |
|
| 41 | + | ||
| 32 | 42 | /* Begin PBXFileSystemSynchronizedRootGroup section */ |
|
| 33 | 43 | 0C54248E2EF79292001BB2ED /* Titan */ = { |
|
| 34 | 44 | isa = PBXFileSystemSynchronizedRootGroup; |
|
| 45 | + | exceptions = ( |
|
| 46 | + | 0C10957F2F04AB0D00120458 /* Exceptions for "Titan" folder in "Titan" target */, |
|
| 47 | + | ); |
|
| 35 | 48 | path = Titan; |
|
| 36 | 49 | sourceTree = "<group>"; |
|
| 37 | 50 | }; |
|
| 400 | 413 | DEVELOPMENT_TEAM = W8QNM2N67P; |
|
| 401 | 414 | ENABLE_PREVIEWS = YES; |
|
| 402 | 415 | GENERATE_INFOPLIST_FILE = YES; |
|
| 416 | + | INFOPLIST_FILE = Titan/Info.plist; |
|
| 403 | 417 | INFOPLIST_KEY_CFBundleDisplayName = "Titan II"; |
|
| 404 | 418 | INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.education"; |
|
| 405 | 419 | INFOPLIST_KEY_NSPhotoLibraryAddUsageDescription = "Titan needs access to save images from Gemini pages"; |
|
| 439 | 453 | DEVELOPMENT_TEAM = W8QNM2N67P; |
|
| 440 | 454 | ENABLE_PREVIEWS = YES; |
|
| 441 | 455 | GENERATE_INFOPLIST_FILE = YES; |
|
| 456 | + | INFOPLIST_FILE = Titan/Info.plist; |
|
| 442 | 457 | INFOPLIST_KEY_CFBundleDisplayName = "Titan II"; |
|
| 443 | 458 | INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.education"; |
|
| 444 | 459 | INFOPLIST_KEY_NSPhotoLibraryAddUsageDescription = "Titan needs access to save images from Gemini pages"; |
|
| 1 | + | <?xml version="1.0" encoding="UTF-8"?> |
|
| 2 | + | <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> |
|
| 3 | + | <plist version="1.0"> |
|
| 4 | + | <dict> |
|
| 5 | + | <key>CFBundleURLTypes</key> |
|
| 6 | + | <array> |
|
| 7 | + | <dict> |
|
| 8 | + | <key>CFBundleTypeRole</key> |
|
| 9 | + | <string>Viewer</string> |
|
| 10 | + | <key>CFBundleURLName</key> |
|
| 11 | + | <string>com.stevedylandev.Titan</string> |
|
| 12 | + | <key>CFBundleURLSchemes</key> |
|
| 13 | + | <array> |
|
| 14 | + | <string>gemini</string> |
|
| 15 | + | </array> |
|
| 16 | + | </dict> |
|
| 17 | + | </array> |
|
| 18 | + | </dict> |
|
| 19 | + | </plist> |
| 10 | 10 | @main |
|
| 11 | 11 | struct TitanApp: App { |
|
| 12 | 12 | @StateObject private var themeSettings = ThemeSettings() |
|
| 13 | + | @State private var pendingDeepLinkURL: URL? |
|
| 13 | 14 | ||
| 14 | 15 | var body: some Scene { |
|
| 15 | 16 | WindowGroup { |
|
| 16 | - | ContentView() |
|
| 17 | + | ContentView(pendingDeepLinkURL: $pendingDeepLinkURL) |
|
| 17 | 18 | .environment(\.themeSettings, themeSettings) |
|
| 18 | 19 | .environmentObject(themeSettings) |
|
| 19 | 20 | .preferredColorScheme(themeSettings.appearanceMode.colorScheme) |
|
| 21 | + | .onOpenURL { url in |
|
| 22 | + | pendingDeepLinkURL = url |
|
| 23 | + | } |
|
| 20 | 24 | } |
|
| 21 | 25 | } |
|
| 22 | 26 | } |
| 7 | 7 | ||
| 8 | 8 | struct ContentView: View { |
|
| 9 | 9 | @EnvironmentObject private var themeSettings: ThemeSettings |
|
| 10 | + | @Binding var pendingDeepLinkURL: URL? |
|
| 10 | 11 | @State private var urlText = "" |
|
| 11 | 12 | @State private var responseText = "" |
|
| 12 | 13 | @State private var isLoading = false |
|
| 124 | 125 | } else if responseText.isEmpty && !urlText.isEmpty { |
|
| 125 | 126 | // Tab has URL but no content (restored from persistence) |
|
| 126 | 127 | navigateTo(urlText) |
|
| 128 | + | } |
|
| 129 | + | } |
|
| 130 | + | .onChange(of: pendingDeepLinkURL) { _, newURL in |
|
| 131 | + | if let url = newURL { |
|
| 132 | + | navigateTo(url.absoluteString) |
|
| 133 | + | pendingDeepLinkURL = nil |
|
| 127 | 134 | } |
|
| 128 | 135 | } |
|
| 129 | 136 | .alert("Input Required", isPresented: $showInputPrompt) { |
|
| 494 | 501 | } |
|
| 495 | 502 | ||
| 496 | 503 | #Preview { |
|
| 497 | - | ContentView() |
|
| 504 | + | ContentView(pendingDeepLinkURL: .constant(nil)) |
|
| 498 | 505 | .environmentObject(ThemeSettings()) |
|
| 499 | 506 | } |
|