fix(mobile): splash/icon sizing, worktree sleep, host removal persistence

- Add worktree.sleep RPC method with full notifier chain (runtime → IPC → renderer)
- Optimistic UI update for sleeping worktrees in mobile client
- Fix splash screen: configure expo-splash-screen plugin, hide splash only after navigator layout
- Regenerate app icon and splash assets at correct density sizes
- Fix host removal not persisting by disabling Android auto-backup (allowBackup=false)
- Guard against invalid host credentials (base64 crash) and prevent navigating into auth-failed hosts
- Extract ActionSheetContent for inline drawer content switching
- Rewrite BottomDrawer as always-mounted Animated.View overlay (replaces Modal)
- Add ConfirmModal component with inline confirm/cancel buttons

Co-authored-by: Orca <help@stably.ai>
This commit is contained in:
Jinwoo-H
2026-04-30 18:03:55 -04:00
co-authored by Orca
parent 36005a7af6
commit e668dce4ec
20 changed files with 414 additions and 125 deletions
@@ -163,6 +163,7 @@ describe('useIpcEvents updater integration', () => {
onRenameTerminal: () => () => {},
onFocusTerminal: () => () => {},
onCloseTerminal: () => () => {},
onSleepWorktree: () => () => {},
onNewBrowserTab: () => () => {},
onRequestTabCreate: () => () => {},
replyTabCreate: () => {},
@@ -357,6 +358,7 @@ describe('useIpcEvents updater integration', () => {
onRenameTerminal: () => () => {},
onFocusTerminal: () => () => {},
onCloseTerminal: () => () => {},
onSleepWorktree: () => () => {},
onNewBrowserTab: () => () => {},
onRequestTabCreate: () => () => {},
replyTabCreate: () => {},
@@ -549,6 +551,7 @@ describe('useIpcEvents updater integration', () => {
onRenameTerminal: () => () => {},
onFocusTerminal: () => () => {},
onCloseTerminal: () => () => {},
onSleepWorktree: () => () => {},
onNewBrowserTab: () => () => {},
onRequestTabCreate: () => () => {},
replyTabCreate: () => {},
@@ -744,6 +747,7 @@ describe('useIpcEvents browser tab close routing', () => {
onRenameTerminal: () => () => {},
onFocusTerminal: () => () => {},
onCloseTerminal: () => () => {},
onSleepWorktree: () => () => {},
onNewBrowserTab: () => () => {},
onRequestTabCreate: () => () => {},
replyTabCreate: () => {},
@@ -933,6 +937,7 @@ describe('useIpcEvents browser tab close routing', () => {
onRenameTerminal: () => () => {},
onFocusTerminal: () => () => {},
onCloseTerminal: () => () => {},
onSleepWorktree: () => () => {},
onNewBrowserTab: () => () => {},
onRequestTabCreate: () => () => {},
replyTabCreate: () => {},
@@ -1117,6 +1122,7 @@ describe('useIpcEvents browser tab close routing', () => {
onRenameTerminal: () => () => {},
onFocusTerminal: () => () => {},
onCloseTerminal: () => () => {},
onSleepWorktree: () => () => {},
onNewBrowserTab: () => () => {},
onRequestTabCreate: () => () => {},
replyTabCreate: () => {},
@@ -1319,6 +1325,7 @@ describe('useIpcEvents shortcut hint clearing', () => {
onRenameTerminal: () => () => {},
onFocusTerminal: () => () => {},
onCloseTerminal: () => () => {},
onSleepWorktree: () => () => {},
onNewBrowserTab: () => () => {},
onRequestTabCreate: () => () => {},
replyTabCreate: () => {},
@@ -1519,6 +1526,7 @@ describe('useIpcEvents CLI-created worktree activation', () => {
onRenameTerminal: () => () => {},
onFocusTerminal: () => () => {},
onCloseTerminal: () => () => {},
onSleepWorktree: () => () => {},
onNewBrowserTab: () => () => {},
onRequestTabCreate: () => () => {},
replyTabCreate: () => {},
+7
View File
@@ -3,6 +3,7 @@ import { useEffect } from 'react'
import { useAppStore } from '../store'
import { applyUIZoom } from '@/lib/ui-zoom'
import { activateAndRevealWorktree } from '@/lib/worktree-activation'
import { runSleepWorktree } from '@/components/sidebar/sleep-worktree-flow'
import { SPLIT_TERMINAL_PANE_EVENT, CLOSE_TERMINAL_PANE_EVENT } from '@/constants/terminal'
import type { SplitTerminalPaneDetail, CloseTerminalPaneDetail } from '@/constants/terminal'
import { getVisibleWorktreeIds } from '@/components/sidebar/visible-worktrees'
@@ -283,6 +284,12 @@ export function useIpcEvents(): void {
})
)
unsubs.push(
window.api.ui.onSleepWorktree(({ worktreeId }) => {
void runSleepWorktree(worktreeId)
})
)
// Hydrate initial update status then subscribe to changes
window.api.updater.getStatus().then((status) => {
useAppStore.getState().setUpdateStatus(status as UpdateStatus)