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.
Files changed (54) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/android/build.gradle +2 -2
  3. package/android/src/debug/java/expo/modules/devlauncher/compose/models/HomeViewModel.kt +8 -3
  4. package/android/src/debug/java/expo/modules/devlauncher/compose/primitives/Accordion.kt +1 -0
  5. package/android/src/debug/java/expo/modules/devlauncher/compose/routes/Updates.kt +15 -1
  6. package/android/src/debug/java/expo/modules/devlauncher/compose/screens/BranchScreen.kt +17 -11
  7. package/android/src/debug/java/expo/modules/devlauncher/compose/screens/BranchesScreen.kt +3 -2
  8. package/android/src/debug/java/expo/modules/devlauncher/compose/screens/HomeScreen.kt +39 -16
  9. package/android/src/debug/java/expo/modules/devlauncher/compose/screens/NoUpdatesScreen.kt +2 -1
  10. package/android/src/debug/java/expo/modules/devlauncher/compose/screens/SettingsScreen.kt +2 -2
  11. package/android/src/debug/java/expo/modules/devlauncher/compose/ui/AppHeader.kt +18 -12
  12. package/android/src/debug/java/expo/modules/devlauncher/compose/ui/AppLoadingErrorDialog.kt +81 -0
  13. package/android/src/debug/java/expo/modules/devlauncher/compose/ui/ProfileLayout.kt +17 -7
  14. package/android/src/debug/java/expo/modules/devlauncher/helpers/DevLauncherReactUtils.kt +2 -2
  15. package/android/src/debug/java/expo/modules/devlauncher/launcher/loaders/DevLauncherExpoAppLoader.kt +2 -2
  16. package/android/src/debug/java/expo/modules/devlauncher/react/DevLauncherDevSupportManagerSwapper.kt +2 -2
  17. package/android/src/debug/java/expo/modules/devlauncher/react/DevLauncherReactNativeHostHandler.kt +0 -5
  18. package/android/src/main/java/expo/modules/devlauncher/react/activitydelegates/DevLauncherReactActivityNOPDelegate.kt +2 -2
  19. package/android/src/main/res/drawable-mdpi/dev_menu_fab_icon.png +0 -0
  20. package/android/src/main/res/drawable-xhdpi/dev_menu_fab_icon.png +0 -0
  21. package/android/src/main/res/drawable-xxhdpi/dev_menu_fab_icon.png +0 -0
  22. package/expo-dev-launcher.podspec +2 -1
  23. package/ios/Assets.xcassets/expo-go-logo.imageset/Contents.json +21 -0
  24. package/ios/Assets.xcassets/expo-go-logo.imageset/expo-go logo.png +0 -0
  25. package/ios/Assets.xcassets/log-in.imageset/Contents.json +21 -0
  26. package/ios/Assets.xcassets/log-in.imageset/log-in.png +0 -0
  27. package/ios/EXDevLauncherController.m +2 -0
  28. package/ios/EXDevLauncherInstallationIDHelper.swift +6 -0
  29. package/ios/EXDevLauncherPendingDeepLinkRegistry.swift +2 -0
  30. package/ios/EXDevLauncherRecentlyOpenedAppsRegistry.swift +1 -0
  31. package/ios/EXDevLauncherUtils.swift +2 -2
  32. package/ios/Errors/EXDevLauncherErrorManager.swift +41 -5
  33. package/ios/Manifest/EXDevLauncherManifestHelper.swift +14 -10
  34. package/ios/ReactNative/EXDevLauncherBundleURLProviderInterceptor.swift +2 -0
  35. package/ios/SwiftUI/AccountSheet.swift +49 -35
  36. package/ios/SwiftUI/CrashReportView.swift +175 -0
  37. package/ios/SwiftUI/DevLauncherTabBarManager.swift +4 -4
  38. package/ios/SwiftUI/DevLauncherViewModel.swift +42 -23
  39. package/ios/SwiftUI/DevLauncherViews.swift +19 -14
  40. package/ios/SwiftUI/DevServerInfoModal.swift +21 -9
  41. package/ios/SwiftUI/DevServersView.swift +21 -18
  42. package/ios/SwiftUI/ErrorView.swift +46 -67
  43. package/ios/SwiftUI/HomeTabView.swift +28 -9
  44. package/ios/SwiftUI/Navigation/Navigation.swift +18 -8
  45. package/ios/SwiftUI/SettingsTabView.swift +90 -32
  46. package/ios/SwiftUI/StackFrameView.swift +29 -0
  47. package/ios/SwiftUI/UpdatesTab/NotSignedInView.swift +31 -18
  48. package/ios/SwiftUI/UpdatesTab/UpdateRow.swift +2 -0
  49. package/ios/SwiftUI/UpdatesTab/UpdatesListView.swift +4 -0
  50. package/ios/SwiftUI/UpdatesTab/UpdatesTabView.swift +1 -12
  51. package/ios/SwiftUI/Utils/Utils.swift +49 -0
  52. package/ios/Tests/EXDevLauncherControllerTest.swift +0 -10
  53. package/ios/Unsafe/RCTPackagerConnection+EXDevLauncherPackagerConnectionInterceptor.m +19 -5
  54. 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
 
