expo-dev-launcher 5.2.0-canary-20250722-599a28f → 5.2.0-canary-20250729-d8899ae
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 +1 -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 +28 -26
- 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 +4 -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 +81 -0
- package/android/src/debug/java/expo/modules/devlauncher/compose/screens/BranchScreen.kt +234 -0
- package/android/src/debug/java/expo/modules/devlauncher/compose/screens/BranchesScreen.kt +261 -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 +35 -13
- package/android/src/debug/java/expo/modules/devlauncher/compose/screens/NoUpdatesScreen.kt +72 -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 +38 -5
- 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 +4 -6
- 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/launcher/errors/DevLauncherErrorActivity.kt +27 -96
- 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/splashscreen/DevLauncherSplashScreen.kt +0 -2
- package/android/src/main/res/values/styles.xml +0 -14
- package/ios/EXDevLauncherUtils.swift +0 -9
- 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,6 +7,7 @@
|
|
|
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))
|
|
10
11
|
|
|
11
12
|
### 🐛 Bug fixes
|
|
12
13
|
|
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-20250729-d8899ae"
|
|
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-20250729-d8899ae"
|
|
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,23 @@
|
|
|
1
1
|
package expo.modules.devlauncher.compose.models
|
|
2
2
|
|
|
3
|
+
import android.content.Context
|
|
3
4
|
import android.util.Log
|
|
4
5
|
import androidx.compose.runtime.mutableStateOf
|
|
5
6
|
import androidx.core.net.toUri
|
|
6
7
|
import androidx.lifecycle.ViewModel
|
|
7
8
|
import androidx.lifecycle.viewModelScope
|
|
9
|
+
import com.google.mlkit.vision.barcode.common.Barcode
|
|
10
|
+
import com.google.mlkit.vision.codescanner.GmsBarcodeScannerOptions
|
|
11
|
+
import com.google.mlkit.vision.codescanner.GmsBarcodeScanning
|
|
8
12
|
import expo.modules.devlauncher.DevLauncherController
|
|
9
|
-
import expo.modules.devlauncher.MeQuery
|
|
10
13
|
import expo.modules.devlauncher.launcher.DevLauncherAppEntry
|
|
11
14
|
import expo.modules.devlauncher.launcher.errors.DevLauncherErrorInstance
|
|
12
|
-
import expo.modules.devlauncher.services.AppService
|
|
13
15
|
import expo.modules.devlauncher.services.ErrorRegistryService
|
|
14
16
|
import expo.modules.devlauncher.services.PackagerInfo
|
|
15
17
|
import expo.modules.devlauncher.services.PackagerService
|
|
16
|
-
import expo.modules.devlauncher.services.SessionService
|
|
17
|
-
import expo.modules.devlauncher.services.UserState
|
|
18
18
|
import expo.modules.devlauncher.services.inject
|
|
19
19
|
import kotlinx.coroutines.flow.launchIn
|
|
20
20
|
import kotlinx.coroutines.flow.onEach
|
|
21
|
-
import kotlinx.coroutines.flow.onStart
|
|
22
21
|
import kotlinx.coroutines.launch
|
|
23
22
|
|
|
24
23
|
sealed interface HomeAction {
|
|
@@ -26,32 +25,24 @@ sealed interface HomeAction {
|
|
|
26
25
|
object RefetchRunningApps : HomeAction
|
|
27
26
|
object ResetRecentlyOpenedApps : HomeAction
|
|
28
27
|
class NavigateToCrashReport(val crashReport: DevLauncherErrorInstance) : HomeAction
|
|
28
|
+
object ScanQRCode : 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
35
|
val crashReport: DevLauncherErrorInstance? = null
|
|
38
36
|
)
|
|
39
37
|
|
|
40
38
|
class HomeViewModel() : ViewModel() {
|
|
41
39
|
val devLauncherController = inject<DevLauncherController>()
|
|
42
|
-
val sessionService = inject<SessionService>()
|
|
43
40
|
val packagerService = inject<PackagerService>()
|
|
44
|
-
val appService = inject<AppService>()
|
|
45
41
|
val errorRegistryService = inject<ErrorRegistryService>()
|
|
46
42
|
|
|
47
43
|
private var _state = mutableStateOf(
|
|
48
44
|
HomeState(
|
|
49
|
-
appName = appService.applicationInfo.appName,
|
|
50
45
|
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
46
|
recentlyOpenedApps = devLauncherController.getRecentlyOpenedApps(),
|
|
56
47
|
crashReport = errorRegistryService.consumeException()
|
|
57
48
|
)
|
|
@@ -70,18 +61,6 @@ class HomeViewModel() : ViewModel() {
|
|
|
70
61
|
}
|
|
71
62
|
.launchIn(viewModelScope)
|
|
72
63
|
|
|
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
64
|
packagerService.isLoading.onEach { isLoading ->
|
|
86
65
|
_state.value = _state.value.copy(
|
|
87
66
|
isFetchingPackagers = isLoading
|
|
@@ -108,6 +87,29 @@ class HomeViewModel() : ViewModel() {
|
|
|
108
87
|
}
|
|
109
88
|
|
|
110
89
|
is HomeAction.NavigateToCrashReport -> IllegalStateException("Navigation action should be handled by the UI layer, not the ViewModel.")
|
|
90
|
+
|
|
91
|
+
is HomeAction.ScanQRCode -> IllegalStateException("QR code scanning should be handled by the UI layer, not the ViewModel.")
|
|
111
92
|
}
|
|
112
93
|
}
|
|
94
|
+
|
|
95
|
+
fun scanQRCode(context: Context, onResult: (String) -> Unit, onError: (String) -> Unit) {
|
|
96
|
+
val options = GmsBarcodeScannerOptions.Builder()
|
|
97
|
+
.setBarcodeFormats(Barcode.FORMAT_QR_CODE)
|
|
98
|
+
.build()
|
|
99
|
+
|
|
100
|
+
val scanner = GmsBarcodeScanning.getClient(context, options)
|
|
101
|
+
|
|
102
|
+
scanner.startScan()
|
|
103
|
+
.addOnSuccessListener { barcode ->
|
|
104
|
+
barcode.rawValue?.let {
|
|
105
|
+
onResult(it)
|
|
106
|
+
} ?: onError("No QR code data found")
|
|
107
|
+
}
|
|
108
|
+
.addOnCanceledListener {
|
|
109
|
+
onError("Scanning cancelled")
|
|
110
|
+
}
|
|
111
|
+
.addOnFailureListener { exception ->
|
|
112
|
+
onError("Scanning failed: ${exception.message ?: "Unknown error"}")
|
|
113
|
+
}
|
|
114
|
+
}
|
|
113
115
|
}
|
|
@@ -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,8 +52,8 @@ 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)
|
|
@@ -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 {
|