expo-dev-launcher 6.0.0 → 6.0.1

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 (49) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/android/build.gradle +3 -3
  3. package/android/src/debug/java/expo/modules/devlauncher/compose/BindingView.kt +4 -2
  4. package/android/src/debug/java/expo/modules/devlauncher/compose/DevLauncherBottomTabsNavigator.kt +4 -2
  5. package/android/src/debug/java/expo/modules/devlauncher/compose/models/BranchesViewModel.kt +57 -13
  6. package/android/src/debug/java/expo/modules/devlauncher/compose/primitives/Accordion.kt +40 -45
  7. package/android/src/debug/java/expo/modules/devlauncher/compose/routes/Profile.kt +98 -18
  8. package/android/src/debug/java/expo/modules/devlauncher/compose/routes/Updates.kt +3 -1
  9. package/android/src/debug/java/expo/modules/devlauncher/compose/screens/BranchScreen.kt +171 -146
  10. package/android/src/debug/java/expo/modules/devlauncher/compose/screens/BranchesScreen.kt +248 -150
  11. package/android/src/debug/java/expo/modules/devlauncher/compose/screens/CrashReportScreen.kt +75 -46
  12. package/android/src/debug/java/expo/modules/devlauncher/compose/screens/HomeScreen.kt +234 -238
  13. package/android/src/debug/java/expo/modules/devlauncher/compose/screens/NoUpdatesScreen.kt +52 -35
  14. package/android/src/debug/java/expo/modules/devlauncher/compose/screens/SettingsScreen.kt +246 -107
  15. package/android/src/debug/java/expo/modules/devlauncher/compose/ui/AccountAvatar.kt +17 -9
  16. package/android/src/debug/java/expo/modules/devlauncher/compose/ui/AccountSelector.kt +63 -46
  17. package/android/src/debug/java/expo/modules/devlauncher/compose/ui/ActionButton.kt +51 -3
  18. package/android/src/debug/java/expo/modules/devlauncher/compose/ui/AppHeader.kt +70 -44
  19. package/android/src/debug/java/expo/modules/devlauncher/compose/ui/BottomSheet.kt +42 -2
  20. package/android/src/debug/java/expo/modules/devlauncher/compose/ui/BottomTabBar.kt +14 -10
  21. package/android/src/debug/java/expo/modules/devlauncher/compose/ui/BottomTabButton.kt +46 -23
  22. package/android/src/debug/java/expo/modules/devlauncher/compose/ui/DevelopmentServerHelp.kt +23 -16
  23. package/android/src/debug/java/expo/modules/devlauncher/compose/ui/RunningAppCard.kt +65 -34
  24. package/android/src/debug/java/expo/modules/devlauncher/compose/ui/ScreenHeaderContainer.kt +0 -5
  25. package/android/src/debug/java/expo/modules/devlauncher/compose/ui/ServerUrlInput.kt +56 -17
  26. package/android/src/debug/java/expo/modules/devlauncher/compose/ui/SignUp.kt +20 -27
  27. package/android/src/main/res/drawable/arrow_right.xml +9 -0
  28. package/android/src/main/res/drawable/check_circle.xml +10 -0
  29. package/android/src/main/res/drawable/chevron_right.xml +10 -0
  30. package/android/src/main/res/drawable/copy.xml +13 -0
  31. package/android/src/main/res/drawable/expo_logo.xml +9 -0
  32. package/android/src/main/res/drawable/home.xml +10 -0
  33. package/android/src/main/res/drawable/inspect.xml +10 -0
  34. package/android/src/main/res/drawable/log_in.xml +12 -0
  35. package/android/src/main/res/drawable/pulse.xml +10 -0
  36. package/android/src/main/res/drawable/reload.xml +10 -0
  37. package/android/src/main/res/drawable/scan.xml +42 -0
  38. package/android/src/main/res/drawable/settings.xml +14 -0
  39. package/android/src/main/res/drawable/show_at_launch.xml +12 -0
  40. package/android/src/main/res/drawable/signal.xml +26 -0
  41. package/android/src/main/res/drawable/user.xml +13 -0
  42. package/ios/EXDevLauncherController.m +23 -4
  43. package/ios/SwiftUI/CrashReportView.swift +11 -3
  44. package/ios/SwiftUI/DevLauncherViews.swift +18 -2
  45. package/ios/SwiftUI/DevServersView.swift +2 -2
  46. package/ios/SwiftUI/HomeTabView.swift +4 -0
  47. package/ios/SwiftUI/Navigation/Navigation.swift +3 -0
  48. package/ios/SwiftUI/SettingsTabView.swift +4 -3
  49. package/package.json +4 -4
