From 40eec6fb5d2b2e0bdcc65a5c3a392fc0ee1d12a1 Mon Sep 17 00:00:00 2001 From: maayanPortugues <97434762+dredstone1@users.noreply.github.com> Date: Fri, 11 Oct 2024 01:58:27 +0300 Subject: [PATCH] add skip options, the same as the web version (#8) * 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 --------- Co-Authored-By: TwistedUmbrellaX --- .../androidtv/preference/UserPreferences.kt | 7 ++- .../CustomPlaybackOverlayFragment.java | 5 +- .../CustomPlaybackTransportControlGlue.java | 16 +++++- .../overlay/action/SelectSkipAction.kt | 53 +++++++++++++++++++ .../playback/segments/SegmentSkipFragment.kt | 33 +++++++----- .../ui/playback/segments/SegmentSkipModes.kt | 21 ++++++++ .../res/drawable/ic_select_skip_auto_skip.xml | 12 +++++ .../drawable/ic_select_skip_hide_button.xml | 9 ++++ .../drawable/ic_select_skip_show_button.xml | 12 +++++ app/src/main/res/values/strings.xml | 3 ++ 10 files changed, 155 insertions(+), 16 deletions(-) create mode 100644 app/src/main/java/org/jellyfin/androidtv/ui/playback/overlay/action/SelectSkipAction.kt create mode 100644 app/src/main/java/org/jellyfin/androidtv/ui/playback/segments/SegmentSkipModes.kt create mode 100644 app/src/main/res/drawable/ic_select_skip_auto_skip.xml create mode 100644 app/src/main/res/drawable/ic_select_skip_hide_button.xml create mode 100644 app/src/main/res/drawable/ic_select_skip_show_button.xml diff --git a/app/src/main/java/org/jellyfin/androidtv/preference/UserPreferences.kt b/app/src/main/java/org/jellyfin/androidtv/preference/UserPreferences.kt index 728c76194d..400e162d19 100644 --- a/app/src/main/java/org/jellyfin/androidtv/preference/UserPreferences.kt +++ b/app/src/main/java/org/jellyfin/androidtv/preference/UserPreferences.kt @@ -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.floatPreference @@ -82,7 +83,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. */ diff --git a/app/src/main/java/org/jellyfin/androidtv/ui/playback/CustomPlaybackOverlayFragment.java b/app/src/main/java/org/jellyfin/androidtv/ui/playback/CustomPlaybackOverlayFragment.java index 1ac08b6bfc..ab5e07854c 100644 --- a/app/src/main/java/org/jellyfin/androidtv/ui/playback/CustomPlaybackOverlayFragment.java +++ b/app/src/main/java/org/jellyfin/androidtv/ui/playback/CustomPlaybackOverlayFragment.java @@ -42,6 +42,7 @@ import org.jellyfin.androidtv.data.service.BackgroundService; import org.jellyfin.androidtv.databinding.OverlayTvGuideBinding; import org.jellyfin.androidtv.databinding.VlcPlayerInterfaceBinding; +import org.jellyfin.androidtv.preference.UserPreferences; import org.jellyfin.androidtv.ui.GuideChannelHeader; import org.jellyfin.androidtv.ui.GuidePagingButton; import org.jellyfin.androidtv.ui.LiveProgramDetailPopup; @@ -73,6 +74,7 @@ import org.jellyfin.sdk.model.api.BaseItemDto; import org.jellyfin.sdk.model.api.BaseItemKind; import org.jellyfin.sdk.model.api.ChapterInfo; +import org.koin.java.KoinJavaComponent; import java.time.LocalDateTime; import java.time.ZoneOffset; @@ -139,6 +141,7 @@ public class CustomPlaybackOverlayFragment extends Fragment implements LiveTvGui private final PlaybackOverlayFragmentHelper helper = new PlaybackOverlayFragmentHelper(this); + private final UserPreferences userPreferences = KoinJavaComponent.get(UserPreferences.class); @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -1243,7 +1246,7 @@ private void prepareChannelAdapter() { } private void initSegmentSkip() { - mSegmentSkipFragment = new SegmentSkipFragment(); + mSegmentSkipFragment = new SegmentSkipFragment(userPreferences); FragmentTransaction transaction = getParentFragmentManager().beginTransaction(); transaction.add(R.id.container, mSegmentSkipFragment, null); diff --git a/app/src/main/java/org/jellyfin/androidtv/ui/playback/overlay/CustomPlaybackTransportControlGlue.java b/app/src/main/java/org/jellyfin/androidtv/ui/playback/overlay/CustomPlaybackTransportControlGlue.java index 4f8f777100..87940ccdb0 100644 --- a/app/src/main/java/org/jellyfin/androidtv/ui/playback/overlay/CustomPlaybackTransportControlGlue.java +++ b/app/src/main/java/org/jellyfin/androidtv/ui/playback/overlay/CustomPlaybackTransportControlGlue.java @@ -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; @@ -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; @@ -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; @@ -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); @@ -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)}); @@ -273,6 +285,7 @@ void addMediaActions() { if (!playerAdapter.isLiveTv()) { secondaryActionsAdapter.add(playbackSpeedAction); secondaryActionsAdapter.add(selectQualityAction); + secondaryActionsAdapter.add(selectSkipAction); } secondaryActionsAdapter.add(zoomAction); @@ -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); @@ -354,7 +367,6 @@ void updatePlayState() { } else { mHandler.removeCallbacks(mRefreshEndTime); } - } public void setInjectedViewsVisibility() { diff --git a/app/src/main/java/org/jellyfin/androidtv/ui/playback/overlay/action/SelectSkipAction.kt b/app/src/main/java/org/jellyfin/androidtv/ui/playback/overlay/action/SelectSkipAction.kt new file mode 100644 index 0000000000..95bb7fd988 --- /dev/null +++ b/app/src/main/java/org/jellyfin/androidtv/ui/playback/overlay/action/SelectSkipAction.kt @@ -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() + } +} diff --git a/app/src/main/java/org/jellyfin/androidtv/ui/playback/segments/SegmentSkipFragment.kt b/app/src/main/java/org/jellyfin/androidtv/ui/playback/segments/SegmentSkipFragment.kt index ced03abe42..6559949589 100644 --- a/app/src/main/java/org/jellyfin/androidtv/ui/playback/segments/SegmentSkipFragment.kt +++ b/app/src/main/java/org/jellyfin/androidtv/ui/playback/segments/SegmentSkipFragment.kt @@ -7,6 +7,7 @@ import android.view.ViewGroup import android.widget.Button 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 @@ -17,7 +18,7 @@ import org.koin.android.ext.android.inject val Number.millis get() = this.toLong() * 1000L -class SegmentSkipFragment() : Fragment() { +class SegmentSkipFragment(userPreferences: UserPreferences) : Fragment() { private val api: ApiClient by inject() private val playbackControllerContainer: PlaybackControllerContainer by inject() @@ -27,6 +28,8 @@ class SegmentSkipFragment() : Fragment() { private var buttonConfig: SegmentButtonConfig? = null private var lastSegment: SegmentModel? = null + private val preferences = userPreferences + override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? @@ -39,18 +42,18 @@ class SegmentSkipFragment() : Fragment() { button = view.findViewById