diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/player/GeneratorPlayer.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/player/GeneratorPlayer.kt index 16b03e4f61c..6fa38b1901b 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/player/GeneratorPlayer.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/player/GeneratorPlayer.kt @@ -67,6 +67,7 @@ import com.lagradost.cloudstream3.isEpisodeBased import com.lagradost.cloudstream3.isLiveStream import com.lagradost.cloudstream3.isMovieType import com.lagradost.cloudstream3.mvvm.Resource +import com.lagradost.cloudstream3.mvvm.launchSafe import com.lagradost.cloudstream3.mvvm.logError import com.lagradost.cloudstream3.mvvm.observe import com.lagradost.cloudstream3.mvvm.observeNullable @@ -131,6 +132,7 @@ import kotlinx.coroutines.isActive import kotlinx.coroutines.launch import java.io.Serializable import java.util.Calendar +import kotlin.coroutines.cancellation.CancellationException @OptIn(UnstableApi::class) class GeneratorPlayer : FullScreenPlayer() { @@ -138,6 +140,7 @@ class GeneratorPlayer : FullScreenPlayer() { const val NOTIFICATION_ID = 2326 const val CHANNEL_ID = 7340 const val STOP_ACTION = "stopcs3" + private const val SKIP_CHAPTER_AUTO_CLICK_COUNTDOWN_SECONDS = 5 private var lastUsedGenerator: IGenerator? = null fun newInstance(generator: IGenerator, syncData: HashMap? = null): Bundle { @@ -1996,12 +1999,70 @@ class GeneratorPlayer : FullScreenPlayer() { } override fun onDestroyView() { + clearSkipChapterAutoClick() binding = null super.onDestroyView() } var skipAnimator: ValueAnimator? = null var skipIndex = 0 + private var skipAutoClickJob: Job? = null + + private fun isAutoSkipPopupEnabled(): Boolean { + val ctx = context ?: return false + return PreferenceManager.getDefaultSharedPreferences(ctx).getBoolean( + ctx.getString(R.string.auto_skip_popup_key), + false + ) + } + + private fun updateSkipChapterButtonText( + timestamp: VideoSkipStamp, + secondsRemaining: Int? = null + ) { + val text = if (isAutoSkipPopupEnabled() && secondsRemaining != null) { + txt(R.string.skip_chapter_countdown_format, timestamp.uiText, secondsRemaining) + } else { + timestamp.uiText + } + + playerBinding?.skipChapterButton?.setText(text) + } + + private fun clearSkipChapterAutoClick() { + skipAutoClickJob?.cancel() + skipAutoClickJob = null + } + + private fun startSkipChapterAutoClick(timestamp: VideoSkipStamp, currentIndex: Int) { + clearSkipChapterAutoClick() + if (!isAutoSkipPopupEnabled()) { + updateSkipChapterButtonText(timestamp) + return + } + + skipAutoClickJob = viewModel.viewModelScope.launchSafe { + try { + for (secondsRemaining in SKIP_CHAPTER_AUTO_CLICK_COUNTDOWN_SECONDS downTo 1) { + if (!isActive) return@launchSafe + if (skipIndex != currentIndex) return@launchSafe + + updateSkipChapterButtonText(timestamp, secondsRemaining) + delay(1000) + } + + if (isActive && skipIndex == currentIndex) { + player.handleEvent(CSPlayerEvent.SkipCurrentChapter) + } + } catch (_: CancellationException) { + // If we get canceled, do nothing. + } finally { + if (isActive) { + clearSkipChapterAutoClick() + } + } + } + } private fun displayTimeStamp(show: Boolean) { if (timestampShowState == show) return @@ -2035,7 +2096,6 @@ class GeneratorPlayer : FullScreenPlayer() { } else { playerBinding?.skipChapterButton?.isVisible = false if (!isShowing) { - // Automatically return focus to play pause playerBinding?.playerPausePlay?.requestFocus() } } @@ -2053,6 +2113,7 @@ class GeneratorPlayer : FullScreenPlayer() { } override fun onTimestampSkipped(timestamp: VideoSkipStamp) { + clearSkipChapterAutoClick() displayTimeStamp(false) } @@ -2065,7 +2126,9 @@ class GeneratorPlayer : FullScreenPlayer() { if (skipIndex == currentIndex) displayTimeStamp(false) }, 6000) + startSkipChapterAutoClick(timestamp, currentIndex) } else { + clearSkipChapterAutoClick() displayTimeStamp(false) } } diff --git a/app/src/main/res/layout/player_custom_layout.xml b/app/src/main/res/layout/player_custom_layout.xml index 72024a918d5..de6886b3d6c 100644 --- a/app/src/main/res/layout/player_custom_layout.xml +++ b/app/src/main/res/layout/player_custom_layout.xml @@ -620,11 +620,12 @@ - \ No newline at end of file + diff --git a/app/src/main/res/layout/player_custom_layout_tv.xml b/app/src/main/res/layout/player_custom_layout_tv.xml index ed06ef2b6a2..82c31dd3d6e 100644 --- a/app/src/main/res/layout/player_custom_layout_tv.xml +++ b/app/src/main/res/layout/player_custom_layout_tv.xml @@ -315,10 +315,11 @@ - \ No newline at end of file + diff --git a/app/src/main/res/values/donottranslate-strings.xml b/app/src/main/res/values/donottranslate-strings.xml index 0b7aab4cb7b..8c32243b68c 100644 --- a/app/src/main/res/values/donottranslate-strings.xml +++ b/app/src/main/res/values/donottranslate-strings.xml @@ -38,6 +38,7 @@ android_tv_interface_on_seek_key swipe_vertical_enabled_key autoplay_next_key + auto_skip_popup_key display_sub_key show_fillers_key show_player_metadata_key diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index e9dd2748fc0..fe6a7dd042d 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -156,6 +156,8 @@ Slide up or down on the left or right side to change brightness or volume Autoplay next episode Start the next episode when the current one ends + Auto-skip OP + Automatically SKIP OP after 5 seconds Double tap to seek Double tap to pause Player seek amount (Seconds) @@ -561,6 +563,7 @@ Mixed opening Credits Intro + %1$s (%2$d) Clear history History Show skip popups for opening/ending diff --git a/app/src/main/res/xml/settings_player.xml b/app/src/main/res/xml/settings_player.xml index 6e136747448..ac197eca7f3 100644 --- a/app/src/main/res/xml/settings_player.xml +++ b/app/src/main/res/xml/settings_player.xml @@ -98,6 +98,12 @@ android:title="@string/video_skip_op" app:defaultValue="true" app:key="@string/enable_skip_op_from_database" /> + - \ No newline at end of file +