Skip to content

Add minimizable phone call UI with home screen banner#6066

Merged
mdmohsin7 merged 8 commits into
mainfrom
mohsin/minimizable-call-ui
Mar 26, 2026
Merged

Add minimizable phone call UI with home screen banner#6066
mdmohsin7 merged 8 commits into
mainfrom
mohsin/minimizable-call-ui

Conversation

@mdmohsin7
Copy link
Copy Markdown
Member

@mdmohsin7 mdmohsin7 commented Mar 26, 2026

Summary

  • Minimizable call screen: Added a back button to ActiveCallPage so users can navigate back to the home screen while a call is in progress (previously the screen was locked with PopScope)
  • Home screen call banner: New ActiveCallBanner widget shows contact info, live transcript snippet, and inline call controls (mute, speaker, end call) on the conversations page — tap to expand back to full call view
  • Global call indicator: Slim green ActiveCallTopBar bar on non-home tabs (Tasks, Memories, Apps) to return to the call
  • UI cleanup during calls: Hides the recording capture widget and the mic record button in the bottom nav bar while a call is active
  • Duplicate call prevention: Blocks placing a second call with a "A call is already in progress" snackbar

Test plan

  • Start a phone call, verify the back arrow appears in the top-left of the call screen
  • Tap the back arrow — should go directly to home screen (not the dialer page)
  • Verify the ActiveCallBanner appears at the top of the conversations list with contact name, duration, transcript, and controls
  • Test mute/speaker/end call controls on the banner work correctly
  • Switch to Tasks/Memories/Apps tabs — verify green top bar appears with contact name and duration
  • Tap the banner or green bar — should navigate back to the full call screen
  • Verify the "Continue Recording" widget and mic button are hidden during the call
  • While on a call, tap the phone icon and try to call another number — should show "A call is already in progress" toast
  • End the call — verify banner/top bar disappear and recording widget/mic button return

🤖 Generated with Claude Code

New widgets that show call status, transcript snippet, and inline controls
when the user minimizes an active phone call. ActiveCallTopBar provides a
slim green bar on non-home tabs to return to the full call screen.
Replace PopScope lock with a back button that lets users minimize the
call and return to the home screen. Uses popUntil to skip the intermediate
PhoneCallsPage.
The ActiveCallBanner replaces this widget during calls so both don't
show simultaneously.
Green bar at the top of Tasks, Memories, and Apps tabs lets users
tap to return to the full call screen from any tab.
Shows a snackbar with 'A call is already in progress' if the user
tries to dial while a call is in connecting/ringing/active state.
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Mar 26, 2026

Greptile Summary

This PR adds a minimizable phone call UI with a persistent home-screen banner (ActiveCallBanner) and a slim indicator bar on non-home tabs (ActiveCallTopBar), replacing the locked PopScope on the active call screen with a back/minimize button. It also hides the recording capture widget and bottom-nav mic button during a call, and blocks placing a second concurrent call.\n\nKey changes:\n- active_call_page.dart: PopScope lock removed; a new minimize back-button calls Navigator.popUntil(isFirst) so users can return to home while the call continues. Auto-pop on call end is correctly guarded by mounted.\n- active_call_banner.dart (new): ActiveCallBanner shows contact, duration, last transcript segment, and inline mute/speaker/end controls on the home tab. ActiveCallTopBar shows a slim green bar on Tasks/Memories/Apps tabs. Both navigate back to ActiveCallPage on tap.\n- phone_calls_page.dart: Early-return guard blocks a second call with a snackbar.\n- processing_capture.dart / bottom_nav_bar.dart: UI elements hidden during active calls.\n- One P1 issue found: _CompactControlButton's GestureDetector always has a non-null onTap handler even when the button is "disabled". This causes the disabled mute/speaker buttons to absorb tap events (preventing the banner's outer onTap navigation from firing) and emit haptic feedback while performing no action.\n- One P2 issue found: The isUser parameter in _TranscriptSnippet is accepted but never used.

Confidence Score: 4/5

Safe to merge after fixing the tap-absorption bug in _CompactControlButton; all other changes are well-structured and correct.

The feature is well-implemented overall — state management is sound, the mounted guard on auto-pop is correct, and duplicate-call prevention is properly placed. One targeted P1 fix remains: _CompactControlButton always registers a non-null GestureDetector.onTap even in the disabled state, which causes disabled buttons to silently absorb taps and block banner navigation. Once that one-liner is addressed, the PR is ready to merge.

app/lib/pages/phone_calls/active_call_banner.dart — _CompactControlButton.build around line 268

Important Files Changed

Filename Overview
app/lib/pages/phone_calls/active_call_banner.dart New file introducing ActiveCallBanner and ActiveCallTopBar widgets; has a P1 tap-absorption bug on disabled compact control buttons and an unused isUser param
app/lib/pages/phone_calls/active_call_page.dart Replaces PopScope lock with a minimize back-button that calls popUntil(isFirst); auto-pop on call-end is correctly guarded by mounted check
app/lib/pages/phone_calls/phone_calls_page.dart Adds early-return guard to block placing a second call while one is already in progress; shows a localized snackbar
app/lib/pages/conversations/widgets/processing_capture.dart Hides ConversationCaptureWidget during active/connecting/ringing call states by returning SizedBox.shrink() early in build
app/lib/widgets/bottom_nav_bar.dart Hides the central mic record button and its spacing reservation during an active phone call; straightforward and correct

Sequence Diagram