@@ -20,13 +20,13 @@ expoModule {
20
20
  }
21
21
 
22
22
  group = "host.exp.exponent"
23
- version = "5.2.0-canary-20250729-d8899ae"
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-20250729-d8899ae"
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
- Log.e("DevLauncher", "Failed to open app: ${action.url}", e)
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.")
@@ -57,6 +57,7 @@ fun Accordion(
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(
@@ -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
- Button(
56
- onClick = goBack,
57
+ RoundedSurface(
58
+ color = Color.Transparent,
57
59
  modifier = Modifier.align(Alignment.CenterStart)
58
60
  ) {
59
- DayNighIcon(
60
- R.drawable.chevron_right_icon,
61
- contentDescription = "Back icon",
62
- modifier = Modifier
63
- .rotate(180f)
64
- .size(Theme.sizing.icon.medium)
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.medium)
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.medium)
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 dialogState = rememberDialogState(initiallyVisible = false)
136
+ val howToStartDevelopmentDialogState = rememberDialogState(initiallyVisible = false)
137
+ val errorDialogState = rememberDialogState(initiallyVisible = false)
136
138
  val scrollState = rememberScrollState()
137
139
 
138
- HowToStartDevelopmentServerDialog(dialogState)
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
- dialogState.visible = true
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(24.dp)
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
- Button(onClick = {
342
- onAction(HomeAction.ResetRecentlyOpenedApps)
343
- }) {
344
- Text(
345
- "Reset",
346
- color = Theme.colors.text.secondary,
347
- fontSize = Theme.typography.small,
348
- fontWeight = FontWeight.Bold
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
- "Floating Action Button",
102
+ "Developer Action Button",
103
103
  // TODO: @behenate Find a proper icon for this option
104
- leftIcon = painterResource(R.drawable.show_menu_at_launch_icon),
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
- AccountAvatar(
69
- url = currentAccount.ownerUserActor?.profilePhoto,
70
- size = Theme.sizing.icon.medium,
71
- modifier = Modifier.clickable(onClick = onProfileClick)
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), modifier = Modifier.clickable(onClick = onProfileClick)) {
75
- DayNighIcon(
76
- id = R.drawable.user_icon,
77
- contentDescription = "Expo Logo",
78
- modifier = Modifier.padding(Theme.spacing.tiny)
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(verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.SpaceBetween, modifier = Modifier.fillMaxWidth()) {
30
- Heading("Account", fontSize = Theme.typography.size25)
31
- Button(onClick = onClose) {
32
- DayNighIcon(
33
- id = R.drawable.x_icon,
34
- contentDescription = "Close"
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("mAllowPackagerServerAccess")
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("mReactHostDelegate")
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) {
@@ -50,7 +50,7 @@ abstract class DevLauncherExpoAppLoader(
50
50
  try {
51
51
  appearanceModule::class.java.setProtectedDeclaredField(
52
52
  obj = appearanceModule,
53
- filedName = "mOverrideColorScheme",
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 = "mColorScheme",
64
+ filedName = "colorScheme",
65
65
  newValue = userInterfaceStyle
66
66
  )
67
67
  } catch (e: Exception) {
@@ -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, "mDevSupportManager", newDevSupportManager)
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, "mDevSupportManager", newDevSupportManager)
76
+ ReactHostImpl::class.java.setProtectedDeclaredField(reactHost, "devSupportManager", newDevSupportManager)
77
77
 
78
78
  closeExistingConnection(devManagerClass, currentDevSupportManager)
79
79
  } catch (e: Exception) {
@@ -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>?, grantResults: IntArray?) {}
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
  }
@@ -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
+ }