feat: interactive device onboarding tutorial#6124
Conversation
… tutorial State management for the 4-step interactive device onboarding flow: transcription demo, ask-a-question, power cycle, and double-tap config. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ce tutorial Routes button events and transcript segments to DeviceOnboardingProvider when interactive onboarding is active. Single-tap during ask-a-question step falls through to normal voice command handling. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Notifies DeviceOnboardingProvider on device disconnect and reconnect. Suppresses the 30-second disconnect notification during active onboarding. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
OnboardingStepScaffold provides consistent layout with progress dots, title, subtitle, content area, and bottom action. OnboardingContinueButton is the standard white pill-shaped button used across all steps. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Simplified real-time transcript view for the onboarding context. Shows segment text without speaker avatars or timestamps. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
User speaks into the device and sees live transcript appear. Shows pulsing mic animation while waiting, then "Good job!" with checkmark after 5+ words detected. Continue button appears after delay. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Guides user through pressing the button, speaking a question, and pressing again to submit. Shows state transitions: waiting → listening → processing → AI response. Observes MessageProvider for the response. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Teaches long press to power off (detects BLE disconnect) and single press to turn back on (detects reconnect). Shows 30-second hint if user hasn't powered off yet. Animated status indicators for each state. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Three selectable cards: End Conversation, Mute/Unmute, Star Conversation. User picks their preference and tries a double tap to confirm. Saves selection to SharedPreferences. Finish button completes onboarding. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Main orchestrator with non-dismissible PageView of 4 steps. Creates DeviceOnboardingProvider locally and wires it into CaptureProvider. Tracks analytics for each step completion via Mixpanel. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Shows "Device Tutorial" item under Device Settings when device is connected. Tapping launches the interactive device onboarding flow. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Track: deviceOnboardingStarted, deviceOnboardingStepCompleted, deviceOnboardingCompleted, deviceOnboardingDoubleTapConfigured. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Greptile SummaryThis PR adds a 4-step interactive device onboarding tutorial (transcription demo → ask a question → power cycle → double-tap config) accessible from Settings when a device is connected. The overall architecture is solid — Key findings:
Confidence Score: 4/5Safe to merge after addressing the Future.delayed-in-build timer accumulation and the onDeviceDisconnected ordering issue. Two P1/P2 logic issues remain that should be fixed before shipping to avoid subtle edge-case bugs, but nothing catastrophic. transcription_demo_step.dart and power_cycle_step.dart (Future.delayed in build), device_provider.dart (onDeviceDisconnected ordering), device_onboarding_provider.dart (list alias) Important Files Changed
|
| } | ||
|
|
||
| void _onStepComplete(String stepName) { | ||
| MixpanelManager().deviceOnboardingStepCompleted(stepName); | ||
|
|
||
| if (_onboardingProvider.currentStep < DeviceOnboardingProvider.totalSteps - 1) { |
There was a problem hiding this comment.
context.read<>() called in dispose()
Calling context.read<CaptureProvider>() inside dispose() is discouraged — by the time dispose() runs the element may be deactivating and Provider can emit warnings or throw in debug mode. Cache the reference in initState instead:
late CaptureProvider _captureProvider;
@override
void initState() {
super.initState();
_captureProvider = context.read<CaptureProvider>();
WidgetsBinding.instance.addPostFrameCallback((_) {
_captureProvider.deviceOnboardingProvider = _onboardingProvider;
_onboardingProvider.startOnboarding();
MixpanelManager().deviceOnboardingStarted();
});
}
@override
void dispose() {
_captureProvider.deviceOnboardingProvider = null;
_onboardingProvider.dispose();
_pageController.dispose();
super.dispose();
}| ), | ||
| const Divider(height: 1, color: Color(0xFF3C3C43)), | ||
| _buildSettingsItem( | ||
| title: 'Device Tutorial', |
There was a problem hiding this comment.
Hardcoded string — l10n required
Every other _buildSettingsItem call in this file uses context.l10n.* (e.g. context.l10n.profile, context.l10n.notifications, context.l10n.developerSettings), but 'Device Tutorial' is a bare string literal. Per the project's localization policy all user-facing strings must go through l10n.
The same applies to all titles, subtitles, button labels, and hint texts in the new onboarding files:
transcription_demo_step.dart—'Speak Into Your Omi','Say a few words...','Good job!'single_press_step.dart—'Ask Omi a Question','Listening...','Processing...', etc.power_cycle_step.dart—'Turn Off & On','Hold the button...','Device is off!', etc.double_press_config_step.dart—'Customize Double Tap', option titles and descriptionsonboarding_step_scaffold.dart—'Continue','Finish'
All of these should be extracted into the app's ARB files and referenced via context.l10n.
Context Used: Flutter localization - all user-facing strings mus... (source)
Track message count at voice session start and only look at messages added after that point. Filter out app notifications (fromIntegration) and incomplete messages. Also show the user's transcribed question above the AI response. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ssion The previous approach tried to snapshot inside _onMessagesChanged when voiceSessionActive was true, but that callback only fires on MessageProvider changes, not DeviceOnboardingProvider changes — so the snapshot was never set, causing the response filter to return early. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
If user accidentally single-taps during the double-press config step, show an amber hint: "That was a single tap — try tapping twice quickly!" Hint clears when they successfully double-tap. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ispose context.read in dispose() crashes because the widget tree is already deactivated. Cache the reference in initState's post-frame callback and use it directly in dispose. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace plain black with a top-to-bottom gradient from deep purple (#1A0033) to black across all onboarding steps. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The AI response can contain markdown (bold, italic, code) which renders as raw asterisks/backticks in a plain Text widget. Strip it before display. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Fully rounded corners (borderRadius 100) on option cards and hint bar - Removed subtitle line below heading - Shorter option descriptions - Replaced bare icon+text for double-tap detected with a styled pill chip Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Selected option gets solid white background with black text/icons instead of a subtle highlight with a checkmark. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Star: stacked conversation cards with live waveform on top, star appears on double-tap - End Conversation: active waveform that cuts on double-tap, new conversation card fades in - Mute/Unmute: conversation card with waveform that toggles to flat/muted state on double-tap Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Instead of showing a new card below, the waveform splits inline: frozen/faded old waveform on the left, a thin vertical divider gap, then a live green waveform continuing on the right. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Star: single card with waveform, star toggles on/off each double-tap - Mute: red dot/waveform/icon when muted, toggles infinitely - End: split resets after 2s so user can split again - Removed "double tap detected" green pill, Finish button shows after first double-tap but user can keep experimenting - Changed doublePressDetected bool to doublePressCount int Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Dart's replaceAll with RegExp treats $1 as literal text, not a backreference. Use replaceAllMapped to properly extract capture groups. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Move waveform animations from a separate widget below the options into the selected option card itself. Updated colors for white card background (dark waveforms, red mute state). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
… on split - Hide Finish button when single-tap hint is showing - Replace frozen waveform on left side of split with horizontal lines graphic representing a generated summary Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Card-based layout: waveform bar with mic icon and word counter while listening, green pill when complete. Transcript appears in a rounded card below. Matches double-tap page design language. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Card-based states: rounded card with touch icon for waiting, green bordered card with waveform while listening, card with spinner while processing, chat bubble layout for question/answer. No more floating circles. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Card-based layout: colored status pill (green/red) showing connection state, instruction card with icon, amber hint card. Animated transitions between states. No more floating circles or bare icons. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…sult UI Remove all waveform animations and AnimationController from the step. Result now shows in a white card with question as grey text above a divider, answer as black text below. Clean, static, readable. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Title changes between "Turn Off" and "Turn On" based on state - Omi device image between title and status card - Connected: omiWithoutRope image, Disconnected: omiWithoutRopeTurnedOff with red X badge on bottom right - AnimatedSwitcher for smooth image transitions Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
@greptile-apps review |
Waveform pulses amplitude in place instead of scrolling left/right. Uses sin(phase) to modulate amplitude rather than shifting the wave. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Image size 140 -> 180, margin below 24 -> 32, red X badge 28 -> 36 with icon 16 -> 20. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…on step Omi device image centered above the status card with 3 concentric pulsating circles radiating outward behind it. Circles fade out as they expand. Hidden after transcription completes. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Start with selectedDoubleTapAction = -1 (none selected) so user must explicitly pick an option. Ignore double-tap events until an option is selected. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…pulses Removed the waveform status card entirely. Omi image 120->160px, pulse container 200->320px so circles radiate much wider. Animation duration 2s->4s for slower pulses. Removed _LiveWavePainter. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Remove CircularProgressIndicator, use ShaderMask with a sweeping LinearGradient on "Processing your question..." text instead. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Shows "Try it now! Double tap your Omi" pill at bottom after user selects an option but before first double-tap. Same style as the single-tap warning but in neutral grey. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Waiting state: Omi device image with an animated finger icon that bobs down to tap and lifts back up on a loop. Listening state: Omi with pulsating circles (like transcription page) plus the waveform bar below it. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When user presses the device button, the Omi image scales down to 0.85 and bounces back over 300ms, giving a "pressed into screen" feel. Finger animation stops when listening starts. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Finger icon starts at bottom-right corner, moves toward the device, presses it (Omi scales down to 0.92), then retreats back out. Pauses briefly before looping. Omi bounces back after each press. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…on Omi Remove finger icon entirely. Waiting state shows Omi image with a looping bounce-click animation (scales down to 0.9 and back). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add device_onboarding_completed field to GET/PATCH /v1/users/onboarding.
Stored in Firestore under users/{uid}.onboarding.device_onboarding_completed.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Extend updateUserOnboardingState to accept deviceOnboardingCompleted parameter for setting the Firestore flag. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
On completion, sets both local pref and calls updateUserOnboardingState to persist device_onboarding_completed=true in Firestore. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When device connects, check if deviceOnboardingCompleted is false (local pref first, then Firestore). If not completed, push the interactive device onboarding as a full-screen route. Works for both new users (first connection) and existing users (next connection after feature ships). Guard prevents showing twice per session. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Summary
PopScope(canPop: false), no back/skip buttonsTest plan
🤖 Generated with Claude Code