Files
dwarf-go/analysis/UI_REFERENCE.md
Jacquin Antoine 814a836c5a Reverse-engineer DWARF II telescope API and build open-source Go client
Complete reverse-engineering of the DWARFLAB Android app (v3.4.0) protocol
and implementation of a working CLI tool to control DWARF II telescopes.

Analysis (from APK decompilation with jadx):
- Extracted 17 protobuf definitions (382 messages) from embedded descriptors
- Mapped all 323 WebSocket command IDs across 16 modules
- Documented the full protocol: BLE discovery, WebSocket control (port 9900),
  RTSP preview, WsPacket envelope (proto v2.3)
- Documented the Android UI structure (screens, navigation, shooting modes)
- Key discovery: telescope responds with type=3 (reply), not type=1 (response),
  and several commands are fire-and-forget (RGB, camera open/close)

dwarfctl Go client:
- Protobuf bindings generated from extracted .proto files (397 messages)
- WebSocket transport layer with request-response matching and notification fan-out
- Typed API covering cameras, motors, astrophotography, focus, tracking, system, power
- Cobra CLI with 30+ subcommands and --debug traffic logging
- 57 unit tests (transport round-trip, command routing, proto encoding)
- Validated on real hardware: state, photo, motor slew (all directions/speeds),
  focus, RGB, time/location sync all confirmed working

💘 Generated with Crush

Assisted-by: Crush:glm-5.2
2026-07-12 15:18:56 +02:00

503 lines
25 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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_1421`):
- **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_129`):
- **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 1610016108)
```
- 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 | 1001510024 | `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 | 1350013505 | `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.