Skip to content

feat: Add Title and Summary to video overlay of playing video#512

Merged
kingargyle merged 1 commit intodevelopfrom
dac_Issue387_video_info
Jan 19, 2026
Merged

feat: Add Title and Summary to video overlay of playing video#512
kingargyle merged 1 commit intodevelopfrom
dac_Issue387_video_info

Conversation

@kingargyle
Copy link
Contributor

@kingargyle kingargyle commented Jan 19, 2026

Adds the Title and Summary information to the video overlay. For series it adds the Series Name and the Episode title along with the summary.

Summary by CodeRabbit

  • New Features

    • Added a video information panel to the player interface, displaying the currently playing video's title and summary above the playback controls.
  • Tests

    • Added test coverage for the new video metadata display functionality.

✏️ Tip: You can customize this high-level summary in your review settings.

Adds the Title and Summary information to the video overlay.
For series it adds the Series Name and the Episode title along with
the summary.
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 19, 2026

Walkthrough

This PR adds video metadata display functionality to the ExoPlayer interface. It introduces a new setVideoInfo method across the contract, presenter, and activity layers, alongside XML layout additions for displaying video title and summary. Tests verify the implementation works correctly.

Changes

Cohort / File(s) Summary
Exoplayer Contract Definition
ExoplayerContract.kt
Added setVideoInfo(title: String?, summary: String?) method to ExoplayerView interface with @AddToEndSingleStrategy annotation
Exoplayer Presenter & Activity Implementation
ExoplayerPresenter.kt, ExoplayerVideoActivity.kt
Presenter now imports EpisodePosterInfo and calls viewState.setVideoInfo() in playVideo() with formatted series/title and summary. Activity implements the method by locating and updating video_title and video_summary TextViews.
Video Control Layout
exo_player_control_view.xml
Added video_info_container LinearLayout at overlay top containing two TextViews: video_title (bold, 24sp, white) and video_summary (white, 16sp, max 3 lines, ellipsized) with semi-transparent background
Unit Tests
ExoplayerPresenterTest.kt, ExoplayerVideoActivityTest.kt
Presenter tests updated to verify setVideoInfo() is called in both transcoding scenarios. Activity test file now includes setVideoInfoUpdatesTitleAndSummary() test and changes TestModule from inner to nested class.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Poem

🐰 Hop along to watch with glee,
Titles dance where all can see,
Summaries sparkle, bold and bright,
Video info shining white! ✨
Our ExoPlayer now knows,
What the watching rabbit shows!

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The pull request title accurately describes the main change: adding title and summary information to the video overlay UI. It aligns with all changes across the codebase including the new contract method, presenter integration, activity implementation, layout resources, and tests.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@sonarqubecloud
Copy link

@codecov
Copy link

codecov bot commented Jan 19, 2026

Codecov Report

❌ Patch coverage is 40.00000% with 3 lines in your changes missing coverage. Please review.
✅ Project coverage is 48.63%. Comparing base (62e9ed1) to head (03fa905).
⚠️ Report is 2 commits behind head on develop.

Files with missing lines Patch % Lines
...serenity/ui/video/player/ExoplayerVideoActivity.kt 50.00% 0 Missing and 2 partials ⚠️
...lds/serenity/ui/video/player/ExoplayerPresenter.kt 0.00% 0 Missing and 1 partial ⚠️
Additional details and impacted files
@@              Coverage Diff              @@
##             develop     #512      +/-   ##
=============================================
+ Coverage      48.61%   48.63%   +0.02%     
- Complexity       473      474       +1     
=============================================
  Files             65       65              
  Lines           2199     2204       +5     
  Branches         309      312       +3     
