Skip to content

[MUON-1999] Add video progress tracking to BpkVideoPlayer - #2793

Open
Joan Fuentes (Nescafemix) wants to merge 9 commits into
mainfrom
muon/MUON-1999-include-video-progress-on-bpkvideoplayer
Open

[MUON-1999] Add video progress tracking to BpkVideoPlayer#2793
Joan Fuentes (Nescafemix) wants to merge 9 commits into
mainfrom
muon/MUON-1999-include-video-progress-on-bpkvideoplayer

Conversation

@Nescafemix

@Nescafemix Joan Fuentes (Nescafemix) commented Aug 18, 2026

Copy link
Copy Markdown
Contributor

MUON-1999

Description

Exposes playback progress from BpkVideoPlayer so consumers can track video position and fire analytics events (e.g. quartile tracking at 25%, 50%, 75%, 100%).

Changes

  • New BpkVideoPlayerProgress data class — holds positionMs, durationMs, and a derived percentage: Float.
  • BpkVideoPlayerController.progressState: State<BpkVideoPlayerProgress?> — new observable property, updated every ~200 ms while the video is playing. Emits null when duration is unknown. Guarantees a final value at 100% when the video ends or loops (via onPositionDiscontinuity(DISCONTINUITY_REASON_AUTO_TRANSITION) for loop-safe detection).
  • Demo — the "Default Controls" story in VideoPlayerStory now shows live progress percentage and position below the player.
  • Tests — integration tests in BpkVideoPlayerTest covering progress polling, pause/resume state retention, end-of-video 100% guarantee, and loop boundary detection; unit tests in BpkVideoPlayerProgressTest for percentage calculation edge cases.
  • README — new "Tracking playback progress" section with quartile tracking example.

How to test

  1. Open the demo app → Video playerDefault Controls
  2. Observe the progress text updating in real time below the player
Screen_recording_20260818_174237_480p.mov

Remember to include the following changes:

  • Component README.md
  • Tests

Copilot AI lite review requested due to automatic review settings August 18, 2026 15:32
@Nescafemix Joan Fuentes (Nescafemix) added the minor A new & backwards compatible feature/component label Aug 18, 2026

Copilot AI left a comment

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.

Pull request overview

Warning

Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.

Expose video playback progress from BpkVideoPlayer to enable analytics (e.g., quartile tracking) and demonstrate/verify the behavior across docs, demo, and tests.

Changes:

  • Added BpkVideoPlayerProgress model + README guidance for progress/quartile tracking.
  • Added progressState to BpkVideoPlayerController with polling + end/loop “final 100%” emission.
  • Updated demo story and added unit/instrumentation tests for progress behavior.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 9 comments.

Show a summary per file
File Description
docs/compose/VideoPlayer/README.md Documents progressState usage and quartile tracking pattern.
backpack-compose/src/main/kotlin/net/skyscanner/backpack/compose/videoplayer/BpkVideoPlayerProgress.kt Introduces the progress model with derived percentage.
backpack-compose/src/main/kotlin/net/skyscanner/backpack/compose/videoplayer/BpkVideoPlayerController.kt Adds observable progress state + polling and final-progress emission on end/loop.
backpack-compose/src/test/kotlin/net/skyscanner/backpack/compose/videoplayer/BpkVideoPlayerProgressTest.kt Unit tests for percentage edge cases.
backpack-compose/src/androidTest/kotlin/net/skyscanner/backpack/compose/videoplayer/BpkVideoPlayerTest.kt Integration tests for progress state behavior during playback/pause/end/loop.
app/src/main/java/net/skyscanner/backpack/demo/compose/VideoPlayerStory.kt Demo UI now displays live progress under the player.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@Nescafemix
Joan Fuentes (Nescafemix) force-pushed the muon/MUON-1999-include-video-progress-on-bpkvideoplayer branch from 6aecbbb to 4bd7dd8 Compare August 19, 2026 12:24
@skyscanner-backpack-bot

Copy link
Copy Markdown
Contributor
Warnings
⚠️ One or more component files were updated, but the tests weren't updated. If your change is not covered by existing tests please add snapshot tests.
⚠️

One or more component files were updated, but the docs screenshots weren't updated. If the changes are visual or it is a new component please regenerate the screenshots via ./gradlew recordScreenshots.

⚠️

One or more package files were created, but BpkComposeComponentUsageDetector.kt wasn't updated. If your component is an equivalent of a core component please add it to the detector.

Generated by 🚫 Danger Kotlin against 4bd7dd8

@mldtms mldtms left a comment

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.

_progressState is only ever written in startProgressPolling()'s loop and emitFinalProgress(). Neither resetToStart() nor play() (when resuming from Ended) touches it.

private val _isMuted = mutableStateOf(config.startsMuted)
val isMuted: State<Boolean> get() = _isMuted

private val _progressState = mutableStateOf<BpkVideoPlayerProgress?>(null)

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.

_progressState is only ever written in startProgressPolling()'s loop and emitFinalProgress(). Neither resetToStart() nor play() (when resuming from Ended) touches it. Maybe -> reset progress explicitly in resetToStart() (and consider doing the same at the start of play() when coming from Ended):

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed. Both resetToStart() and play() (when coming from Ended) now reset _progressState immediately to BpkVideoPlayerProgress(0L, duration) instead of leaving a stale 100% value. If duration is somehow unavailable it falls back to null. Added two integration tests to cover both cases. ff41ca3


BpkText(
modifier = Modifier
.weight(1f)

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.

Why would we use this? Why would we take the whole space that's left? can we just place the text below the video.

@Nescafemix Joan Fuentes (Nescafemix) Aug 20, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The weight(1f) is intentional — it ensures the progress text is always visible on screen regardless of the video height, by splitting the available space between the video and the text within the Column. Without it, on small screens the text could be pushed off screen. Note that this text is only here as a demo to show that progress can be retrieved from the controller — it is not part of the component itself.

val durationMs: Long,
) {
val percentage: Float
get() = if (durationMs > 0) positionMs.toFloat() / durationMs.toFloat() else 0f

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.

maybe add .coerceIn(0f, 1f) ?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done, added .coerceIn(0f, 1f) to percentage. Also added unit tests for both out-of-range cases (position > duration and negative position). ff41ca3

@skyscanner-backpack-bot

Copy link
Copy Markdown
Contributor
Warnings
⚠️ One or more component files were updated, but the tests weren't updated. If your change is not covered by existing tests please add snapshot tests.
⚠️

One or more component files were updated, but the docs screenshots weren't updated. If the changes are visual or it is a new component please regenerate the screenshots via ./gradlew recordScreenshots.

⚠️

One or more package files were created, but BpkComposeComponentUsageDetector.kt wasn't updated. If your component is an equivalent of a core component please add it to the detector.

Generated by 🚫 Danger Kotlin against ff41ca3

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

minor A new & backwards compatible feature/component

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants