Skip to content

Commit

Permalink
add skip options, the same as the web version (#8)
Browse files Browse the repository at this point in the history
* Publish 10.10 to Discord, release 10.9

* first version, contain bugs, and unclean code

* Publish 10.10 to Discord, release 10.9

* No mod should be needed in 10.10

* Avoid confusion with official build

* Update README.md to clarify 10.9 target

* clean up some code, and some more stuff

* clean up some code, and some more stuff

* clean up some code, adding 3 new icons, moving to enum...

* random stuff

* random stuff

* random stuff

* TODO LIST:
-add labels

* Add labels and optimize kotlin calls

---------

Make the code more manageable

Fix dependency injection for prefs

Co-Authored-By: TwistedUmbrellaX <[email protected]>
  • Loading branch information
dredstone1 and AbandonedCart committed Oct 11, 2024
1 parent e64e488 commit c0a185d
Show file tree
Hide file tree
Showing 9 changed files with 152 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import org.jellyfin.androidtv.preference.constant.NextUpBehavior
import org.jellyfin.androidtv.preference.constant.RatingType
import org.jellyfin.androidtv.preference.constant.RefreshRateSwitchingBehavior
import org.jellyfin.androidtv.preference.constant.WatchedIndicatorBehavior
import org.jellyfin.androidtv.ui.playback.segments.SegmentMode
import org.jellyfin.preference.booleanPreference
import org.jellyfin.preference.enumPreference
import org.jellyfin.preference.intPreference
Expand Down Expand Up @@ -81,7 +82,11 @@ class UserPreferences(context: Context) : SharedPreferenceStore(
*/
var cinemaModeEnabled = booleanPreference("pref_enable_cinema_mode", true)

/* Playback - Video */
/**
* Configure segment handling behavior (Auto skip, Show skip button, Hide skip button).
*/
var skipMode = enumPreference("skip_mode", SegmentMode.SHOW_SKIP_BUTTON)

/**
* Whether to use an external playback application or not.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import static java.lang.Math.round;

import android.annotation.SuppressLint;
import android.content.Context;
import android.os.Handler;
import android.view.KeyEvent;
Expand Down Expand Up @@ -41,9 +42,11 @@
import org.jellyfin.androidtv.ui.playback.overlay.action.RewindAction;
import org.jellyfin.androidtv.ui.playback.overlay.action.SelectAudioAction;
import org.jellyfin.androidtv.ui.playback.overlay.action.SelectQualityAction;
import org.jellyfin.androidtv.ui.playback.overlay.action.SelectSkipAction;
import org.jellyfin.androidtv.ui.playback.overlay.action.SkipNextAction;
import org.jellyfin.androidtv.ui.playback.overlay.action.SkipPreviousAction;
import org.jellyfin.androidtv.ui.playback.overlay.action.ZoomAction;
import org.jellyfin.androidtv.ui.playback.segments.SegmentMode;
import org.jellyfin.androidtv.util.DateTimeExtensionsKt;
import org.koin.java.KoinJavaComponent;

Expand All @@ -61,6 +64,7 @@ public class CustomPlaybackTransportControlGlue extends PlaybackTransportControl
private SelectAudioAction selectAudioAction;
private ClosedCaptionsAction closedCaptionsAction;
private SelectQualityAction selectQualityAction;
private SelectSkipAction selectSkipAction;
private PlaybackSpeedAction playbackSpeedAction;
private ZoomAction zoomAction;
private ChapterAction chapterAction;
Expand Down Expand Up @@ -130,11 +134,13 @@ protected RowPresenter.ViewHolder createRowViewHolder(ViewGroup parent) {
if (showClock == ClockBehavior.ALWAYS || showClock == ClockBehavior.IN_VIDEO) {
Context context = parent.getContext();
mEndsText = new TextView(context);
//noinspection PrivateResource
mEndsText.setTextAppearance(context, androidx.leanback.R.style.Widget_Leanback_PlaybackControlsTimeStyle);
setEndTime();

LinearLayout view = (LinearLayout) vh.view;

@SuppressLint("RestrictedApi")
PlaybackTransportRowView bar = (PlaybackTransportRowView) view.getChildAt(1);
FrameLayout v = (FrameLayout) bar.getChildAt(0);
mButtonRef = (LinearLayout) v.getChildAt(0);
Expand Down Expand Up @@ -195,6 +201,12 @@ private void initActions(Context context) {
playbackSpeedAction.setLabels(new String[]{context.getString(R.string.lbl_playback_speed)});
zoomAction = new ZoomAction(context, this);
zoomAction.setLabels(new String[]{context.getString(R.string.lbl_zoom)});
selectSkipAction = new SelectSkipAction(context, this, KoinJavaComponent.get(UserPreferences.class));
selectSkipAction.setLabels(new String[]{
context.getString(SegmentMode.AUTO_SKIP.label()),
context.getString(SegmentMode.SHOW_SKIP_BUTTON.label()),
context.getString(SegmentMode.HIDE_SKIP_BUTTON.label())
});
chapterAction = new ChapterAction(context, this);
chapterAction.setLabels(new String[]{context.getString(R.string.lbl_chapters)});

Expand Down Expand Up @@ -273,6 +285,7 @@ void addMediaActions() {
if (!playerAdapter.isLiveTv()) {
secondaryActionsAdapter.add(playbackSpeedAction);
secondaryActionsAdapter.add(selectQualityAction);
secondaryActionsAdapter.add(selectSkipAction);
}

secondaryActionsAdapter.add(zoomAction);
Expand Down Expand Up @@ -310,7 +323,7 @@ private void setEndTime() {
mEndsText.setText(getContext().getString(R.string.lbl_playback_control_ends, DateTimeExtensionsKt.getTimeFormatter(getContext()).format(endTime)));
}

private void notifyActionChanged(Action action) {
public void notifyActionChanged(Action action) {
ArrayObjectAdapter adapter = primaryActionsAdapter;
if (adapter.indexOf(action) >= 0) {
adapter.notifyArrayItemRangeChanged(adapter.indexOf(action), 1);
Expand Down Expand Up @@ -354,7 +367,6 @@ void updatePlayState() {
} else {
mHandler.removeCallbacks(mRefreshEndTime);
}

}

public void setInjectedViewsVisibility() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package org.jellyfin.androidtv.ui.playback.overlay.action

import android.content.Context
import android.view.Gravity
import android.view.View
import android.widget.PopupMenu
import org.jellyfin.androidtv.preference.UserPreferences
import org.jellyfin.androidtv.ui.playback.PlaybackController
import org.jellyfin.androidtv.ui.playback.overlay.CustomPlaybackTransportControlGlue
import org.jellyfin.androidtv.ui.playback.overlay.VideoPlayerAdapter
import org.jellyfin.androidtv.ui.playback.segments.SegmentMode

class SelectSkipAction(
context: Context,
customPlaybackTransportControlGlue: CustomPlaybackTransportControlGlue,
userPreferences: UserPreferences
) : CustomAction(context, customPlaybackTransportControlGlue) {
private val preferences = userPreferences
private val customPlaybackTransportControlGlue1 = customPlaybackTransportControlGlue

init {
initializeWithIcon(preferences[UserPreferences.skipMode].icon())
}

override fun handleClickAction(
playbackController: PlaybackController,
videoPlayerAdapter: VideoPlayerAdapter,
context: Context,
view: View,
) {
videoPlayerAdapter.leanbackOverlayFragment.setFading(false)
PopupMenu(context, view, Gravity.END).apply {
SegmentMode.entries.forEach {
menu.add(0, it.ordinal, it.ordinal, context.getString(it.label())).apply {
isChecked = preferences[UserPreferences.skipMode] == it
}
}
menu.setGroupCheckable(0, true, true)

setOnDismissListener {
videoPlayerAdapter.leanbackOverlayFragment.setFading(true)
}

setOnMenuItemClickListener { item ->
preferences[UserPreferences.skipMode] = SegmentMode.entries[item.itemId]

initializeWithIcon(preferences[UserPreferences.skipMode].icon())
customPlaybackTransportControlGlue1.notifyActionChanged(this@SelectSkipAction)
true
}
}.show()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,24 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Button
import androidx.core.view.isVisible
import androidx.fragment.app.Fragment
import org.jellyfin.androidtv.R
import org.jellyfin.androidtv.preference.UserPreferences
import org.jellyfin.androidtv.ui.playback.PlaybackControllerContainer
import org.jellyfin.sdk.api.client.ApiClient
import org.jellyfin.sdk.api.client.extensions.get
import org.jellyfin.sdk.model.UUID
import org.jellyfin.sdk.model.api.BaseItemDto
import org.koin.android.ext.android.inject
import org.koin.java.KoinJavaComponent.get

val Number.millis
get() = this.toLong() * 1000L

class SegmentSkipFragment() : Fragment() {
class SegmentSkipFragment : Fragment() {

private val preferences = get<UserPreferences>(UserPreferences::class.java)

private val api: ApiClient by inject()
private val playbackControllerContainer: PlaybackControllerContainer by inject()
Expand All @@ -39,18 +44,18 @@ class SegmentSkipFragment() : Fragment() {

button = view.findViewById<Button>(R.id.skip_segment_button).apply {
setOnClickListener {
buttonClicked()
doSkip()
}
}
}

private fun buttonClicked() {
private fun doSkip() {
lastSegment?.let { segment ->
playbackControllerContainer.playbackController?.let { player ->
if ((segment.endTime + 3).millis > player.getDuration() && player.hasNextItem()) {
player.next()
playbackControllerContainer.playbackController?.run {
if ((segment.endTime + 3).millis > getDuration() && hasNextItem()) {
next()
} else {
player.seek(segment.endTime.millis)
seek(segment.endTime.millis)
}
}
}
Expand All @@ -68,16 +73,19 @@ class SegmentSkipFragment() : Fragment() {
val currentSegment = getCurrentSegment(currentPosition) ?: lastSegment ?: return
lastSegment = currentSegment

val shouldShowButton = buttonConfig?.skipButtonVisible == true &&
currentPosition >= currentSegment.showAt.millis &&
currentPosition < currentSegment.hideAt.millis
val isSkipSegment = currentPosition >= currentSegment.showAt.millis && currentPosition < currentSegment.hideAt.millis

if (shouldShowButton && button.visibility != View.VISIBLE) {
button.visibility = View.VISIBLE
if (!button.isVisible && isSkipSegment && preferences[UserPreferences.skipMode] == SegmentMode.SHOW_SKIP_BUTTON
&& buttonConfig?.skipButtonVisible == true) {
button.isVisible = true
updateButtonText(currentSegment)
button.requestFocus()
} else if (!shouldShowButton && button.visibility == View.VISIBLE) {
button.visibility = View.GONE
} else if (button.isVisible && (!isSkipSegment || preferences[UserPreferences.skipMode] != SegmentMode.SHOW_SKIP_BUTTON)) {
button.isVisible = false
}

if (isSkipSegment && preferences[UserPreferences.skipMode] == SegmentMode.AUTO_SKIP) {
doSkip()
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package org.jellyfin.androidtv.ui.playback.segments

import org.jellyfin.androidtv.R

enum class SegmentMode {
SHOW_SKIP_BUTTON {
override fun icon(): Int = R.drawable.ic_select_skip_show_button
override fun label(): Int = R.string.lbl_show_skip_button
},
AUTO_SKIP {
override fun icon(): Int = R.drawable.ic_select_skip_auto_skip
override fun label(): Int = R.string.lbl_auto_skip
},
HIDE_SKIP_BUTTON {
override fun icon(): Int = R.drawable.ic_select_skip_hide_button
override fun label(): Int = R.string.lbl_hide_skip_button
};

abstract fun icon(): Int
abstract fun label(): Int
}
12 changes: 12 additions & 0 deletions app/src/main/res/drawable/ic_select_skip_auto_skip.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="M 20.34 11.52 C 18.72 10.61 15.45 8.79 13.83 7.89 L 22 4.25 L 21.15 7.95 L 20.34 11.52 Z M 18.86 5.65 C 13.97 -1.57 2.57 2.73 2 11.52 L 4.01 11.52 C 4.8 3.88 13.38 1.14 16.98 6.49 L 18.86 5.66 Z" />
<path
android:fillColor="@android:color/white"
android:pathData="M 9.17 12.88 L 8.13 16.06 L 6.77 16.06 L 10.22 5.95 L 11.78 5.95 L 15.23 16.06 L 13.84 16.06 L 12.76 12.88 L 9.18 12.88 Z M 12.49 11.85 L 11.5 8.94 C 11.28 8.28 11.12 7.68 10.98 7.1 L 10.94 7.1 C 10.81 7.7 10.64 8.31 10.44 8.93 L 9.45 11.85 L 12.49 11.85 Z" />
</vector>
9 changes: 9 additions & 0 deletions app/src/main/res/drawable/ic_select_skip_hide_button.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="M 20.38 11.49 C 20.79 9.68 21.63 6.03 22.04 4.22 L 13.87 7.86 C 15.5 8.76 18.76 10.58 20.38 11.49 Z M 18.9 5.62 L 17.02 6.45 C 15.38 4.02 12.99 3.2 10.49 3.82 L 9.41 2.38 C 9.41 2.38 14.8 0.37 18.9 5.62 Z M 7.81 4.95 C 5.86 6.22 4.37 8.49 4.06 11.48 L 2.05 11.48 C 2.28 7.98 4.26 5.25 6.79 3.56 C 7.09 3.36 9.22 4.03 7.82 4.94 Z M 5.27 1.57 L 6.08 1 L 18.13 17.02 L 17.32 17.59 L 5.27 1.57 Z" />
</vector>
12 changes: 12 additions & 0 deletions app/src/main/res/drawable/ic_select_skip_show_button.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="M 20.34 11.52 C 18.72 10.61 15.45 8.79 13.83 7.89 L 22 4.25 L 21.15 7.95 L 20.34 11.52 Z M 18.86 5.65 C 13.97 -1.57 2.57 2.73 2 11.52 L 4.01 11.52 C 4.8 3.88 13.38 1.14 16.98 6.49 L 18.86 5.66 Z" />
<path
android:fillColor="@android:color/white"
android:pathData="M 12.05 9.79 L 9 7.5 L 9 16.5 L 12.05 14.21 L 15 12 L 12.05 9.79 Z" />
</vector>
3 changes: 3 additions & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,9 @@
<string name="lbl_zoom">Zoom</string>
<string name="lbl_auto_crop">Auto crop</string>
<string name="lbl_stretch">Stretch</string>
<string name="lbl_auto_skip">Auto skip</string>
<string name="lbl_show_skip_button">Show skip buttons</string>
<string name="lbl_hide_skip_button">Hide skip buttons</string>
<string name="lbl_fit">Normal</string>
<string name="lbl_audio_track">Select audio track</string>
<string name="lbl_playback_speed">Playback speed</string>
Expand Down

0 comments on commit c0a185d

Please sign in to comment.