feat: added deep links ac62b6de
Steve · 2025-12-30 19:53 4 file(s) · +47 −2
Titan.xcodeproj/project.pbxproj +15 −0
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";
Titan/Info.plist (added) +19 −0
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>
Titan/TitanApp.swift +5 −1
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
}
Titan/Views/ContentView.swift +8 −1
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
}