expo-dev-launcher 5.2.0-canary-20250729-d8899ae → 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 +4 -0
- package/android/build.gradle +2 -2
- package/android/src/debug/java/expo/modules/devlauncher/compose/models/HomeViewModel.kt +8 -3
- package/android/src/debug/java/expo/modules/devlauncher/compose/primitives/Accordion.kt +1 -0
- package/android/src/debug/java/expo/modules/devlauncher/compose/routes/Updates.kt +15 -1
- package/android/src/debug/java/expo/modules/devlauncher/compose/screens/BranchScreen.kt +17 -11
- package/android/src/debug/java/expo/modules/devlauncher/compose/screens/BranchesScreen.kt +3 -2
- package/android/src/debug/java/expo/modules/devlauncher/compose/screens/HomeScreen.kt +39 -16
- package/android/src/debug/java/expo/modules/devlauncher/compose/screens/NoUpdatesScreen.kt +2 -1
- package/android/src/debug/java/expo/modules/devlauncher/compose/screens/SettingsScreen.kt +2 -2
- package/android/src/debug/java/expo/modules/devlauncher/compose/ui/AppHeader.kt +18 -12
- package/android/src/debug/java/expo/modules/devlauncher/compose/ui/AppLoadingErrorDialog.kt +81 -0
- package/android/src/debug/java/expo/modules/devlauncher/compose/ui/ProfileLayout.kt +17 -7
- package/android/src/debug/java/expo/modules/devlauncher/helpers/DevLauncherReactUtils.kt +2 -2
- 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/main/java/expo/modules/devlauncher/react/activitydelegates/DevLauncherReactActivityNOPDelegate.kt +2 -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/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 -2
- 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/CHANGELOG.md
CHANGED
|
@@ -8,15 +8,19 @@
|
|
|
8
8
|
|
|
9
9
|
- [iOS] Reimplement UI in SwiftUI. ([#37413](https://github.com/expo/expo/pull/37413) by [@alanjhughes](https://github.com/alanjhughes))
|
|
10
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))
|
|
11
12
|
|
|
12
13
|
### 🐛 Bug fixes
|
|
13
14
|
|
|
14
15
|
- [iOS] Fix missing CDP headers when using static frameworks. ([#37448](https://github.com/expo/expo/pull/37448) by [@alanjhughes](https://github.com/alanjhughes))
|
|
15
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))
|
|
16
18
|
|
|
17
19
|
### 💡 Others
|
|
18
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))
|
|
19
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))
|
|
20
24
|
|
|
21
25
|
### ⚠️ Notices
|
|
22
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 {
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
package expo.modules.devlauncher.compose.models
|
|
2
2
|
|
|
3
3
|
import android.content.Context
|
|
4
|
-
import android.util.Log
|
|
5
4
|
import androidx.compose.runtime.mutableStateOf
|
|
6
5
|
import androidx.core.net.toUri
|
|
7
6
|
import androidx.lifecycle.ViewModel
|
|
@@ -26,13 +25,15 @@ sealed interface HomeAction {
|
|
|
26
25
|
object ResetRecentlyOpenedApps : HomeAction
|
|
27
26
|
class NavigateToCrashReport(val crashReport: DevLauncherErrorInstance) : HomeAction
|
|
28
27
|
object ScanQRCode : HomeAction
|
|
28
|
+
object ClearLoadingError : HomeAction
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
data class HomeState(
|
|
32
32
|
val runningPackagers: Set<PackagerInfo> = emptySet(),
|
|
33
33
|
val isFetchingPackagers: Boolean = false,
|
|
34
34
|
val recentlyOpenedApps: List<DevLauncherAppEntry> = emptyList(),
|
|
35
|
-
val crashReport: DevLauncherErrorInstance? = null
|
|
35
|
+
val crashReport: DevLauncherErrorInstance? = null,
|
|
36
|
+
val loadingError: String? = null
|
|
36
37
|
)
|
|
37
38
|
|
|
38
39
|
class HomeViewModel() : ViewModel() {
|
|
@@ -75,7 +76,9 @@ class HomeViewModel() : ViewModel() {
|
|
|
75
76
|
try {
|
|
76
77
|
devLauncherController.loadApp(action.url.toUri(), mainActivity = null)
|
|
77
78
|
} catch (e: Exception) {
|
|
78
|
-
|
|
79
|
+
_state.value = _state.value.copy(
|
|
80
|
+
loadingError = e.message ?: "Unknown error"
|
|
81
|
+
)
|
|
79
82
|
}
|
|
80
83
|
}
|
|
81
84
|
|
|
@@ -86,6 +89,8 @@ class HomeViewModel() : ViewModel() {
|
|
|
86
89
|
_state.value = _state.value.copy(recentlyOpenedApps = emptyList())
|
|
87
90
|
}
|
|
88
91
|
|
|
92
|
+
is HomeAction.ClearLoadingError -> _state.value = _state.value.copy(loadingError = null)
|
|
93
|
+
|
|
89
94
|
is HomeAction.NavigateToCrashReport -> IllegalStateException("Navigation action should be handled by the UI layer, not the ViewModel.")
|
|
90
95
|
|
|
91
96
|
is HomeAction.ScanQRCode -> IllegalStateException("QR code scanning should be handled by the UI layer, not the ViewModel.")
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
package expo.modules.devlauncher.compose.routes
|
|
2
2
|
|
|
3
|
+
import androidx.compose.animation.AnimatedContentTransitionScope
|
|
4
|
+
import androidx.compose.animation.core.tween
|
|
3
5
|
import androidx.compose.runtime.Composable
|
|
4
6
|
import androidx.compose.runtime.getValue
|
|
5
7
|
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
|
@@ -25,7 +27,19 @@ fun UpdatesRoute(
|
|
|
25
27
|
DefaultScreenContainer {
|
|
26
28
|
NavHost(
|
|
27
29
|
navController = updatesNavController,
|
|
28
|
-
startDestination = Routes.Updates.Branches
|
|
30
|
+
startDestination = Routes.Updates.Branches,
|
|
31
|
+
enterTransition = {
|
|
32
|
+
slideIntoContainer(
|
|
33
|
+
AnimatedContentTransitionScope.SlideDirection.Up,
|
|
34
|
+
animationSpec = tween(400)
|
|
35
|
+
)
|
|
36
|
+
},
|
|
37
|
+
exitTransition = {
|
|
38
|
+
slideOutOfContainer(
|
|
39
|
+
AnimatedContentTransitionScope.SlideDirection.Down,
|
|
40
|
+
animationSpec = tween(400)
|
|
41
|
+
)
|
|
42
|
+
}
|
|
29
43
|
) {
|
|
30
44
|
composable<Routes.Updates.Branches> {
|
|
31
45
|
val viewModel = viewModel<BranchesViewModel>()
|
|
@@ -4,6 +4,7 @@ import androidx.compose.foundation.layout.Arrangement
|
|
|
4
4
|
import androidx.compose.foundation.layout.Box
|
|
5
5
|
import androidx.compose.foundation.layout.Column
|
|
6
6
|
import androidx.compose.foundation.layout.Row
|
|
7
|
+
import androidx.compose.foundation.layout.fillMaxSize
|
|
7
8
|
import androidx.compose.foundation.layout.fillMaxWidth
|
|
8
9
|
import androidx.compose.foundation.layout.padding
|
|
9
10
|
import androidx.compose.foundation.layout.size
|
|
@@ -18,6 +19,7 @@ import androidx.compose.runtime.remember
|
|
|
18
19
|
import androidx.compose.ui.Alignment
|
|
19
20
|
import androidx.compose.ui.Modifier
|
|
20
21
|
import androidx.compose.ui.draw.rotate
|
|
22
|
+
import androidx.compose.ui.graphics.Color
|
|
21
23
|
import androidx.compose.ui.res.painterResource
|
|
22
24
|
import androidx.compose.ui.text.style.TextAlign
|
|
23
25
|
import androidx.compose.ui.text.style.TextOverflow
|
|
@@ -45,24 +47,28 @@ fun BranchScreen(
|
|
|
45
47
|
goBack: () -> Unit = {},
|
|
46
48
|
onAction: (BranchAction) -> Unit = {}
|
|
47
49
|
) {
|
|
48
|
-
Column {
|
|
50
|
+
Column(modifier = Modifier.fillMaxSize()) {
|
|
49
51
|
ScreenHeaderContainer {
|
|
50
52
|
Box(
|
|
51
53
|
modifier = Modifier
|
|
52
54
|
.fillMaxWidth()
|
|
53
55
|
.padding(Theme.spacing.small)
|
|
54
56
|
) {
|
|
55
|
-
|
|
56
|
-
|
|
57
|
+
RoundedSurface(
|
|
58
|
+
color = Color.Transparent,
|
|
57
59
|
modifier = Modifier.align(Alignment.CenterStart)
|
|
58
60
|
) {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
.
|
|
64
|
-
|
|
65
|
-
|
|
61
|
+
Button(
|
|
62
|
+
onClick = goBack
|
|
63
|
+
) {
|
|
64
|
+
DayNighIcon(
|
|
65
|
+
R.drawable.chevron_right_icon,
|
|
66
|
+
contentDescription = "Back icon",
|
|
67
|
+
modifier = Modifier
|
|
68
|
+
.rotate(180f)
|
|
69
|
+
.size(Theme.sizing.icon.small)
|
|
70
|
+
)
|
|
71
|
+
}
|
|
66
72
|
}
|
|
67
73
|
|
|
68
74
|
Heading(branchName, modifier = Modifier.align(Alignment.Center))
|
|
@@ -126,7 +132,7 @@ fun BranchScreen(
|
|
|
126
132
|
DayNighIcon(
|
|
127
133
|
painter = painterResource(R.drawable.chevron_right_icon),
|
|
128
134
|
contentDescription = "Chevron Right Icon",
|
|
129
|
-
modifier = Modifier.size(Theme.sizing.icon.
|
|
135
|
+
modifier = Modifier.size(Theme.sizing.icon.extraSmall)
|
|
130
136
|
)
|
|
131
137
|
}
|
|
132
138
|
|
|
@@ -4,6 +4,7 @@ import androidx.compose.foundation.background
|
|
|
4
4
|
import androidx.compose.foundation.layout.Arrangement
|
|
5
5
|
import androidx.compose.foundation.layout.Column
|
|
6
6
|
import androidx.compose.foundation.layout.Row
|
|
7
|
+
import androidx.compose.foundation.layout.fillMaxSize
|
|
7
8
|
import androidx.compose.foundation.layout.fillMaxWidth
|
|
8
9
|
import androidx.compose.foundation.layout.padding
|
|
9
10
|
import androidx.compose.foundation.layout.size
|
|
@@ -85,7 +86,7 @@ fun BranchesScreen(
|
|
|
85
86
|
onProfileClick: () -> Unit = {},
|
|
86
87
|
onAction: (BranchesAction) -> Unit = { _ -> }
|
|
87
88
|
) {
|
|
88
|
-
Column {
|
|
89
|
+
Column(modifier = Modifier.fillMaxSize()) {
|
|
89
90
|
ScreenHeaderContainer(modifier = Modifier.padding(Theme.spacing.medium)) {
|
|
90
91
|
AppHeader(
|
|
91
92
|
onProfileClick = onProfileClick
|
|
@@ -134,7 +135,7 @@ fun BranchesScreen(
|
|
|
134
135
|
DayNighIcon(
|
|
135
136
|
painter = painterResource(R.drawable.chevron_right_icon),
|
|
136
137
|
contentDescription = "Chevron Right Icon",
|
|
137
|
-
modifier = Modifier.size(Theme.sizing.icon.
|
|
138
|
+
modifier = Modifier.size(Theme.sizing.icon.extraSmall)
|
|
138
139
|
)
|
|
139
140
|
}
|
|
140
141
|
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
package expo.modules.devlauncher.compose.screens
|
|
2
2
|
|
|
3
|
-
import android.util.Log
|
|
4
3
|
import androidx.compose.foundation.Image
|
|
5
4
|
import androidx.compose.foundation.background
|
|
6
5
|
import androidx.compose.foundation.layout.Box
|
|
@@ -22,6 +21,7 @@ import androidx.compose.runtime.setValue
|
|
|
22
21
|
import androidx.compose.ui.Modifier
|
|
23
22
|
import androidx.compose.ui.draw.clip
|
|
24
23
|
import androidx.compose.ui.draw.drawBehind
|
|
24
|
+
import androidx.compose.ui.graphics.Color
|
|
25
25
|
import androidx.compose.ui.graphics.SolidColor
|
|
26
26
|
import androidx.compose.ui.res.painterResource
|
|
27
27
|
import androidx.compose.ui.text.font.FontWeight
|
|
@@ -39,6 +39,7 @@ import expo.modules.devlauncher.compose.models.HomeAction
|
|
|
39
39
|
import expo.modules.devlauncher.compose.models.HomeState
|
|
40
40
|
import expo.modules.devlauncher.compose.primitives.Accordion
|
|
41
41
|
import expo.modules.devlauncher.compose.ui.AppHeader
|
|
42
|
+
import expo.modules.devlauncher.compose.ui.AppLoadingErrorDialog
|
|
42
43
|
import expo.modules.devlauncher.compose.ui.DevelopmentSessionHelper
|
|
43
44
|
import expo.modules.devlauncher.compose.ui.RunningAppCard
|
|
44
45
|
import expo.modules.devlauncher.compose.ui.ScreenHeaderContainer
|
|
@@ -132,10 +133,27 @@ fun HomeScreen(
|
|
|
132
133
|
onProfileClick: () -> Unit
|
|
133
134
|
) {
|
|
134
135
|
val hasPackager = state.runningPackagers.isNotEmpty()
|
|
135
|
-
val
|
|
136
|
+
val howToStartDevelopmentDialogState = rememberDialogState(initiallyVisible = false)
|
|
137
|
+
val errorDialogState = rememberDialogState(initiallyVisible = false)
|
|
136
138
|
val scrollState = rememberScrollState()
|
|
137
139
|
|
|
138
|
-
|
|
140
|
+
LaunchedEffect(state.loadingError) {
|
|
141
|
+
if (state.loadingError != null) {
|
|
142
|
+
errorDialogState.visible = true
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
LaunchedEffect(errorDialogState.visible) {
|
|
147
|
+
if (!errorDialogState.visible) {
|
|
148
|
+
onAction(HomeAction.ClearLoadingError)
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
HowToStartDevelopmentServerDialog(howToStartDevelopmentDialogState)
|
|
153
|
+
AppLoadingErrorDialog(
|
|
154
|
+
errorDialogState,
|
|
155
|
+
currentError = state.loadingError
|
|
156
|
+
)
|
|
139
157
|
|
|
140
158
|
Column {
|
|
141
159
|
ScreenHeaderContainer(modifier = Modifier.padding(Theme.spacing.medium)) {
|
|
@@ -174,7 +192,7 @@ fun HomeScreen(
|
|
|
174
192
|
if (hasPackager) {
|
|
175
193
|
Row {
|
|
176
194
|
Button(onClick = {
|
|
177
|
-
|
|
195
|
+
howToStartDevelopmentDialogState.visible = true
|
|
178
196
|
}) {
|
|
179
197
|
Theme.colors.icon
|
|
180
198
|
DayNighIcon(
|
|
@@ -218,7 +236,6 @@ fun HomeScreen(
|
|
|
218
236
|
var fetchStartTime by remember { mutableStateOf<Instant?>(null) }
|
|
219
237
|
|
|
220
238
|
LaunchedEffect(isFetching) {
|
|
221
|
-
Log.e("DevLauncher", "isFetchingPackagers changed: $isFetching")
|
|
222
239
|
if (isFetching) {
|
|
223
240
|
isFetchingUIState = true
|
|
224
241
|
fetchStartTime = Clock.System.now()
|
|
@@ -301,7 +318,7 @@ fun HomeScreen(
|
|
|
301
318
|
Image(
|
|
302
319
|
painter = painterResource(R.drawable.qr_code),
|
|
303
320
|
contentDescription = "QR Code Icon",
|
|
304
|
-
modifier = Modifier.size(
|
|
321
|
+
modifier = Modifier.size(Theme.spacing.medium)
|
|
305
322
|
)
|
|
306
323
|
}
|
|
307
324
|
) {
|
|
@@ -338,18 +355,24 @@ fun HomeScreen(
|
|
|
338
355
|
"Recently",
|
|
339
356
|
rightIcon = {
|
|
340
357
|
Row {
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
358
|
+
RoundedSurface(color = Color.Unspecified, borderRadius = Theme.sizing.borderRadius.extraSmall) {
|
|
359
|
+
Button(
|
|
360
|
+
onClick = {
|
|
361
|
+
onAction(HomeAction.ResetRecentlyOpenedApps)
|
|
362
|
+
}
|
|
363
|
+
) {
|
|
364
|
+
Text(
|
|
365
|
+
"Reset",
|
|
366
|
+
color = Theme.colors.text.secondary,
|
|
367
|
+
fontSize = Theme.typography.small,
|
|
368
|
+
fontWeight = FontWeight.Bold,
|
|
369
|
+
modifier = Modifier
|
|
370
|
+
.padding(horizontal = Theme.spacing.tiny, vertical = Theme.spacing.micro)
|
|
371
|
+
)
|
|
372
|
+
}
|
|
350
373
|
}
|
|
351
374
|
|
|
352
|
-
Spacer(Theme.spacing.small)
|
|
375
|
+
Spacer(Theme.spacing.small - Theme.spacing.tiny)
|
|
353
376
|
}
|
|
354
377
|
}
|
|
355
378
|
)
|
|
@@ -3,6 +3,7 @@ package expo.modules.devlauncher.compose.screens
|
|
|
3
3
|
import androidx.compose.foundation.Image
|
|
4
4
|
import androidx.compose.foundation.layout.Column
|
|
5
5
|
import androidx.compose.foundation.layout.Row
|
|
6
|
+
import androidx.compose.foundation.layout.fillMaxSize
|
|
6
7
|
import androidx.compose.foundation.layout.padding
|
|
7
8
|
import androidx.compose.runtime.Composable
|
|
8
9
|
import androidx.compose.ui.Alignment
|
|
@@ -26,7 +27,7 @@ import expo.modules.devmenu.compose.theme.Theme
|
|
|
26
27
|
|
|
27
28
|
@Composable
|
|
28
29
|
fun NoUpdatesScreen(onProfileClick: () -> Unit = {}) {
|
|
29
|
-
Column {
|
|
30
|
+
Column(modifier = Modifier.fillMaxSize()) {
|
|
30
31
|
ScreenHeaderContainer(modifier = Modifier.padding(Theme.spacing.medium)) {
|
|
31
32
|
AppHeader(
|
|
32
33
|
onProfileClick = onProfileClick
|
|
@@ -99,9 +99,9 @@ fun SettingsScreen(
|
|
|
99
99
|
)
|
|
100
100
|
Divider()
|
|
101
101
|
MenuButton(
|
|
102
|
-
"
|
|
102
|
+
"Developer Action Button",
|
|
103
103
|
// TODO: @behenate Find a proper icon for this option
|
|
104
|
-
leftIcon = painterResource(R.drawable.
|
|
104
|
+
leftIcon = painterResource(R.drawable.dev_menu_fab_icon),
|
|
105
105
|
onClick = {
|
|
106
106
|
onAction(SettingsAction.ToggleShowFabAtLaunch(!state.showFabAtLaunch))
|
|
107
107
|
},
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
package expo.modules.devlauncher.compose.ui
|
|
2
2
|
|
|
3
|
-
import androidx.compose.foundation.clickable
|
|
4
3
|
import androidx.compose.foundation.layout.Column
|
|
5
4
|
import androidx.compose.foundation.layout.padding
|
|
6
5
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
|
@@ -8,6 +7,7 @@ import androidx.compose.runtime.Composable
|
|
|
8
7
|
import androidx.compose.ui.Modifier
|
|
9
8
|
import androidx.compose.ui.tooling.preview.Preview
|
|
10
9
|
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
|
10
|
+
import com.composeunstyled.Button
|
|
11
11
|
import expo.modules.devlauncher.MeQuery
|
|
12
12
|
import expo.modules.devlauncher.R
|
|
13
13
|
import expo.modules.devlauncher.services.AppService
|
|
@@ -65,18 +65,24 @@ fun AppHeader(
|
|
|
65
65
|
},
|
|
66
66
|
rightComponent = {
|
|
67
67
|
if (currentAccount != null) {
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
68
|
+
Surface(shape = RoundedCornerShape(Theme.sizing.borderRadius.full)) {
|
|
69
|
+
Button(onClick = onProfileClick) {
|
|
70
|
+
AccountAvatar(
|
|
71
|
+
url = currentAccount.ownerUserActor?.profilePhoto,
|
|
72
|
+
size = Theme.sizing.icon.medium
|
|
73
|
+
)
|
|
74
|
+
}
|
|
75
|
+
}
|
|
73
76
|
} else {
|
|
74
|
-
Surface(shape = RoundedCornerShape(Theme.sizing.borderRadius.full)
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
77
|
+
Surface(shape = RoundedCornerShape(Theme.sizing.borderRadius.full)) {
|
|
78
|
+
Button(onClick = onProfileClick) {
|
|
79
|
+
DayNighIcon(
|
|
80
|
+
id = R.drawable.user_icon,
|
|
81
|
+
contentDescription = "Expo Logo",
|
|
82
|
+
modifier = Modifier
|
|
83
|
+
.padding(Theme.spacing.tiny)
|
|
84
|
+
)
|
|
85
|
+
}
|
|
80
86
|
}
|
|
81
87
|
}
|
|
82
88
|
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
package expo.modules.devlauncher.compose.ui
|
|
2
|
+
|
|
3
|
+
import androidx.compose.foundation.background
|
|
4
|
+
import androidx.compose.foundation.layout.Column
|
|
5
|
+
import androidx.compose.foundation.layout.Row
|
|
6
|
+
import androidx.compose.foundation.layout.displayCutoutPadding
|
|
7
|
+
import androidx.compose.foundation.layout.padding
|
|
8
|
+
import androidx.compose.foundation.layout.systemBarsPadding
|
|
9
|
+
import androidx.compose.foundation.shape.RoundedCornerShape
|
|
10
|
+
import androidx.compose.runtime.Composable
|
|
11
|
+
import androidx.compose.ui.Modifier
|
|
12
|
+
import androidx.compose.ui.draw.clip
|
|
13
|
+
import androidx.compose.ui.tooling.preview.Preview
|
|
14
|
+
import androidx.compose.ui.unit.dp
|
|
15
|
+
import com.composables.core.Dialog
|
|
16
|
+
import com.composables.core.DialogPanel
|
|
17
|
+
import com.composables.core.DialogState
|
|
18
|
+
import com.composables.core.Scrim
|
|
19
|
+
import com.composables.core.rememberDialogState
|
|
20
|
+
import com.composeunstyled.Button
|
|
21
|
+
import com.composeunstyled.Text
|
|
22
|
+
import expo.modules.devlauncher.R
|
|
23
|
+
import expo.modules.devmenu.compose.primitives.DayNighIcon
|
|
24
|
+
import expo.modules.devmenu.compose.primitives.Divider
|
|
25
|
+
import expo.modules.devmenu.compose.primitives.Heading
|
|
26
|
+
import expo.modules.devmenu.compose.primitives.RowLayout
|
|
27
|
+
import expo.modules.devmenu.compose.theme.Theme
|
|
28
|
+
|
|
29
|
+
@Composable
|
|
30
|
+
fun AppLoadingErrorDialog(
|
|
31
|
+
dialogState: DialogState,
|
|
32
|
+
currentError: String?
|
|
33
|
+
) {
|
|
34
|
+
Dialog(state = dialogState) {
|
|
35
|
+
Scrim()
|
|
36
|
+
|
|
37
|
+
DialogPanel(
|
|
38
|
+
modifier = Modifier
|
|
39
|
+
.displayCutoutPadding()
|
|
40
|
+
.systemBarsPadding()
|
|
41
|
+
.padding(horizontal = Theme.spacing.medium)
|
|
42
|
+
.clip(RoundedCornerShape(12.dp))
|
|
43
|
+
.background(Theme.colors.background.default)
|
|
44
|
+
) {
|
|
45
|
+
Column {
|
|
46
|
+
RowLayout(
|
|
47
|
+
rightComponent = {
|
|
48
|
+
Button(onClick = {
|
|
49
|
+
dialogState.visible = false
|
|
50
|
+
}) {
|
|
51
|
+
DayNighIcon(
|
|
52
|
+
id = R.drawable.x_icon,
|
|
53
|
+
contentDescription = "Close dialog"
|
|
54
|
+
)
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
modifier = Modifier.padding(Theme.spacing.medium)
|
|
58
|
+
) {
|
|
59
|
+
Heading("Error loading app")
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
Divider()
|
|
63
|
+
|
|
64
|
+
Row(modifier = Modifier.padding(Theme.spacing.medium)) {
|
|
65
|
+
Text(currentError ?: "No error message available.")
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
@Preview
|
|
73
|
+
@Composable
|
|
74
|
+
fun AppLoadingErrorDialogPreview() {
|
|
75
|
+
val dialogState = rememberDialogState(initiallyVisible = true)
|
|
76
|
+
|
|
77
|
+
AppLoadingErrorDialog(
|
|
78
|
+
dialogState = dialogState,
|
|
79
|
+
currentError = "An error occurred while loading the app."
|
|
80
|
+
)
|
|
81
|
+
}
|
|
@@ -5,14 +5,17 @@ import androidx.compose.foundation.layout.Column
|
|
|
5
5
|
import androidx.compose.foundation.layout.Row
|
|
6
6
|
import androidx.compose.foundation.layout.fillMaxWidth
|
|
7
7
|
import androidx.compose.foundation.layout.padding
|
|
8
|
+
import androidx.compose.foundation.layout.size
|
|
8
9
|
import androidx.compose.runtime.Composable
|
|
9
10
|
import androidx.compose.ui.Alignment
|
|
10
11
|
import androidx.compose.ui.Modifier
|
|
12
|
+
import androidx.compose.ui.graphics.Color
|
|
11
13
|
import androidx.compose.ui.unit.dp
|
|
12
14
|
import com.composeunstyled.Button
|
|
13
15
|
import expo.modules.devlauncher.R
|
|
14
16
|
import expo.modules.devmenu.compose.primitives.DayNighIcon
|
|
15
17
|
import expo.modules.devmenu.compose.primitives.Heading
|
|
18
|
+
import expo.modules.devmenu.compose.primitives.RoundedSurface
|
|
16
19
|
import expo.modules.devmenu.compose.primitives.Spacer
|
|
17
20
|
import expo.modules.devmenu.compose.theme.Theme
|
|
18
21
|
|
|
@@ -26,13 +29,20 @@ fun ProfileLayout(
|
|
|
26
29
|
.padding(horizontal = 12.dp)
|
|
27
30
|
.padding(top = 12.dp)
|
|
28
31
|
) {
|
|
29
|
-
Row(
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
32
|
+
Row(
|
|
33
|
+
verticalAlignment = Alignment.CenterVertically,
|
|
34
|
+
horizontalArrangement = Arrangement.SpaceBetween,
|
|
35
|
+
modifier = Modifier.fillMaxWidth()
|
|
36
|
+
) {
|
|
37
|
+
Heading("Account", fontSize = Theme.typography.size22)
|
|
38
|
+
RoundedSurface(color = Color.Unspecified) {
|
|
39
|
+
Button(onClick = onClose) {
|
|
40
|
+
DayNighIcon(
|
|
41
|
+
id = R.drawable.x_icon,
|
|
42
|
+
contentDescription = "Close",
|
|
43
|
+
modifier = Modifier.size(Theme.sizing.icon.small)
|
|
44
|
+
)
|
|
45
|
+
}
|
|
36
46
|
}
|
|
37
47
|
}
|
|
38
48
|
|
|
@@ -185,14 +185,14 @@ private fun injectLocalBundleLoader(
|
|
|
185
185
|
// [0] Disable `mAllowPackagerServerAccess`
|
|
186
186
|
// so that ReactHost could use jsBundlerLoader from ReactHostDelegate
|
|
187
187
|
val reactHostClass = ReactHostImpl::class.java
|
|
188
|
-
val mAllowPackagerServerAccessField = reactHostClass.getDeclaredField("
|
|
188
|
+
val mAllowPackagerServerAccessField = reactHostClass.getDeclaredField("allowPackagerServerAccess")
|
|
189
189
|
mAllowPackagerServerAccessField.isAccessible = true
|
|
190
190
|
mAllowPackagerServerAccessField[reactHost] = false
|
|
191
191
|
|
|
192
192
|
val newJsBundleLoader = JSBundleLoader.createFileLoader(bundlePath)
|
|
193
193
|
|
|
194
194
|
// [1] Replace the ReactHostDelegate.jsBundlerLoader with our new loader
|
|
195
|
-
val mReactHostDelegateField = reactHostClass.getDeclaredField("
|
|
195
|
+
val mReactHostDelegateField = reactHostClass.getDeclaredField("reactHostDelegate")
|
|
196
196
|
mReactHostDelegateField.isAccessible = true
|
|
197
197
|
val reactHostDelegate = mReactHostDelegateField[reactHost] as ReactHostDelegate
|
|
198
198
|
if (reactHostDelegate.javaClass.canonicalName == EXPO_REACT_HOST_DELEGATE_CLASS) {
|
package/android/src/debug/java/expo/modules/devlauncher/launcher/loaders/DevLauncherExpoAppLoader.kt
CHANGED
|
@@ -50,7 +50,7 @@ abstract class DevLauncherExpoAppLoader(
|
|
|
50
50
|
try {
|
|
51
51
|
appearanceModule::class.java.setProtectedDeclaredField(
|
|
52
52
|
obj = appearanceModule,
|
|
53
|
-
filedName = "
|
|
53
|
+
filedName = "overrideColorScheme",
|
|
54
54
|
newValue = object : AppearanceModule.OverrideColorScheme {
|
|
55
55
|
override fun getScheme(): String {
|
|
56
56
|
return userInterfaceStyle
|
|
@@ -61,7 +61,7 @@ abstract class DevLauncherExpoAppLoader(
|
|
|
61
61
|
|
|
62
62
|
appearanceModule::class.java.setProtectedDeclaredField(
|
|
63
63
|
obj = appearanceModule,
|
|
64
|
-
filedName = "
|
|
64
|
+
filedName = "colorScheme",
|
|
65
65
|
newValue = userInterfaceStyle
|
|
66
66
|
)
|
|
67
67
|
} catch (e: Exception) {
|
package/android/src/debug/java/expo/modules/devlauncher/react/DevLauncherDevSupportManagerSwapper.kt
CHANGED
|
@@ -47,7 +47,7 @@ internal class DevLauncherDevSupportManagerSwapper : DevLauncherKoinComponent {
|
|
|
47
47
|
val devManagerClass = DevSupportManagerBase::class.java
|
|
48
48
|
val newDevSupportManager = createDevLauncherBridgeDevSupportManager(devManagerClass, currentDevSupportManager)
|
|
49
49
|
|
|
50
|
-
ReactInstanceManager::class.java.setProtectedDeclaredField(reactInstanceManager, "
|
|
50
|
+
ReactInstanceManager::class.java.setProtectedDeclaredField(reactInstanceManager, "devSupportManager", newDevSupportManager)
|
|
51
51
|
|
|
52
52
|
closeExistingConnection(devManagerClass, currentDevSupportManager)
|
|
53
53
|
} catch (e: Exception) {
|
|
@@ -73,7 +73,7 @@ internal class DevLauncherDevSupportManagerSwapper : DevLauncherKoinComponent {
|
|
|
73
73
|
currentDevSupportManager
|
|
74
74
|
)
|
|
75
75
|
|
|
76
|
-
ReactHostImpl::class.java.setProtectedDeclaredField(reactHost, "
|
|
76
|
+
ReactHostImpl::class.java.setProtectedDeclaredField(reactHost, "devSupportManager", newDevSupportManager)
|
|
77
77
|
|
|
78
78
|
closeExistingConnection(devManagerClass, currentDevSupportManager)
|
|
79
79
|
} catch (e: Exception) {
|
package/android/src/debug/java/expo/modules/devlauncher/react/DevLauncherReactNativeHostHandler.kt
CHANGED
|
@@ -4,8 +4,6 @@ import android.content.Context
|
|
|
4
4
|
import com.facebook.hermes.reactexecutor.HermesExecutorFactory
|
|
5
5
|
import com.facebook.react.bridge.JavaScriptExecutorFactory
|
|
6
6
|
import com.facebook.react.devsupport.DevSupportManagerFactory
|
|
7
|
-
import com.facebook.react.jscexecutor.JSCExecutorFactory
|
|
8
|
-
import com.facebook.react.modules.systeminfo.AndroidInfoHelpers
|
|
9
7
|
import com.facebook.soloader.SoLoader
|
|
10
8
|
import expo.modules.core.interfaces.ReactNativeHostHandler
|
|
11
9
|
import expo.modules.devlauncher.DevLauncherController
|
|
@@ -35,9 +33,6 @@ class DevLauncherReactNativeHostHandler(context: Context) : ReactNativeHostHandl
|
|
|
35
33
|
// return null here to use the default value.
|
|
36
34
|
return null
|
|
37
35
|
}
|
|
38
|
-
if (SoLoader.getLibraryPath("libjsc.so") != null) {
|
|
39
|
-
return JSCExecutorFactory(applicationContext.packageName, AndroidInfoHelpers.getFriendlyDeviceName())
|
|
40
|
-
}
|
|
41
36
|
return HermesExecutorFactory()
|
|
42
37
|
}
|
|
43
38
|
|
|
@@ -16,6 +16,6 @@ open class DevLauncherReactActivityNOPDelegate(activity: ReactActivity) :
|
|
|
16
16
|
override fun onNewIntent(intent: Intent?): Boolean = true
|
|
17
17
|
override fun onBackPressed(): Boolean = true
|
|
18
18
|
override fun onWindowFocusChanged(hasFocus: Boolean) {}
|
|
19
|
-
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String
|
|
20
|
-
override fun onConfigurationChanged(newConfig: Configuration
|
|
19
|
+
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {}
|
|
20
|
+
override fun onConfigurationChanged(newConfig: Configuration) {}
|
|
21
21
|
}
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -20,7 +20,8 @@ Pod::Spec.new do |s|
|
|
|
20
20
|
s.author = package['author']
|
|
21
21
|
s.homepage = package['homepage']
|
|
22
22
|
s.platforms = {
|
|
23
|
-
:ios => '15.1'
|
|
23
|
+
:ios => '15.1',
|
|
24
|
+
:tvos => '15.1'
|
|
24
25
|
}
|
|
25
26
|
s.swift_version = '5.2'
|
|
26
27
|
s.source = { :git => 'https://github.com/github_account/expo-development-client.git', :tag => "#{s.version}" }
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"images" : [
|
|
3
|
+
{
|
|
4
|
+
"filename" : "expo-go logo.png",
|
|
5
|
+
"idiom" : "universal",
|
|
6
|
+
"scale" : "1x"
|
|
7
|
+
},
|
|
8
|
+
{
|
|
9
|
+
"idiom" : "universal",
|
|
10
|
+
"scale" : "2x"
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
"idiom" : "universal",
|
|
14
|
+
"scale" : "3x"
|
|
15
|
+
}
|
|
16
|
+
],
|
|
17
|
+
"info" : {
|
|
18
|
+
"author" : "xcode",
|
|
19
|
+
"version" : 1
|
|
20
|
+
}
|
|
21
|
+
}
|
|
Binary file
|