sequenceDiagram
    participant User
    participant PhoneCallsPage
    participant ActiveCallPage
    participant PhoneCallProvider
    participant ActiveCallBanner
    participant ActiveCallTopBar

    User->>PhoneCallsPage: Tap Call button
    PhoneCallsPage->>PhoneCallProvider: check callState != idle
    alt Call already in progress
        PhoneCallProvider-->>PhoneCallsPage: callState != idle
        PhoneCallsPage-->>User: Snackbar A call is already in progress
    else No call in progress
        PhoneCallsPage->>PhoneCallProvider: startCall(number)
        PhoneCallProvider-->>PhoneCallsPage: callState = connecting
        PhoneCallsPage->>ActiveCallPage: Navigator.push
        User->>ActiveCallPage: Tap back arrow (minimize)
        ActiveCallPage->>ActiveCallPage: Navigator.popUntil(isFirst)
        Note over ActiveCallBanner: Banner appears on home tab
        Note over ActiveCallTopBar: Top bar appears on other tabs
        User->>ActiveCallBanner: Tap banner
        ActiveCallBanner->>ActiveCallPage: Navigator.push (new instance)
        PhoneCallProvider-->>ActiveCallPage: callState = ended
        ActiveCallPage->>ActiveCallPage: Future.delayed(2s) pop
        Note over ActiveCallBanner,ActiveCallTopBar: Banner/TopBar disappear (callState = idle)
    end
Loading

Reviews (1): Last reviewed commit: "Block placing a second call while one is..." | Re-trigger Greptile

Comment on lines +268 to +271
return GestureDetector(
onTap: () {
HapticFeedback.mediumImpact();
onTap?.call();
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Disabled buttons still absorb taps and fire haptics

_CompactControlButton's GestureDetector.onTap is always set to a non-null closure (it just calls HapticFeedback.mediumImpact(); onTap?.call();), even when the outer onTap parameter is null (i.e., during the connecting state). Because Flutter gesture arena disambiguation gives the inner GestureDetector priority, tapping on the mute or speaker button while they are disabled will:

  1. Fire a haptic impact (misleading — the button didn't do anything).
  2. Consume the tap event, so the outer ActiveCallBanner's onTap (which navigates to the full call page) never fires.

The fix is to pass null as onTap to the GestureDetector when the button is disabled:

Suggested change
return GestureDetector(
onTap: () {
HapticFeedback.mediumImpact();
onTap?.call();
return GestureDetector(
onTap: onTap == null
? null
: () {
HapticFeedback.mediumImpact();
onTap!();
},

Comment on lines +169 to +174
class _TranscriptSnippet extends StatelessWidget {
final String text;
final bool isUser;
final String speakerLabel;

const _TranscriptSnippet({required this.text, required this.isUser, required this.speakerLabel});
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 isUser field accepted but never used

_TranscriptSnippet receives an isUser flag but the widget doesn't use it — both user and remote transcripts render identically. In the full _LiveTranscriptView this flag is used to align bubbles left/right, so the banner snippet visually loses that distinction. Either use it (e.g. a subtle tint / border difference) or remove it to avoid dead parameters.

Suggested change
class _TranscriptSnippet extends StatelessWidget {
final String text;
final bool isUser;
final String speakerLabel;
const _TranscriptSnippet({required this.text, required this.isUser, required this.speakerLabel});
const _TranscriptSnippet({required this.text, required this.speakerLabel});

…param

Address Greptile review: pass null onTap to GestureDetector when button
is disabled so taps propagate to the banner, and remove dead isUser field
from _TranscriptSnippet.
@mdmohsin7 mdmohsin7 merged commit 251585d into main Mar 26, 2026
1 check passed
@mdmohsin7 mdmohsin7 deleted the mohsin/minimizable-call-ui branch March 26, 2026 19:30
Glucksberg pushed a commit to Glucksberg/omi-local that referenced this pull request Apr 28, 2026
…6066)

## Summary
- **Minimizable call screen**: Added a back button to `ActiveCallPage`
so users can navigate back to the home screen while a call is in
progress (previously the screen was locked with `PopScope`)
- **Home screen call banner**: New `ActiveCallBanner` widget shows
contact info, live transcript snippet, and inline call controls (mute,
speaker, end call) on the conversations page — tap to expand back to
full call view
- **Global call indicator**: Slim green `ActiveCallTopBar` bar on
non-home tabs (Tasks, Memories, Apps) to return to the call
- **UI cleanup during calls**: Hides the recording capture widget and
the mic record button in the bottom nav bar while a call is active
- **Duplicate call prevention**: Blocks placing a second call with a "A
call is already in progress" snackbar

## Test plan
- [x] Start a phone call, verify the back arrow appears in the top-left
of the call screen
- [x] Tap the back arrow — should go directly to home screen (not the
dialer page)
- [x] Verify the `ActiveCallBanner` appears at the top of the
conversations list with contact name, duration, transcript, and controls
- [x] Test mute/speaker/end call controls on the banner work correctly
- [x] Switch to Tasks/Memories/Apps tabs — verify green top bar appears
with contact name and duration
- [x] Tap the banner or green bar — should navigate back to the full
call screen
- [x] Verify the "Continue Recording" widget and mic button are hidden
during the call
- [x] While on a call, tap the phone icon and try to call another number
— should show "A call is already in progress" toast
- [x] End the call — verify banner/top bar disappear and recording
widget/mic button return

🤖 Generated with [Claude Code](https://claude.com/claude-code)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant