This commit is contained in:
Sai Mukesh Cheekatla 2026-05-16 14:00:24 +02:00 committed by GitHub
commit 0a9d49819f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 76 additions and 2 deletions

View file

@ -56,6 +56,7 @@ actual object PlayerSettingsStorage {
private const val nextEpisodeThresholdMinutesBeforeEndKey = "next_episode_threshold_minutes_before_end_v2" private const val nextEpisodeThresholdMinutesBeforeEndKey = "next_episode_threshold_minutes_before_end_v2"
private const val useLibassKey = "use_libass" private const val useLibassKey = "use_libass"
private const val libassRenderTypeKey = "libass_render_type" private const val libassRenderTypeKey = "libass_render_type"
private const val swipeGesturesEnabledKey = "swipe_gestures_enabled"
private val syncKeys = listOf( private val syncKeys = listOf(
showLoadingOverlayKey, showLoadingOverlayKey,
resizeModeKey, resizeModeKey,
@ -92,6 +93,7 @@ actual object PlayerSettingsStorage {
nextEpisodeThresholdMinutesBeforeEndKey, nextEpisodeThresholdMinutesBeforeEndKey,
useLibassKey, useLibassKey,
libassRenderTypeKey, libassRenderTypeKey,
swipeGesturesEnabledKey,
) )
private var preferences: SharedPreferences? = null private var preferences: SharedPreferences? = null
@ -652,6 +654,23 @@ actual object PlayerSettingsStorage {
?.apply() ?.apply()
} }
actual fun loadSwipeGesturesEnabled(): Boolean? =
preferences?.let { sharedPreferences ->
val key = ProfileScopedKey.of(swipeGesturesEnabledKey)
if (sharedPreferences.contains(key)) {
sharedPreferences.getBoolean(key, true)
} else {
null
}
}
actual fun saveSwipeGesturesEnabled(enabled: Boolean) {
preferences
?.edit()
?.putBoolean(ProfileScopedKey.of(swipeGesturesEnabledKey), enabled)
?.apply()
}
actual fun exportToSyncPayload(): JsonObject = buildJsonObject { actual fun exportToSyncPayload(): JsonObject = buildJsonObject {
loadShowLoadingOverlay()?.let { put(showLoadingOverlayKey, encodeSyncBoolean(it)) } loadShowLoadingOverlay()?.let { put(showLoadingOverlayKey, encodeSyncBoolean(it)) }
loadResizeMode()?.let { put(resizeModeKey, encodeSyncString(it)) } loadResizeMode()?.let { put(resizeModeKey, encodeSyncString(it)) }
@ -688,6 +707,7 @@ actual object PlayerSettingsStorage {
loadNextEpisodeThresholdMinutesBeforeEnd()?.let { put(nextEpisodeThresholdMinutesBeforeEndKey, encodeSyncFloat(it)) } loadNextEpisodeThresholdMinutesBeforeEnd()?.let { put(nextEpisodeThresholdMinutesBeforeEndKey, encodeSyncFloat(it)) }
loadUseLibass()?.let { put(useLibassKey, encodeSyncBoolean(it)) } loadUseLibass()?.let { put(useLibassKey, encodeSyncBoolean(it)) }
loadLibassRenderType()?.let { put(libassRenderTypeKey, encodeSyncString(it)) } loadLibassRenderType()?.let { put(libassRenderTypeKey, encodeSyncString(it)) }
loadSwipeGesturesEnabled()?.let { put(swipeGesturesEnabledKey, encodeSyncBoolean(it)) }
} }
actual fun replaceFromSyncPayload(payload: JsonObject) { actual fun replaceFromSyncPayload(payload: JsonObject) {
@ -732,5 +752,6 @@ actual object PlayerSettingsStorage {
payload.decodeSyncFloat(nextEpisodeThresholdMinutesBeforeEndKey)?.let(::saveNextEpisodeThresholdMinutesBeforeEnd) payload.decodeSyncFloat(nextEpisodeThresholdMinutesBeforeEndKey)?.let(::saveNextEpisodeThresholdMinutesBeforeEnd)
payload.decodeSyncBoolean(useLibassKey)?.let(::saveUseLibass) payload.decodeSyncBoolean(useLibassKey)?.let(::saveUseLibass)
payload.decodeSyncString(libassRenderTypeKey)?.let(::saveLibassRenderType) payload.decodeSyncString(libassRenderTypeKey)?.let(::saveLibassRenderType)
payload.decodeSyncBoolean(swipeGesturesEnabledKey)?.let(::saveSwipeGesturesEnabled)
} }
} }

View file

@ -732,6 +732,8 @@
<string name="settings_playback_hold_speed">Hold Speed</string> <string name="settings_playback_hold_speed">Hold Speed</string>
<string name="settings_playback_hold_to_speed">Hold To Speed</string> <string name="settings_playback_hold_to_speed">Hold To Speed</string>
<string name="settings_playback_hold_to_speed_description">Long-press anywhere on the player surface to temporarily boost playback speed.</string> <string name="settings_playback_hold_to_speed_description">Long-press anywhere on the player surface to temporarily boost playback speed.</string>
<string name="settings_playback_enable_swipe_gestures">Swipe Gestures</string>
<string name="settings_playback_enable_swipe_gestures_description">Allow vertical swiping on the player surface to control volume and brightness.</string>
<string name="settings_playback_invalid_regex_pattern">Invalid regex pattern</string> <string name="settings_playback_invalid_regex_pattern">Invalid regex pattern</string>
<string name="settings_playback_last_link_cache_duration">Last Link Cache Duration</string> <string name="settings_playback_last_link_cache_duration">Last Link Cache Duration</string>
<string name="settings_playback_map_dv7_to_hevc">DV7 - HEVC Fallback</string> <string name="settings_playback_map_dv7_to_hevc">DV7 - HEVC Fallback</string>

View file

@ -1556,10 +1556,10 @@ fun PlayerScreen(
abs(totalDx) > viewConfiguration.touchSlop && abs(totalDx) > viewConfiguration.touchSlop &&
abs(totalDx) > abs(totalDy) abs(totalDx) > abs(totalDy)
val verticalDominant = val verticalDominant =
!holdToSpeedActive && playerSettingsUiState.swipeGesturesEnabled &&
!holdToSpeedActive &&
abs(totalDy) > viewConfiguration.touchSlop && abs(totalDy) > viewConfiguration.touchSlop &&
abs(totalDy) > abs(totalDx) abs(totalDy) > abs(totalDx)
gestureMode = when { gestureMode = when {
horizontalDominant -> { horizontalDominant -> {
deactivateHoldToSpeedState.value() deactivateHoldToSpeedState.value()

View file

@ -43,6 +43,7 @@ data class PlayerSettingsUiState(
val nextEpisodeThresholdMinutesBeforeEnd: Float = 2f, val nextEpisodeThresholdMinutesBeforeEnd: Float = 2f,
val useLibass: Boolean = false, val useLibass: Boolean = false,
val libassRenderType: String = "CUES", val libassRenderType: String = "CUES",
val swipeGesturesEnabled: Boolean = true,
) )
object PlayerSettingsRepository { object PlayerSettingsRepository {
@ -84,6 +85,7 @@ object PlayerSettingsRepository {
private var nextEpisodeThresholdMinutesBeforeEnd = 2f private var nextEpisodeThresholdMinutesBeforeEnd = 2f
private var useLibass = false private var useLibass = false
private var libassRenderType = "CUES" private var libassRenderType = "CUES"
private var swipeGesturesEnabled = true
fun ensureLoaded() { fun ensureLoaded() {
if (hasLoaded) return if (hasLoaded) return
@ -130,6 +132,7 @@ object PlayerSettingsRepository {
nextEpisodeThresholdMinutesBeforeEnd = 2f nextEpisodeThresholdMinutesBeforeEnd = 2f
useLibass = false useLibass = false
libassRenderType = "CUES" libassRenderType = "CUES"
swipeGesturesEnabled = true
publish() publish()
} }
@ -204,6 +207,7 @@ object PlayerSettingsRepository {
nextEpisodeThresholdMinutesBeforeEnd = PlayerSettingsStorage.loadNextEpisodeThresholdMinutesBeforeEnd() ?: 2f nextEpisodeThresholdMinutesBeforeEnd = PlayerSettingsStorage.loadNextEpisodeThresholdMinutesBeforeEnd() ?: 2f
useLibass = PlayerSettingsStorage.loadUseLibass() ?: false useLibass = PlayerSettingsStorage.loadUseLibass() ?: false
libassRenderType = PlayerSettingsStorage.loadLibassRenderType() ?: "CUES" libassRenderType = PlayerSettingsStorage.loadLibassRenderType() ?: "CUES"
swipeGesturesEnabled = PlayerSettingsStorage.loadSwipeGesturesEnabled() ?: true
publish() publish()
} }
@ -498,6 +502,14 @@ object PlayerSettingsRepository {
PlayerSettingsStorage.saveLibassRenderType(renderType) PlayerSettingsStorage.saveLibassRenderType(renderType)
} }
fun setSwipeGesturesEnabled(enabled: Boolean) {
ensureLoaded()
if (swipeGesturesEnabled == enabled) return
swipeGesturesEnabled = enabled
publish()
PlayerSettingsStorage.saveSwipeGesturesEnabled(enabled)
}
private fun publish() { private fun publish() {
_uiState.value = PlayerSettingsUiState( _uiState.value = PlayerSettingsUiState(
showLoadingOverlay = showLoadingOverlay, showLoadingOverlay = showLoadingOverlay,
@ -534,6 +546,7 @@ object PlayerSettingsRepository {
nextEpisodeThresholdMinutesBeforeEnd = nextEpisodeThresholdMinutesBeforeEnd, nextEpisodeThresholdMinutesBeforeEnd = nextEpisodeThresholdMinutesBeforeEnd,
useLibass = useLibass, useLibass = useLibass,
libassRenderType = libassRenderType, libassRenderType = libassRenderType,
swipeGesturesEnabled = swipeGesturesEnabled,
) )
} }

View file

@ -78,6 +78,8 @@ internal expect object PlayerSettingsStorage {
fun saveUseLibass(enabled: Boolean) fun saveUseLibass(enabled: Boolean)
fun loadLibassRenderType(): String? fun loadLibassRenderType(): String?
fun saveLibassRenderType(renderType: String) fun saveLibassRenderType(renderType: String)
fun loadSwipeGesturesEnabled(): Boolean?
fun saveSwipeGesturesEnabled(enabled: Boolean)
fun exportToSyncPayload(): JsonObject fun exportToSyncPayload(): JsonObject
fun replaceFromSyncPayload(payload: JsonObject) fun replaceFromSyncPayload(payload: JsonObject)
} }

View file

@ -86,6 +86,7 @@ internal fun LazyListScope.playbackSettingsContent(
tunnelingEnabled: Boolean, tunnelingEnabled: Boolean,
useLibass: Boolean, useLibass: Boolean,
libassRenderType: String, libassRenderType: String,
swipeGesturesEnabled: Boolean,
) { ) {
item { item {
PlaybackSettingsSection( PlaybackSettingsSection(
@ -104,6 +105,7 @@ internal fun LazyListScope.playbackSettingsContent(
tunnelingEnabled = tunnelingEnabled, tunnelingEnabled = tunnelingEnabled,
useLibass = useLibass, useLibass = useLibass,
libassRenderType = libassRenderType, libassRenderType = libassRenderType,
swipeGesturesEnabled = swipeGesturesEnabled,
) )
} }
} }
@ -166,6 +168,7 @@ private fun PlaybackSettingsSection(
tunnelingEnabled: Boolean, tunnelingEnabled: Boolean,
useLibass: Boolean, useLibass: Boolean,
libassRenderType: String, libassRenderType: String,
swipeGesturesEnabled: Boolean,
) { ) {
var showPreferredAudioDialog by remember { mutableStateOf(false) } var showPreferredAudioDialog by remember { mutableStateOf(false) }
var showSecondaryAudioDialog by remember { mutableStateOf(false) } var showSecondaryAudioDialog by remember { mutableStateOf(false) }
@ -262,6 +265,14 @@ private fun PlaybackSettingsSection(
onClick = { showHoldToSpeedValueDialog = true }, onClick = { showHoldToSpeedValueDialog = true },
) )
} }
SettingsGroupDivider(isTablet = isTablet)
SettingsSwitchRow(
title = stringResource(Res.string.settings_playback_enable_swipe_gestures),
description = stringResource(Res.string.settings_playback_enable_swipe_gestures_description),
checked = swipeGesturesEnabled,
isTablet = isTablet,
onCheckedChange = PlayerSettingsRepository::setSwipeGesturesEnabled,
)
} }
} }

View file

@ -226,6 +226,7 @@ fun SettingsScreen(
tunnelingEnabled = playerSettingsUiState.tunnelingEnabled, tunnelingEnabled = playerSettingsUiState.tunnelingEnabled,
useLibass = playerSettingsUiState.useLibass, useLibass = playerSettingsUiState.useLibass,
libassRenderType = playerSettingsUiState.libassRenderType, libassRenderType = playerSettingsUiState.libassRenderType,
swipeGesturesEnabled = playerSettingsUiState.swipeGesturesEnabled,
selectedTheme = selectedTheme, selectedTheme = selectedTheme,
onThemeSelected = ThemeSettingsRepository::setTheme, onThemeSelected = ThemeSettingsRepository::setTheme,
amoledEnabled = amoledEnabled, amoledEnabled = amoledEnabled,
@ -274,6 +275,7 @@ fun SettingsScreen(
tunnelingEnabled = playerSettingsUiState.tunnelingEnabled, tunnelingEnabled = playerSettingsUiState.tunnelingEnabled,
useLibass = playerSettingsUiState.useLibass, useLibass = playerSettingsUiState.useLibass,
libassRenderType = playerSettingsUiState.libassRenderType, libassRenderType = playerSettingsUiState.libassRenderType,
swipeGesturesEnabled = playerSettingsUiState.swipeGesturesEnabled,
selectedTheme = selectedTheme, selectedTheme = selectedTheme,
onThemeSelected = ThemeSettingsRepository::setTheme, onThemeSelected = ThemeSettingsRepository::setTheme,
amoledEnabled = amoledEnabled, amoledEnabled = amoledEnabled,
@ -332,6 +334,7 @@ private fun MobileSettingsScreen(
tunnelingEnabled: Boolean, tunnelingEnabled: Boolean,
useLibass: Boolean, useLibass: Boolean,
libassRenderType: String, libassRenderType: String,
swipeGesturesEnabled: Boolean,
selectedTheme: AppTheme, selectedTheme: AppTheme,
onThemeSelected: (AppTheme) -> Unit, onThemeSelected: (AppTheme) -> Unit,
amoledEnabled: Boolean, amoledEnabled: Boolean,
@ -493,6 +496,7 @@ private fun MobileSettingsScreen(
tunnelingEnabled = tunnelingEnabled, tunnelingEnabled = tunnelingEnabled,
useLibass = useLibass, useLibass = useLibass,
libassRenderType = libassRenderType, libassRenderType = libassRenderType,
swipeGesturesEnabled = swipeGesturesEnabled,
) )
SettingsPage.Appearance -> appearanceSettingsContent( SettingsPage.Appearance -> appearanceSettingsContent(
isTablet = false, isTablet = false,
@ -639,6 +643,7 @@ private fun TabletSettingsScreen(
tunnelingEnabled: Boolean, tunnelingEnabled: Boolean,
useLibass: Boolean, useLibass: Boolean,
libassRenderType: String, libassRenderType: String,
swipeGesturesEnabled: Boolean,
selectedTheme: AppTheme, selectedTheme: AppTheme,
onThemeSelected: (AppTheme) -> Unit, onThemeSelected: (AppTheme) -> Unit,
amoledEnabled: Boolean, amoledEnabled: Boolean,
@ -859,6 +864,7 @@ private fun TabletSettingsScreen(
tunnelingEnabled = tunnelingEnabled, tunnelingEnabled = tunnelingEnabled,
useLibass = useLibass, useLibass = useLibass,
libassRenderType = libassRenderType, libassRenderType = libassRenderType,
swipeGesturesEnabled = swipeGesturesEnabled,
) )
SettingsPage.Appearance -> appearanceSettingsContent( SettingsPage.Appearance -> appearanceSettingsContent(
isTablet = true, isTablet = true,

View file

@ -54,6 +54,7 @@ actual object PlayerSettingsStorage {
private const val nextEpisodeThresholdMinutesBeforeEndKey = "next_episode_threshold_minutes_before_end_v2" private const val nextEpisodeThresholdMinutesBeforeEndKey = "next_episode_threshold_minutes_before_end_v2"
private const val useLibassKey = "use_libass" private const val useLibassKey = "use_libass"
private const val libassRenderTypeKey = "libass_render_type" private const val libassRenderTypeKey = "libass_render_type"
private const val swipeGesturesEnabledKey = "swipe_gestures_enabled"
private val syncKeys = listOf( private val syncKeys = listOf(
showLoadingOverlayKey, showLoadingOverlayKey,
resizeModeKey, resizeModeKey,
@ -90,6 +91,7 @@ actual object PlayerSettingsStorage {
nextEpisodeThresholdMinutesBeforeEndKey, nextEpisodeThresholdMinutesBeforeEndKey,
useLibassKey, useLibassKey,
libassRenderTypeKey, libassRenderTypeKey,
swipeGesturesEnabledKey,
) )
actual fun loadShowLoadingOverlay(): Boolean? { actual fun loadShowLoadingOverlay(): Boolean? {
@ -102,6 +104,21 @@ actual object PlayerSettingsStorage {
} }
} }
actual fun loadSwipeGesturesEnabled(): Boolean? {
val defaults = NSUserDefaults.standardUserDefaults
val key = ProfileScopedKey.of(swipeGesturesEnabledKey)
return if (defaults.objectForKey(key) != null) {
defaults.boolForKey(key)
} else {
null
}
}
actual fun saveSwipeGesturesEnabled(enabled: Boolean) {
val defaults = NSUserDefaults.standardUserDefaults
defaults.setBool(enabled, ProfileScopedKey.of(swipeGesturesEnabledKey))
}
actual fun saveShowLoadingOverlay(enabled: Boolean) { actual fun saveShowLoadingOverlay(enabled: Boolean) {
NSUserDefaults.standardUserDefaults.setBool(enabled, forKey = ProfileScopedKey.of(showLoadingOverlayKey)) NSUserDefaults.standardUserDefaults.setBool(enabled, forKey = ProfileScopedKey.of(showLoadingOverlayKey))
} }
@ -588,6 +605,7 @@ actual object PlayerSettingsStorage {
loadNextEpisodeThresholdMinutesBeforeEnd()?.let { put(nextEpisodeThresholdMinutesBeforeEndKey, encodeSyncFloat(it)) } loadNextEpisodeThresholdMinutesBeforeEnd()?.let { put(nextEpisodeThresholdMinutesBeforeEndKey, encodeSyncFloat(it)) }
loadUseLibass()?.let { put(useLibassKey, encodeSyncBoolean(it)) } loadUseLibass()?.let { put(useLibassKey, encodeSyncBoolean(it)) }
loadLibassRenderType()?.let { put(libassRenderTypeKey, encodeSyncString(it)) } loadLibassRenderType()?.let { put(libassRenderTypeKey, encodeSyncString(it)) }
loadSwipeGesturesEnabled()?.let { put(swipeGesturesEnabledKey, encodeSyncBoolean(it)) }
} }
actual fun replaceFromSyncPayload(payload: JsonObject) { actual fun replaceFromSyncPayload(payload: JsonObject) {
@ -631,5 +649,6 @@ actual object PlayerSettingsStorage {
payload.decodeSyncFloat(nextEpisodeThresholdMinutesBeforeEndKey)?.let(::saveNextEpisodeThresholdMinutesBeforeEnd) payload.decodeSyncFloat(nextEpisodeThresholdMinutesBeforeEndKey)?.let(::saveNextEpisodeThresholdMinutesBeforeEnd)
payload.decodeSyncBoolean(useLibassKey)?.let(::saveUseLibass) payload.decodeSyncBoolean(useLibassKey)?.let(::saveUseLibass)
payload.decodeSyncString(libassRenderTypeKey)?.let(::saveLibassRenderType) payload.decodeSyncString(libassRenderTypeKey)?.let(::saveLibassRenderType)
payload.decodeSyncBoolean(swipeGesturesEnabledKey)?.let(::saveSwipeGesturesEnabled)
} }
} }