# DWARFLAB App — UI / UX Reference (reverse-engineered) Reverse-engineered from `DWARFLAB.apk` v3.4.0 (`com.convergence.dwarflab`). This document describes the **user interface, screen hierarchy, navigation, and interactions** so the app can be reimplemented in another language/framework. Focus: **Splash → Home → Connection → Capture (main shooter) → Settings**. (Atlas/Sky-Atlas and Album/Gallery screens are documented separately.) --- ## 1. App structure & navigation model The app uses **Jetpack Navigation** (single-activity `MainActivity` + a `NavHostFragment`) with a **`BottomNavigationView`** of 4 tabs, plus several full-screen Activities launched outside the nav graph. ### 1.1 Entry / launch flow ``` SplashActivity (launcher, branding + init) └─▶ MainActivity (NavHost + BottomNavigationView, 4 tabs) ├─ Tab 1: Home → HomeFragment ├─ Tab 2: Atlas → AtlasActivity (separate) ├─ Tab 3: Album → AlbumFragment / AlbumActivity └─ Tab 4: Settings → SettingsFragment ``` - `mobile_navigation.xml` is the main nav graph; `startDestination = navigation_device` (Home). - `HeartbeatEntryActivity` is a transparent launcher alias used to keep a foreground service alive (the BLE/Wi-Fi heartbeat to the scope). - Tab labels (from `bottom_nav_menu.xml` + strings `home_3/4/5`, `camera_astro_69`): | tab | id | label (en) | icon | |-----|----|-----------|------| | 1 | `navigation_device` | **Home** | `icon_function_tabbar_home` | | 2 | `navigation_atlas` | **Atlas** | `icon_function_tabbar_atlas` | | 3 | `navigation_album` | **Album** | `icon_function_tabbar_album` | | 4 | `navigation_settings` | **Settings** | `icon_function_tabbar_settings` | The bottom bar can be hidden (`MainActivity.isShowBottomNav`) when entering full-screen sub-flows (device connect, OTA, capture). ### 1.2 Activities (beyond the nav graph) | Activity | Purpose | |----------|---------| | `SplashActivity` | Cold-start splash, version checks, routing to connect vs. main | | `MainActivity` | Hosts the 4 tabs + NavHost | | `CaptureActivity` | **The shooting screen** (9199 lines — the heart of the app) | | `AtlasActivity` | Sky atlas / star map / GoTo target selection | | `AlbumActivity` | Gallery of captured photos/videos/FITS | | `LocationActivity` | Map to set observing location | | `CaliFrameActivity` | Calibration-frame capture/management | | `HelperActivity` | In-app help / guide center | | `WebActivity` / `NavActivity` | Embedded web views (privacy, OSS notice, help docs) | | `NfcWriteActivity` | NFC tag update (device name change) | | `MosaicGuideActivity`, `SkyLightTipActivity`, `StarSearchActivity` | Atlas sub-screens | --- ## 2. Splash & first-run `SplashActivity` → decides between: - **Not connected**: routes to `HomeFragment` which shows a *device-discovery / connect* CTA when no scope is paired. - **App upgrade available**: shows `AppUpdateDialog` (force-update path uses `FirmwareForceUpdateDialog`). - **System notice**: `AppNotice` banner. `MainActivity` also handles: app-upgrade dialogs, product-activation dialog (`ProductActivateDialog`), not-enough-storage dialog, and an activation-error dialog. Activation is gated behind internet access (strings `settings_25`–`45`). --- ## 3. Home tab (`HomeFragment`) — `fragment_home.xml` The dashboard / device hub. Two visual states: ### 3.1 Disconnected state - Title bar: device-name placeholder + a **"Guide"** button (`home_16`, top-right, primary pill). - Centered illustration + **"Connect"** call-to-action → navigates to `DeviceSearchFragment` (BLE scan). - `view_bg_home_disconnected` background shown. ### 3.2 Connected state Top bar becomes a **device selector dropdown** (`tv_title` with `drawableEnd icon_action_arrow_down`): tapping opens device switcher. Below: device status card, then action entries. Navigation actions declared on `navigation_device` (HomeFragment): | Action | Destination | Meaning | |--------|-------------|---------| | `action_deviceFragment_to_deviceSearchFragment` | Device Search | Add/switch device | | `action_homeFragment_to_locationFragment` | Location | Set GPS/observing site | | `action_homeFragment_to_ScheduleFragment` | Schedule | Shooting plans list | | `action_homeFragment_to_upgradeFragment` | OTA Upgrade | Firmware update | | `action_homeFragment_to_scheduleDetailFragment` | Schedule Detail | Edit a plan | | `action_homeFragment_to_helperFragment` | Helper | In-app guide | | `action_homeFragment_to_webFragment` | Web | Embedded web content | | `action_home_to_taskListFragment` | Task List | Task/creation jobs (`createType` arg) | | `action_home_to_astroFitsFragment` | Astro FITS | View a FITS file (`filePath`) | | `action_home_to_caliFrameListFragment` | Cali-Frame List | Manage calibration frames (`caliFrameType`, `cameraType`) | So **Home is a launcher** into: connect, location, schedule, OTA, tasks, cali-frames, help. The actual *shooting* is entered by tapping the connected device card → launches `CaptureActivity`. --- ## 4. Device connection flow A multi-step wizard (mostly bottom-sheet dialogs) living under `navigation_device_connect` and friends. ``` DeviceSearchFragment (BLE scan, lists nearby scopes) ├─▶ DeviceConnectFragment (dialog) — enter device password │ ├─ success → DeviceConnectSuccessFragment │ ├─ wrong pwd → DeviceConnectPwdErrorAgainFragment │ └─ upgrade needed → UpgradeReminderFragment → OTAUpgradeFragment ├─▶ WiFiListFragment (STA mode: scan Wi-Fi for the scope) │ └─▶ StaInfoFragment (enter Wi-Fi password) → DeviceConnectFragment ├─▶ DeviceConnectManualFragment (manual IP entry) ├─▶ DeviceStaPwdFragment / DeviceStaConnectFailedFragment └─▶ DeviceResetTutorialFragment / DeviceConnectFailedFragment ``` Key strings reveal the model: - **Connection modes** (`settings_connection_14–21`): - **Auto (Recommended)** — auto-choose AP vs STA. - **STA mode** — phone & scope join the same home Wi-Fi (scope gets internet). - **AP mode** — connect directly to the DWARF hotspot (outdoor/no-Wi-Fi). - **Wi-Fi Compatible Mode** + **Enable 2.4GHz** toggles for region/legacy fixes. - **Region** setting (`settings_connection_10`) — country code for Wi-Fi regs. - **Activate Wi-Fi at Startup** — auto-enable hotspot on boot. - Device password screen distinguishes **default password** vs custom (`isDefaultPwd` arg → `DevicePasswordFragment`). `DeviceSearchFragment` args: `type` (0 = first connect, 1 = add another), `deviceName` (nullable, for reconnect). Result carries a `DeviceInfo` (`com.convergence.dwarflab.net.discovery.DeviceInfo`) containing BLE-resolved IP/SSID/PSK (see API_REFERENCE §2.1 for the BLE `DwarfEcho` payload). --- ## 5. Capture screen (`CaptureActivity`) — the shooter This is the most complex screen (~9200 lines). Landscape-oriented camera viewfinder with overlaid controls. Layout: `activity_capture.xml`. ### 5.1 Layout regions ``` ┌──────────────────────────────────────────────────────────────┐ │ [ TechniqueBar (top-right) ] [ Sky-finder actions (top-right) ] │ │ │ │ ┌────────────────────────────┐ ┌──────────┐ │ │ │ │ │ Wide PIP │ ← wide-angle │ │ │ MAIN PREVIEW (RTSP) │ │ preview │ inset (top-L) │ │ │ Tele camera │ └──────────┘ │ │ │ (RtspPlayerView) │ │ │ │ + TrackBoxView overlay │ [ RGB container (right) ] │ │ │ + PreviewBorderView │ │ │ │ + ShootingProgressView │ │ │ └────────────────────────────┘ │ │ │ │ ┌─Left─┐ ┌─Joystick─┐ ┌──Right panel──┐ │ │ │panel │ │ (polar │ │ Focus │ │ │ │ │ │ D-pad) │ │ ┌───────────┐ │ │ │ │ ✕back│ │ │ │ │ CAPTURE │ │ │ │ │ PIP │ └──────────┘ │ │ BUTTON │ │ │ │ │ more │ │ └───────────┘ │ │ │ │ ? │ [ ParameterIndicatorBar ] │ Parameter │ │ │ │ album│ [ DeviceIndicatorBar ] └───────────────┘ │ │ │ clear│ │ │ └──────┘ [ GoTo composition pill ] [ ZoomLensPanel ] │ │ │ │ (overlays: FocusProgress, StopProgress, CaptureStatus, │ │ FullscreenProgress, CaliFrameProgress, PanoComposition) │ └──────────────────────────────────────────────────────────────┘ ``` ### 5.2 Left control panel (`view_capture_left_control_panel.xml`, 48dp wide) Vertical icon stack, top→bottom: | id | icon | action | |----|------|--------| | `iv_photography_cancel` | arrow-left | **Back** (exit capture) | | `iv_photography_pip` | pip icon | **Toggle PIP** (picture-in-picture wide inset) | | `iv_photography_more_feature_set` | (dynamic) | **More settings** (opens `CamMoreFeatureSetDialog`) | | `iv_photography_guide` | question-circle | **Guide/help** (hidden by default) | | `iv_open_album` | album icon | **Open Album** (jump to gallery) | | `ivClearAll` | clear-all | **Clear** (reset selection/overlay) | ### 5.3 Right control panel (`view_capture_right_panel.xml`, 84dp wide) Vertical stack: | id | label | icon | action | |----|-------|------|--------| | `btn_focus_view_capture_right_panel` | **Focus** (`camera_general_2`) | `icon_function_main_focus` | Open focus controls (AF, manual, astro-AF) | | `item_main_capture_button_view` | — (76dp circular) | dynamic | **Main shutter** (see §5.5) | | `btn_parameter_view_capture_right_panel` | **Parameter** (`camera_astro_222`) | `icon_function_general_parameter` | Open `CamParameterSetDialog` (exposure/gain/WB/ISP) | `ZoomLensPanel` sits just left of the right panel (zoom/crop-ratio control). ### 5.4 TechniqueBar (top-right) — mode selector A pill that shows the current **ShootingModeType** + **ShootingTech** and a right-side action (`RightActionType`). Tapping opens `ShootingModeSelectDialog` to pick a mode. **`ShootingModeType`** (the "scene"/target class) — `ShootingModeType.java`: | value | name | notes | |-------|------|-------| | 1 | `NORMAL` | generic | | 2 | `DSO` | deep-sky object (needs calibration + EQ) | | 3 | `SUN_MOON` | solar/lunar | | 4 | `MILKY_WAY` | Milky Way wide-field | | 5 | `STAR_TRAIL` | star-trail time accumulation | | 6 | `AUTO_TRACKING` | generic object tracking | | 7 | `PANORAMA` | panorama/grid capture | | 8 | `SUN` | sun (ND filter warning!) | | 9 | `MOON` | moon | | 10 | `PLANET` | planetary | | 0 | `UNKNOWN` | default | Each mode carries flags: `isWidePreviewOnly`, `isWidePreviewSuggested`, `isPipWindowBtnEnable`, `isHidePip`, `isViewRectangleVisible`, `isAddQuickSet`, `cameraType` (Tele/Wide), `shootingTech`, `isAstroFocus`, `isShowAutoFocusSwitch`, `isSunOrMoon`, `isLongTouchStop`, `isSolarSystem`, `isShowZoomLens`, `isEnterAtlasVisible`, `isEnableCurves`, `isAreaFocusEnable`. These drive which UI controls are visible. **`ShootingTech`** (the capture technique) — `ShootingTech.java`: | value | name | UI ring style | |-------|------|---------------| | 0 | `UNKNOWN` | — | | 1 | `SINGLE_SHOT` | single photo | | 2 | `STACKING` | live-stacking (astro) | | 3 | `BURST` | burst | | 4 | `VIDEO` | video record | | 5 | `TIMELAPSE` | timelapse | | 6 | `PANORAMA` | panorama/grid | **`RightActionType`** (what the TechniqueBar's right button does): `NORMAL, FOCUS, PARAMETER, TECHNOLOGY, TECHNOLOGY_SETTING, MODE, LongPressStop`. ### 5.5 Main capture button (`MainCaptureButtonView`) A 76dp circular shutter whose appearance is driven by **`CaptureState`** (`CaptureState.java`) and the current `ShootingModeType`/`ShootingTech`. States include: `None, PreparingAstronomyDarkFrame, RawDarkTaking, RawDarkStopping, RawDarkStopped, RawTaking, RawStopping, GoLive, AIEnhance, AIEnhanceStopping, PanoramaTaking, PanoramaStopping, RecordTaking, RecordStopping, …` Behavior: - **Tap** → start capture (photo/burst/stack/record depending on tech). - **Long-press** → stop (`isLongPressTriggered`; shows `item_long_press_stop` pill "Long Press to Stop" / `camera_general_153`, then "Stopping…"). - Ring/teeth animations reflect exposure countdown (`ShootingProgressView`) and long-exposure progress (`NotifyProto.LongExpPhotoProgress`). ### 5.6 Joystick (`PolarDpadJoystickView`, 258dp) Bottom-left polar D-pad for manual slewing. Sends `CMD_STEP_MOTOR_SERVICE_JOYSTICK` (14006) with `vector_angle`/`vector_length`. Has low/high speed indicators and four directional triangle overlays. ### 5.7 Overlays (z-ordered by elevation) | Widget | elevation | purpose | |--------|-----------|---------| | `TrackBoxView` (tele + wide) | 4dp | tracking bounding-box overlay | | `PreviewBorderView` | — | PIP border / crop frame | | `ShootingProgressView` (main + minor) | 1dp | exposure countdown ring/text | | `FocusProgressLayout` | 3dp | autofocus sweep overlay | | `StopProgressLayout` | 3dp | stop-in-progress overlay | | `CaptureStatusLayout` | 3dp | status HUD (bottom-center) | | `FullscreenProgressLayout` | 4dp | full-screen progress (calibration, GoTo) | | `CaliFrameProgressLayout` | 4dp | calibration-frame progress | | `PanoCompositionLayout` | 30dp (top) | panorama composition canvas | | `ParameterIndicatorBar` / `DeviceIndicatorBar` | 1dp | bottom status chips | ### 5.8 Sky-finder / Milky-Way action rows (top-right & bottom-center) - `item_action_sky_finder`: calibration icon, AR-toggle, exit — for the Sky-Target-Finder / AR overlay mode (`CMD_ASTRO_START_SKY_TARGET_FINDER`). - `item_action_milky_way`: "Locate Milky Way" (`camera_astro_419`) + "Confirm" (`camera_astro_412`) pills — Milky Way composition helper. - `flGoComposition`: "GoTo" composition pill (`camera_pano_52`) for panorama framing. ### 5.9 Key dialogs launched from Capture | Dialog | Trigger | Purpose | |--------|---------|---------| | `ShootingModeSelectDialog` | TechniqueBar tap | Pick ShootingModeType | | `CamModeSelectDialog` | mode button | Pick ShootingTech (photo/video/stack/…) | | `CamParameterSetDialog` / `CamParamSetVM` | Parameter button | Exposure/Gain/WB/ISP per camera | | `CamMoreFeatureSetDialog` | left "more" icon | Extra feature toggles | | `PenalSetDialog` | panel button | Side-panel config | | `StatusHUDDialog` | indicator bar | Detailed status overlay | | `DarkSceneShootingDialog` | dark-frame flow | Dark-frame capture wizard | | `CaliFramePrepareDialog` | cali-frame flow | Calibration-frame prep | | `AtlasGotoDialog` | GoTo action | Confirm GoTo target | | `AiEnhanceProgressDialog` | AI enhance | AI post-process progress | | `ReservationCurveDialog` | curves | Tone/exposure curves editor | | `SkyFinderNodeTargetsDialog` | sky finder | Pick target from AR nodes | | `TrackSunHintDialog` | sun tracking | Sun-tracking safety hint | | `BottomTipDialog` / `TipDialog` / `MessageDialog` | various | Tips & confirmations | --- ## 6. Settings tab (`SettingsFragment`) — `fragment_settings.xml` A single `RecyclerView` whose rows are built programmatically in `SettingsFragment.java` (grouped sections). Title: "Settings" (`settings_1`). ### 6.1 Top-level rows (from nav actions on `navigation_settings`) | Row (string) | Destination fragment | |--------------|----------------------| | Profile / Login-Register | `ProfileFragment` / `LoginRegisterFragment` | | **My Device** (`settings_2`) | `MyDeviceFragment` | | **Connection Settings** (`settings_3`) | `ConnectionSettingsFragment` | | **Advanced Settings** (`settings_4`) | `AdvancedFragment` | | **Location** (`settings_5`) | `LocationFragment` | | **General** (`settings_6`) | `GeneralFragment` | | **Voice Assistant** | `VoiceAssistantFragment` | | **Support** (`settings_7`) | `SupportFragment` | | **About** (`settings_9`) | `AboutFragment` | | Clear Cache (`settings_8`) | (action, no nav) | ### 6.2 My Device (`MyDeviceFragment`) sub-tree - Device name → `DeviceNameFragment` (edit name; also triggers NFC update). - Device password → `DevicePasswordFragment` (change pwd; `isDefaultPwd` flag) → `DeviceResetFragment` (factory reset). - **NFC Update** (`settings_64`) → `NfcWriteActivity` — hold phone near ring light. - **Activation info** → `ActivateInfoFragment` (status, time, warranty). - **Storage** → `StorageFragment` (total/available size args). - Firmware/OTA — reuses `OTAUpgradeFragment`. ### 6.3 Connection Settings (`ConnectionSettingsFragment`) Toggles + radio (strings `settings_connection_1–29`): - **Connection mode**: Auto / STA / AP (radio). - **Activate Wi-Fi at Startup** (switch). - **Enable 2.4GHz**, **Wi-Fi Compatible Mode** (switches). - **Region** → `RegionSettingsFragment` (country code). - Configure STA network → `WiFiListFragment` → `StaInfoFragment`/`StaInfoSetFragment`. ### 6.4 General (`GeneralFragment`) sub-tree - **Language** → `LanguageSettingsFragment`. - **Temperature unit** → `TemperatureUnitFragment`. - **Appearance / Dark mode** → `AppearanceFragment`. - **Image correction** → `ImageCorrectionFragment` → list (`ImageCorrectionListFragment`) → item (`ImageCorrectionListItemFragment`) + helper. - **Floating window** → `FloatingWindowFragment`. - **Calendar** (dialog) → `CalendarFragment`. - **Auto-stop duration** → `AutoStopDurationFragment`. - **Emotion / voice** → `EmotionFragment`, `EmotionScaleFragment`, `SpeechRateFragment`, `VoiceTypeFragment`, `VoiceNavigationModeFragment`. - **Upload log / Log type** → `UploadLogFragment`, `LogTypeFragment`. ### 6.5 Advanced (`AdvancedFragment`) Device-level toggles: master lock, MTP mode, CPU mode, low-temp protection, lens defog, auto-cooling, auto-shutdown (the `CMD_SYSTEM_*` / `CMD_DEVICE_*` commands). Shows `layout_advanced_settings_unavailable.xml` when the connected device/firmware doesn't support an option. ### 6.6 Support / About - **Support** (`settings_7`): FAQ/web links, contact `support@dwarflab.com`, log upload. - **About** (`settings_9`): app version, OSS notice (`site.dwarflabapp.com/app-about/open-source-software-android`), privacy & terms (en/zh). --- ## 7. OTA / firmware upgrade flow ``` UpgradeReminderFragment (dialog: "new firmware available") └─▶ OTAUpgradeFragment (download + apply) └─▶ WiFiConnectFragment (dialog, if scope needs Wi-Fi for download) ``` - Args: `ssid`, `psd`, `isStaMode` — the scope may need to join Wi-Fi to fetch the firmware; the app drives this via BLE (`ReqSta`) then polls download progress. - Firmware download URL: `https://dwarflab.com/pages/dwarflab-app-firmware-download`. - `FirmwareForceUpdateDialog` blocks the app if firmware is too old for a required feature (e.g. astrophotography — see `camera_astro_116`). --- ## 8. Schedule / shooting-plan flow ``` HomeFragment └─▶ ScheduleFragment (list of plans) ├─▶ ScheduleDetailFragment (edit one plan; add targets, set params) │ └─▶ ScheduleErrorReasonFragment (if sync fails) [args: reason] └─▶ (sync/lock/unlock/delete via ScheduleProto cmds 16100–16108) ``` - A plan = a timed shooting session with one or more targets, per-camera params, and a date/time window (sunset→sunrise auto-calculated from Atlas). - Plans can be **locked** (16107) so they reserve their time slot; unlocking (16106) frees it. - "Add to Schedule" (`camera_general_113`), "Date of Plan" (`camera_general_114`), and the 12-hour-ahead sync limit (`camera_general_118`) are key UX constraints. --- ## 9. Shared UI conventions & components ### 9.1 Custom widgets (`ui/widget/`) | Widget | Path | Role | |--------|------|------| | `RtspPlayerView` | `media/` | RTSP preview (ijkplayer, TCP transport) | | `PolarDpadJoystickView` | `widget/joystick/` | Polar slew D-pad | | `TechniqueBar` | `widget/capture/` | Mode/tech selector pill | | `MainCaptureButtonView` | `widget/capture/` | Circular shutter | | `CaptureLeftControlPanel` / `CaptureRightControlPanel` | `widget/capture/` | Side control columns | | `ZoomLensPanel` | `widget/capture/` | Zoom / crop-ratio | | `ParameterIndicatorBar` / `DeviceIndicatorBar` | `widget/capture/` | Bottom status chips | | `ShootingProgressView` | `widget/capture/` | Exposure countdown ring | | `TrackBoxView` | `widget/camera/module/` | Tracking bbox overlay | | `PreviewBorderView` | `widget/camera/module/` | PIP/crop border | | `PanoPreviewGridLineView` | `widget/camera/module/` | Panorama grid | | `TargetRectView` | `widget/camera/module/` | Target rectangle | | `FocusProgressLayout` / `StopProgressLayout` | `widget/camera/module/` | Full-screen progress | | `RGBContainerLayout` | `widget/camera/function/` | RGB ring-light control | | `FullscreenProgressLayout` / `CaliFrameProgressLayout` / `PanoCompositionLayout` | `widget/capture/` | Full-screen overlays | | `DWRangeSliderView` | `widget/atlas/` | Range slider (params) | | `FitSystemView` | `widget/` | Status-bar inset helper | ### 9.2 Design tokens - Material 3 color scheme: `dl_color_on_surface`, `dl_color_surface_container_low_dark`, `dl_color_primary_dark`, `dl_color_mask_strong`, `dl_color_border_variant_dark`, `dl_color_white_80`, `dl_color_transparent`… - Spacing scale: `dl_gap_level_4/8/12/16/24/32` (4-pt grid), `dl_margin_level_3`, `dl_padding_level_2`, `dl_radius_rounded`, `dl_radius_medium`. - Typography styles: `title_large_emphasized`, `title_small_emphasized`, `body_medium`, `body_medium_emphasized`, `body_small_emphasized`, `label_medium`, `Photography_label_2`, `CamControlBtnStyle`. - Transitions: `right_slide_enter/exit`, `left_slide_enter/exit` (push), `dialog_bottom_enter/exit` (bottom-sheets). ### 9.3 Guide / onboarding overlays `ui/guide/overlay/`: `BaseGuideDialogFragment`, `GuideDialogFragment`, `ActivityGuideDialogFragment`, `FullScreenOverlayDialogFragment` — coach-mark overlays with anchor points (`ui/guide/anchor/`) used for first-run feature discovery. --- ## 10. Internationalization - Default strings in `res/values/strings.xml`; localized variants exist (Chinese `values-zh`, etc.). All user-visible text is keyed (`camera_astro_N`, `camera_general_N`, `settings_N`, `home_N`, `settings_connection_N`, `album_N`, `guide_N`…). - Help docs link to language-specific URLs: `https://help.dwarflab.com/en` vs `/zh`. - Voice assistant has its own strings and supports emotion/speech-rate tuning. --- ## 11. Map: UI action → API command | UI action | WS command(s) | Proto | |-----------|---------------|-------| | Tap shutter (photo) | 10002 / 12022 | `ReqPhotograph` | | Burst start/stop | 10003 / 10004 | `…Burst` | | Video record start/stop | 10005 / 10006 | `…Record` | | Set exposure | 10009 / 12004 | `ReqSetExp` | | Set gain | 10013 / 12006 | `ReqSetGain` | | WB / brightness / contrast / saturation / hue / sharpness | 10015–10024 | `ReqSetWB…` | | Open/close camera | 10000/10001 (tele), 12000/12001 (wide) | — | | Joystick slew | 14006 | `ReqMotorServiceJoystick` | | GoTo target | 11002/11003/11013/11014 | `ReqStartGotoDSO`/`…SolarSystem` | | Calibrate | 11000 | `ReqStartCalibration` | | Live stacking | 11005/11006 | `Req…LiveStacking` | | Dark frames | 11007/11021 | `Req…RawDark…` | | Auto-focus | 15000 | `ReqAutoFocus` | | Start track | 14800 | `ReqStartTrack` | | Panorama grid | 15500/15501 | `Req…Grid` | | AI enhance | 11029/11030 | `Req…AiEnhance` | | EQ solving | 11018/11019 | `Req…EqSolving` | | Power / reboot / RGB | 13500–13505 | `RGB.proto` | | Set time/location | 13000/13010 | `ReqSetTime`/`ReqSetLocation` | | Sync schedule | 16100 | `Schedule.proto` | Full command table: `CMD_TABLE.md`. Proto payloads: `analysis/protos/`. --- ## 12. Suggested reimplementation plan (cross-platform) 1. **Screens to build first** (MVP): Splash → Home (connect CTA) → DeviceSearch (BLE) → DeviceConnect (password) → Capture (preview + shutter + params + joystick) → Settings (My Device + Connection). 2. **State model**: a single `DeviceStore` (connected? device_id, ip, cameras on/off, current ShootingModeType/Tech, CaptureState, live params) fed by the WebSocket NOTIFY stream (§API_REFERENCE §3.2). All UI reads from this. 3. **Capture screen** is the hard part — replicate the overlay z-order (§5.7) and drive the capture button from `CaptureState`. 4. **Two preview surfaces** (Tele main + Wide PIP) each need an RTSP consumer; toggle PIP via `CMD_SWITCH_MAIN_PREVIEW` (14809). 5. Keep the **mode-driven visibility** model: each `ShootingModeType` flag (`isWidePreviewOnly`, `isAstroFocus`, `isShowZoomLens`…) controls which controls render — don't hardcode per-screen logic.