@@ -1,11 +1,12 @@
1
1
  package expo.modules.devlauncher.compose.screens
2
2
 
3
- import androidx.compose.foundation.Image
4
3
  import androidx.compose.foundation.background
5
- import androidx.compose.foundation.layout.Box
4
+ import androidx.compose.foundation.clickable
5
+ import androidx.compose.foundation.layout.Arrangement
6
6
  import androidx.compose.foundation.layout.Column
7
7
  import androidx.compose.foundation.layout.Row
8
8
  import androidx.compose.foundation.layout.displayCutoutPadding
9
+ import androidx.compose.foundation.layout.fillMaxWidth
9
10
  import androidx.compose.foundation.layout.padding
10
11
  import androidx.compose.foundation.layout.size
11
12
  import androidx.compose.foundation.layout.systemBarsPadding
@@ -18,10 +19,9 @@ import androidx.compose.runtime.getValue
18
19
  import androidx.compose.runtime.mutableStateOf
19
20
  import androidx.compose.runtime.remember
20
21
  import androidx.compose.runtime.setValue
22
+ import androidx.compose.ui.Alignment
21
23
  import androidx.compose.ui.Modifier
22
24
  import androidx.compose.ui.draw.clip
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
@@ -33,8 +33,10 @@ import com.composables.core.DialogState
33
33
  import com.composables.core.Scrim
34
34
  import com.composables.core.rememberDialogState
35
35
  import com.composeunstyled.Button
36
+ import com.composeunstyled.Icon
36
37
  import expo.modules.core.utilities.EmulatorUtilities
37
38
  import expo.modules.devlauncher.R
39
+ import expo.modules.devlauncher.compose.DefaultScreenContainer
38
40
  import expo.modules.devlauncher.compose.models.HomeAction
39
41
  import expo.modules.devlauncher.compose.models.HomeState
40
42
  import expo.modules.devlauncher.compose.primitives.Accordion
@@ -42,21 +44,19 @@ import expo.modules.devlauncher.compose.ui.AppHeader
42
44
  import expo.modules.devlauncher.compose.ui.AppLoadingErrorDialog
43
45
  import expo.modules.devlauncher.compose.ui.DevelopmentSessionHelper
44
46
  import expo.modules.devlauncher.compose.ui.RunningAppCard
45
- import expo.modules.devlauncher.compose.ui.ScreenHeaderContainer
46
- import expo.modules.devlauncher.compose.ui.SectionHeader
47
47
  import expo.modules.devlauncher.compose.ui.ServerUrlInput
48
- import expo.modules.devlauncher.compose.utils.withIsLast
49
48
  import expo.modules.devlauncher.launcher.DevLauncherAppEntry
50
49
  import expo.modules.devlauncher.launcher.errors.DevLauncherErrorInstance
50
+ import expo.modules.devlauncher.services.PackagerInfo
51
+ import expo.modules.devmenu.compose.newtheme.NewAppTheme
51
52
  import expo.modules.devmenu.compose.primitives.DayNighIcon
52
53
  import expo.modules.devmenu.compose.primitives.Divider
53
54
  import expo.modules.devmenu.compose.primitives.Heading
54
- import expo.modules.devmenu.compose.primitives.RoundedSurface
55
+ import expo.modules.devmenu.compose.primitives.NewText
55
56
  import expo.modules.devmenu.compose.primitives.RowLayout
56
57
  import expo.modules.devmenu.compose.primitives.Spacer
57
- import expo.modules.devmenu.compose.primitives.Text
58
58
  import expo.modules.devmenu.compose.primitives.pulseEffect
59
- import expo.modules.devmenu.compose.theme.Theme
59
+ import expo.modules.devmenu.compose.ui.Warning
60
60
  import kotlinx.coroutines.delay
61
61
  import kotlin.time.Clock
62
62
  import kotlin.time.Duration.Companion.seconds
