Live video on the AT Protocol
at eli/lexicon-dev 146 lines 4.8 kB view raw
1/** 2 * Shared linking configuration for react-navigation 3 * Used both for URL parsing (inbound) and URL generation (outbound) 4 */ 5 6import { LinkingOptions, getStateFromPath } from "@react-navigation/native"; 7import * as ExpoLinking from "expo-linking"; 8 9export const SCREEN_PATHS = { 10 // HomeTab screens 11 HomeMain: "", 12 About: "about", 13 Download: "download", 14 LiveDashboard: "live", 15 Login: "login", 16 Multi: "multi/:config", 17 Support: "support", 18 // Settings screens 19 MainSettings: "settings", 20 AboutCategory: "settings/about", 21 AccountCategory: "settings/account", 22 StreamingCategory: "settings/streaming", 23 WebhooksSettings: "settings/streaming/webhooks", 24 RecommendationsSettings: "settings/streaming/recommendations", 25 PrivacyCategory: "settings/privacy", 26 DanmuCategory: "settings/danmu", 27 AdvancedCategory: "settings/advanced", 28 DeveloperSettings: "settings/developer", 29 MultistreamCategory: "settings/streaming/multistream", 30 KeyManagement: "settings/streaming/key-management", 31 LanguagesCategory: "settings/languages", 32 BrandingAdmin: "settings/branding", 33 // Tabs 34 GoLiveTab: "go-live", 35 // Root stack screens 36 Stream: ":user", 37 MobileGoLive: "mobile-golive", 38 AVSync: "sync-test", 39 AppReturn: "app-return/:scheme", 40 PopoutChat: "chat-popout/:user", 41 Embed: "embed/:user", 42 InfoWidgetEmbed: "info-widget", 43 LegacyStream: "legacy/:user", 44 DanmuOBS: "widgets/:user/danmu", 45} as const; 46 47/** 48 * Convert screen path to absolute URL path 49 * Adds leading slash if not present 50 */ 51export function getAbsolutePath(screenName: keyof typeof SCREEN_PATHS): string { 52 const path = SCREEN_PATHS[screenName]; 53 return path.startsWith("/") ? path : `/${path}`; 54} 55 56/** 57 * Interpolate params into a path template 58 * Example: interpolateParams("/:user", { user: "alice" }) => "/alice" 59 */ 60export function interpolateParams( 61 path: string, 62 params?: Record<string, any>, 63): string { 64 if (!params || typeof params !== "object") { 65 return path; 66 } 67 68 let result = path; 69 for (const [key, value] of Object.entries(params)) { 70 result = result.replace(`:${key}`, String(value)); 71 } 72 return result; 73} 74 75/** 76 * Check if a screen name is valid 77 */ 78export function isValidScreenName( 79 name: string, 80): name is keyof typeof SCREEN_PATHS { 81 return name in SCREEN_PATHS; 82} 83 84export const streamplaceLinkingOptions: LinkingOptions<ReactNavigation.RootParamList> = 85 { 86 prefixes: [ExpoLinking.createURL("")], 87 config: { 88 screens: { 89 // Main tabs (used on all platforms, tab bar hidden on web) 90 MainTabs: { 91 screens: { 92 HomeTab: { 93 screens: { 94 HomeMain: SCREEN_PATHS.HomeMain, 95 About: SCREEN_PATHS.About, 96 Download: SCREEN_PATHS.Download, 97 LiveDashboard: SCREEN_PATHS.LiveDashboard, 98 Login: SCREEN_PATHS.Login, 99 Multi: SCREEN_PATHS.Multi, 100 Support: SCREEN_PATHS.Support, 101 }, 102 }, 103 GoLiveTab: SCREEN_PATHS.GoLiveTab, 104 SettingsTab: { 105 screens: { 106 MainSettings: SCREEN_PATHS.MainSettings, 107 AboutCategory: SCREEN_PATHS.AboutCategory, 108 AccountCategory: SCREEN_PATHS.AccountCategory, 109 StreamingCategory: SCREEN_PATHS.StreamingCategory, 110 WebhooksSettings: SCREEN_PATHS.WebhooksSettings, 111 RecommendationsSettings: SCREEN_PATHS.RecommendationsSettings, 112 PrivacyCategory: SCREEN_PATHS.PrivacyCategory, 113 DanmuCategory: SCREEN_PATHS.DanmuCategory, 114 AdvancedCategory: SCREEN_PATHS.AdvancedCategory, 115 DeveloperSettings: SCREEN_PATHS.DeveloperSettings, 116 MultistreamCategory: SCREEN_PATHS.MultistreamCategory, 117 KeyManagement: SCREEN_PATHS.KeyManagement, 118 LanguagesCategory: SCREEN_PATHS.LanguagesCategory, 119 BrandingAdmin: SCREEN_PATHS.BrandingAdmin, 120 }, 121 }, 122 }, 123 }, 124 // Root stack screens (outside tabs - full-screen experiences) 125 Stream: { 126 path: SCREEN_PATHS.Stream, 127 }, 128 MobileGoLive: SCREEN_PATHS.MobileGoLive, 129 AVSync: SCREEN_PATHS.AVSync, 130 AppReturn: SCREEN_PATHS.AppReturn, 131 PopoutChat: SCREEN_PATHS.PopoutChat, 132 Embed: SCREEN_PATHS.Embed, 133 InfoWidgetEmbed: SCREEN_PATHS.InfoWidgetEmbed, 134 LegacyStream: SCREEN_PATHS.LegacyStream, 135 DanmuOBS: SCREEN_PATHS.DanmuOBS, 136 }, 137 }, 138 }; 139 140export function getStreamplaceStateFromPath(path: string) { 141 const ret = getStateFromPath(path, streamplaceLinkingOptions.config); 142 if (!ret) { 143 throw new Error(`Invalid path: ${path}`); 144 } 145 return ret; 146}