=============================================
+ Hits            1069     1072       +3     
+ Misses          1002     1001       -1     
- Partials         128      131       +3     
Flag Coverage Δ
unittests 48.63% <40.00%> (+0.02%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Fix all issues with AI agents
In
`@serenity-app/src/main/kotlin/us/nineworlds/serenity/ui/video/player/ExoplayerPresenter.kt`:
- Around line 162-166: Normalize the series and title before formatting to avoid
literal "null" or stray newlines: in playVideo(), fetch video.seriesName and
video.getTitle() into local vars, trim and treat null/blank as empty (or a
fallback like an empty string), then build the display string by conditionally
joining non-empty parts (e.g., only prepend seriesName + "\n" when seriesName is
non-empty) and pass that sanitized string to viewState.setVideoInfo along with
video.getSummary(); update references to playVideo(), viewState.setVideoInfo,
video.seriesName, and video.getTitle() accordingly.

In
`@serenity-app/src/main/kotlin/us/nineworlds/serenity/ui/video/player/ExoplayerVideoActivity.kt`:
- Around line 403-409: In setVideoInfo, stop calling playerView.findViewById and
instead use a ViewBinding instance for the ExoPlayer control layout (e.g.,
ExoPlayerControlViewBinding) that you initialize/reuse as a property; replace
lookups of R.id.video_title and R.id.video_summary with
controlBinding.videoTitle.text = title and controlBinding.videoSummary.text =
summary (ensure controlBinding is created from playerView or inflated once and
reused so setVideoInfo only updates the binding fields).

In
`@serenity-app/src/test/kotlin/us/nineworlds/serenity/ui/video/player/ExoplayerPresenterTest.kt`:
- Around line 193-205: Add a new test case in ExoplayerPresenterTest that sets
videoContentInfo.seriesTitle to a non-null value (e.g., "Series Title"), assigns
presenter.video = videoContentInfo, stubs the same dependencies
(isDirectPlaySupportedForContainer and mockSerenityClient.createTranscodeUrl),
calls presenter.playVideo(), and then verify that mockView.setVideoInfo is
invoked with a title argument that contains the formatted series title
"Series\nTitle" (use a matcher/predicate in verify to assert the string contains
the newline-formatted series title) in addition to verifying the other expected
view calls (updateSerenityDebugInfo and initializePlayer) as in the existing
test.
🧹 Nitpick comments (1)
serenity-app/src/main/res/layout/exo_player_control_view.xml (1)

13-39: Guard long titles to prevent overlay collisions.

Consider adding maxLines and ellipsize on video_title (similar to summary) so very long titles don’t overlap other controls.

🔧 Suggested tweak
     <TextView
       android:id="@+id/video_title"
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       android:textColor="@android:color/white"
       android:textSize="24sp"
-      android:textStyle="bold" />
+      android:textStyle="bold"
+      android:maxLines="2"
+      android:ellipsize="end" />

Comment on lines 162 to 166
override fun playVideo() {
val videoUrl: String = transcoderUrl()
startPlaying()
viewState.setVideoInfo(if (video.seriesName != null) "${video.seriesName}\n${video.getTitle()}" else video.getTitle(), video.getSummary())
viewState.updateSerenityDebugInfo(isTranscoding, video.videoCodec, video.audioCodec, 0)
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Avoid displaying literal "null" or stray newline in the title.

If video.getTitle() is null (or blank), the current interpolation can render "null" or an empty line. Consider normalizing title/series values before building the display string.

🔧 Suggested fix
-        viewState.setVideoInfo(if (video.seriesName != null) "${video.seriesName}\n${video.getTitle()}" else video.getTitle(), video.getSummary())
+        val displayTitle = if (!video.seriesName.isNullOrBlank()) {
+            listOfNotNull(video.seriesName, video.getTitle()).joinToString("\n")
+        } else {
+            video.getTitle().orEmpty()
+        }
+        viewState.setVideoInfo(displayTitle, video.getSummary())
🤖 Prompt for AI Agents
In
`@serenity-app/src/main/kotlin/us/nineworlds/serenity/ui/video/player/ExoplayerPresenter.kt`
around lines 162 - 166, Normalize the series and title before formatting to
avoid literal "null" or stray newlines: in playVideo(), fetch video.seriesName
and video.getTitle() into local vars, trim and treat null/blank as empty (or a
fallback like an empty string), then build the display string by conditionally
joining non-empty parts (e.g., only prepend seriesName + "\n" when seriesName is
non-empty) and pass that sanitized string to viewState.setVideoInfo along with
video.getSummary(); update references to playVideo(), viewState.setVideoInfo,
video.seriesName, and video.getTitle() accordingly.

Comment on lines +403 to +409
override fun setVideoInfo(title: String?, summary: String?) {
val videoTitle = playerView.findViewById<TextView>(R.id.video_title)
val videoSummary = playerView.findViewById<TextView>(R.id.video_summary)

videoTitle?.text = title
videoSummary?.text = summary
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Replace findViewById with View Binding for control views.

This Activity should avoid direct findViewById access. Prefer ExoPlayerControlViewBinding (or equivalent) and reuse it for title/summary updates. As per coding guidelines, use View Binding in Activities.

♻️ Suggested change (within this method)
-        val videoTitle = playerView.findViewById<TextView>(R.id.video_title)
-        val videoSummary = playerView.findViewById<TextView>(R.id.video_summary)
-
-        videoTitle?.text = title
-        videoSummary?.text = summary
+        val controlsBinding = ExoPlayerControlViewBinding.bind(
+            playerView.findViewById(R.id.exo_controller)
+        )
+        controlsBinding.videoTitle.text = title
+        controlsBinding.videoSummary.text = summary
🤖 Prompt for AI Agents
In
`@serenity-app/src/main/kotlin/us/nineworlds/serenity/ui/video/player/ExoplayerVideoActivity.kt`
around lines 403 - 409, In setVideoInfo, stop calling playerView.findViewById
and instead use a ViewBinding instance for the ExoPlayer control layout (e.g.,
ExoPlayerControlViewBinding) that you initialize/reuse as a property; replace
lookups of R.id.video_title and R.id.video_summary with
controlBinding.videoTitle.text = title and controlBinding.videoSummary.text =
summary (ensure controlBinding is created from playerView or inflated once and
reused so setVideoInfo only updates the binding fields).

Comment on lines +193 to 205
videoContentInfo.seriesTitle = null
videoContentInfo.setTitle("Title")
videoContentInfo.setSummary("Summary")
presenter.video = videoContentInfo

every { presenter.isDirectPlaySupportedForContainer(any()) } returns false
every { mockSerenityClient.createTranscodeUrl(any(), any()) } returns "http://transcode.url"

presenter.playVideo()

verify { mockView.setVideoInfo("Title", "Summary") }
verify { mockView.updateSerenityDebugInfo(true, "h264", "ac3", 0) }
verify { mockView.initializePlayer("http://transcode.url", 0) }
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Add coverage for the series-title formatting branch.

Current tests only cover seriesTitle == null. Please add a case where seriesTitle is non-null to assert the "Series\nTitle" formatting for the overlay. As per coding guidelines, new feature branches should be covered by tests.

🤖 Prompt for AI Agents
In
`@serenity-app/src/test/kotlin/us/nineworlds/serenity/ui/video/player/ExoplayerPresenterTest.kt`
around lines 193 - 205, Add a new test case in ExoplayerPresenterTest that sets
videoContentInfo.seriesTitle to a non-null value (e.g., "Series Title"), assigns
presenter.video = videoContentInfo, stubs the same dependencies
(isDirectPlaySupportedForContainer and mockSerenityClient.createTranscodeUrl),
calls presenter.playVideo(), and then verify that mockView.setVideoInfo is
invoked with a title argument that contains the formatted series title
"Series\nTitle" (use a matcher/predicate in verify to assert the string contains
the newline-formatted series title) in addition to verifying the other expected
view calls (updateSerenityDebugInfo and initializePlayer) as in the existing
test.

@kingargyle kingargyle merged commit 566c0c0 into develop Jan 19, 2026
4 of 5 checks passed
@kingargyle
Copy link
Contributor Author

Close #387

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