expo-dev-launcher 5.2.0-canary-20250722-599a28f → 5.2.0-canary-20250811-5c940c0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +5 -0
- package/android/build.gradle +6 -2
- package/android/src/debug/AndroidManifest.xml +4 -2
- package/android/src/debug/java/expo/modules/devlauncher/DevLauncherController.kt +12 -5
- package/android/src/debug/java/expo/modules/devlauncher/compose/DevLauncherBottomTabsNavigator.kt +14 -6
- package/android/src/debug/java/expo/modules/devlauncher/compose/UpdatesModels.kt +14 -0
- package/android/src/debug/java/expo/modules/devlauncher/compose/models/BranchViewModel.kt +105 -0
- package/android/src/debug/java/expo/modules/devlauncher/compose/models/BranchesViewModel.kt +113 -0
- package/android/src/debug/java/expo/modules/devlauncher/compose/models/ErrorViewModel.kt +50 -0
- package/android/src/debug/java/expo/modules/devlauncher/compose/models/HomeViewModel.kt +36 -29
- package/android/src/debug/java/expo/modules/devlauncher/compose/models/SettingsViewModel.kt +12 -3
- package/android/src/debug/java/expo/modules/devlauncher/compose/primitives/Accordion.kt +5 -4
- package/android/src/debug/java/expo/modules/devlauncher/compose/primitives/Asyncimage.kt +1 -2
- package/android/src/debug/java/expo/modules/devlauncher/compose/primitives/CircularProgressBar.kt +89 -0
- package/android/src/debug/java/expo/modules/devlauncher/compose/routes/Home.kt +16 -4
- package/android/src/debug/java/expo/modules/devlauncher/compose/routes/Routes.kt +20 -0
- package/android/src/debug/java/expo/modules/devlauncher/compose/routes/Settings.kt +0 -4
- package/android/src/debug/java/expo/modules/devlauncher/compose/routes/Updates.kt +95 -0
- package/android/src/debug/java/expo/modules/devlauncher/compose/screens/BranchScreen.kt +240 -0
- package/android/src/debug/java/expo/modules/devlauncher/compose/screens/BranchesScreen.kt +262 -0
- package/android/src/debug/java/expo/modules/devlauncher/compose/screens/CrashReportScreen.kt +8 -2
- package/android/src/debug/java/expo/modules/devlauncher/compose/screens/ErrorScreen.kt +79 -0
- package/android/src/debug/java/expo/modules/devlauncher/compose/screens/HomeScreen.kt +73 -28
- package/android/src/debug/java/expo/modules/devlauncher/compose/screens/NoUpdatesScreen.kt +73 -0
- package/android/src/debug/java/expo/modules/devlauncher/compose/screens/SettingsScreen.kt +38 -10
- package/android/src/debug/java/expo/modules/devlauncher/compose/ui/AccountAvatar.kt +3 -4
- package/android/src/debug/java/expo/modules/devlauncher/compose/ui/AccountSelector.kt +3 -4
- package/android/src/debug/java/expo/modules/devlauncher/compose/ui/AppHeader.kt +54 -15
- package/android/src/debug/java/expo/modules/devlauncher/compose/ui/AppLoadingErrorDialog.kt +81 -0
- package/android/src/debug/java/expo/modules/devlauncher/compose/ui/BottomTabBar.kt +10 -6
- package/android/src/debug/java/expo/modules/devlauncher/compose/ui/BottomTabButton.kt +6 -3
- package/android/src/debug/java/expo/modules/devlauncher/compose/ui/DevelopmentServerHelp.kt +0 -4
- package/android/src/debug/java/expo/modules/devlauncher/compose/ui/ProfileLayout.kt +18 -10
- package/android/src/debug/java/expo/modules/devlauncher/compose/ui/RunningAppCard.kt +2 -1
- package/android/src/debug/java/expo/modules/devlauncher/compose/ui/ScreenHeaderContainer.kt +2 -1
- package/android/src/debug/java/expo/modules/devlauncher/compose/ui/SectionHeader.kt +0 -24
- package/android/src/debug/java/expo/modules/devlauncher/compose/ui/ServerUrlInput.kt +1 -0
- package/android/src/debug/java/expo/modules/devlauncher/compose/utils/DateFormat.kt +40 -0
- package/android/src/debug/java/expo/modules/devlauncher/compose/utils/UpdatesUtils.kt +12 -0
- package/android/src/debug/java/expo/modules/devlauncher/helpers/DevLauncherReactUtils.kt +2 -2
- package/android/src/debug/java/expo/modules/devlauncher/launcher/errors/DevLauncherErrorActivity.kt +27 -96
- package/android/src/debug/java/expo/modules/devlauncher/launcher/loaders/DevLauncherExpoAppLoader.kt +2 -2
- package/android/src/debug/java/expo/modules/devlauncher/react/DevLauncherDevSupportManagerSwapper.kt +2 -2
- package/android/src/debug/java/expo/modules/devlauncher/react/DevLauncherReactNativeHostHandler.kt +0 -5
- package/android/src/debug/java/expo/modules/devlauncher/services/ApolloClientService.kt +53 -0
- package/android/src/debug/java/expo/modules/devlauncher/services/DependencyInjection.kt +2 -1
- package/android/src/debug/java/expo/modules/devlauncher/services/ImageLoaderService.kt +17 -5
- package/android/src/debug/java/expo/modules/devlauncher/services/PackagerService.kt +0 -1
- package/android/src/debug/java/expo/modules/devlauncher/services/SessionService.kt +1 -6
- package/android/src/debug/res/drawable-mdpi/qr_code.png +0 -0
- package/android/src/debug/res/drawable-night-mdpi/qr_code.png +0 -0
- package/android/src/debug/res/drawable-night-xhdpi/qr_code.png +0 -0
- package/android/src/debug/res/drawable-night-xxhdpi/qr_code.png +0 -0
- package/android/src/debug/res/drawable-xhdpi/qr_code.png +0 -0
- package/android/src/debug/res/drawable-xxhdpi/qr_code.png +0 -0
- package/android/src/main/AndroidManifest.xml +6 -1
- package/android/src/main/graphql/GetBranches.graphql +17 -5
- package/android/src/main/graphql/GetUpdates.graphql +0 -13
- package/android/src/main/java/expo/modules/devlauncher/react/activitydelegates/DevLauncherReactActivityNOPDelegate.kt +2 -2
- package/android/src/main/java/expo/modules/devlauncher/splashscreen/DevLauncherSplashScreen.kt +0 -2
- package/android/src/main/res/drawable-mdpi/dev_menu_fab_icon.png +0 -0
- package/android/src/main/res/drawable-xhdpi/dev_menu_fab_icon.png +0 -0
- package/android/src/main/res/drawable-xxhdpi/dev_menu_fab_icon.png +0 -0
- package/android/src/main/res/values/styles.xml +0 -14
- package/expo-dev-launcher.podspec +2 -1
- package/ios/Assets.xcassets/expo-go-logo.imageset/Contents.json +21 -0
- package/ios/Assets.xcassets/expo-go-logo.imageset/expo-go logo.png +0 -0
- package/ios/Assets.xcassets/log-in.imageset/Contents.json +21 -0
- package/ios/Assets.xcassets/log-in.imageset/log-in.png +0 -0
- package/ios/EXDevLauncherController.m +2 -0
- package/ios/EXDevLauncherInstallationIDHelper.swift +6 -0
- package/ios/EXDevLauncherPendingDeepLinkRegistry.swift +2 -0
- package/ios/EXDevLauncherRecentlyOpenedAppsRegistry.swift +1 -0
- package/ios/EXDevLauncherUtils.swift +2 -11
- package/ios/Errors/EXDevLauncherErrorManager.swift +41 -5
- package/ios/Manifest/EXDevLauncherManifestHelper.swift +14 -10
- package/ios/ReactNative/EXDevLauncherBundleURLProviderInterceptor.swift +2 -0
- package/ios/SwiftUI/AccountSheet.swift +49 -35
- package/ios/SwiftUI/CrashReportView.swift +175 -0
- package/ios/SwiftUI/DevLauncherTabBarManager.swift +4 -4
- package/ios/SwiftUI/DevLauncherViewModel.swift +42 -23
- package/ios/SwiftUI/DevLauncherViews.swift +19 -14
- package/ios/SwiftUI/DevServerInfoModal.swift +21 -9
- package/ios/SwiftUI/DevServersView.swift +21 -18
- package/ios/SwiftUI/ErrorView.swift +46 -67
- package/ios/SwiftUI/HomeTabView.swift +28 -9
- package/ios/SwiftUI/Navigation/Navigation.swift +18 -8
- package/ios/SwiftUI/SettingsTabView.swift +90 -32
- package/ios/SwiftUI/StackFrameView.swift +29 -0
- package/ios/SwiftUI/UpdatesTab/NotSignedInView.swift +31 -18
- package/ios/SwiftUI/UpdatesTab/UpdateRow.swift +2 -0
- package/ios/SwiftUI/UpdatesTab/UpdatesListView.swift +4 -0
- package/ios/SwiftUI/UpdatesTab/UpdatesTabView.swift +1 -12
- package/ios/SwiftUI/Utils/Utils.swift +49 -0
- package/ios/Tests/EXDevLauncherControllerTest.swift +0 -10
- package/ios/Unsafe/RCTPackagerConnection+EXDevLauncherPackagerConnectionInterceptor.m +19 -5
- package/package.json +4 -4
- package/android/src/debug/res/drawable-mdpi/__node_modules_reactnavigation_elements_lib_module_assets_backicon.png +0 -0
- package/android/src/debug/res/drawable-mdpi/__node_modules_reactnavigation_elements_lib_module_assets_backiconmask.png +0 -0
- package/android/src/debug/res/drawable-mdpi/__node_modules_reactnavigation_elements_lib_module_assets_clearicon.png +0 -0
- package/android/src/debug/res/drawable-mdpi/__node_modules_reactnavigation_elements_lib_module_assets_closeicon.png +0 -0
- package/android/src/debug/res/drawable-mdpi/__node_modules_reactnavigation_elements_lib_module_assets_searchicon.png +0 -0
- package/android/src/debug/res/drawable-mdpi/_expodevclientcomponents_assets_branchiconlight.png +0 -0
- package/android/src/debug/res/drawable-mdpi/_expodevclientcomponents_assets_checkiconlight.png +0 -0
- package/android/src/debug/res/drawable-mdpi/_expodevclientcomponents_assets_clipboardicon.png +0 -0
- package/android/src/debug/res/drawable-mdpi/_expodevclientcomponents_assets_debugicon.png +0 -0
- package/android/src/debug/res/drawable-mdpi/_expodevclientcomponents_assets_extensionsfilledactiveicon.png +0 -0
- package/android/src/debug/res/drawable-mdpi/_expodevclientcomponents_assets_extensionsfilledactiveiconlight.png +0 -0
- package/android/src/debug/res/drawable-mdpi/_expodevclientcomponents_assets_extensionsfilledinactiveicon.png +0 -0
- package/android/src/debug/res/drawable-mdpi/_expodevclientcomponents_assets_extensionsfilledinactiveiconlight.png +0 -0
- package/android/src/debug/res/drawable-mdpi/_expodevclientcomponents_assets_extensionsiconlight.png +0 -0
- package/android/src/debug/res/drawable-mdpi/_expodevclientcomponents_assets_homefilledactiveicon.png +0 -0
- package/android/src/debug/res/drawable-mdpi/_expodevclientcomponents_assets_homefilledactiveiconlight.png +0 -0
- package/android/src/debug/res/drawable-mdpi/_expodevclientcomponents_assets_homefilledinactiveiconlight.png +0 -0
- package/android/src/debug/res/drawable-mdpi/_expodevclientcomponents_assets_infoiconlight.png +0 -0
- package/android/src/debug/res/drawable-mdpi/_expodevclientcomponents_assets_inspectelementicon.png +0 -0
- package/android/src/debug/res/drawable-mdpi/_expodevclientcomponents_assets_loadingindicatoricon.png +0 -0
- package/android/src/debug/res/drawable-mdpi/_expodevclientcomponents_assets_logoicon.png +0 -0
- package/android/src/debug/res/drawable-mdpi/_expodevclientcomponents_assets_performanceicon.png +0 -0
- package/android/src/debug/res/drawable-mdpi/_expodevclientcomponents_assets_questionmarkicon.png +0 -0
- package/android/src/debug/res/drawable-mdpi/_expodevclientcomponents_assets_refreshicon.png +0 -0
- package/android/src/debug/res/drawable-mdpi/_expodevclientcomponents_assets_runicon.png +0 -0
- package/android/src/debug/res/drawable-mdpi/_expodevclientcomponents_assets_settingsfilledactiveicon.png +0 -0
- package/android/src/debug/res/drawable-mdpi/_expodevclientcomponents_assets_settingsfilledactiveiconlight.png +0 -0
- package/android/src/debug/res/drawable-mdpi/_expodevclientcomponents_assets_settingsfilledinactiveiconlight.png +0 -0
- package/android/src/debug/res/drawable-mdpi/_expodevclientcomponents_assets_showmenuatlaunchiconlight.png +0 -0
- package/android/src/debug/res/drawable-mdpi/_expodevclientcomponents_assets_threefingerlongpressiconlight.png +0 -0
- package/android/src/debug/res/drawable-mdpi/_expodevclientcomponents_assets_toolbaroverlayicon.png +0 -0
- package/android/src/debug/res/drawable-mdpi/_expodevclientcomponents_assets_updateiconlight.png +0 -0
- package/android/src/debug/res/drawable-mdpi/_expodevclientcomponents_assets_usericonlight.png +0 -0
- package/android/src/debug/res/drawable-mdpi/_expodevclientcomponents_assets_warningtriangleicon.png +0 -0
- package/android/src/debug/res/drawable-mdpi/_expodevclientcomponents_assets_warningtriangleiconlight.png +0 -0
- package/android/src/debug/res/drawable-mdpi/_expodevclientcomponents_assets_xiconlight.png +0 -0
- package/android/src/debug/res/drawable-xhdpi/__node_modules_reactnavigation_elements_lib_module_assets_backicon.png +0 -0
- package/android/src/debug/res/drawable-xhdpi/__node_modules_reactnavigation_elements_lib_module_assets_clearicon.png +0 -0
- package/android/src/debug/res/drawable-xhdpi/__node_modules_reactnavigation_elements_lib_module_assets_closeicon.png +0 -0
- package/android/src/debug/res/drawable-xhdpi/__node_modules_reactnavigation_elements_lib_module_assets_searchicon.png +0 -0
- package/android/src/debug/res/drawable-xhdpi/_expodevclientcomponents_assets_branchiconlight.png +0 -0
- package/android/src/debug/res/drawable-xhdpi/_expodevclientcomponents_assets_checkiconlight.png +0 -0
- package/android/src/debug/res/drawable-xhdpi/_expodevclientcomponents_assets_clipboardicon.png +0 -0
- package/android/src/debug/res/drawable-xhdpi/_expodevclientcomponents_assets_debugicon.png +0 -0
- package/android/src/debug/res/drawable-xhdpi/_expodevclientcomponents_assets_extensionsfilledactiveicon.png +0 -0
- package/android/src/debug/res/drawable-xhdpi/_expodevclientcomponents_assets_extensionsfilledactiveiconlight.png +0 -0
- package/android/src/debug/res/drawable-xhdpi/_expodevclientcomponents_assets_extensionsfilledinactiveicon.png +0 -0
- package/android/src/debug/res/drawable-xhdpi/_expodevclientcomponents_assets_extensionsfilledinactiveiconlight.png +0 -0
- package/android/src/debug/res/drawable-xhdpi/_expodevclientcomponents_assets_extensionsiconlight.png +0 -0
- package/android/src/debug/res/drawable-xhdpi/_expodevclientcomponents_assets_homefilledactiveicon.png +0 -0
- package/android/src/debug/res/drawable-xhdpi/_expodevclientcomponents_assets_homefilledactiveiconlight.png +0 -0
- package/android/src/debug/res/drawable-xhdpi/_expodevclientcomponents_assets_homefilledinactiveiconlight.png +0 -0
- package/android/src/debug/res/drawable-xhdpi/_expodevclientcomponents_assets_infoiconlight.png +0 -0
- package/android/src/debug/res/drawable-xhdpi/_expodevclientcomponents_assets_inspectelementicon.png +0 -0
- package/android/src/debug/res/drawable-xhdpi/_expodevclientcomponents_assets_loadingindicatoricon.png +0 -0
- package/android/src/debug/res/drawable-xhdpi/_expodevclientcomponents_assets_logoicon.png +0 -0
- package/android/src/debug/res/drawable-xhdpi/_expodevclientcomponents_assets_performanceicon.png +0 -0
- package/android/src/debug/res/drawable-xhdpi/_expodevclientcomponents_assets_questionmarkicon.png +0 -0
- package/android/src/debug/res/drawable-xhdpi/_expodevclientcomponents_assets_refreshicon.png +0 -0
- package/android/src/debug/res/drawable-xhdpi/_expodevclientcomponents_assets_runicon.png +0 -0
- package/android/src/debug/res/drawable-xhdpi/_expodevclientcomponents_assets_settingsfilledactiveicon.png +0 -0
- package/android/src/debug/res/drawable-xhdpi/_expodevclientcomponents_assets_settingsfilledactiveiconlight.png +0 -0
- package/android/src/debug/res/drawable-xhdpi/_expodevclientcomponents_assets_settingsfilledinactiveiconlight.png +0 -0
- package/android/src/debug/res/drawable-xhdpi/_expodevclientcomponents_assets_showmenuatlaunchiconlight.png +0 -0
- package/android/src/debug/res/drawable-xhdpi/_expodevclientcomponents_assets_threefingerlongpressiconlight.png +0 -0
- package/android/src/debug/res/drawable-xhdpi/_expodevclientcomponents_assets_toolbaroverlayicon.png +0 -0
- package/android/src/debug/res/drawable-xhdpi/_expodevclientcomponents_assets_updateiconlight.png +0 -0
- package/android/src/debug/res/drawable-xhdpi/_expodevclientcomponents_assets_usericonlight.png +0 -0
- package/android/src/debug/res/drawable-xhdpi/_expodevclientcomponents_assets_warningtriangleicon.png +0 -0
- package/android/src/debug/res/drawable-xhdpi/_expodevclientcomponents_assets_warningtriangleiconlight.png +0 -0
- package/android/src/debug/res/drawable-xhdpi/_expodevclientcomponents_assets_xiconlight.png +0 -0
- package/android/src/debug/res/drawable-xxhdpi/__node_modules_reactnavigation_elements_lib_module_assets_backicon.png +0 -0
- package/android/src/debug/res/drawable-xxhdpi/__node_modules_reactnavigation_elements_lib_module_assets_clearicon.png +0 -0
- package/android/src/debug/res/drawable-xxhdpi/__node_modules_reactnavigation_elements_lib_module_assets_closeicon.png +0 -0
- package/android/src/debug/res/drawable-xxhdpi/__node_modules_reactnavigation_elements_lib_module_assets_searchicon.png +0 -0
- package/android/src/debug/res/drawable-xxhdpi/_expodevclientcomponents_assets_branchiconlight.png +0 -0
- package/android/src/debug/res/drawable-xxhdpi/_expodevclientcomponents_assets_checkiconlight.png +0 -0
- package/android/src/debug/res/drawable-xxhdpi/_expodevclientcomponents_assets_clipboardicon.png +0 -0
- package/android/src/debug/res/drawable-xxhdpi/_expodevclientcomponents_assets_debugicon.png +0 -0
- package/android/src/debug/res/drawable-xxhdpi/_expodevclientcomponents_assets_extensionsfilledactiveicon.png +0 -0
- package/android/src/debug/res/drawable-xxhdpi/_expodevclientcomponents_assets_extensionsfilledactiveiconlight.png +0 -0
- package/android/src/debug/res/drawable-xxhdpi/_expodevclientcomponents_assets_extensionsfilledinactiveicon.png +0 -0
- package/android/src/debug/res/drawable-xxhdpi/_expodevclientcomponents_assets_extensionsfilledinactiveiconlight.png +0 -0
- package/android/src/debug/res/drawable-xxhdpi/_expodevclientcomponents_assets_extensionsiconlight.png +0 -0
- package/android/src/debug/res/drawable-xxhdpi/_expodevclientcomponents_assets_homefilledactiveicon.png +0 -0
- package/android/src/debug/res/drawable-xxhdpi/_expodevclientcomponents_assets_homefilledactiveiconlight.png +0 -0
- package/android/src/debug/res/drawable-xxhdpi/_expodevclientcomponents_assets_homefilledinactiveiconlight.png +0 -0
- package/android/src/debug/res/drawable-xxhdpi/_expodevclientcomponents_assets_infoiconlight.png +0 -0
- package/android/src/debug/res/drawable-xxhdpi/_expodevclientcomponents_assets_inspectelementicon.png +0 -0
- package/android/src/debug/res/drawable-xxhdpi/_expodevclientcomponents_assets_loadingindicatoricon.png +0 -0
- package/android/src/debug/res/drawable-xxhdpi/_expodevclientcomponents_assets_logoicon.png +0 -0
- package/android/src/debug/res/drawable-xxhdpi/_expodevclientcomponents_assets_performanceicon.png +0 -0
- package/android/src/debug/res/drawable-xxhdpi/_expodevclientcomponents_assets_questionmarkicon.png +0 -0
- package/android/src/debug/res/drawable-xxhdpi/_expodevclientcomponents_assets_refreshicon.png +0 -0
- package/android/src/debug/res/drawable-xxhdpi/_expodevclientcomponents_assets_runicon.png +0 -0
- package/android/src/debug/res/drawable-xxhdpi/_expodevclientcomponents_assets_settingsfilledactiveicon.png +0 -0
- package/android/src/debug/res/drawable-xxhdpi/_expodevclientcomponents_assets_settingsfilledactiveiconlight.png +0 -0
- package/android/src/debug/res/drawable-xxhdpi/_expodevclientcomponents_assets_settingsfilledinactiveiconlight.png +0 -0
- package/android/src/debug/res/drawable-xxhdpi/_expodevclientcomponents_assets_showmenuatlaunchiconlight.png +0 -0
- package/android/src/debug/res/drawable-xxhdpi/_expodevclientcomponents_assets_threefingerlongpressiconlight.png +0 -0
- package/android/src/debug/res/drawable-xxhdpi/_expodevclientcomponents_assets_toolbaroverlayicon.png +0 -0
- package/android/src/debug/res/drawable-xxhdpi/_expodevclientcomponents_assets_updateiconlight.png +0 -0
- package/android/src/debug/res/drawable-xxhdpi/_expodevclientcomponents_assets_usericonlight.png +0 -0
- package/android/src/debug/res/drawable-xxhdpi/_expodevclientcomponents_assets_warningtriangleicon.png +0 -0
- package/android/src/debug/res/drawable-xxhdpi/_expodevclientcomponents_assets_warningtriangleiconlight.png +0 -0
- package/android/src/debug/res/drawable-xxhdpi/_expodevclientcomponents_assets_xiconlight.png +0 -0
- package/android/src/debug/res/drawable-xxxhdpi/__node_modules_reactnavigation_elements_lib_module_assets_backicon.png +0 -0
- package/android/src/debug/res/drawable-xxxhdpi/__node_modules_reactnavigation_elements_lib_module_assets_clearicon.png +0 -0
- package/android/src/debug/res/drawable-xxxhdpi/__node_modules_reactnavigation_elements_lib_module_assets_closeicon.png +0 -0
- package/android/src/debug/res/drawable-xxxhdpi/__node_modules_reactnavigation_elements_lib_module_assets_searchicon.png +0 -0
- package/android/src/main/res/drawable-mdpi/_expodevclientcomponents_assets_logoicon.png +0 -0
- package/android/src/main/res/drawable-xhdpi/_expodevclientcomponents_assets_logoicon.png +0 -0
- package/android/src/main/res/drawable-xxhdpi/_expodevclientcomponents_assets_logoicon.png +0 -0
- /package/android/src/debug/res/drawable-mdpi/{_expodevclientcomponents_assets_branchicon.png → branch_icon.png} +0 -0
- /package/android/src/debug/res/drawable-mdpi/{_expodevclientcomponents_assets_buildingicon.png → building_icon.png} +0 -0
- /package/android/src/debug/res/drawable-mdpi/{_expodevclientcomponents_assets_checkicon.png → check_icon.png} +0 -0
- /package/android/src/debug/res/drawable-mdpi/{_expodevclientcomponents_assets_chevronrighticon.png → chevron_right_icon.png} +0 -0
- /package/android/src/debug/res/drawable-mdpi/{_expodevclientcomponents_assets_extensionsicon.png → extensions_icon.png} +0 -0
- /package/android/src/debug/res/drawable-mdpi/{_expodevclientcomponents_assets_homefilledinactiveicon.png → home_icon.png} +0 -0
- /package/android/src/debug/res/drawable-mdpi/{_expodevclientcomponents_assets_infoicon.png → info_icon.png} +0 -0
- /package/android/src/debug/res/drawable-mdpi/{_expodevclientcomponents_assets_settingsfilledinactiveicon.png → settings_icon.png} +0 -0
- /package/android/src/debug/res/drawable-mdpi/{_expodevclientcomponents_assets_shakedeviceicon.png → shake_device_icon.png} +0 -0
- /package/android/src/debug/res/drawable-mdpi/{_expodevclientcomponents_assets_showmenuatlaunchicon.png → show_menu_at_launch_icon.png} +0 -0
- /package/android/src/debug/res/drawable-mdpi/{_expodevclientcomponents_assets_terminalicon.png → terminal_icon.png} +0 -0
- /package/android/src/debug/res/drawable-mdpi/{_expodevclientcomponents_assets_threefingerlongpressicon.png → three_finger_long_press_icon.png} +0 -0
- /package/android/src/debug/res/drawable-mdpi/{_expodevclientcomponents_assets_updateicon.png → update_icon.png} +0 -0
- /package/android/src/debug/res/drawable-mdpi/{_expodevclientcomponents_assets_usericon.png → user_icon.png} +0 -0
- /package/android/src/debug/res/drawable-mdpi/{_expodevclientcomponents_assets_xicon.png → x_icon.png} +0 -0
- /package/android/src/debug/res/{drawable-mdpi/_expodevclientcomponents_assets_shakedeviceiconlight.png → drawable-night-mdpi/shake_device_icon.png} +0 -0
- /package/android/src/debug/res/{drawable-xhdpi/_expodevclientcomponents_assets_shakedeviceiconlight.png → drawable-night-xhdpi/shake_device_icon.png} +0 -0
- /package/android/src/debug/res/{drawable-xxhdpi/_expodevclientcomponents_assets_shakedeviceiconlight.png → drawable-night-xxhdpi/shake_device_icon.png} +0 -0
- /package/android/src/debug/res/drawable-xhdpi/{_expodevclientcomponents_assets_branchicon.png → branch_icon.png} +0 -0
- /package/android/src/debug/res/drawable-xhdpi/{_expodevclientcomponents_assets_buildingicon.png → building_icon.png} +0 -0
- /package/android/src/debug/res/drawable-xhdpi/{_expodevclientcomponents_assets_checkicon.png → check_icon.png} +0 -0
- /package/android/src/debug/res/drawable-xhdpi/{_expodevclientcomponents_assets_chevronrighticon.png → chevron_right_icon.png} +0 -0
- /package/android/src/debug/res/drawable-xhdpi/{_expodevclientcomponents_assets_extensionsicon.png → extensions_icon.png} +0 -0
- /package/android/src/debug/res/drawable-xhdpi/{_expodevclientcomponents_assets_homefilledinactiveicon.png → home_icon.png} +0 -0
- /package/android/src/debug/res/drawable-xhdpi/{_expodevclientcomponents_assets_infoicon.png → info_icon.png} +0 -0
- /package/android/src/debug/res/drawable-xhdpi/{_expodevclientcomponents_assets_settingsfilledinactiveicon.png → settings_icon.png} +0 -0
- /package/android/src/debug/res/drawable-xhdpi/{_expodevclientcomponents_assets_shakedeviceicon.png → shake_device_icon.png} +0 -0
- /package/android/src/debug/res/drawable-xhdpi/{_expodevclientcomponents_assets_showmenuatlaunchicon.png → show_menu_at_launch_icon.png} +0 -0
- /package/android/src/debug/res/drawable-xhdpi/{_expodevclientcomponents_assets_terminalicon.png → terminal_icon.png} +0 -0
- /package/android/src/debug/res/drawable-xhdpi/{_expodevclientcomponents_assets_threefingerlongpressicon.png → three_finger_long_press_icon.png} +0 -0
- /package/android/src/debug/res/drawable-xhdpi/{_expodevclientcomponents_assets_updateicon.png → update_icon.png} +0 -0
- /package/android/src/debug/res/drawable-xhdpi/{_expodevclientcomponents_assets_usericon.png → user_icon.png} +0 -0
- /package/android/src/debug/res/drawable-xhdpi/{_expodevclientcomponents_assets_xicon.png → x_icon.png} +0 -0
- /package/android/src/debug/res/drawable-xxhdpi/{_expodevclientcomponents_assets_branchicon.png → branch_icon.png} +0 -0
- /package/android/src/debug/res/drawable-xxhdpi/{_expodevclientcomponents_assets_buildingicon.png → building_icon.png} +0 -0
- /package/android/src/debug/res/drawable-xxhdpi/{_expodevclientcomponents_assets_checkicon.png → check_icon.png} +0 -0
- /package/android/src/debug/res/drawable-xxhdpi/{_expodevclientcomponents_assets_chevronrighticon.png → chevron_right_icon.png} +0 -0
- /package/android/src/debug/res/drawable-xxhdpi/{_expodevclientcomponents_assets_extensionsicon.png → extensions_icon.png} +0 -0
- /package/android/src/debug/res/drawable-xxhdpi/{_expodevclientcomponents_assets_homefilledinactiveicon.png → home_icon.png} +0 -0
- /package/android/src/debug/res/drawable-xxhdpi/{_expodevclientcomponents_assets_infoicon.png → info_icon.png} +0 -0
- /package/android/src/debug/res/drawable-xxhdpi/{_expodevclientcomponents_assets_settingsfilledinactiveicon.png → settings_icon.png} +0 -0
- /package/android/src/debug/res/drawable-xxhdpi/{_expodevclientcomponents_assets_shakedeviceicon.png → shake_device_icon.png} +0 -0
- /package/android/src/debug/res/drawable-xxhdpi/{_expodevclientcomponents_assets_showmenuatlaunchicon.png → show_menu_at_launch_icon.png} +0 -0
- /package/android/src/debug/res/drawable-xxhdpi/{_expodevclientcomponents_assets_terminalicon.png → terminal_icon.png} +0 -0
- /package/android/src/debug/res/drawable-xxhdpi/{_expodevclientcomponents_assets_threefingerlongpressicon.png → three_finger_long_press_icon.png} +0 -0
- /package/android/src/debug/res/drawable-xxhdpi/{_expodevclientcomponents_assets_updateicon.png → update_icon.png} +0 -0
- /package/android/src/debug/res/drawable-xxhdpi/{_expodevclientcomponents_assets_usericon.png → user_icon.png} +0 -0
- /package/android/src/debug/res/drawable-xxhdpi/{_expodevclientcomponents_assets_xicon.png → x_icon.png} +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -7,15 +7,20 @@
|
|
|
7
7
|
### 🎉 New features
|
|
8
8
|
|
|
9
9
|
- [iOS] Reimplement UI in SwiftUI. ([#37413](https://github.com/expo/expo/pull/37413) by [@alanjhughes](https://github.com/alanjhughes))
|
|
10
|
+
- [Android] Add floating action button option in the settings menu. ([#38247](https://github.com/expo/expo/pull/38247) by [@behenate](https://github.com/behenate))
|
|
11
|
+
- [iOS] Partial support for Apple TV. ([#38388](https://github.com/expo/expo/pull/38388) by [@douglowder](https://github.com/douglowder))
|
|
10
12
|
|
|
11
13
|
### 🐛 Bug fixes
|
|
12
14
|
|
|
13
15
|
- [iOS] Fix missing CDP headers when using static frameworks. ([#37448](https://github.com/expo/expo/pull/37448) by [@alanjhughes](https://github.com/alanjhughes))
|
|
14
16
|
- [Android] Use same strings in UI as iOS. ([#37786](https://github.com/expo/expo/pull/37786) by [@douglowder](https://github.com/douglowder))
|
|
17
|
+
- [iOS] Fix an issue where the packager commands stop working after a reload. ([#38579](https://github.com/expo/expo/pull/38579) by [@alanjhughes](https://github.com/alanjhughes))
|
|
15
18
|
|
|
16
19
|
### 💡 Others
|
|
17
20
|
|
|
21
|
+
- [Android] RN 0.81.0: patched some reflection issues after kotlin upgrade ([#38451](https://github.com/expo/expo/pull/38451) by [@chrfalch](https://github.com/chrfalch))
|
|
18
22
|
- Fixed release build error on Android. ([#37579](https://github.com/expo/expo/pull/37579) by [@kudo](https://github.com/kudo))
|
|
23
|
+
- Informational message for tvOS on signin page. ([#38518](https://github.com/expo/expo/pull/38518) by [@douglowder](https://github.com/douglowder))
|
|
19
24
|
|
|
20
25
|
### ⚠️ Notices
|
|
21
26
|
|
package/android/build.gradle
CHANGED
|
@@ -20,13 +20,13 @@ expoModule {
|
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
group = "host.exp.exponent"
|
|
23
|
-
version = "5.2.0-canary-
|
|
23
|
+
version = "5.2.0-canary-20250811-5c940c0"
|
|
24
24
|
|
|
25
25
|
android {
|
|
26
26
|
namespace "expo.modules.devlauncher"
|
|
27
27
|
defaultConfig {
|
|
28
28
|
versionCode 9
|
|
29
|
-
versionName "5.2.0-canary-
|
|
29
|
+
versionName "5.2.0-canary-20250811-5c940c0"
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
buildTypes {
|
|
@@ -97,6 +97,10 @@ dependencies {
|
|
|
97
97
|
implementation "androidx.compose.ui:ui:$composeVersion"
|
|
98
98
|
implementation "androidx.compose.ui:ui-tooling:$composeVersion"
|
|
99
99
|
implementation "androidx.navigation:navigation-compose:2.9.0"
|
|
100
|
+
implementation "com.google.android.gms:play-services-code-scanner:16.1.0"
|
|
101
|
+
implementation "com.google.mlkit:barcode-scanning:17.3.0"
|
|
102
|
+
|
|
103
|
+
implementation("org.jetbrains.kotlinx:kotlinx-datetime:0.7.1")
|
|
100
104
|
|
|
101
105
|
implementation("com.apollographql.apollo:apollo-runtime:4.3.1")
|
|
102
106
|
|
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
|
2
|
+
|
|
2
3
|
<application>
|
|
3
4
|
<activity
|
|
4
5
|
android:name="expo.modules.devlauncher.launcher.DevLauncherActivity"
|
|
5
6
|
android:exported="true"
|
|
6
7
|
android:launchMode="singleTask"
|
|
7
|
-
android:theme="@style/Theme.
|
|
8
|
+
android:theme="@style/Theme.AppCompat.DayNight.NoActionBar" />
|
|
8
9
|
|
|
9
10
|
<activity
|
|
10
11
|
android:name="expo.modules.devlauncher.compose.AuthActivity"
|
|
11
12
|
android:exported="true"
|
|
12
|
-
android:launchMode="singleTask"
|
|
13
|
+
android:launchMode="singleTask"
|
|
14
|
+
android:theme="@style/Theme.AppCompat.DayNight.NoActionBar">
|
|
13
15
|
<intent-filter>
|
|
14
16
|
<action android:name="android.intent.action.VIEW" />
|
|
15
17
|
|
|
@@ -5,6 +5,7 @@ import android.content.Context
|
|
|
5
5
|
import android.content.Intent
|
|
6
6
|
import android.net.Uri
|
|
7
7
|
import android.os.Bundle
|
|
8
|
+
import android.util.Log
|
|
8
9
|
import androidx.annotation.UiThread
|
|
9
10
|
import androidx.core.net.toUri
|
|
10
11
|
import com.facebook.react.ReactActivity
|
|
@@ -52,10 +53,6 @@ import org.koin.core.component.get
|
|
|
52
53
|
import org.koin.core.component.inject
|
|
53
54
|
import org.koin.dsl.module
|
|
54
55
|
|
|
55
|
-
// Use this to load from a development server for the development client launcher UI
|
|
56
|
-
// private val DEV_LAUNCHER_HOST = "10.0.0.175:8090";
|
|
57
|
-
private val DEV_LAUNCHER_HOST: String? = null
|
|
58
|
-
|
|
59
56
|
private const val NEW_ACTIVITY_FLAGS = Intent.FLAG_ACTIVITY_NEW_TASK or
|
|
60
57
|
Intent.FLAG_ACTIVITY_CLEAR_TASK or
|
|
61
58
|
Intent.FLAG_ACTIVITY_NO_ANIMATION
|
|
@@ -90,7 +87,6 @@ class DevLauncherController private constructor() :
|
|
|
90
87
|
|
|
91
88
|
override val coroutineScope = CoroutineScope(Dispatchers.Default)
|
|
92
89
|
|
|
93
|
-
|
|
94
90
|
private val recentlyOpedAppsRegistry = DevLauncherRecentlyOpenedAppsRegistry(context)
|
|
95
91
|
override var manifest: Manifest? = null
|
|
96
92
|
private set
|
|
@@ -419,6 +415,17 @@ class DevLauncherController private constructor() :
|
|
|
419
415
|
|
|
420
416
|
@JvmStatic
|
|
421
417
|
internal fun initialize(context: Context, reactHost: ReactHostWrapper) {
|
|
418
|
+
try {
|
|
419
|
+
val splashScreenManagerClass = Class.forName("expo.modules.splashscreen.SplashScreenManager")
|
|
420
|
+
val splashScreenManager = splashScreenManagerClass
|
|
421
|
+
.kotlin
|
|
422
|
+
.objectInstance
|
|
423
|
+
splashScreenManagerClass.getMethod("hide")
|
|
424
|
+
.invoke(splashScreenManager)
|
|
425
|
+
} catch (e: Throwable) {
|
|
426
|
+
Log.e("DevLauncherController", "Failed to hide splash screen", e)
|
|
427
|
+
}
|
|
428
|
+
|
|
422
429
|
val testInterceptor = DevLauncherKoinContext.app.koin.get<DevLauncherTestInterceptor>()
|
|
423
430
|
if (!testInterceptor.allowReinitialization()) {
|
|
424
431
|
check(!wasInitialized()) { "DevelopmentClientController was initialized." }
|
package/android/src/debug/java/expo/modules/devlauncher/compose/DevLauncherBottomTabsNavigator.kt
CHANGED
|
@@ -8,6 +8,7 @@ import androidx.compose.foundation.background
|
|
|
8
8
|
import androidx.compose.foundation.layout.Box
|
|
9
9
|
import androidx.compose.foundation.layout.fillMaxSize
|
|
10
10
|
import androidx.compose.runtime.Composable
|
|
11
|
+
import androidx.compose.runtime.remember
|
|
11
12
|
import androidx.compose.ui.Modifier
|
|
12
13
|
import androidx.compose.ui.graphics.painter.Painter
|
|
13
14
|
import androidx.navigation.compose.NavHost
|
|
@@ -16,11 +17,11 @@ import androidx.navigation.compose.rememberNavController
|
|
|
16
17
|
import expo.modules.devlauncher.compose.primitives.DefaultScaffold
|
|
17
18
|
import expo.modules.devlauncher.compose.routes.CrashReport
|
|
18
19
|
import expo.modules.devlauncher.compose.routes.CrashReportRoute
|
|
19
|
-
import expo.modules.devlauncher.compose.routes.Home
|
|
20
20
|
import expo.modules.devlauncher.compose.routes.HomeRoute
|
|
21
21
|
import expo.modules.devlauncher.compose.routes.ProfileRoute
|
|
22
|
-
import expo.modules.devlauncher.compose.routes.
|
|
22
|
+
import expo.modules.devlauncher.compose.routes.Routes
|
|
23
23
|
import expo.modules.devlauncher.compose.routes.SettingsRoute
|
|
24
|
+
import expo.modules.devlauncher.compose.routes.UpdatesRoute
|
|
24
25
|
import expo.modules.devlauncher.compose.ui.BottomTabBar
|
|
25
26
|
import expo.modules.devlauncher.compose.ui.Full
|
|
26
27
|
import expo.modules.devlauncher.compose.ui.rememberBottomSheetState
|
|
@@ -55,6 +56,10 @@ fun DevLauncherBottomTabsNavigator() {
|
|
|
55
56
|
val bottomTabsNavController = rememberNavController()
|
|
56
57
|
val bottomSheetState = rememberBottomSheetState()
|
|
57
58
|
|
|
59
|
+
val navigateToProfile = remember {
|
|
60
|
+
{ bottomSheetState.targetDetent = Full }
|
|
61
|
+
}
|
|
62
|
+
|
|
58
63
|
NavHost(
|
|
59
64
|
navController = mainNavController,
|
|
60
65
|
startDestination = Main
|
|
@@ -78,7 +83,7 @@ fun DevLauncherBottomTabsNavigator() {
|
|
|
78
83
|
}) {
|
|
79
84
|
NavHost(
|
|
80
85
|
navController = bottomTabsNavController,
|
|
81
|
-
startDestination = Home,
|
|
86
|
+
startDestination = Routes.Home,
|
|
82
87
|
enterTransition = {
|
|
83
88
|
EnterTransition.None
|
|
84
89
|
},
|
|
@@ -86,10 +91,13 @@ fun DevLauncherBottomTabsNavigator() {
|
|
|
86
91
|
ExitTransition.None
|
|
87
92
|
}
|
|
88
93
|
) {
|
|
89
|
-
composable<Home> {
|
|
90
|
-
HomeRoute(navController = mainNavController, onProfileClick =
|
|
94
|
+
composable<Routes.Home> {
|
|
95
|
+
HomeRoute(navController = mainNavController, onProfileClick = navigateToProfile)
|
|
96
|
+
}
|
|
97
|
+
composable<Routes.Updates> {
|
|
98
|
+
UpdatesRoute(onProfileClick = navigateToProfile)
|
|
91
99
|
}
|
|
92
|
-
composable<Settings> {
|
|
100
|
+
composable<Routes.Settings> {
|
|
93
101
|
SettingsRoute()
|
|
94
102
|
}
|
|
95
103
|
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
package expo.modules.devlauncher.compose
|
|
2
|
+
|
|
3
|
+
data class Update(
|
|
4
|
+
val id: String,
|
|
5
|
+
val name: String,
|
|
6
|
+
val createdAt: String?,
|
|
7
|
+
val isCompatible: Boolean = false,
|
|
8
|
+
val permalink: String
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
data class Branch(
|
|
12
|
+
val name: String,
|
|
13
|
+
val compatibleUpdate: Update? = null
|
|
14
|
+
)
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
package expo.modules.devlauncher.compose.models
|
|
2
|
+
|
|
3
|
+
import androidx.compose.runtime.mutableStateOf
|
|
4
|
+
import androidx.lifecycle.ViewModel
|
|
5
|
+
import androidx.lifecycle.viewModelScope
|
|
6
|
+
import expo.modules.devlauncher.DevLauncherController
|
|
7
|
+
import expo.modules.devlauncher.compose.Update
|
|
8
|
+
import expo.modules.devlauncher.compose.utils.formatUpdateUrl
|
|
9
|
+
import expo.modules.devlauncher.services.ApolloClientService
|
|
10
|
+
import expo.modules.devlauncher.services.AppService
|
|
11
|
+
import expo.modules.devlauncher.services.ApplicationInfo
|
|
12
|
+
import expo.modules.devlauncher.services.inject
|
|
13
|
+
import kotlinx.coroutines.flow.MutableStateFlow
|
|
14
|
+
import kotlinx.coroutines.flow.SharingStarted.Companion.WhileSubscribed
|
|
15
|
+
import kotlinx.coroutines.flow.onStart
|
|
16
|
+
import kotlinx.coroutines.flow.stateIn
|
|
17
|
+
import kotlinx.coroutines.launch
|
|
18
|
+
|
|
19
|
+
sealed interface BranchAction {
|
|
20
|
+
object LoadMoreUpdates : BranchAction
|
|
21
|
+
class OpenUpdate(val update: Update) : BranchAction
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
data class BranchState(
|
|
25
|
+
val updates: List<Update> = emptyList(),
|
|
26
|
+
val isLoading: Boolean = false
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
class BranchViewModel(private val branchName: String) : ViewModel() {
|
|
30
|
+
private val appService = inject<AppService>()
|
|
31
|
+
private val apolloClientService = inject<ApolloClientService>()
|
|
32
|
+
private val launcher = inject<DevLauncherController>()
|
|
33
|
+
|
|
34
|
+
private val hasMore = mutableStateOf(true)
|
|
35
|
+
|
|
36
|
+
private var _state = MutableStateFlow(
|
|
37
|
+
BranchState(
|
|
38
|
+
updates = emptyList(),
|
|
39
|
+
isLoading = true
|
|
40
|
+
)
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
val state = _state.onStart {
|
|
44
|
+
hasMore.value = true
|
|
45
|
+
loadMoreUpdates()
|
|
46
|
+
}.stateIn(
|
|
47
|
+
scope = viewModelScope,
|
|
48
|
+
started = WhileSubscribed(5_000),
|
|
49
|
+
initialValue = _state.value
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
private suspend fun loadMoreUpdates() {
|
|
53
|
+
if (!hasMore.value) {
|
|
54
|
+
return
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
val updateConfiguration = appService.applicationInfo as? ApplicationInfo.Updates
|
|
58
|
+
if (updateConfiguration == null) {
|
|
59
|
+
return
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
_state.value = _state.value.copy(isLoading = true)
|
|
63
|
+
|
|
64
|
+
val appId = updateConfiguration.appId
|
|
65
|
+
val runtimeVersion = updateConfiguration.runtimeVersion
|
|
66
|
+
val limit = 50
|
|
67
|
+
|
|
68
|
+
val updates = apolloClientService.fetchUpdates(
|
|
69
|
+
appId = appId,
|
|
70
|
+
branchName = branchName,
|
|
71
|
+
limit = limit,
|
|
72
|
+
offset = _state.value.updates.size
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
val uiUpdates = updates.data?.app?.byId?.updateBranchByName?.updates?.map { update ->
|
|
76
|
+
Update(
|
|
77
|
+
id = update.id,
|
|
78
|
+
name = update.message ?: "No message",
|
|
79
|
+
createdAt = update.createdAt as? String,
|
|
80
|
+
isCompatible = update.runtimeVersion == runtimeVersion,
|
|
81
|
+
permalink = update.manifestPermalink
|
|
82
|
+
)
|
|
83
|
+
} ?: emptyList()
|
|
84
|
+
|
|
85
|
+
hasMore.value = uiUpdates.size == limit
|
|
86
|
+
|
|
87
|
+
_state.value = _state.value.copy(
|
|
88
|
+
updates = _state.value.updates + uiUpdates,
|
|
89
|
+
isLoading = false
|
|
90
|
+
)
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
fun onAction(action: BranchAction) {
|
|
94
|
+
when (action) {
|
|
95
|
+
BranchAction.LoadMoreUpdates -> viewModelScope.launch { loadMoreUpdates() }
|
|
96
|
+
is BranchAction.OpenUpdate -> {
|
|
97
|
+
launcher.coroutineScope.launch {
|
|
98
|
+
launcher.loadApp(
|
|
99
|
+
formatUpdateUrl(action.update.permalink, action.update.name)
|
|
100
|
+
)
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
package expo.modules.devlauncher.compose.models
|
|
2
|
+
|
|
3
|
+
import androidx.compose.runtime.mutableStateOf
|
|
4
|
+
import androidx.lifecycle.ViewModel
|
|
5
|
+
import androidx.lifecycle.viewModelScope
|
|
6
|
+
import expo.modules.devlauncher.compose.Branch
|
|
7
|
+
import expo.modules.devlauncher.compose.Update
|
|
8
|
+
import expo.modules.devlauncher.services.ApolloClientService
|
|
9
|
+
import expo.modules.devlauncher.services.AppService
|
|
10
|
+
import expo.modules.devlauncher.services.ApplicationInfo
|
|
11
|
+
import expo.modules.devlauncher.services.inject
|
|
12
|
+
import kotlinx.coroutines.flow.MutableStateFlow
|
|
13
|
+
import kotlinx.coroutines.flow.SharingStarted.Companion.WhileSubscribed
|
|
14
|
+
import kotlinx.coroutines.flow.onStart
|
|
15
|
+
import kotlinx.coroutines.flow.stateIn
|
|
16
|
+
import kotlinx.coroutines.launch
|
|
17
|
+
|
|
18
|
+
sealed interface BranchesAction {
|
|
19
|
+
object LoadMoreBranches : BranchesAction
|
|
20
|
+
class OpenBranch(val branchName: String) : BranchesAction
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
data class BranchesState(
|
|
24
|
+
val branches: List<Branch> = emptyList(),
|
|
25
|
+
val isLoading: Boolean = false
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
class BranchesViewModel : ViewModel() {
|
|
29
|
+
private val apolloClientService = inject<ApolloClientService>()
|
|
30
|
+
private val appService = inject<AppService>()
|
|
31
|
+
|
|
32
|
+
private val hasMore = mutableStateOf(true)
|
|
33
|
+
|
|
34
|
+
val areUpdatesConfigured get() = appService.applicationInfo is ApplicationInfo.Updates
|
|
35
|
+
|
|
36
|
+
private var _state = MutableStateFlow(
|
|
37
|
+
BranchesState(
|
|
38
|
+
branches = emptyList(),
|
|
39
|
+
isLoading = areUpdatesConfigured
|
|
40
|
+
)
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
val state = _state.onStart {
|
|
44
|
+
if (areUpdatesConfigured) {
|
|
45
|
+
hasMore.value = true
|
|
46
|
+
loadMoreBranches()
|
|
47
|
+
}
|
|
48
|
+
}.stateIn(
|
|
49
|
+
scope = viewModelScope,
|
|
50
|
+
started = WhileSubscribed(5_000),
|
|
51
|
+
initialValue = _state.value
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
private suspend fun loadMoreBranches() {
|
|
55
|
+
val updateConfiguration = appService.applicationInfo as? ApplicationInfo.Updates
|
|
56
|
+
|
|
57
|
+
// If the app is not configured for updates, we don't need to fetch branches.
|
|
58
|
+
if (updateConfiguration == null || !hasMore.value) {
|
|
59
|
+
return
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
val appId = updateConfiguration.appId
|
|
63
|
+
val runtimeVersion = updateConfiguration.runtimeVersion
|
|
64
|
+
val limit = 50
|
|
65
|
+
|
|
66
|
+
val branches = if (runtimeVersion != null) {
|
|
67
|
+
apolloClientService.fetchBranches(
|
|
68
|
+
appId = appId,
|
|
69
|
+
runtimeVersion = runtimeVersion,
|
|
70
|
+
offset = _state.value.branches.size,
|
|
71
|
+
limit = limit
|
|
72
|
+
).data?.app?.byId?.updateBranches?.map { updateBranch ->
|
|
73
|
+
Branch(
|
|
74
|
+
name = updateBranch.name,
|
|
75
|
+
compatibleUpdate = updateBranch.compatibleUpdates.firstOrNull()?.let { update ->
|
|
76
|
+
Update(
|
|
77
|
+
id = update.id,
|
|
78
|
+
name = update.message ?: "No message",
|
|
79
|
+
createdAt = update.createdAt as? String,
|
|
80
|
+
isCompatible = true,
|
|
81
|
+
permalink = update.manifestPermalink
|
|
82
|
+
)
|
|
83
|
+
}
|
|
84
|
+
)
|
|
85
|
+
}
|
|
86
|
+
} else {
|
|
87
|
+
apolloClientService.fetchBranches(
|
|
88
|
+
appId = appId,
|
|
89
|
+
offset = _state.value.branches.size,
|
|
90
|
+
limit = limit
|
|
91
|
+
).data?.app?.byId?.updateBranches?.map { updateBranch ->
|
|
92
|
+
Branch(
|
|
93
|
+
name = updateBranch.name,
|
|
94
|
+
compatibleUpdate = null
|
|
95
|
+
)
|
|
96
|
+
}
|
|
97
|
+
} ?: emptyList()
|
|
98
|
+
|
|
99
|
+
hasMore.value = branches.size == limit
|
|
100
|
+
|
|
101
|
+
_state.value = _state.value.copy(
|
|
102
|
+
isLoading = false,
|
|
103
|
+
branches = _state.value.branches + branches
|
|
104
|
+
)
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
fun onAction(action: BranchesAction) {
|
|
108
|
+
when (action) {
|
|
109
|
+
BranchesAction.LoadMoreBranches -> viewModelScope.launch { loadMoreBranches() }
|
|
110
|
+
is BranchesAction.OpenBranch -> throw IllegalStateException("Opening branches should be handled in the screen, not in the ViewModel.")
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
package expo.modules.devlauncher.compose.models
|
|
2
|
+
|
|
3
|
+
import androidx.compose.runtime.mutableStateOf
|
|
4
|
+
import androidx.lifecycle.ViewModel
|
|
5
|
+
import com.facebook.react.ReactActivity
|
|
6
|
+
import expo.modules.devlauncher.DevLauncherController
|
|
7
|
+
import expo.modules.devlauncher.launcher.errors.DevLauncherAppError
|
|
8
|
+
import expo.modules.devlauncher.services.inject
|
|
9
|
+
import kotlinx.coroutines.launch
|
|
10
|
+
|
|
11
|
+
sealed interface ErrorAction {
|
|
12
|
+
object Reload : ErrorAction
|
|
13
|
+
object GoToHome : ErrorAction
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
class ErrorViewModel() : ViewModel() {
|
|
17
|
+
private val devLauncher = inject<DevLauncherController>()
|
|
18
|
+
|
|
19
|
+
private val _appError = mutableStateOf<DevLauncherAppError?>(null)
|
|
20
|
+
|
|
21
|
+
val appError
|
|
22
|
+
get() = _appError.value
|
|
23
|
+
|
|
24
|
+
fun setError(error: DevLauncherAppError) {
|
|
25
|
+
_appError.value = error
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
fun onAction(action: ErrorAction) {
|
|
29
|
+
when (action) {
|
|
30
|
+
is ErrorAction.Reload -> {
|
|
31
|
+
val appUrl = devLauncher.latestLoadedApp
|
|
32
|
+
|
|
33
|
+
if (appUrl == null) {
|
|
34
|
+
devLauncher.navigateToLauncher()
|
|
35
|
+
return
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
devLauncher.coroutineScope.launch {
|
|
39
|
+
devLauncher
|
|
40
|
+
.loadApp(
|
|
41
|
+
appUrl,
|
|
42
|
+
devLauncher.appHost.currentReactContext?.currentActivity as? ReactActivity?
|
|
43
|
+
)
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
is ErrorAction.GoToHome -> devLauncher.navigateToLauncher()
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
@@ -1,24 +1,22 @@
|
|
|
1
1
|
package expo.modules.devlauncher.compose.models
|
|
2
2
|
|
|
3
|
-
import android.
|
|
3
|
+
import android.content.Context
|
|
4
4
|
import androidx.compose.runtime.mutableStateOf
|
|
5
5
|
import androidx.core.net.toUri
|
|
6
6
|
import androidx.lifecycle.ViewModel
|
|
7
7
|
import androidx.lifecycle.viewModelScope
|
|
8
|
+
import com.google.mlkit.vision.barcode.common.Barcode
|
|
9
|
+
import com.google.mlkit.vision.codescanner.GmsBarcodeScannerOptions
|
|
10
|
+
import com.google.mlkit.vision.codescanner.GmsBarcodeScanning
|
|
8
11
|
import expo.modules.devlauncher.DevLauncherController
|
|
9
|
-
import expo.modules.devlauncher.MeQuery
|
|
10
12
|
import expo.modules.devlauncher.launcher.DevLauncherAppEntry
|
|
11
13
|
import expo.modules.devlauncher.launcher.errors.DevLauncherErrorInstance
|
|
12
|
-
import expo.modules.devlauncher.services.AppService
|
|
13
14
|
import expo.modules.devlauncher.services.ErrorRegistryService
|
|
14
15
|
import expo.modules.devlauncher.services.PackagerInfo
|
|
15
16
|
import expo.modules.devlauncher.services.PackagerService
|
|
16
|
-
import expo.modules.devlauncher.services.SessionService
|
|
17
|
-
import expo.modules.devlauncher.services.UserState
|
|
18
17
|
import expo.modules.devlauncher.services.inject
|
|
19
18
|
import kotlinx.coroutines.flow.launchIn
|
|
20
19
|
import kotlinx.coroutines.flow.onEach
|
|
21
|
-
import kotlinx.coroutines.flow.onStart
|
|
22
20
|
import kotlinx.coroutines.launch
|
|
23
21
|
|
|
24
22
|
sealed interface HomeAction {
|
|
@@ -26,32 +24,26 @@ sealed interface HomeAction {
|
|
|
26
24
|
object RefetchRunningApps : HomeAction
|
|
27
25
|
object ResetRecentlyOpenedApps : HomeAction
|
|
28
26
|
class NavigateToCrashReport(val crashReport: DevLauncherErrorInstance) : HomeAction
|
|
27
|
+
object ScanQRCode : HomeAction
|
|
28
|
+
object ClearLoadingError : HomeAction
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
data class HomeState(
|
|
32
|
-
val appName: String = "Unknown App",
|
|
33
32
|
val runningPackagers: Set<PackagerInfo> = emptySet(),
|
|
34
33
|
val isFetchingPackagers: Boolean = false,
|
|
35
|
-
val currentAccount: MeQuery.Account? = null,
|
|
36
34
|
val recentlyOpenedApps: List<DevLauncherAppEntry> = emptyList(),
|
|
37
|
-
val crashReport: DevLauncherErrorInstance? = null
|
|
35
|
+
val crashReport: DevLauncherErrorInstance? = null,
|
|
36
|
+
val loadingError: String? = null
|
|
38
37
|
)
|
|
39
38
|
|
|
40
39
|
class HomeViewModel() : ViewModel() {
|
|
41
40
|
val devLauncherController = inject<DevLauncherController>()
|
|
42
|
-
val sessionService = inject<SessionService>()
|
|
43
41
|
val packagerService = inject<PackagerService>()
|
|
44
|
-
val appService = inject<AppService>()
|
|
45
42
|
val errorRegistryService = inject<ErrorRegistryService>()
|
|
46
43
|
|
|
47
44
|
private var _state = mutableStateOf(
|
|
48
45
|
HomeState(
|
|
49
|
-
appName = appService.applicationInfo.appName,
|
|
50
46
|
runningPackagers = packagerService.runningPackagers.value,
|
|
51
|
-
currentAccount = when (val userState = sessionService.user.value) {
|
|
52
|
-
UserState.Fetching, UserState.LoggedOut -> null
|
|
53
|
-
is UserState.LoggedIn -> userState.selectedAccount
|
|
54
|
-
},
|
|
55
47
|
recentlyOpenedApps = devLauncherController.getRecentlyOpenedApps(),
|
|
56
48
|
crashReport = errorRegistryService.consumeException()
|
|
57
49
|
)
|
|
@@ -70,18 +62,6 @@ class HomeViewModel() : ViewModel() {
|
|
|
70
62
|
}
|
|
71
63
|
.launchIn(viewModelScope)
|
|
72
64
|
|
|
73
|
-
sessionService.user.onEach { newUser ->
|
|
74
|
-
when (newUser) {
|
|
75
|
-
UserState.Fetching, UserState.LoggedOut -> _state.value = _state.value.copy(
|
|
76
|
-
currentAccount = null
|
|
77
|
-
)
|
|
78
|
-
|
|
79
|
-
is UserState.LoggedIn -> _state.value = _state.value.copy(
|
|
80
|
-
currentAccount = newUser.selectedAccount
|
|
81
|
-
)
|
|
82
|
-
}
|
|
83
|
-
}.launchIn(viewModelScope)
|
|
84
|
-
|
|
85
65
|
packagerService.isLoading.onEach { isLoading ->
|
|
86
66
|
_state.value = _state.value.copy(
|
|
87
67
|
isFetchingPackagers = isLoading
|
|
@@ -96,7 +76,9 @@ class HomeViewModel() : ViewModel() {
|
|
|
96
76
|
try {
|
|
97
77
|
devLauncherController.loadApp(action.url.toUri(), mainActivity = null)
|
|
98
78
|
} catch (e: Exception) {
|
|
99
|
-
|
|
79
|
+
_state.value = _state.value.copy(
|
|
80
|
+
loadingError = e.message ?: "Unknown error"
|
|
81
|
+
)
|
|
100
82
|
}
|
|
101
83
|
}
|
|
102
84
|
|
|
@@ -107,7 +89,32 @@ class HomeViewModel() : ViewModel() {
|
|
|
107
89
|
_state.value = _state.value.copy(recentlyOpenedApps = emptyList())
|
|
108
90
|
}
|
|
109
91
|
|
|
92
|
+
is HomeAction.ClearLoadingError -> _state.value = _state.value.copy(loadingError = null)
|
|
93
|
+
|
|
110
94
|
is HomeAction.NavigateToCrashReport -> IllegalStateException("Navigation action should be handled by the UI layer, not the ViewModel.")
|
|
95
|
+
|
|
96
|
+
is HomeAction.ScanQRCode -> IllegalStateException("QR code scanning should be handled by the UI layer, not the ViewModel.")
|
|
111
97
|
}
|
|
112
98
|
}
|
|
99
|
+
|
|
100
|
+
fun scanQRCode(context: Context, onResult: (String) -> Unit, onError: (String) -> Unit) {
|
|
101
|
+
val options = GmsBarcodeScannerOptions.Builder()
|
|
102
|
+
.setBarcodeFormats(Barcode.FORMAT_QR_CODE)
|
|
103
|
+
.build()
|
|
104
|
+
|
|
105
|
+
val scanner = GmsBarcodeScanning.getClient(context, options)
|
|
106
|
+
|
|
107
|
+
scanner.startScan()
|
|
108
|
+
.addOnSuccessListener { barcode ->
|
|
109
|
+
barcode.rawValue?.let {
|
|
110
|
+
onResult(it)
|
|
111
|
+
} ?: onError("No QR code data found")
|
|
112
|
+
}
|
|
113
|
+
.addOnCanceledListener {
|
|
114
|
+
onError("Scanning cancelled")
|
|
115
|
+
}
|
|
116
|
+
.addOnFailureListener { exception ->
|
|
117
|
+
onError("Scanning failed: ${exception.message ?: "Unknown error"}")
|
|
118
|
+
}
|
|
119
|
+
}
|
|
113
120
|
}
|
|
@@ -13,7 +13,9 @@ data class SettingsState(
|
|
|
13
13
|
val isShakeEnable: Boolean = true,
|
|
14
14
|
val isThreeFingerLongPressEnable: Boolean = true,
|
|
15
15
|
val isKeyCommandEnabled: Boolean = true,
|
|
16
|
-
val applicationInfo: ApplicationInfo? = null
|
|
16
|
+
val applicationInfo: ApplicationInfo? = null,
|
|
17
|
+
// TODO @behenate - make true the default for VR
|
|
18
|
+
val showFabAtLaunch: Boolean = false
|
|
17
19
|
)
|
|
18
20
|
|
|
19
21
|
sealed interface SettingsAction {
|
|
@@ -21,6 +23,7 @@ sealed interface SettingsAction {
|
|
|
21
23
|
data class ToggleShakeEnable(val newValue: Boolean) : SettingsAction
|
|
22
24
|
data class ToggleThreeFingerLongPressEnable(val newValue: Boolean) : SettingsAction
|
|
23
25
|
data class ToggleKeyCommandEnable(val newValue: Boolean) : SettingsAction
|
|
26
|
+
data class ToggleShowFabAtLaunch(val newValue: Boolean) : SettingsAction
|
|
24
27
|
}
|
|
25
28
|
|
|
26
29
|
class SettingsViewModel(application: Application) : AndroidViewModel(application) {
|
|
@@ -33,7 +36,8 @@ class SettingsViewModel(application: Application) : AndroidViewModel(application
|
|
|
33
36
|
isShakeEnable = menuPreferences.motionGestureEnabled,
|
|
34
37
|
isThreeFingerLongPressEnable = menuPreferences.touchGestureEnabled,
|
|
35
38
|
isKeyCommandEnabled = menuPreferences.keyCommandsEnabled,
|
|
36
|
-
applicationInfo = appService.applicationInfo
|
|
39
|
+
applicationInfo = appService.applicationInfo,
|
|
40
|
+
showFabAtLaunch = menuPreferences.showFab
|
|
37
41
|
)
|
|
38
42
|
)
|
|
39
43
|
|
|
@@ -45,7 +49,8 @@ class SettingsViewModel(application: Application) : AndroidViewModel(application
|
|
|
45
49
|
showMenuAtLaunch = menuPreferences.showsAtLaunch,
|
|
46
50
|
isShakeEnable = menuPreferences.motionGestureEnabled,
|
|
47
51
|
isThreeFingerLongPressEnable = menuPreferences.touchGestureEnabled,
|
|
48
|
-
isKeyCommandEnabled = menuPreferences.keyCommandsEnabled
|
|
52
|
+
isKeyCommandEnabled = menuPreferences.keyCommandsEnabled,
|
|
53
|
+
showFabAtLaunch = menuPreferences.showFab
|
|
49
54
|
)
|
|
50
55
|
}
|
|
51
56
|
|
|
@@ -75,6 +80,10 @@ class SettingsViewModel(application: Application) : AndroidViewModel(application
|
|
|
75
80
|
is SettingsAction.ToggleKeyCommandEnable -> {
|
|
76
81
|
menuPreferences.keyCommandsEnabled = action.newValue
|
|
77
82
|
}
|
|
83
|
+
|
|
84
|
+
is SettingsAction.ToggleShowFabAtLaunch -> {
|
|
85
|
+
menuPreferences.showFab = action.newValue
|
|
86
|
+
}
|
|
78
87
|
}
|
|
79
88
|
}
|
|
80
89
|
}
|
|
@@ -20,9 +20,9 @@ import androidx.compose.runtime.setValue
|
|
|
20
20
|
import androidx.compose.ui.Alignment
|
|
21
21
|
import androidx.compose.ui.Modifier
|
|
22
22
|
import androidx.compose.ui.draw.rotate
|
|
23
|
-
import androidx.compose.ui.res.painterResource
|
|
24
23
|
import androidx.compose.ui.tooling.preview.Preview
|
|
25
|
-
import
|
|
24
|
+
import expo.modules.devlauncher.R
|
|
25
|
+
import expo.modules.devmenu.compose.primitives.DayNighIcon
|
|
26
26
|
import expo.modules.devmenu.compose.primitives.Text
|
|
27
27
|
import expo.modules.devmenu.compose.theme.Theme
|
|
28
28
|
|
|
@@ -52,11 +52,12 @@ fun Accordion(
|
|
|
52
52
|
modifier = Modifier
|
|
53
53
|
.padding(Theme.spacing.medium)
|
|
54
54
|
) {
|
|
55
|
-
|
|
56
|
-
|
|
55
|
+
DayNighIcon(
|
|
56
|
+
id = R.drawable.chevron_right_icon,
|
|
57
57
|
contentDescription = "Accordion Arrow",
|
|
58
58
|
modifier = Modifier
|
|
59
59
|
.rotate(arrowRotation)
|
|
60
|
+
.size(Theme.sizing.icon.extraSmall)
|
|
60
61
|
)
|
|
61
62
|
Spacer(Modifier.size(Theme.spacing.small))
|
|
62
63
|
Text(
|
|
@@ -8,7 +8,6 @@ import androidx.compose.runtime.mutableStateOf
|
|
|
8
8
|
import androidx.compose.runtime.remember
|
|
9
9
|
import androidx.compose.runtime.rememberCoroutineScope
|
|
10
10
|
import androidx.compose.runtime.setValue
|
|
11
|
-
import androidx.compose.ui.graphics.ImageBitmap
|
|
12
11
|
import androidx.compose.ui.graphics.asImageBitmap
|
|
13
12
|
import expo.modules.devlauncher.services.ImageLoaderService
|
|
14
13
|
import expo.modules.devlauncher.services.inject
|
|
@@ -20,7 +19,7 @@ fun AsyncImage(
|
|
|
20
19
|
) {
|
|
21
20
|
val imageLoaderService = inject<ImageLoaderService>()
|
|
22
21
|
val scope = rememberCoroutineScope()
|
|
23
|
-
var imageBitmap by remember { mutableStateOf
|
|
22
|
+
var imageBitmap by remember { mutableStateOf(imageLoaderService.loadFromMemory(url)?.asImageBitmap()) }
|
|
24
23
|
|
|
25
24
|
LaunchedEffect(url) {
|
|
26
25
|
scope.launch {
|