This commit is contained in:
Sai Mukesh Cheekatla 2026-05-13 12:47:45 +02:00 committed by GitHub
commit ae4306fb4f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 265 additions and 3 deletions

View file

@ -56,6 +56,8 @@ 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 swipeToSeekEnabledKey = "swipe_to_seek_enabled"
private const val swipeToSeekSensitivityKey = "swipe_to_seek_sensitivity"
private val syncKeys = listOf( private val syncKeys = listOf(
showLoadingOverlayKey, showLoadingOverlayKey,
resizeModeKey, resizeModeKey,
@ -92,6 +94,8 @@ actual object PlayerSettingsStorage {
nextEpisodeThresholdMinutesBeforeEndKey, nextEpisodeThresholdMinutesBeforeEndKey,
useLibassKey, useLibassKey,
libassRenderTypeKey, libassRenderTypeKey,
swipeToSeekEnabledKey,
swipeToSeekSensitivityKey,
) )
private var preferences: SharedPreferences? = null private var preferences: SharedPreferences? = null
@ -688,6 +692,8 @@ 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)) }
loadSwipeToSeekEnabled()?.let { put(swipeToSeekEnabledKey, encodeSyncBoolean(it)) }
loadSwipeToSeekSensitivity()?.let { put(swipeToSeekSensitivityKey, encodeSyncString(it)) }
} }
actual fun replaceFromSyncPayload(payload: JsonObject) { actual fun replaceFromSyncPayload(payload: JsonObject) {
@ -732,5 +738,34 @@ 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(swipeToSeekEnabledKey)?.let(::saveSwipeToSeekEnabled)
payload.decodeSyncString(swipeToSeekSensitivityKey)?.let(::saveSwipeToSeekSensitivity)
}
actual fun loadSwipeToSeekEnabled(): Boolean? =
preferences?.let { sharedPreferences ->
val key = ProfileScopedKey.of(swipeToSeekEnabledKey)
if (sharedPreferences.contains(key)) {
sharedPreferences.getBoolean(key, true)
} else {
null
}
}
actual fun saveSwipeToSeekEnabled(enabled: Boolean) {
preferences
?.edit()
?.putBoolean(ProfileScopedKey.of(swipeToSeekEnabledKey), enabled)
?.apply()
}
actual fun loadSwipeToSeekSensitivity(): String? =
preferences?.getString(ProfileScopedKey.of(swipeToSeekSensitivityKey), null)
actual fun saveSwipeToSeekSensitivity(sensitivity: String) {
preferences
?.edit()
?.putString(ProfileScopedKey.of(swipeToSeekSensitivityKey), sensitivity)
?.apply()
} }
} }

View file

@ -718,6 +718,13 @@
<string name="settings_playback_regex_matches_against">Matches against stream name/title/description/addon/url. Example: 4K|2160p|Remux</string> <string name="settings_playback_regex_matches_against">Matches against stream name/title/description/addon/url. Example: 4K|2160p|Remux</string>
<string name="settings_playback_regex_pattern">Regex Pattern</string> <string name="settings_playback_regex_pattern">Regex Pattern</string>
<string name="settings_playback_regex_placeholder">No pattern set. Example: 4K|2160p|Remux</string> <string name="settings_playback_regex_placeholder">No pattern set. Example: 4K|2160p|Remux</string>
<string name="settings_playback_swipe_to_seek">Swipe to Seek</string>
<string name="settings_playback_swipe_to_seek_description">Swipe horizontally on the player surface to seek forward or backward.</string>
<string name="settings_playback_swipe_to_seek_sensitivity">Swipe to Seek Sensitivity</string>
<string name="settings_playback_swipe_to_seek_sensitivity_description">Adjust the drag distance required to trigger a seek.</string>
<string name="settings_playback_swipe_to_seek_sensitivity_low">Low</string>
<string name="settings_playback_swipe_to_seek_sensitivity_medium">Medium</string>
<string name="settings_playback_swipe_to_seek_sensitivity_high">High</string>
<string name="settings_playback_regex_preset_any_1080p">Any 1080p+</string> <string name="settings_playback_regex_preset_any_1080p">Any 1080p+</string>
<string name="settings_playback_regex_preset_avc_x264">AVC / x264</string> <string name="settings_playback_regex_preset_avc_x264">AVC / x264</string>
<string name="settings_playback_regex_preset_bluray_quality">BluRay Quality</string> <string name="settings_playback_regex_preset_bluray_quality">BluRay Quality</string>

View file

@ -1480,8 +1480,10 @@ fun PlayerScreen(
if (gestureMode == null) { if (gestureMode == null) {
val holdToSpeedActive = isHoldToSpeedGestureActiveState.value val holdToSpeedActive = isHoldToSpeedGestureActiveState.value
val horizontalDominant = val horizontalDominant =
playerSettingsUiState.swipeToSeekEnabled &&
!holdToSpeedActive && !holdToSpeedActive &&
abs(totalDx) > viewConfiguration.touchSlop && abs(totalDx) > viewConfiguration.touchSlop *
playerSettingsUiState.swipeToSeekSensitivity.triggerMultiplier &&
abs(totalDx) > abs(totalDy) abs(totalDx) > abs(totalDy)
val verticalDominant = val verticalDominant =
!holdToSpeedActive && !holdToSpeedActive &&
@ -1518,7 +1520,7 @@ fun PlayerScreen(
else -> 60f else -> 60f
} }
val previewOffsetMs = val previewOffsetMs =
((totalDx / width) * sensitivitySeconds * 1000f).roundToLong() ((totalDx / width) * sensitivitySeconds * playerSettingsUiState.swipeToSeekSensitivity.speedMultiplier * 1000f).roundToLong()
val unclampedPreviewMs = horizontalSeekBaselineMs + previewOffsetMs val unclampedPreviewMs = horizontalSeekBaselineMs + previewOffsetMs
horizontalSeekPreviewMs = currentDurationMsState.value horizontalSeekPreviewMs = currentDurationMsState.value
.takeIf { it > 0L } .takeIf { it > 0L }

View file

@ -8,6 +8,24 @@ import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.asStateFlow
enum class SwipeToSeekSensitivity {
LOW, MEDIUM, HIGH;
val triggerMultiplier: Float
get() = when (this) {
LOW -> 4.0f
MEDIUM -> 1.0f
HIGH -> 0.5f
}
val speedMultiplier: Float
get() = when (this) {
LOW -> 0.5f
MEDIUM -> 1.0f
HIGH -> 2.0f
}
}
data class PlayerSettingsUiState( data class PlayerSettingsUiState(
val showLoadingOverlay: Boolean = true, val showLoadingOverlay: Boolean = true,
val resizeMode: PlayerResizeMode = PlayerResizeMode.Fit, val resizeMode: PlayerResizeMode = PlayerResizeMode.Fit,
@ -31,6 +49,8 @@ data class PlayerSettingsUiState(
val streamAutoPlaySelectedPlugins: Set<String> = emptySet(), val streamAutoPlaySelectedPlugins: Set<String> = emptySet(),
val streamAutoPlayRegex: String = "", val streamAutoPlayRegex: String = "",
val streamAutoPlayTimeoutSeconds: Int = 3, val streamAutoPlayTimeoutSeconds: Int = 3,
val swipeToSeekEnabled: Boolean = true,
val swipeToSeekSensitivity: SwipeToSeekSensitivity = SwipeToSeekSensitivity.MEDIUM,
val skipIntroEnabled: Boolean = true, val skipIntroEnabled: Boolean = true,
val animeSkipEnabled: Boolean = false, val animeSkipEnabled: Boolean = false,
val animeSkipClientId: String = "", val animeSkipClientId: String = "",
@ -84,6 +104,8 @@ 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 swipeToSeekEnabled = true
private var swipeToSeekSensitivity = SwipeToSeekSensitivity.MEDIUM
fun ensureLoaded() { fun ensureLoaded() {
if (hasLoaded) return if (hasLoaded) return
@ -204,6 +226,12 @@ 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"
swipeToSeekEnabled = PlayerSettingsStorage.loadSwipeToSeekEnabled() ?: true
swipeToSeekSensitivity = try {
SwipeToSeekSensitivity.valueOf(PlayerSettingsStorage.loadSwipeToSeekSensitivity() ?: "MEDIUM")
} catch (e: Exception) {
SwipeToSeekSensitivity.MEDIUM
}
publish() publish()
} }
@ -498,6 +526,22 @@ object PlayerSettingsRepository {
PlayerSettingsStorage.saveLibassRenderType(renderType) PlayerSettingsStorage.saveLibassRenderType(renderType)
} }
fun setSwipeToSeekEnabled(enabled: Boolean) {
ensureLoaded()
if (swipeToSeekEnabled == enabled) return
swipeToSeekEnabled = enabled
publish()
PlayerSettingsStorage.saveSwipeToSeekEnabled(enabled)
}
fun setSwipeToSeekSensitivity(sensitivity: SwipeToSeekSensitivity) {
ensureLoaded()
if (swipeToSeekSensitivity == sensitivity) return
swipeToSeekSensitivity = sensitivity
publish()
PlayerSettingsStorage.saveSwipeToSeekSensitivity(sensitivity.name)
}
private fun publish() { private fun publish() {
_uiState.value = PlayerSettingsUiState( _uiState.value = PlayerSettingsUiState(
showLoadingOverlay = showLoadingOverlay, showLoadingOverlay = showLoadingOverlay,
@ -534,6 +578,8 @@ object PlayerSettingsRepository {
nextEpisodeThresholdMinutesBeforeEnd = nextEpisodeThresholdMinutesBeforeEnd, nextEpisodeThresholdMinutesBeforeEnd = nextEpisodeThresholdMinutesBeforeEnd,
useLibass = useLibass, useLibass = useLibass,
libassRenderType = libassRenderType, libassRenderType = libassRenderType,
swipeToSeekEnabled = swipeToSeekEnabled,
swipeToSeekSensitivity = swipeToSeekSensitivity,
) )
} }

View file

@ -78,6 +78,10 @@ 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 loadSwipeToSeekEnabled(): Boolean?
fun saveSwipeToSeekEnabled(enabled: Boolean)
fun loadSwipeToSeekSensitivity(): String?
fun saveSwipeToSeekSensitivity(sensitivity: String)
fun exportToSyncPayload(): JsonObject fun exportToSyncPayload(): JsonObject
fun replaceFromSyncPayload(payload: JsonObject) fun replaceFromSyncPayload(payload: JsonObject)
} }

View file

@ -56,6 +56,7 @@ import com.nuvio.app.features.player.AvailableLanguageOptions
import com.nuvio.app.features.player.ExternalPlayerApp import com.nuvio.app.features.player.ExternalPlayerApp
import com.nuvio.app.features.player.ExternalPlayerPlatform import com.nuvio.app.features.player.ExternalPlayerPlatform
import com.nuvio.app.features.player.PlayerSettingsRepository import com.nuvio.app.features.player.PlayerSettingsRepository
import com.nuvio.app.features.player.SwipeToSeekSensitivity
import com.nuvio.app.features.player.SubtitleLanguageOption import com.nuvio.app.features.player.SubtitleLanguageOption
import com.nuvio.app.features.player.formatPlaybackSpeedLabel import com.nuvio.app.features.player.formatPlaybackSpeedLabel
import com.nuvio.app.features.player.languageLabelForCode import com.nuvio.app.features.player.languageLabelForCode
@ -86,6 +87,8 @@ internal fun LazyListScope.playbackSettingsContent(
tunnelingEnabled: Boolean, tunnelingEnabled: Boolean,
useLibass: Boolean, useLibass: Boolean,
libassRenderType: String, libassRenderType: String,
swipeToSeekEnabled: Boolean,
swipeToSeekSensitivity: SwipeToSeekSensitivity,
) { ) {
item { item {
PlaybackSettingsSection( PlaybackSettingsSection(
@ -104,6 +107,8 @@ internal fun LazyListScope.playbackSettingsContent(
tunnelingEnabled = tunnelingEnabled, tunnelingEnabled = tunnelingEnabled,
useLibass = useLibass, useLibass = useLibass,
libassRenderType = libassRenderType, libassRenderType = libassRenderType,
swipeToSeekEnabled = swipeToSeekEnabled,
swipeToSeekSensitivity = swipeToSeekSensitivity,
) )
} }
} }
@ -166,6 +171,8 @@ private fun PlaybackSettingsSection(
tunnelingEnabled: Boolean, tunnelingEnabled: Boolean,
useLibass: Boolean, useLibass: Boolean,
libassRenderType: String, libassRenderType: String,
swipeToSeekEnabled: Boolean,
swipeToSeekSensitivity: SwipeToSeekSensitivity,
) { ) {
var showPreferredAudioDialog by remember { mutableStateOf(false) } var showPreferredAudioDialog by remember { mutableStateOf(false) }
var showSecondaryAudioDialog by remember { mutableStateOf(false) } var showSecondaryAudioDialog by remember { mutableStateOf(false) }
@ -181,6 +188,7 @@ private fun PlaybackSettingsSection(
var showAutoPlayAddonSelectionDialog by remember { mutableStateOf(false) } var showAutoPlayAddonSelectionDialog by remember { mutableStateOf(false) }
var showAutoPlayPluginSelectionDialog by remember { mutableStateOf(false) } var showAutoPlayPluginSelectionDialog by remember { mutableStateOf(false) }
var showAutoPlayRegexDialog by remember { mutableStateOf(false) } var showAutoPlayRegexDialog by remember { mutableStateOf(false) }
var showSwipeSensitivityDialog by remember { mutableStateOf(false) }
val pluginsEnabled = AppFeaturePolicy.pluginsEnabled val pluginsEnabled = AppFeaturePolicy.pluginsEnabled
val autoPlayPlayerSettings by PlayerSettingsRepository.uiState.collectAsStateWithLifecycle() val autoPlayPlayerSettings by PlayerSettingsRepository.uiState.collectAsStateWithLifecycle()
val availableExternalPlayers = ExternalPlayerPlatform.availablePlayers() val availableExternalPlayers = ExternalPlayerPlatform.availablePlayers()
@ -262,6 +270,27 @@ private fun PlaybackSettingsSection(
onClick = { showHoldToSpeedValueDialog = true }, onClick = { showHoldToSpeedValueDialog = true },
) )
} }
SettingsGroupDivider(isTablet = isTablet)
SettingsSwitchRow(
title = stringResource(Res.string.settings_playback_swipe_to_seek),
description = stringResource(Res.string.settings_playback_swipe_to_seek_description),
checked = swipeToSeekEnabled,
isTablet = isTablet,
onCheckedChange = PlayerSettingsRepository::setSwipeToSeekEnabled,
)
if (swipeToSeekEnabled) {
SettingsGroupDivider(isTablet = isTablet)
SettingsNavigationRow(
title = stringResource(Res.string.settings_playback_swipe_to_seek_sensitivity),
description = when (swipeToSeekSensitivity) {
SwipeToSeekSensitivity.LOW -> stringResource(Res.string.settings_playback_swipe_to_seek_sensitivity_low)
SwipeToSeekSensitivity.MEDIUM -> stringResource(Res.string.settings_playback_swipe_to_seek_sensitivity_medium)
SwipeToSeekSensitivity.HIGH -> stringResource(Res.string.settings_playback_swipe_to_seek_sensitivity_high)
},
isTablet = isTablet,
onClick = { showSwipeSensitivityDialog = true },
)
}
} }
} }
@ -865,6 +894,14 @@ private fun PlaybackSettingsSection(
) )
} }
if (showSwipeSensitivityDialog) {
SwipeToSeekSensitivityDialog(
selected = swipeToSeekSensitivity,
onSelect = PlayerSettingsRepository::setSwipeToSeekSensitivity,
onDismiss = { showSwipeSensitivityDialog = false },
)
}
if (showAutoPlayModeDialog) { if (showAutoPlayModeDialog) {
StreamAutoPlayModeDialog( StreamAutoPlayModeDialog(
selectedMode = autoPlayPlayerSettings.streamAutoPlayMode, selectedMode = autoPlayPlayerSettings.streamAutoPlayMode,
@ -2324,3 +2361,89 @@ private fun libassRenderTypeRes(renderType: String): StringResource = when (rend
@Composable @Composable
private fun libassRenderTypeLabel(renderType: String): String = stringResource(libassRenderTypeRes(renderType)) private fun libassRenderTypeLabel(renderType: String): String = stringResource(libassRenderTypeRes(renderType))
@Composable
@OptIn(ExperimentalMaterial3Api::class)
private fun SwipeToSeekSensitivityDialog(
selected: SwipeToSeekSensitivity,
onSelect: (SwipeToSeekSensitivity) -> Unit,
onDismiss: () -> Unit,
) {
val options = SwipeToSeekSensitivity.entries
BasicAlertDialog(onDismissRequest = onDismiss) {
Surface(
modifier = Modifier.fillMaxWidth(),
shape = RoundedCornerShape(20.dp),
color = MaterialTheme.colorScheme.surface,
) {
Column(
modifier = Modifier.padding(20.dp),
verticalArrangement = Arrangement.spacedBy(12.dp),
) {
Text(
text = stringResource(Res.string.settings_playback_swipe_to_seek_sensitivity),
style = MaterialTheme.typography.titleLarge,
color = MaterialTheme.colorScheme.onSurface,
fontWeight = FontWeight.SemiBold,
)
Text(
text = stringResource(Res.string.settings_playback_swipe_to_seek_sensitivity_description),
style = MaterialTheme.typography.bodySmall,
color = MaterialTheme.colorScheme.onSurfaceVariant,
)
Column(
modifier = Modifier.fillMaxWidth(),
verticalArrangement = Arrangement.spacedBy(8.dp),
) {
options.forEach { option ->
val isSelected = option == selected
val containerColor = if (isSelected) {
MaterialTheme.colorScheme.primary.copy(alpha = 0.14f)
} else {
MaterialTheme.colorScheme.surfaceVariant.copy(alpha = 0.35f)
}
Surface(
modifier = Modifier
.fillMaxWidth()
.clickable {
onSelect(option)
onDismiss()
},
shape = RoundedCornerShape(12.dp),
color = containerColor,
) {
Row(
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 14.dp, vertical = 12.dp),
verticalAlignment = Alignment.CenterVertically,
) {
Text(
text = when (option) {
SwipeToSeekSensitivity.LOW -> stringResource(Res.string.settings_playback_swipe_to_seek_sensitivity_low)
SwipeToSeekSensitivity.MEDIUM -> stringResource(Res.string.settings_playback_swipe_to_seek_sensitivity_medium)
SwipeToSeekSensitivity.HIGH -> stringResource(Res.string.settings_playback_swipe_to_seek_sensitivity_high)
else -> stringResource(Res.string.settings_playback_swipe_to_seek_sensitivity_medium)
},
style = MaterialTheme.typography.bodyLarge,
color = MaterialTheme.colorScheme.onSurface,
modifier = Modifier.weight(1f),
)
if (isSelected) {
Icon(
imageVector = Icons.Rounded.Check,
contentDescription = null,
tint = MaterialTheme.colorScheme.primary,
)
}
}
}
}
}
}
}
}
}

View file

@ -66,6 +66,9 @@ import com.nuvio.app.features.mdblist.MdbListSettingsRepository
import com.nuvio.app.features.notifications.EpisodeReleaseNotificationsRepository import com.nuvio.app.features.notifications.EpisodeReleaseNotificationsRepository
import com.nuvio.app.features.notifications.EpisodeReleaseNotificationsUiState import com.nuvio.app.features.notifications.EpisodeReleaseNotificationsUiState
import com.nuvio.app.features.player.PlayerSettingsRepository import com.nuvio.app.features.player.PlayerSettingsRepository
import com.nuvio.app.features.player.PlayerResizeMode
import com.nuvio.app.features.player.SwipeToSeekSensitivity
import com.nuvio.app.features.player.skip.NextEpisodeThresholdMode
import com.nuvio.app.features.trakt.TraktAuthUiState import com.nuvio.app.features.trakt.TraktAuthUiState
import com.nuvio.app.features.trakt.TraktAuthRepository import com.nuvio.app.features.trakt.TraktAuthRepository
import com.nuvio.app.features.trakt.TraktCommentsSettings import com.nuvio.app.features.trakt.TraktCommentsSettings
@ -220,6 +223,8 @@ fun SettingsScreen(
tunnelingEnabled = playerSettingsUiState.tunnelingEnabled, tunnelingEnabled = playerSettingsUiState.tunnelingEnabled,
useLibass = playerSettingsUiState.useLibass, useLibass = playerSettingsUiState.useLibass,
libassRenderType = playerSettingsUiState.libassRenderType, libassRenderType = playerSettingsUiState.libassRenderType,
swipeToSeekEnabled = playerSettingsUiState.swipeToSeekEnabled,
swipeToSeekSensitivity = playerSettingsUiState.swipeToSeekSensitivity,
selectedTheme = selectedTheme, selectedTheme = selectedTheme,
onThemeSelected = ThemeSettingsRepository::setTheme, onThemeSelected = ThemeSettingsRepository::setTheme,
amoledEnabled = amoledEnabled, amoledEnabled = amoledEnabled,
@ -267,6 +272,8 @@ fun SettingsScreen(
tunnelingEnabled = playerSettingsUiState.tunnelingEnabled, tunnelingEnabled = playerSettingsUiState.tunnelingEnabled,
useLibass = playerSettingsUiState.useLibass, useLibass = playerSettingsUiState.useLibass,
libassRenderType = playerSettingsUiState.libassRenderType, libassRenderType = playerSettingsUiState.libassRenderType,
swipeToSeekEnabled = playerSettingsUiState.swipeToSeekEnabled,
swipeToSeekSensitivity = playerSettingsUiState.swipeToSeekSensitivity,
selectedTheme = selectedTheme, selectedTheme = selectedTheme,
onThemeSelected = ThemeSettingsRepository::setTheme, onThemeSelected = ThemeSettingsRepository::setTheme,
amoledEnabled = amoledEnabled, amoledEnabled = amoledEnabled,
@ -324,6 +331,8 @@ private fun MobileSettingsScreen(
tunnelingEnabled: Boolean, tunnelingEnabled: Boolean,
useLibass: Boolean, useLibass: Boolean,
libassRenderType: String, libassRenderType: String,
swipeToSeekEnabled: Boolean,
swipeToSeekSensitivity: SwipeToSeekSensitivity,
selectedTheme: AppTheme, selectedTheme: AppTheme,
onThemeSelected: (AppTheme) -> Unit, onThemeSelected: (AppTheme) -> Unit,
amoledEnabled: Boolean, amoledEnabled: Boolean,
@ -484,6 +493,8 @@ private fun MobileSettingsScreen(
tunnelingEnabled = tunnelingEnabled, tunnelingEnabled = tunnelingEnabled,
useLibass = useLibass, useLibass = useLibass,
libassRenderType = libassRenderType, libassRenderType = libassRenderType,
swipeToSeekEnabled = swipeToSeekEnabled,
swipeToSeekSensitivity = swipeToSeekSensitivity,
) )
SettingsPage.Appearance -> appearanceSettingsContent( SettingsPage.Appearance -> appearanceSettingsContent(
isTablet = false, isTablet = false,
@ -625,6 +636,8 @@ private fun TabletSettingsScreen(
tunnelingEnabled: Boolean, tunnelingEnabled: Boolean,
useLibass: Boolean, useLibass: Boolean,
libassRenderType: String, libassRenderType: String,
swipeToSeekEnabled: Boolean,
swipeToSeekSensitivity: SwipeToSeekSensitivity,
selectedTheme: AppTheme, selectedTheme: AppTheme,
onThemeSelected: (AppTheme) -> Unit, onThemeSelected: (AppTheme) -> Unit,
amoledEnabled: Boolean, amoledEnabled: Boolean,
@ -844,6 +857,8 @@ private fun TabletSettingsScreen(
tunnelingEnabled = tunnelingEnabled, tunnelingEnabled = tunnelingEnabled,
useLibass = useLibass, useLibass = useLibass,
libassRenderType = libassRenderType, libassRenderType = libassRenderType,
swipeToSeekEnabled = swipeToSeekEnabled,
swipeToSeekSensitivity = swipeToSeekSensitivity,
) )
SettingsPage.Appearance -> appearanceSettingsContent( SettingsPage.Appearance -> appearanceSettingsContent(
isTablet = true, isTablet = true,

View file

@ -54,6 +54,8 @@ 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 swipeToSeekEnabledKey = "swipe_to_seek_enabled"
private const val swipeToSeekSensitivityKey = "swipe_to_seek_sensitivity"
private val syncKeys = listOf( private val syncKeys = listOf(
showLoadingOverlayKey, showLoadingOverlayKey,
resizeModeKey, resizeModeKey,
@ -90,6 +92,8 @@ actual object PlayerSettingsStorage {
nextEpisodeThresholdMinutesBeforeEndKey, nextEpisodeThresholdMinutesBeforeEndKey,
useLibassKey, useLibassKey,
libassRenderTypeKey, libassRenderTypeKey,
swipeToSeekEnabledKey,
swipeToSeekSensitivityKey,
) )
actual fun loadShowLoadingOverlay(): Boolean? { actual fun loadShowLoadingOverlay(): Boolean? {
@ -588,6 +592,8 @@ 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)) }
loadSwipeToSeekEnabled()?.let { put(swipeToSeekEnabledKey, encodeSyncBoolean(it)) }
loadSwipeToSeekSensitivity()?.let { put(swipeToSeekSensitivityKey, encodeSyncString(it)) }
} }
actual fun replaceFromSyncPayload(payload: JsonObject) { actual fun replaceFromSyncPayload(payload: JsonObject) {
@ -631,5 +637,29 @@ 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(swipeToSeekEnabledKey)?.let(::saveSwipeToSeekEnabled)
payload.decodeSyncString(swipeToSeekSensitivityKey)?.let(::saveSwipeToSeekSensitivity)
}
actual fun loadSwipeToSeekEnabled(): Boolean? {
val defaults = NSUserDefaults.standardUserDefaults
val key = ProfileScopedKey.of(swipeToSeekEnabledKey)
return if (defaults.objectForKey(key) != null) {
defaults.boolForKey(key)
} else {
null
}
}
actual fun saveSwipeToSeekEnabled(enabled: Boolean) {
val defaults = NSUserDefaults.standardUserDefaults
defaults.setBool(enabled, ProfileScopedKey.of(swipeToSeekEnabledKey))
}
actual fun loadSwipeToSeekSensitivity(): String? =
NSUserDefaults.standardUserDefaults.stringForKey(ProfileScopedKey.of(swipeToSeekSensitivityKey))
actual fun saveSwipeToSeekSensitivity(sensitivity: String) {
NSUserDefaults.standardUserDefaults.setObject(sensitivity, ProfileScopedKey.of(swipeToSeekSensitivityKey))
} }
} }