Skip to content

feat(ui): implement predictive back gesture and migrate Key.Back to BackHandler - #498

Open
Himanth-reddy wants to merge 4 commits into
ProdigyV21:mainfrom
Himanth-reddy:feat/predictive-back-gesture
Open

feat(ui): implement predictive back gesture and migrate Key.Back to BackHandler#498
Himanth-reddy wants to merge 4 commits into
ProdigyV21:mainfrom
Himanth-reddy:feat/predictive-back-gesture

Conversation

@Himanth-reddy

Copy link
Copy Markdown
Collaborator

Summary

This PR implements predictive back gesture support for the Stream Searching page (StreamSelector.kt) and refactors app-wide back navigation handling to ensure compatibility with Android 13+ (OnBackPressedDispatcher).

Key Changes

  1. Predictive Back Support (StreamSelector.kt & AndroidManifest.xml)

    • Enabled android:enableOnBackInvokedCallback="true" in AndroidManifest.xml.
    • Added Compose PredictiveBackHandler in StreamSelector.kt with top-level progress tracking.
    • Separated StreamSelector root layout into an outer scrim Box (animating dark overlay alpha) and an inner content Box (animating scale, translation, and alpha via graphicsLayer).
    • Handled coroutine cancellation properly by rethrowing CancellationException.
  2. App-Wide Key.Back -> BackHandler Migration (25 Files)

    • Replaced legacy Compose Key.Back interceptions with BackHandler across all screens, overlays, and modals to prevent back navigation from breaking when enableOnBackInvokedCallback="true" is active on API 33+.
    • Retained Key.Escape in key listeners for hardware keyboard and desktop users.
    • Ensured single-ownership rule for back handling inside modals and overlays.

@Himanth-reddy
Himanth-reddy force-pushed the feat/predictive-back-gesture branch 3 times, most recently from 5e9f121 to fc777c6 Compare July 28, 2026 11:52
…Selector

- Create ArvioPredictiveBack motion primitive (M3 surface scale 90%, edge-aware shift, touchY tilt, and instant release handling)
- Apply ArvioBackSurface, ArvioBackPeek, and AnimatedVisibility exit transitions to SettingsScreen sub-pages
- Apply ArvioBackModal and smooth fade/slide-down exit transitions to StreamSelector modal overlay
@Himanth-reddy
Himanth-reddy force-pushed the feat/predictive-back-gesture branch from f2f5bc1 to d65e5ff Compare July 29, 2026 12:34
@Himanth-reddy
Himanth-reddy marked this pull request as ready for review July 29, 2026 12:46

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 5df9fb5c05

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

android:allowBackup="false"
android:banner="@drawable/app_banner"
android:enableOnBackInvokedCallback="false"
android:enableOnBackInvokedCallback="true"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Finish migrating Key.Back before enabling predictive back

With this application-wide flag enabled on API 33+ / targetSdk 36, system Back is delivered through the OnBackInvoked/OnBackPressed path instead of the Compose key-event path, but a repo-wide check still shows screens and modals that only handle Key.Back in onKeyEvent/onPreviewKeyEvent and have no BackHandler in those files, e.g. app/src/main/kotlin/com/arflix/tv/ui/components/TextInputModal.kt:142 and app/src/main/kotlin/com/arflix/tv/ui/screens/plugin/PluginScreen.kt:130. In those contexts Back will no longer dismiss/navigate as intended and can fall through to the activity/root back behavior, so either keep this flag off or migrate the remaining Key.Back handlers to BackHandler before enabling it globally.

Useful? React with 👍 / 👎.

@ProdigyV21 ProdigyV21 left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Thanks Himanth — ArvioPredictiveBack.kt is genuinely good work: M3-spec easing, real commit/cancel settle animations, and the CancellationException rethrow is handled correctly. The StreamSelector and mobile Settings integrations look right. This is closer to mergeable than #495, but there's one blocker that makes it dangerous to land as-is.