@@ -72,8 +72,9 @@ fun HowToStartDevelopmentServerDialog(dialogState: DialogState) {
72
72
  modifier = Modifier
73
73
  .displayCutoutPadding()
74
74
  .systemBarsPadding()
75
- .clip(RoundedCornerShape(12.dp))
76
- .background(Theme.colors.background.default)
75
+ .padding(horizontal = NewAppTheme.spacing.`3`)
76
+ .clip(RoundedCornerShape(NewAppTheme.borderRadius.xl))
77
+ .background(NewAppTheme.colors.background.default)
77
78
  ) {
78
79
  Column {
79
80
  RowLayout(
@@ -87,14 +88,14 @@ fun HowToStartDevelopmentServerDialog(dialogState: DialogState) {
87
88
  )
88
89
  }
89
90
  },
90
- modifier = Modifier.padding(Theme.spacing.medium)
91
+ modifier = Modifier.padding(NewAppTheme.spacing.`3`)
91
92
  ) {
92
93
  Heading("Development servers")
93
94
  }
94
95
 
95
96
  Divider()
96
97
 
97
- Row(modifier = Modifier.padding(Theme.spacing.medium)) {
98
+ Row(modifier = Modifier.padding(NewAppTheme.spacing.`3`)) {
98
99
  DevelopmentSessionHelper()
99
100
  }
100
101
  }
@@ -111,15 +112,12 @@ fun CrashReport(
111
112
  return
112
113
  }
113
114
 
114
- Spacer(Theme.spacing.large)
115
-
116
- RoundedSurface {
115
+ Row(modifier = Modifier.padding(top = NewAppTheme.spacing.`6` - NewAppTheme.spacing.`4`)) {
117
116
  Button(onClick = {
118
117
  onClick(crashReport)
119
118
  }) {
120
- Text(
121
- "The last time you tried to open an app the development build crashed. Tap to get more information.",
122
- modifier = Modifier.padding(Theme.spacing.medium)
119
+ Warning(
120
+ "The last time you tried to open an app the development build crashed. Tap to get more information."
123
121
  )
124
122
  }
125
123
  }
@@ -150,258 +148,242 @@ fun HomeScreen(
150
148
  }
151
149
 
152
150
  HowToStartDevelopmentServerDialog(howToStartDevelopmentDialogState)
151
+
153
152
  AppLoadingErrorDialog(
154
153
  errorDialogState,
155
154
  currentError = state.loadingError
156
155
  )
157
156
 
158
- Column {
159
- ScreenHeaderContainer(modifier = Modifier.padding(Theme.spacing.medium)) {
160
- AppHeader(
161
- onProfileClick = onProfileClick
162
- )
163
- }
157
+ Column(
158
+ modifier = Modifier.padding(horizontal = NewAppTheme.spacing.`4`)
159
+ ) {
160
+ AppHeader(
161
+ onProfileClick = onProfileClick,
162
+ modifier = Modifier.padding(vertical = NewAppTheme.spacing.`4`)
163
+ )
164
+
165
+ val crashReport = state.crashReport
166
+ CrashReport(
167
+ crashReport = crashReport,
168
+ onClick = {
169
+ onAction(HomeAction.NavigateToCrashReport(it))
170
+ }
171
+ )
164
172
 
165
173
  Column(
166
174
  modifier = Modifier
175
+ .padding(vertical = NewAppTheme.spacing.`6`)
167
176
  .verticalScroll(scrollState)
168
- .padding(horizontal = Theme.spacing.medium)
169
177
  ) {
170
- val crashReport = state.crashReport
171
- CrashReport(
172
- crashReport = crashReport,
173
- onClick = {
174
- onAction(HomeAction.NavigateToCrashReport(it))
175
- }
176
- )
177
-
178
- Spacer(Theme.spacing.large)
179
-
180
- Row {
181
- Spacer(Theme.spacing.small)
182
-
183
- SectionHeader(
184
- "Development servers",
185
- leftIcon = {
186
- Image(
187
- painter = painterResource(R.drawable.terminal_icon),
188
- contentDescription = "Terminal Icon"
189
- )
190
- },
191
- rightIcon = {
192
- if (hasPackager) {
193
- Row {
194
- Button(onClick = {
195
- howToStartDevelopmentDialogState.visible = true
196
- }) {
197
- Theme.colors.icon
198
- DayNighIcon(
199
- id = R.drawable.info_icon,
200
- contentDescription = "Info Icon"
201
- )
202
- }
178
+ Row(
179
+ horizontalArrangement = Arrangement.SpaceBetween,
180
+ modifier = Modifier.fillMaxWidth()
181
+ ) {
182
+ NewText(
183
+ "DEVELOPMENT SERVERS",
184
+ style = NewAppTheme.font.sm.merge(
185
+ fontWeight = FontWeight.Medium,
186
+ fontFamily = NewAppTheme.font.mono
187
+ ),
188
+ color = NewAppTheme.colors.text.quaternary
189
+ )
203
190
 
204
- Spacer(Theme.spacing.small)
205
- }
206
- }
191
+ NewText(
192
+ "INFO",
193
+ style = NewAppTheme.font.sm.merge(
194
+ fontWeight = FontWeight.Medium,
195
+ fontFamily = NewAppTheme.font.mono
196
+ ),
197
+ color = NewAppTheme.colors.text.link,
198
+ modifier = Modifier.clickable {
199
+ howToStartDevelopmentDialogState.visible = true
207
200
  }
208
201
  )
209
202
  }
210
203
 
211
- Spacer(Theme.spacing.small)
204
+ Spacer(NewAppTheme.spacing.`3`)
212
205
 
213
- RoundedSurface {
214
- Column {
215
- if (hasPackager) {
216
- for (packager in state.runningPackagers) {
217
- RunningAppCard(
218
- appIp = packager.url,
219
- appName = packager.description
220
- ) {
221
- onAction(HomeAction.OpenApp(packager.url))
222
- }
223
- Divider()
224
- }
225
- } else {
226
- Box(modifier = Modifier.padding(Theme.spacing.medium)) {
227
- DevelopmentSessionHelper()
206
+ if (hasPackager) {
207
+ Column(
208
+ verticalArrangement = Arrangement.spacedBy(NewAppTheme.spacing.`1`)
209
+ ) {
210
+ for (packager in state.runningPackagers) {
211
+ RunningAppCard(
212
+ appIp = packager.url,
213
+ appName = packager.description
214
+ ) {
215
+ onAction(HomeAction.OpenApp(packager.url))
228
216
  }
229
- Divider()
230
217
  }
218
+ }
219
+ } else {
220
+ DevelopmentSessionHelper()
221
+ Spacer(NewAppTheme.spacing.`2`)
222
+ }
231
223
 
232
- val infoColor = Theme.colors.status.info
233
- val defaultColor = Theme.colors.status.default
234
- val isFetching = state.isFetchingPackagers
235
- var isFetchingUIState by remember { mutableStateOf(isFetching) }
236
- var fetchStartTime by remember { mutableStateOf<Instant?>(null) }
237
-
238
- LaunchedEffect(isFetching) {
239
- if (isFetching) {
240
- isFetchingUIState = true
241
- fetchStartTime = Clock.System.now()
242
- return@LaunchedEffect
243
- }
224
+ val isFetching = state.isFetchingPackagers
225
+ var isFetchingUIState by remember { mutableStateOf(isFetching) }
226
+ var fetchStartTime by remember { mutableStateOf<Instant?>(null) }
244
227
 
245
- if (!isFetchingUIState) {
246
- return@LaunchedEffect
247
- }
228
+ LaunchedEffect(isFetching) {
229
+ if (isFetching) {
230
+ isFetchingUIState = true
231
+ fetchStartTime = Clock.System.now()
232
+ return@LaunchedEffect
233
+ }
248
234
 
249
- val startTime = fetchStartTime
250
- if (startTime == null) {
251
- isFetchingUIState = false
252
- return@LaunchedEffect
253
- }
235
+ if (!isFetchingUIState) {
236
+ return@LaunchedEffect
237
+ }
254
238
 
255
- val elapsedTime = startTime - Clock.System.now()
256
- val remainingTime = 2.seconds - elapsedTime
239
+ val startTime = fetchStartTime
240
+ if (startTime == null) {
241
+ isFetchingUIState = false
242
+ return@LaunchedEffect
243
+ }
257
244
 
258
- delay(remainingTime)
245
+ val elapsedTime = startTime - Clock.System.now()
246
+ val remainingTime = 2.seconds - elapsedTime
259
247
 
260
- if (!state.isFetchingPackagers) {
261
- isFetchingUIState = false
262
- }
263
- }
248
+ delay(remainingTime)
264
249
 
265
- Button(
266
- onClick = {
267
- onAction(HomeAction.RefetchRunningApps)
268
- },
269
- enabled = !isFetchingUIState
270
- ) {
271
- RowLayout(
272
- modifier = Modifier.padding(Theme.spacing.medium),
273
- leftComponent = {
274
- Box(
275
- modifier = Modifier
276
- .size(Theme.spacing.small)
277
- .drawBehind {
278
- drawCircle(
279
- color = defaultColor,
280
- radius = size.minDimension / 2f
281
- )
282
- }
283
- .then(
284
- if (isFetchingUIState) {
285
- Modifier.pulseEffect(
286
- initialScale = 0.95f,
287
- targetScale = 2f,
288
- brush = SolidColor(infoColor)
289
- )
290
- } else {
291
- Modifier
292
- }
293
- )
294
- )
295
- }
296
- ) {
297
- Text(
250
+ isFetchingUIState = state.isFetchingPackagers
251
+ }
252
+
253
+ Button(
254
+ onClick = {
255
+ onAction(HomeAction.RefetchRunningApps)
256
+ },
257
+ enabled = !isFetchingUIState
258
+ ) {
259
+ Row(
260
+ horizontalArrangement = Arrangement.spacedBy(NewAppTheme.spacing.`2`),
261
+ verticalAlignment = Alignment.CenterVertically,
262
+ modifier = Modifier
263
+ .fillMaxWidth()
264
+ .padding(vertical = 12.dp)
265
+ ) {
266
+ Icon(
267
+ painter = painterResource(R.drawable.signal),
268
+ contentDescription = "Signal Icon",
269
+ tint = NewAppTheme.colors.text.link,
270
+ modifier = Modifier
271
+ .size(16.dp)
272
+ .then(
298
273
  if (isFetchingUIState) {
299
- "Searching for development servers..."
274
+ Modifier.pulseEffect(
275
+ initialScale = 0.2f,
276
+ brush = SolidColor(NewAppTheme.colors.text.link.copy(alpha = 0.4f))
277
+ )
300
278
  } else {
301
- "Fetch development servers"
279
+ Modifier
302
280
  }
303
281
  )
304
- }
305
- }
306
-
307
- Divider()
282
+ )
308
283
 
309
- if (!EmulatorUtilities.isRunningOnEmulator()) {
310
- Button(
311
- onClick = {
312
- onAction(HomeAction.ScanQRCode)
313
- }
314
- ) {
315
- RowLayout(
316
- modifier = Modifier.padding(Theme.spacing.medium),
317
- leftComponent = {
318
- Image(
319
- painter = painterResource(R.drawable.qr_code),
320
- contentDescription = "QR Code Icon",
321
- modifier = Modifier.size(Theme.spacing.medium)
322
- )
323
- }
324
- ) {
325
- Text("Scan QR code")
326
- }
327
- }
284
+ NewText(
285
+ if (isFetchingUIState) {
286
+ "Searching for development servers..."
287
+ } else {
288
+ "Fetch development servers"
289
+ },
290
+ style = NewAppTheme.font.sm,
291
+ color = NewAppTheme.colors.text.link
292
+ )
293
+ }
294
+ }
328
295
 
329
- Divider()
296
+ if (!EmulatorUtilities.isRunningOnEmulator()) {
297
+ Button(
298
+ onClick = {
299
+ onAction(HomeAction.ScanQRCode)
330
300
  }
301
+ ) {
302
+ Row(
303
+ horizontalArrangement = Arrangement.spacedBy(NewAppTheme.spacing.`2`),
304
+ verticalAlignment = Alignment.CenterVertically,
305
+ modifier = Modifier
306
+ .fillMaxWidth()
307
+ .padding(vertical = 12.dp)
308
+ ) {
309
+ Icon(
310
+ painter = painterResource(R.drawable.scan),
311
+ contentDescription = "QR code",
312
+ tint = NewAppTheme.colors.text.link,
313
+ modifier = Modifier
314
+ .size(16.dp)
315
+ )
331
316
 
332
- Accordion("Enter URL manually", initialState = false) {
333
- Column {
334
- Spacer(Theme.spacing.tiny)
335
-
336
- ServerUrlInput(
337
- openApp = { urlValue ->
338
- onAction(HomeAction.OpenApp(urlValue))
339
- }
340
- )
317
+ NewText(
318
+ "Scan QR code",
319
+ style = NewAppTheme.font.sm,
320
+ color = NewAppTheme.colors.text.link
321
+ )
322
+ }
323
+ }
324
+ }
341
325
 
342
- Spacer(Theme.spacing.small)
326
+ Accordion(
327
+ "Enter URL manually",
328
+ initialState = false,
329
+ modifier = Modifier
330
+ .fillMaxWidth()
331
+ .padding(vertical = 12.dp)
332
+ ) {
333
+ Column {
334
+ Spacer(NewAppTheme.spacing.`1`)
335
+ ServerUrlInput(
336
+ openApp = { urlValue ->
337
+ onAction(HomeAction.OpenApp(urlValue))
343
338
  }
344
- }
339
+ )
345
340
  }
346
341
  }
347
342
 
348
343
  if (state.recentlyOpenedApps.isNotEmpty()) {
349
- Spacer(Theme.spacing.large)
350
-
351
- Row {
352
- Spacer(Theme.spacing.small)
353
-
354
- SectionHeader(
355
- "Recently",
356
- rightIcon = {
357
- Row {
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
- }
373
- }
344
+ Spacer(NewAppTheme.spacing.`6`)
374
345
 
375
- Spacer(Theme.spacing.small - Theme.spacing.tiny)
376
- }
346
+ Row(
347
+ horizontalArrangement = Arrangement.SpaceBetween,
348
+ modifier = Modifier.fillMaxWidth()
349
+ ) {
350
+ NewText(
351
+ "RECENTLY OPEND",
352
+ style = NewAppTheme.font.sm.merge(
353
+ fontWeight = FontWeight.Medium,
354
+ fontFamily = NewAppTheme.font.mono
355
+ ),
356
+ color = NewAppTheme.colors.text.quaternary
357
+ )
358
+
359
+ NewText(
360
+ "RESET",
361
+ style = NewAppTheme.font.sm.merge(
362
+ fontWeight = FontWeight.Medium,
363
+ fontFamily = NewAppTheme.font.mono
364
+ ),
365
+ color = NewAppTheme.colors.text.link,
366
+ modifier = Modifier.clickable {
367
+ onAction(HomeAction.ResetRecentlyOpenedApps)
377
368
  }
378
369
  )
379
370
  }
380
371
 
381
- Spacer(Theme.spacing.small)
382
-
383
- RoundedSurface {
384
- Column {
385
- for ((packager, isLast) in state.recentlyOpenedApps.withIsLast()) {
386
- val url = packager.url
387
- val description = packager.name
372
+ Spacer(NewAppTheme.spacing.`3`)
388
373
 
389
- RunningAppCard(
390
- appIp = url,
391
- appName = description
392
- ) {
393
- onAction(HomeAction.OpenApp(url))
394
- }
395
-
396
- if (!isLast) {
397
- Divider()
398
- }
374
+ Column(
375
+ verticalArrangement = Arrangement.spacedBy(NewAppTheme.spacing.`1`)
376
+ ) {
377
+ for (packager in state.recentlyOpenedApps) {
378
+ RunningAppCard(
379
+ appIp = packager.url,
380
+ appName = packager.name
381
+ ) {
382
+ onAction(HomeAction.OpenApp(packager.url))
399
383
  }
400
384
  }
401
385
  }
402
386
  }
403
-
404
- Spacer(Theme.spacing.large)
405
387
  }
406
388
  }
407
389
  }
@@ -409,20 +391,34 @@ fun HomeScreen(
409
391
  @Preview(showBackground = true)
410
392
  @Composable
411
393
  fun HomeScreenPreview() {
412
- HomeScreen(
413
- state = HomeState(
414
- recentlyOpenedApps = listOf(
415
- DevLauncherAppEntry(
416
- timestamp = 1752249592809L,
417
- name = "BareExpo",
418
- url = "http://10.0.2.2:8081",
419
- isEASUpdate = false,
420
- updateMessage = null,
421
- branchName = null
394
+ DefaultScreenContainer {
395
+ HomeScreen(
396
+ state = HomeState(
397
+ runningPackagers = setOf(
398
+ PackagerInfo(
399
+ description = "BareExpo",
400
+ url = "http://localhost:8081",
401
+ isDevelopmentSession = true
402
+ ),
403
+ PackagerInfo(
404
+ description = "Another App",
405
+ url = "http://localhost:8081",
406
+ isDevelopmentSession = true
407
+ )
408
+ ),
409
+ recentlyOpenedApps = listOf(
410
+ DevLauncherAppEntry(
411
+ timestamp = 1752249592809L,
412
+ name = "BareExpo",
413
+ url = "http://10.0.2.2:8081",
414
+ isEASUpdate = false,
415
+ updateMessage = null,
416
+ branchName = null
417
+ )
422
418
  )
423
- )
424
- ),
425
- onAction = {},
426
- onProfileClick = {}
427
- )
419
+ ),
420
+ onAction = {},
421
+ onProfileClick = {}
422
+ )
423
+ }
428
424
  }