3.5 KiB
3.5 KiB
Mobile Voice Refactor Plan
Goals
- Reduce the surface area of
src/app/index.tsxwithout changing product behavior. - Make device, network, and monitoring flows easier to reason about.
- Move toward React Native / Expo best practices for state, effects, and file structure.
- Use the new lint warnings as refactor prompts, not as permanent background noise.
Current Pain Points
DictationScreencurrently owns onboarding, permissions, Whisper/model lifecycle, dictation, pairing, server/session sync, relay registration, notification handling, and most UI rendering.- The screen mixes render-time derived state, imperative refs, polling, persistence, and native cleanup in one place.
- There are many nested conditionals and long derived blocks that are hard to scan.
- Best-effort async cleanup and silent catches make failures harder to understand.
Target Shape
src/app/index.tsx- compose hooks and presentational sections
- keep only screen-level orchestration
src/features/onboarding/- onboarding step config
- onboarding UI component
src/features/dictation/use-whisper-dictation- transcript helpers
src/features/servers/- server/session refresh and pairing helpers
- persisted server state helpers
src/features/monitoring/- foreground SSE monitoring
- notification payload handling
- relay registration helpers
src/lib/- parser/validation helpers
- logger helper for dev-only diagnostics
Refactor Order
Phase 1: Extract pure helpers first
- Move onboarding step text/style selection into a config object or array.
- Move server/session payload parsing into dedicated helpers.
- Keep existing behavior and props the same.
Phase 2: Extract onboarding UI
- Create an
OnboardingFlowcomponent that receives explicit state and handlers. - Keep onboarding persistence in the screen until the UI extraction is stable.
Phase 3: Extract dictation logic
- Move Whisper loading, recording, bulk/realtime transcription, and waveform state into a
useWhisperDictationhook. - Expose a small interface: recording state, transcript, actions, and model status.
Phase 4: Extract server/session management
- Move server restore/save, pairing, health refresh, and active server/session selection into a dedicated hook.
- Centralize server parsing and dedupe logic.
Phase 5: Extract monitoring and notifications
- Move SSE monitoring, push payload handling, and relay registration into a
useMonitoringhook. - Keep side effects close to the feature that owns them.
Phase 6: Lint burn-down
- Replace
anywith explicit parsed shapes. - Reduce nested ternaries in favor of config tables.
- Replace ad hoc
console.logcalls with a logger helper or__DEV__-gated diagnostics. - Audit bare
.catch(() => {})and convert non-trivial cases to explicit best-effort helpers or real error handling.
Guardrails During Refactor
- Keep one behavior-preserving slice per PR.
- Do not introduce more derived state in
useEffect. - Prefer explicit hook inputs/outputs over hidden cross-hook coupling.
- Only use refs for imperative APIs, subscriptions, and race control.
- Re-run lint after each slice.
- Validate app behavior in the dev client for microphone, notifications, pairing, and monitoring flows.
Exit Criteria
src/app/index.tsxis mostly screen composition and stays under roughly 800-1200 lines.- Feature logic lives in focused hooks/components with clearer ownership.
- New payload parsing does not rely on
any. - Lint warnings trend down instead of growing.