Skip to content

Replace calendar day arrows with edge taps on video - #48

Open
LukeNeedham wants to merge 6 commits into
mainfrom
claude/calendar-date-nav-redesign-0ibu4u
Open

Replace calendar day arrows with edge taps on video#48
LukeNeedham wants to merge 6 commits into
mainfrom
claude/calendar-date-nav-redesign-0ibu4u

Conversation

@LukeNeedham

Copy link
Copy Markdown
Owner

Summary

  • Removes the previous/next chevron arrow buttons from the calendar day selector (CalendarDaySelector), leaving just the tappable date label.
  • Adds edge-tap navigation on the video itself: tapping the left ~25% of the video goes back a day, tapping the right ~25% goes forward a day.
  • Edge taps are distinguished from swipes via touch-slop distance, so swipe-to-scroll through days and press-and-hold-to-pause playback both continue to work unchanged.

Test plan

  • ./gradlew :app:compileDebugKotlin — compiles cleanly
  • ./gradlew :app:testDebugUnitTest :app:assembleDebug — unit tests pass, debug APK builds
  • Manual verification on device/emulator: tap left/right edges of video to change day, swipe to scroll through days, press-and-hold to pause playback

Generated by Claude Code

Removes the previous/next chevron buttons from the calendar date
selector. Tapping the left or right edge of the video now navigates
to the previous/next day instead, while swiping through days and
press-and-hold to pause playback keep working as before.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VbtRXD54bQgJSoNBeLVMHP
@github-actions

github-actions Bot commented Aug 15, 2026

Copy link
Copy Markdown

App apk at:
https://github.com/LukeNeedham/VideoDiary/releases/download/claude-calendar-date-nav-redesign-0ibu4u-148-1/app-debug.apk

  • Triggered by: PR Commit ea69d473bc8c4f8569270fe65972e77bf6e7193a
  • Built at: 17/08/2026 03:58:27

claude added 5 commits August 15, 2026 23:56
A long press (holding to pause playback) with no movement was
still short enough in distance to pass the tap-detection check,
so releasing it after a long hold incorrectly navigated to the
previous/next day. Edge taps now also require the press to be
released within the platform's long-press timeout.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VbtRXD54bQgJSoNBeLVMHP
onPrevious/onNext computed the target page from pagerState.currentPage,
which only updates once an in-flight animateScrollToPage animation
settles. A tap landing while the previous page-flip was still animating
therefore resolved to the same page already being animated to - a
no-op - making rapid edge taps feel unresponsive for as long as the
prior animation was still running.

Use pagerState.targetPage instead, which reflects the page the pager
is currently animating towards (or currentPage when idle), so each
tap advances immediately regardless of any animation in progress.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VbtRXD54bQgJSoNBeLVMHP
The targetPage fix wasn't enough - edge taps could still go dead for
a second or two right after a page change. The actual cause: each
page in the pager mounted its own VideoPlayerExo when it became
current, and that composable creates a brand new native TextureView
and rebinds the shared ExoPlayer's video surface to it every time.
Recreating that native view on every day navigation left the video
area unresponsive to touch for a beat, regardless of how the target
page was computed.

Now the live player is hosted once, persistently, as an overlay in
CalendarScroller, only ever swapping which video it points at rather
than tearing down and recreating its surface. Each page in the pager
only ever shows its static thumbnail (VideoPlayer gets a new
showPlayer = false flag for this). The overlay hides while the pager
is mid-swipe, since it doesn't track page-drag offset itself - pages
show their thumbnail during the drag, and the live video reappears
once a swipe settles, matching how incoming pages already behaved.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VbtRXD54bQgJSoNBeLVMHP
The previous fix hoisted the player to a single overlay, but still
gated its composition on !pagerState.isScrollInProgress. Since that
flips true then false on every single tap/swipe, the overlay was
still being unmounted and remounted on each navigation - recreating
the native TextureView just as before, only one level up. That's why
the touch dead-zone persisted after that change.

Now VideoPlayerExo stays composed continuously (gated only on there
being a video at all, not on scroll state), so its native view is
created once and never torn down during ordinary day-to-day
navigation. It's hidden during an active swipe via alpha instead of
being removed from composition, preserving the previous show/hide
behaviour without the teardown/recreate cost.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VbtRXD54bQgJSoNBeLVMHP
The manual PointerEventPass.Initial loop (awaitFirstDown +
waitForUpOrCancellation in a hand-written while(true), with our own
touch-slop/long-press-duration math) had some subtle bug causing a
one-to-two second window after the first tap where further taps
weren't registered at all - rapid tapping on an edge should page
through days one at a time, not stall after the first.

Switch to detectTapGestures, Compose's standard primitive for this
exact tap/long-press/drag arbitration: onPress still pauses/resumes
playback for the whole gesture regardless of how it ends, onLongPress
(a no-op) is enough to make onTap only fire for genuine taps, and
onTap fires the edge navigation. Letting the pager's own scrollable
(a descendant, so it sees drag motion first on the default Main pass)
naturally consume real swipes - rather than us intercepting on the
Initial pass and re-deriving swipe-vs-tap ourselves - removes the
custom logic that was likely behind the stall.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VbtRXD54bQgJSoNBeLVMHP
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