Blocker: the manifest flag is flipped app-wide, but the migration it requires isn't in this PR.

The description says "App-Wide Key.BackBackHandler Migration (25 Files)" — the diff migrates exactly one (StreamSelector). Checked against the branch:

  • The codebase has 55 Key.Back interceptions across 25 files. After this PR, 54 remain: PlayerScreen keeps 7, the TV Settings layout keeps 14, and 17 files — every context menu, AudioTrackSelector, PersonModal, TextInputModal, QuickZapOverlay, SearchOverlay, NextEpisodeOverlay, DetailsScreen, EpgGrid, and more — have Key.Back as their only back mechanism, with no BackHandler at all.
  • With enableOnBackInvokedCallback="true" and targetSdk 36, Android 13+ stops delivering KEYCODE_BACK to the app's views entirely — that's the documented contract of opting in. Every remaining interceptor goes silently dead on Android 13+.
  • Concrete failure: on a Google TV Streamer (Android 14), Back with a context menu open no longer closes the menu — it fires whatever BackHandler sits underneath (or exits the screen) while the menu stays on screen. Same for the audio-track selector during playback, the person modal, text input, quick-zap… Back is the navigation primitive on TV, and this forks its behavior by OS version: fine on Android ≤ 12, broken on 13+.

Note the risk/benefit inversion: predictive back gestures don't exist on TV (d-pad Back commits with no progress events), so the flag's visible benefit is mobile-only — while the breakage lands on the TV form factor.

What would make this mergeable — either path works:

  1. Do the migration the description promises: move all 55 Key.Back sites to BackHandler/PredictiveBackHandler with correct enabled state and modal ownership (topmost layer wins), then flip the flag — and test on an actual Android 13+ device, since ≤ 12 can't reveal any of these regressions.
  2. Ship the motion work now, defer the flag: keep enableOnBackInvokedCallback="false", land ArvioPredictiveBack.kt + the StreamSelector/Settings integrations (they work fine via the compat dispatcher), and flip the flag in a follow-up once the migration is complete.

Option 2 gets your animation work in quickly and safely.

Also please split out the TvLazyColumnLazyColumn migration in StreamSelector. It changes d-pad focus/scroll behavior in the source picker, it's unrelated to predictive back, and it deserves its own PR where it can be reviewed and tested as what it is.

@Himanth-reddy
Himanth-reddy requested a review from ProdigyV21 July 30, 2026 17:05
@Himanth-reddy

Copy link
Copy Markdown
Collaborator Author

Thanks @ProdigyV21! Addressed all review feedback in the latest commit () on :

1. Completed App-Wide Migration (Option 1)

  • Kept in .
  • Replaced legacy handling across all 25 files with Compose / with explicit ownership and state management:
    • Modals & Overlays: PersonModal, TextInputModal, QuickActionMenu, NextEpisodeOverlay, MediaContextMenu, ContextMenu, AudioTrackSelector, AppUpdateModal
    • Live TV & EPG: SearchOverlay, QuickZapOverlay, LiveTvEnhancements, EpgGrid, CategorySidebar, LiveTvScreen
    • Player & Screens: PlayerScreen, HomeScreen, SearchScreen, WatchlistScreen, DetailsScreen, CollectionDetailsScreen, PluginScreen, TelegramSettingsScreen, SettingsScreen (TV layout & dialogs).
  • Ensured topmost overlay/modal handles dismissal first, preventing background screens from capturing back events.

2. Isolated in

  • Reverted back to TvLazyColumn (and rememberTvLazyListState) in StreamSelector.kt to keep scrolling/focus behavior changes isolated.
  • Kept all ArvioPredictiveBack motion primitives and arvioBackModal animations intact.

3. Verification

  • Verified compilation with ./gradlew :app:compileSideloadDebugKotlin (BUILD SUCCESSFUL).

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.

2 participants