Skip to content

Commit 1c7b4e1

Browse files
committed
Add chapter markers support to seekbar and update UI elements
1 parent 0533326 commit 1c7b4e1

3 files changed

Lines changed: 73 additions & 2 deletions

File tree

app/src/main/java/org/schabi/newpipe/player/ui/VideoPlayerUi.java

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,9 @@
6565
import org.schabi.newpipe.extractor.MediaFormat;
6666
import org.schabi.newpipe.extractor.stream.AudioStream;
6767
import org.schabi.newpipe.extractor.stream.StreamInfo;
68+
import org.schabi.newpipe.extractor.stream.StreamSegment;
6869
import org.schabi.newpipe.extractor.stream.VideoStream;
70+
import org.schabi.newpipe.views.ChaptersSeekBar;
6971
import org.schabi.newpipe.fragments.detail.VideoDetailFragment;
7072
import org.schabi.newpipe.ktx.AnimationType;
7173
import org.schabi.newpipe.player.Player;
@@ -85,6 +87,7 @@
8587
import org.schabi.newpipe.util.external_communication.ShareUtils;
8688
import org.schabi.newpipe.views.player.PlayerFastSeekOverlay;
8789

90+
import java.util.Collections;
8891
import java.util.List;
8992
import java.util.Objects;
9093
import java.util.Optional;
@@ -147,6 +150,9 @@ private enum PlayButtonAction {
147150
private final SeekbarPreviewThumbnailHolder seekbarPreviewThumbnailHolder =
148151
new SeekbarPreviewThumbnailHolder();
149152

153+
@NonNull
154+
private List<StreamSegment> currentChapters = Collections.emptyList();
155+
150156

151157
/*//////////////////////////////////////////////////////////////////////////
152158
// Constructor, setup, destroy
@@ -585,6 +591,14 @@ public void onProgressChanged(final SeekBar seekBar, final int progress,
585591
binding.currentSeekbarPreviewThumbnail,
586592
binding.subtitleView::getWidth);
587593

594+
// Chapter title tooltip
595+
if (!currentChapters.isEmpty()) {
596+
final StreamSegment chapter = getChapterAtMs(progress);
597+
if (chapter != null && chapter.getTitle() != null) {
598+
binding.currentChapterTitle.setText(chapter.getTitle());
599+
}
600+
}
601+
588602
adjustSeekbarPreviewContainer();
589603
}
590604

@@ -638,6 +652,10 @@ public void onStartTrackingTouch(final SeekBar seekBar) {
638652
AnimationType.SCALE_AND_ALPHA);
639653
animate(binding.currentSeekbarPreviewThumbnail, true, DEFAULT_CONTROLS_DURATION,
640654
AnimationType.SCALE_AND_ALPHA);
655+
if (!currentChapters.isEmpty()) {
656+
animate(binding.currentChapterTitle, true, DEFAULT_CONTROLS_DURATION,
657+
AnimationType.SCALE_AND_ALPHA);
658+
}
641659
}
642660

643661
@Override // seekbar listener
@@ -654,6 +672,7 @@ public void onStopTrackingTouch(final SeekBar seekBar) {
654672
binding.playbackCurrentTime.setText(getTimeString(seekBar.getProgress()));
655673
animate(binding.currentDisplaySeek, false, 200, AnimationType.SCALE_AND_ALPHA);
656674
animate(binding.currentSeekbarPreviewThumbnail, false, 200, AnimationType.SCALE_AND_ALPHA);
675+
animate(binding.currentChapterTitle, false, 200, AnimationType.SCALE_AND_ALPHA);
657676

658677
if (player.getCurrentState() == STATE_PAUSED_SEEK) {
659678
player.changeState(STATE_BUFFERING);
@@ -664,6 +683,25 @@ public void onStopTrackingTouch(final SeekBar seekBar) {
664683

665684
showControlsThenHide();
666685
}
686+
687+
/**
688+
* Returns the chapter active at the given playback position, or {@code null} if
689+
* {@code currentChapters} is empty.
690+
*
691+
* @param positionMs playback position in milliseconds
692+
* @return the {@link StreamSegment} whose window contains {@code positionMs}
693+
*/
694+
@Nullable
695+
private StreamSegment getChapterAtMs(final long positionMs) {
696+
StreamSegment result = null;
697+
for (final StreamSegment seg : currentChapters) {
698+
if (seg.getStartTimeSeconds() * 1000L > positionMs) {
699+
break;
700+
}
701+
result = seg;
702+
}
703+
return result;
704+
}
667705
//endregion
668706

669707

@@ -1020,6 +1058,22 @@ public void onMetadataChanged(@NonNull final StreamInfo info) {
10201058
binding.channelTextView.setText(info.getUploaderName());
10211059

10221060
this.seekbarPreviewThumbnailHolder.resetFrom(player.getContext(), info.getPreviewFrames());
1061+
1062+
// Chapter markers on seekbar
1063+
currentChapters = info.getStreamSegments() != null
1064+
? info.getStreamSegments() : Collections.emptyList();
1065+
Log.d(TAG, "onMetadataChanged: seekBarClass="
1066+
+ binding.playbackSeekBar.getClass().getSimpleName()
1067+
+ " segments=" + currentChapters.size()
1068+
+ " duration=" + info.getDuration());
1069+
if (binding.playbackSeekBar instanceof ChaptersSeekBar) {
1070+
((ChaptersSeekBar) binding.playbackSeekBar)
1071+
.setChapters(currentChapters, info.getDuration());
1072+
} else {
1073+
Log.e(TAG, "onMetadataChanged: playbackSeekBar is NOT a ChaptersSeekBar! "
1074+
+ "Check that player.xml was rebuilt.");
1075+
}
1076+
binding.currentChapterTitle.setVisibility(View.GONE);
10231077
}
10241078

10251079
private void updateStreamRelatedViews() {

app/src/main/java/org/schabi/newpipe/views/FocusAwareSeekBar.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
* (onStartTrackingTouch/onStopTrackingTouch), so existing code does not need to be changed to
3434
* work with it.
3535
*/
36-
public final class FocusAwareSeekBar extends AppCompatSeekBar {
36+
public class FocusAwareSeekBar extends AppCompatSeekBar {
3737
private NestedListener listener;
3838

3939
private ViewTreeObserver treeObserver;

app/src/main/res/layout/player.xml

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -415,6 +415,23 @@
415415
android:orientation="vertical"
416416
android:paddingBottom="12dp">
417417

418+
<org.schabi.newpipe.views.NewPipeTextView
419+
android:id="@+id/currentChapterTitle"
420+
android:layout_width="wrap_content"
421+
android:layout_height="wrap_content"
422+
android:background="#60000000"
423+
android:ellipsize="end"
424+
android:maxLines="1"
425+
android:paddingLeft="5dp"
426+
android:paddingRight="5dp"
427+
android:paddingBottom="2dp"
428+
android:textColor="@android:color/white"
429+
android:textSize="12sp"
430+
android:visibility="gone"
431+
tools:ignore="RtlHardcoded"
432+
tools:text="Introduction"
433+
tools:visibility="visible" />
434+
418435
<org.schabi.newpipe.views.NewPipeTextView
419436
android:id="@+id/currentDisplaySeek"
420437
android:layout_width="wrap_content"
@@ -467,7 +484,7 @@
467484
tools:text="1:06:29" />
468485

469486

470-
<org.schabi.newpipe.views.FocusAwareSeekBar
487+
<org.schabi.newpipe.views.ChaptersSeekBar
471488
android:id="@+id/playbackSeekBar"
472489
style="@style/Widget.AppCompat.SeekBar"
473490
android:layout_width="0dp"

0 commit comments

Comments
 (0)