mirror of
https://github.com/TeamNewPipe/NewPipe
synced 2026-10-14 19:51:49 +00:00
update the video-audio screen viewmodel, and tests
This commit is contained in:
committed by
Aayush Gupta
parent
62784f3cad
commit
561afbf5a6
@@ -58,7 +58,7 @@
|
||||
<string name="night_theme_summary">Select your favorite night theme — %1$s</string>
|
||||
<string name="night_theme_available">This option is only available if %1$s is selected for Theme</string>
|
||||
<string name="select_night_theme_toast">You can select your favorite night theme below</string>
|
||||
<string name="show_hold_to_append_title">Show \"Hold to enqueue\" tip</string>
|
||||
<string name="show_hold_to_append_title">Show "Hold to enqueue" tip</string>
|
||||
<string name="show_hold_to_append_summary">Show tip when pressing the background or the popup button in video \"Details:\"</string>
|
||||
<string name="tablet_mode_title">Tablet mode</string>
|
||||
<string name="list_view_mode">List view mode</string>
|
||||
@@ -94,7 +94,7 @@
|
||||
<string name="use_external_video_player_title">Use external video player</string>
|
||||
<string name="use_external_video_player_summary">Removes audio at some resolutions</string>
|
||||
<string name="use_external_audio_player_title">Use external audio player</string>
|
||||
<string name="show_play_with_kodi_title">Show \"Play with Kodi\" option</string>
|
||||
<string name="show_play_with_kodi_title">Show "Play with Kodi" option</string>
|
||||
<string name="show_play_with_kodi_summary">Display an option to play a video via Kodi media center</string>
|
||||
<string name="seekbar_preview_thumbnail_title">Seekbar thumbnail preview</string>
|
||||
<string name="high_quality_larger">High quality (larger)</string>
|
||||
@@ -103,7 +103,7 @@
|
||||
|
||||
<!-- Video/Audio Settings: Behavior section -->
|
||||
<string name="settings_category_player_behavior_title">Behavior</string>
|
||||
<string name="preferred_open_action_settings_title">Preferred \'open\' action</string>
|
||||
<string name="preferred_open_action_settings_title">Preferred 'open' action</string>
|
||||
<string name="preferred_open_action_settings_summary">Default action when opening content — %1$s</string>
|
||||
<string name="show_info">Show info</string>
|
||||
<string name="video_player">Video player</string>
|
||||
|
||||
@@ -1,2 +1,36 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2026 NewPipe e.V. <https://newpipe-ev.de>
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
package net.newpipe.app.composable
|
||||
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.tooling.preview.PreviewLightDark
|
||||
import androidx.compose.ui.tooling.preview.PreviewWrapper
|
||||
import androidx.compose.ui.unit.dp
|
||||
import net.newpipe.app.preview.ThemePreviewProvider
|
||||
|
||||
/**
|
||||
* Section header inside a settings screen
|
||||
*/
|
||||
@Composable
|
||||
fun PreferenceCategoryTitle(title: String, modifier: Modifier = Modifier) {
|
||||
Text(
|
||||
text = title,
|
||||
modifier = modifier.padding(start = 16.dp, top = 24.dp, end = 16.dp, bottom = 8.dp),
|
||||
color = MaterialTheme.colorScheme.primary,
|
||||
style = MaterialTheme.typography.titleSmall
|
||||
)
|
||||
}
|
||||
|
||||
@PreviewWrapper(ThemePreviewProvider::class)
|
||||
@PreviewLightDark
|
||||
@Composable
|
||||
private fun PreferenceCategoryTitlePreview() {
|
||||
PreferenceCategoryTitle(title = "Player")
|
||||
}
|
||||
+333
-5
@@ -14,15 +14,20 @@ import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.SnackbarHost
|
||||
import androidx.compose.material3.SnackbarHostState
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.tooling.preview.PreviewLightDark
|
||||
import androidx.compose.ui.tooling.preview.PreviewWrapper
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import kotlinx.coroutines.launch
|
||||
import net.newpipe.app.composable.ListPreference
|
||||
import net.newpipe.app.composable.ListPreferenceEntry
|
||||
import net.newpipe.app.composable.PreferenceCategoryTitle
|
||||
import net.newpipe.app.composable.SwitchPreference
|
||||
import net.newpipe.app.composable.TopAppBar
|
||||
import net.newpipe.app.navigation.Navigator
|
||||
@@ -30,20 +35,77 @@ import net.newpipe.app.preferences.VideoAudioPreferences
|
||||
import net.newpipe.app.preview.ThemePreviewProvider
|
||||
import net.newpipe.app.viewmodel.settings.VideoAudioSettingsViewModel
|
||||
import newpipe.shared.generated.resources.Res
|
||||
import newpipe.shared.generated.resources.add_to_playlist
|
||||
import newpipe.shared.generated.resources.always
|
||||
import newpipe.shared.generated.resources.always_ask_open_action
|
||||
import newpipe.shared.generated.resources.auto_queue_summary
|
||||
import newpipe.shared.generated.resources.auto_queue_title
|
||||
import newpipe.shared.generated.resources.autoplay_summary
|
||||
import newpipe.shared.generated.resources.autoplay_title
|
||||
import newpipe.shared.generated.resources.background_player
|
||||
import newpipe.shared.generated.resources.best_resolution
|
||||
import newpipe.shared.generated.resources.brightness
|
||||
import newpipe.shared.generated.resources.clear_queue_confirmation_summary
|
||||
import newpipe.shared.generated.resources.clear_queue_confirmation_title
|
||||
import newpipe.shared.generated.resources.default_audio_format_title
|
||||
import newpipe.shared.generated.resources.default_popup_resolution_title
|
||||
import newpipe.shared.generated.resources.default_resolution_title
|
||||
import newpipe.shared.generated.resources.default_video_format_title
|
||||
import newpipe.shared.generated.resources.dont_show
|
||||
import newpipe.shared.generated.resources.download
|
||||
import newpipe.shared.generated.resources.enqueue_stream
|
||||
import newpipe.shared.generated.resources.high_quality_larger
|
||||
import newpipe.shared.generated.resources.ignore_hardware_media_buttons_summary
|
||||
import newpipe.shared.generated.resources.ignore_hardware_media_buttons_title
|
||||
import newpipe.shared.generated.resources.left_gesture_control_summary
|
||||
import newpipe.shared.generated.resources.left_gesture_control_title
|
||||
import newpipe.shared.generated.resources.limit_data_usage_none_description
|
||||
import newpipe.shared.generated.resources.limit_mobile_data_usage_title
|
||||
import newpipe.shared.generated.resources.low_quality_smaller
|
||||
import newpipe.shared.generated.resources.minimize_on_exit_background_description
|
||||
import newpipe.shared.generated.resources.minimize_on_exit_none_description
|
||||
import newpipe.shared.generated.resources.minimize_on_exit_popup_description
|
||||
import newpipe.shared.generated.resources.minimize_on_exit_summary
|
||||
import newpipe.shared.generated.resources.minimize_on_exit_title
|
||||
import newpipe.shared.generated.resources.never
|
||||
import newpipe.shared.generated.resources.new_seek_duration_toast
|
||||
import newpipe.shared.generated.resources.none
|
||||
import newpipe.shared.generated.resources.popup_player
|
||||
import newpipe.shared.generated.resources.popup_remember_size_pos_summary
|
||||
import newpipe.shared.generated.resources.popup_remember_size_pos_title
|
||||
import newpipe.shared.generated.resources.prefer_descriptive_audio_summary
|
||||
import newpipe.shared.generated.resources.prefer_descriptive_audio_title
|
||||
import newpipe.shared.generated.resources.prefer_original_audio_summary
|
||||
import newpipe.shared.generated.resources.prefer_original_audio_title
|
||||
import newpipe.shared.generated.resources.preferred_open_action_settings_summary
|
||||
import newpipe.shared.generated.resources.preferred_open_action_settings_title
|
||||
import newpipe.shared.generated.resources.resume_on_audio_focus_gain_summary
|
||||
import newpipe.shared.generated.resources.resume_on_audio_focus_gain_title
|
||||
import newpipe.shared.generated.resources.right_gesture_control_summary
|
||||
import newpipe.shared.generated.resources.right_gesture_control_title
|
||||
import newpipe.shared.generated.resources.seconds
|
||||
import newpipe.shared.generated.resources.seek_duration_title
|
||||
import newpipe.shared.generated.resources.seekbar_preview_thumbnail_title
|
||||
import newpipe.shared.generated.resources.settings_category_player_behavior_title
|
||||
import newpipe.shared.generated.resources.settings_category_player_title
|
||||
import newpipe.shared.generated.resources.settings_category_video_audio_title
|
||||
import newpipe.shared.generated.resources.show_higher_resolutions_summary
|
||||
import newpipe.shared.generated.resources.show_higher_resolutions_title
|
||||
import newpipe.shared.generated.resources.show_info
|
||||
import newpipe.shared.generated.resources.show_play_with_kodi_summary
|
||||
import newpipe.shared.generated.resources.show_play_with_kodi_title
|
||||
import newpipe.shared.generated.resources.start_main_player_fullscreen_summary
|
||||
import newpipe.shared.generated.resources.start_main_player_fullscreen_title
|
||||
import newpipe.shared.generated.resources.use_external_audio_player_title
|
||||
import newpipe.shared.generated.resources.use_external_video_player_summary
|
||||
import newpipe.shared.generated.resources.use_external_video_player_title
|
||||
import newpipe.shared.generated.resources.use_inexact_seek_summary
|
||||
import newpipe.shared.generated.resources.use_inexact_seek_title
|
||||
import newpipe.shared.generated.resources.video_player
|
||||
import newpipe.shared.generated.resources.volume
|
||||
import newpipe.shared.generated.resources.wifi_only
|
||||
import org.jetbrains.compose.resources.getString
|
||||
import org.jetbrains.compose.resources.pluralStringResource
|
||||
import org.jetbrains.compose.resources.stringResource
|
||||
import org.koin.compose.koinInject
|
||||
import org.koin.compose.viewmodel.koinViewModel
|
||||
@@ -57,16 +119,38 @@ fun VideoAudioSettingsScreen(
|
||||
val defaultPopupResolution by viewModel.defaultPopupResolution.collectAsStateWithLifecycle()
|
||||
val mobileDataResolution by viewModel.mobileDataResolution.collectAsStateWithLifecycle()
|
||||
val showHigherResolutions by viewModel.showHigherResolutions.collectAsStateWithLifecycle()
|
||||
val videoFormat by viewModel.videoFormat.collectAsStateWithLifecycle()
|
||||
val audioFormat by viewModel.audioFormat.collectAsStateWithLifecycle()
|
||||
val preferOriginalAudio by viewModel.preferOriginalAudio.collectAsStateWithLifecycle()
|
||||
val preferDescriptiveAudio by viewModel.preferDescriptiveAudio.collectAsStateWithLifecycle()
|
||||
val useExternalVideoPlayer by viewModel.useExternalVideoPlayer.collectAsStateWithLifecycle()
|
||||
val useExternalAudioPlayer by viewModel.useExternalAudioPlayer.collectAsStateWithLifecycle()
|
||||
val showPlayWithKodi by viewModel.showPlayWithKodi.collectAsStateWithLifecycle()
|
||||
val seekbarPreviewThumbnail by viewModel.seekbarPreviewThumbnail.collectAsStateWithLifecycle()
|
||||
val preferredOpenAction by viewModel.preferredOpenAction.collectAsStateWithLifecycle()
|
||||
val minimizeOnExit by viewModel.minimizeOnExit.collectAsStateWithLifecycle()
|
||||
val startMainPlayerFullscreen by viewModel.startMainPlayerFullscreen.collectAsStateWithLifecycle()
|
||||
val autoplay by viewModel.autoplay.collectAsStateWithLifecycle()
|
||||
val autoQueue by viewModel.autoQueue.collectAsStateWithLifecycle()
|
||||
val resumeOnAudioFocusGain by viewModel.resumeOnAudioFocusGain.collectAsStateWithLifecycle()
|
||||
val leftGestureControl by viewModel.leftGestureControl.collectAsStateWithLifecycle()
|
||||
val rightGestureControl by viewModel.rightGestureControl.collectAsStateWithLifecycle()
|
||||
val popupRememberSizePos by viewModel.popupRememberSizePos.collectAsStateWithLifecycle()
|
||||
val useInexactSeek by viewModel.useInexactSeek.collectAsStateWithLifecycle()
|
||||
val seekDuration by viewModel.seekDuration.collectAsStateWithLifecycle()
|
||||
val clearQueueConfirmation by viewModel.clearQueueConfirmation.collectAsStateWithLifecycle()
|
||||
val ignoreHardwareMediaButtons by viewModel.ignoreHardwareMediaButtons.collectAsStateWithLifecycle()
|
||||
|
||||
// Option lists are pure functions of their toggles, so derive them instead of storing them.
|
||||
val resolutionValues = remember(showHigherResolutions) {
|
||||
VideoAudioPreferences.resolutions(showHigherResolutions)
|
||||
}
|
||||
val mobileDataResolutionValues = remember(showHigherResolutions) {
|
||||
VideoAudioPreferences.mobileDataResolutions(showHigherResolutions)
|
||||
}
|
||||
val videoFormat by viewModel.videoFormat.collectAsStateWithLifecycle()
|
||||
val audioFormat by viewModel.audioFormat.collectAsStateWithLifecycle()
|
||||
val preferOriginalAudio by viewModel.preferOriginalAudio.collectAsStateWithLifecycle()
|
||||
val preferDescriptiveAudio by viewModel.preferDescriptiveAudio.collectAsStateWithLifecycle()
|
||||
val seekDurationValues = remember(useInexactSeek) {
|
||||
VideoAudioPreferences.seekDurationsMs(useInexactSeek)
|
||||
}
|
||||
|
||||
VideoAudioSettingsScreenContent(
|
||||
defaultResolution = defaultResolution,
|
||||
@@ -79,6 +163,24 @@ fun VideoAudioSettingsScreen(
|
||||
audioFormat = audioFormat,
|
||||
preferOriginalAudio = preferOriginalAudio,
|
||||
preferDescriptiveAudio = preferDescriptiveAudio,
|
||||
useExternalVideoPlayer = useExternalVideoPlayer,
|
||||
useExternalAudioPlayer = useExternalAudioPlayer,
|
||||
showPlayWithKodi = showPlayWithKodi,
|
||||
seekbarPreviewThumbnail = seekbarPreviewThumbnail,
|
||||
preferredOpenAction = preferredOpenAction,
|
||||
minimizeOnExit = minimizeOnExit,
|
||||
startMainPlayerFullscreen = startMainPlayerFullscreen,
|
||||
autoplay = autoplay,
|
||||
autoQueue = autoQueue,
|
||||
resumeOnAudioFocusGain = resumeOnAudioFocusGain,
|
||||
leftGestureControl = leftGestureControl,
|
||||
rightGestureControl = rightGestureControl,
|
||||
popupRememberSizePos = popupRememberSizePos,
|
||||
useInexactSeek = useInexactSeek,
|
||||
seekDuration = seekDuration,
|
||||
seekDurationValues = seekDurationValues,
|
||||
clearQueueConfirmation = clearQueueConfirmation,
|
||||
ignoreHardwareMediaButtons = ignoreHardwareMediaButtons,
|
||||
onDefaultResolutionChange = viewModel::setDefaultResolution,
|
||||
onDefaultPopupResolutionChange = viewModel::setDefaultPopupResolution,
|
||||
onMobileDataResolutionChange = viewModel::setMobileDataResolution,
|
||||
@@ -87,6 +189,23 @@ fun VideoAudioSettingsScreen(
|
||||
onAudioFormatChange = viewModel::setAudioFormat,
|
||||
onPreferOriginalAudioChange = viewModel::setPreferOriginalAudio,
|
||||
onPreferDescriptiveAudioChange = viewModel::setPreferDescriptiveAudio,
|
||||
onUseExternalVideoPlayerChange = viewModel::setUseExternalVideoPlayer,
|
||||
onUseExternalAudioPlayerChange = viewModel::setUseExternalAudioPlayer,
|
||||
onShowPlayWithKodiChange = viewModel::setShowPlayWithKodi,
|
||||
onSeekbarPreviewThumbnailChange = viewModel::setSeekbarPreviewThumbnail,
|
||||
onPreferredOpenActionChange = viewModel::setPreferredOpenAction,
|
||||
onMinimizeOnExitChange = viewModel::setMinimizeOnExit,
|
||||
onStartMainPlayerFullscreenChange = viewModel::setStartMainPlayerFullscreen,
|
||||
onAutoplayChange = viewModel::setAutoplay,
|
||||
onAutoQueueChange = viewModel::setAutoQueue,
|
||||
onResumeOnAudioFocusGainChange = viewModel::setResumeOnAudioFocusGain,
|
||||
onLeftGestureControlChange = viewModel::setLeftGestureControl,
|
||||
onRightGestureControlChange = viewModel::setRightGestureControl,
|
||||
onPopupRememberSizePosChange = viewModel::setPopupRememberSizePos,
|
||||
onUseInexactSeekChange = viewModel::setUseInexactSeek,
|
||||
onSeekDurationChange = viewModel::setSeekDuration,
|
||||
onClearQueueConfirmationChange = viewModel::setClearQueueConfirmation,
|
||||
onIgnoreHardwareMediaButtonsChange = viewModel::setIgnoreHardwareMediaButtons,
|
||||
onNavigateUp = { navigator.navigateUp() }
|
||||
)
|
||||
}
|
||||
@@ -103,6 +222,24 @@ fun VideoAudioSettingsScreenContent(
|
||||
audioFormat: String = VideoAudioPreferences.DEFAULT_AUDIO_FORMAT,
|
||||
preferOriginalAudio: Boolean = VideoAudioPreferences.DEFAULT_PREFER_ORIGINAL_AUDIO,
|
||||
preferDescriptiveAudio: Boolean = VideoAudioPreferences.DEFAULT_PREFER_DESCRIPTIVE_AUDIO,
|
||||
useExternalVideoPlayer: Boolean = VideoAudioPreferences.DEFAULT_USE_EXTERNAL_VIDEO_PLAYER,
|
||||
useExternalAudioPlayer: Boolean = VideoAudioPreferences.DEFAULT_USE_EXTERNAL_AUDIO_PLAYER,
|
||||
showPlayWithKodi: Boolean = VideoAudioPreferences.DEFAULT_SHOW_PLAY_WITH_KODI,
|
||||
seekbarPreviewThumbnail: String = VideoAudioPreferences.DEFAULT_SEEKBAR_PREVIEW_THUMBNAIL,
|
||||
preferredOpenAction: String = VideoAudioPreferences.DEFAULT_PREFERRED_OPEN_ACTION,
|
||||
minimizeOnExit: String = VideoAudioPreferences.DEFAULT_MINIMIZE_ON_EXIT,
|
||||
startMainPlayerFullscreen: Boolean = VideoAudioPreferences.DEFAULT_START_MAIN_PLAYER_FULLSCREEN,
|
||||
autoplay: String = VideoAudioPreferences.DEFAULT_AUTOPLAY,
|
||||
autoQueue: Boolean = VideoAudioPreferences.DEFAULT_AUTO_QUEUE,
|
||||
resumeOnAudioFocusGain: Boolean = VideoAudioPreferences.DEFAULT_RESUME_ON_AUDIO_FOCUS_GAIN,
|
||||
leftGestureControl: String = VideoAudioPreferences.DEFAULT_LEFT_GESTURE_CONTROL,
|
||||
rightGestureControl: String = VideoAudioPreferences.DEFAULT_RIGHT_GESTURE_CONTROL,
|
||||
popupRememberSizePos: Boolean = VideoAudioPreferences.DEFAULT_POPUP_REMEMBER_SIZE_POS,
|
||||
useInexactSeek: Boolean = VideoAudioPreferences.DEFAULT_USE_INEXACT_SEEK,
|
||||
seekDuration: String = VideoAudioPreferences.DEFAULT_SEEK_DURATION_MS,
|
||||
seekDurationValues: List<String> = VideoAudioPreferences.SEEK_DURATIONS_MS,
|
||||
clearQueueConfirmation: Boolean = VideoAudioPreferences.DEFAULT_CLEAR_QUEUE_CONFIRMATION,
|
||||
ignoreHardwareMediaButtons: Boolean = VideoAudioPreferences.DEFAULT_IGNORE_HARDWARE_MEDIA_BUTTONS,
|
||||
onDefaultResolutionChange: (String) -> Unit = {},
|
||||
onDefaultPopupResolutionChange: (String) -> Unit = {},
|
||||
onMobileDataResolutionChange: (String) -> Unit = {},
|
||||
@@ -111,8 +248,28 @@ fun VideoAudioSettingsScreenContent(
|
||||
onAudioFormatChange: (String) -> Unit = {},
|
||||
onPreferOriginalAudioChange: (Boolean) -> Unit = {},
|
||||
onPreferDescriptiveAudioChange: (Boolean) -> Unit = {},
|
||||
onUseExternalVideoPlayerChange: (Boolean) -> Unit = {},
|
||||
onUseExternalAudioPlayerChange: (Boolean) -> Unit = {},
|
||||
onShowPlayWithKodiChange: (Boolean) -> Unit = {},
|
||||
onSeekbarPreviewThumbnailChange: (String) -> Unit = {},
|
||||
onPreferredOpenActionChange: (String) -> Unit = {},
|
||||
onMinimizeOnExitChange: (String) -> Unit = {},
|
||||
onStartMainPlayerFullscreenChange: (Boolean) -> Unit = {},
|
||||
onAutoplayChange: (String) -> Unit = {},
|
||||
onAutoQueueChange: (Boolean) -> Unit = {},
|
||||
onResumeOnAudioFocusGainChange: (Boolean) -> Unit = {},
|
||||
onLeftGestureControlChange: (String) -> Unit = {},
|
||||
onRightGestureControlChange: (String) -> Unit = {},
|
||||
onPopupRememberSizePosChange: (Boolean) -> Unit = {},
|
||||
onUseInexactSeekChange: (Boolean) -> Unit = {},
|
||||
onSeekDurationChange: (String) -> Unit = {},
|
||||
onClearQueueConfirmationChange: (Boolean) -> Unit = {},
|
||||
onIgnoreHardwareMediaButtonsChange: (Boolean) -> Unit = {},
|
||||
onNavigateUp: () -> Unit = {}
|
||||
) {
|
||||
val scope = rememberCoroutineScope()
|
||||
val snackbarHostState = remember { SnackbarHostState() }
|
||||
|
||||
val bestResolutionLabel = stringResource(Res.string.best_resolution)
|
||||
val noLimitLabel = stringResource(Res.string.limit_data_usage_none_description)
|
||||
|
||||
@@ -126,6 +283,8 @@ fun VideoAudioSettingsScreenContent(
|
||||
title = if (value == VideoAudioPreferences.LIMIT_DATA_USAGE_NONE) noLimitLabel else value
|
||||
)
|
||||
|
||||
fun selectedTitle(entries: List<ListPreferenceEntry>, value: String) = entries.firstOrNull { it.value == value }?.title.orEmpty()
|
||||
|
||||
val resolutionEntries = resolutionValues.map(::resolutionEntry)
|
||||
val mobileDataEntries = mobileDataResolutionValues.map(::mobileDataEntry)
|
||||
val videoFormatEntries = VideoAudioPreferences.VIDEO_FORMATS.map { (value, label) ->
|
||||
@@ -134,6 +293,40 @@ fun VideoAudioSettingsScreenContent(
|
||||
val audioFormatEntries = VideoAudioPreferences.AUDIO_FORMATS.map { (value, label) ->
|
||||
ListPreferenceEntry(value, label)
|
||||
}
|
||||
val seekbarThumbnailEntries = listOf(
|
||||
ListPreferenceEntry(VideoAudioPreferences.SEEKBAR_THUMBNAIL_HIGH_QUALITY, stringResource(Res.string.high_quality_larger)),
|
||||
ListPreferenceEntry(VideoAudioPreferences.SEEKBAR_THUMBNAIL_LOW_QUALITY, stringResource(Res.string.low_quality_smaller)),
|
||||
ListPreferenceEntry(VideoAudioPreferences.SEEKBAR_THUMBNAIL_NONE, stringResource(Res.string.dont_show))
|
||||
)
|
||||
val openActionEntries = listOf(
|
||||
ListPreferenceEntry(VideoAudioPreferences.OPEN_ACTION_SHOW_INFO, stringResource(Res.string.show_info)),
|
||||
ListPreferenceEntry(VideoAudioPreferences.OPEN_ACTION_VIDEO_PLAYER, stringResource(Res.string.video_player)),
|
||||
ListPreferenceEntry(VideoAudioPreferences.OPEN_ACTION_BACKGROUND_PLAYER, stringResource(Res.string.background_player)),
|
||||
ListPreferenceEntry(VideoAudioPreferences.OPEN_ACTION_POPUP_PLAYER, stringResource(Res.string.popup_player)),
|
||||
ListPreferenceEntry(VideoAudioPreferences.OPEN_ACTION_DOWNLOAD, stringResource(Res.string.download)),
|
||||
ListPreferenceEntry(VideoAudioPreferences.OPEN_ACTION_ADD_TO_PLAYLIST, stringResource(Res.string.add_to_playlist)),
|
||||
ListPreferenceEntry(VideoAudioPreferences.OPEN_ACTION_ENQUEUE, stringResource(Res.string.enqueue_stream)),
|
||||
ListPreferenceEntry(VideoAudioPreferences.OPEN_ACTION_ALWAYS_ASK, stringResource(Res.string.always_ask_open_action))
|
||||
)
|
||||
val minimizeOnExitEntries = listOf(
|
||||
ListPreferenceEntry(VideoAudioPreferences.MINIMIZE_ON_EXIT_NONE, stringResource(Res.string.minimize_on_exit_none_description)),
|
||||
ListPreferenceEntry(VideoAudioPreferences.MINIMIZE_ON_EXIT_BACKGROUND, stringResource(Res.string.minimize_on_exit_background_description)),
|
||||
ListPreferenceEntry(VideoAudioPreferences.MINIMIZE_ON_EXIT_POPUP, stringResource(Res.string.minimize_on_exit_popup_description))
|
||||
)
|
||||
val autoplayEntries = listOf(
|
||||
ListPreferenceEntry(VideoAudioPreferences.AUTOPLAY_ALWAYS, stringResource(Res.string.always)),
|
||||
ListPreferenceEntry(VideoAudioPreferences.AUTOPLAY_WIFI, stringResource(Res.string.wifi_only)),
|
||||
ListPreferenceEntry(VideoAudioPreferences.AUTOPLAY_NEVER, stringResource(Res.string.never))
|
||||
)
|
||||
val gestureEntries = listOf(
|
||||
ListPreferenceEntry(VideoAudioPreferences.GESTURE_BRIGHTNESS, stringResource(Res.string.brightness)),
|
||||
ListPreferenceEntry(VideoAudioPreferences.GESTURE_VOLUME, stringResource(Res.string.volume)),
|
||||
ListPreferenceEntry(VideoAudioPreferences.GESTURE_NONE, stringResource(Res.string.none))
|
||||
)
|
||||
val seekDurationEntries = seekDurationValues.map { value ->
|
||||
val seconds = VideoAudioPreferences.seekDurationSeconds(value)
|
||||
ListPreferenceEntry(value, pluralStringResource(Res.plurals.seconds, seconds, seconds))
|
||||
}
|
||||
|
||||
Scaffold(
|
||||
topBar = {
|
||||
@@ -141,7 +334,8 @@ fun VideoAudioSettingsScreenContent(
|
||||
title = stringResource(Res.string.settings_category_video_audio_title),
|
||||
onNavigateUp = onNavigateUp
|
||||
)
|
||||
}
|
||||
},
|
||||
snackbarHost = { SnackbarHost(snackbarHostState) }
|
||||
) { paddingValues ->
|
||||
Column(
|
||||
modifier = Modifier
|
||||
@@ -198,6 +392,140 @@ fun VideoAudioSettingsScreenContent(
|
||||
checked = preferDescriptiveAudio,
|
||||
onCheckedChange = onPreferDescriptiveAudioChange
|
||||
)
|
||||
|
||||
// TODO: ExoPlayer settings sub-screen link goes here once that screen is migrated.
|
||||
|
||||
PreferenceCategoryTitle(title = stringResource(Res.string.settings_category_player_title))
|
||||
SwitchPreference(
|
||||
title = stringResource(Res.string.use_external_video_player_title),
|
||||
summary = stringResource(Res.string.use_external_video_player_summary),
|
||||
checked = useExternalVideoPlayer,
|
||||
onCheckedChange = onUseExternalVideoPlayerChange
|
||||
)
|
||||
SwitchPreference(
|
||||
title = stringResource(Res.string.use_external_audio_player_title),
|
||||
checked = useExternalAudioPlayer,
|
||||
onCheckedChange = onUseExternalAudioPlayerChange
|
||||
)
|
||||
SwitchPreference(
|
||||
title = stringResource(Res.string.show_play_with_kodi_title),
|
||||
summary = stringResource(Res.string.show_play_with_kodi_summary),
|
||||
checked = showPlayWithKodi,
|
||||
onCheckedChange = onShowPlayWithKodiChange
|
||||
)
|
||||
ListPreference(
|
||||
title = stringResource(Res.string.seekbar_preview_thumbnail_title),
|
||||
entries = seekbarThumbnailEntries,
|
||||
selectedValue = seekbarPreviewThumbnail,
|
||||
onValueSelected = onSeekbarPreviewThumbnailChange
|
||||
)
|
||||
|
||||
PreferenceCategoryTitle(title = stringResource(Res.string.settings_category_player_behavior_title))
|
||||
ListPreference(
|
||||
title = stringResource(Res.string.preferred_open_action_settings_title),
|
||||
entries = openActionEntries,
|
||||
selectedValue = preferredOpenAction,
|
||||
onValueSelected = onPreferredOpenActionChange,
|
||||
summary = stringResource(
|
||||
Res.string.preferred_open_action_settings_summary,
|
||||
selectedTitle(openActionEntries, preferredOpenAction)
|
||||
)
|
||||
)
|
||||
// TODO(follow-up): when popup is selected without draw-over-apps permission, the
|
||||
// legacy screen shows a snackbar linking to the system permission settings. Needs a
|
||||
// platform actions interface (like AppearanceActions) and is deliberately deferred.
|
||||
ListPreference(
|
||||
title = stringResource(Res.string.minimize_on_exit_title),
|
||||
entries = minimizeOnExitEntries,
|
||||
selectedValue = minimizeOnExit,
|
||||
onValueSelected = onMinimizeOnExitChange,
|
||||
summary = stringResource(
|
||||
Res.string.minimize_on_exit_summary,
|
||||
selectedTitle(minimizeOnExitEntries, minimizeOnExit)
|
||||
)
|
||||
)
|
||||
SwitchPreference(
|
||||
title = stringResource(Res.string.start_main_player_fullscreen_title),
|
||||
summary = stringResource(Res.string.start_main_player_fullscreen_summary),
|
||||
checked = startMainPlayerFullscreen,
|
||||
onCheckedChange = onStartMainPlayerFullscreenChange
|
||||
)
|
||||
ListPreference(
|
||||
title = stringResource(Res.string.autoplay_title),
|
||||
entries = autoplayEntries,
|
||||
selectedValue = autoplay,
|
||||
onValueSelected = onAutoplayChange,
|
||||
summary = stringResource(
|
||||
Res.string.autoplay_summary,
|
||||
selectedTitle(autoplayEntries, autoplay)
|
||||
)
|
||||
)
|
||||
SwitchPreference(
|
||||
title = stringResource(Res.string.auto_queue_title),
|
||||
summary = stringResource(Res.string.auto_queue_summary),
|
||||
checked = autoQueue,
|
||||
onCheckedChange = onAutoQueueChange
|
||||
)
|
||||
SwitchPreference(
|
||||
title = stringResource(Res.string.resume_on_audio_focus_gain_title),
|
||||
summary = stringResource(Res.string.resume_on_audio_focus_gain_summary),
|
||||
checked = resumeOnAudioFocusGain,
|
||||
onCheckedChange = onResumeOnAudioFocusGainChange
|
||||
)
|
||||
ListPreference(
|
||||
title = stringResource(Res.string.left_gesture_control_title),
|
||||
entries = gestureEntries,
|
||||
selectedValue = leftGestureControl,
|
||||
onValueSelected = onLeftGestureControlChange,
|
||||
summary = stringResource(Res.string.left_gesture_control_summary)
|
||||
)
|
||||
ListPreference(
|
||||
title = stringResource(Res.string.right_gesture_control_title),
|
||||
entries = gestureEntries,
|
||||
selectedValue = rightGestureControl,
|
||||
onValueSelected = onRightGestureControlChange,
|
||||
summary = stringResource(Res.string.right_gesture_control_summary)
|
||||
)
|
||||
SwitchPreference(
|
||||
title = stringResource(Res.string.popup_remember_size_pos_title),
|
||||
summary = stringResource(Res.string.popup_remember_size_pos_summary),
|
||||
checked = popupRememberSizePos,
|
||||
onCheckedChange = onPopupRememberSizePosChange
|
||||
)
|
||||
SwitchPreference(
|
||||
title = stringResource(Res.string.use_inexact_seek_title),
|
||||
summary = stringResource(Res.string.use_inexact_seek_summary),
|
||||
checked = useInexactSeek,
|
||||
onCheckedChange = { checked ->
|
||||
// The view model applies the same adjustment. this only decides whether to
|
||||
// tell the user about it, mirroring the legacy toast.
|
||||
VideoAudioPreferences.adjustedSeekDurationMs(seekDuration, checked)?.let { adjustedMs ->
|
||||
val newSeconds = VideoAudioPreferences.seekDurationSeconds(adjustedMs)
|
||||
scope.launch {
|
||||
snackbarHostState.showSnackbar(getString(Res.string.new_seek_duration_toast, newSeconds))
|
||||
}
|
||||
}
|
||||
onUseInexactSeekChange(checked)
|
||||
}
|
||||
)
|
||||
ListPreference(
|
||||
title = stringResource(Res.string.seek_duration_title),
|
||||
entries = seekDurationEntries,
|
||||
selectedValue = seekDuration,
|
||||
onValueSelected = onSeekDurationChange
|
||||
)
|
||||
SwitchPreference(
|
||||
title = stringResource(Res.string.clear_queue_confirmation_title),
|
||||
summary = stringResource(Res.string.clear_queue_confirmation_summary),
|
||||
checked = clearQueueConfirmation,
|
||||
onCheckedChange = onClearQueueConfirmationChange
|
||||
)
|
||||
SwitchPreference(
|
||||
title = stringResource(Res.string.ignore_hardware_media_buttons_title),
|
||||
summary = stringResource(Res.string.ignore_hardware_media_buttons_summary),
|
||||
checked = ignoreHardwareMediaButtons,
|
||||
onCheckedChange = onIgnoreHardwareMediaButtonsChange
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+121
-76
@@ -16,87 +16,88 @@ import org.koin.core.annotation.KoinViewModel
|
||||
class VideoAudioSettingsViewModel(private val settings: Settings) : ViewModel() {
|
||||
|
||||
val defaultResolution: StateFlow<String>
|
||||
field = MutableStateFlow(
|
||||
settings.getString(
|
||||
VideoAudioPreferences.KEY_DEFAULT_RESOLUTION,
|
||||
VideoAudioPreferences.DEFAULT_RESOLUTION
|
||||
)
|
||||
)
|
||||
field = stringFlow(VideoAudioPreferences.KEY_DEFAULT_RESOLUTION, VideoAudioPreferences.DEFAULT_RESOLUTION)
|
||||
|
||||
val defaultPopupResolution: StateFlow<String>
|
||||
field = MutableStateFlow(
|
||||
settings.getString(
|
||||
VideoAudioPreferences.KEY_DEFAULT_POPUP_RESOLUTION,
|
||||
VideoAudioPreferences.DEFAULT_POPUP_RESOLUTION
|
||||
)
|
||||
)
|
||||
field = stringFlow(VideoAudioPreferences.KEY_DEFAULT_POPUP_RESOLUTION, VideoAudioPreferences.DEFAULT_POPUP_RESOLUTION)
|
||||
|
||||
val mobileDataResolution: StateFlow<String>
|
||||
field = MutableStateFlow(
|
||||
settings.getString(
|
||||
VideoAudioPreferences.KEY_LIMIT_MOBILE_DATA_USAGE,
|
||||
VideoAudioPreferences.DEFAULT_LIMIT_MOBILE_DATA_USAGE
|
||||
)
|
||||
)
|
||||
field = stringFlow(VideoAudioPreferences.KEY_LIMIT_MOBILE_DATA_USAGE, VideoAudioPreferences.DEFAULT_LIMIT_MOBILE_DATA_USAGE)
|
||||
|
||||
val showHigherResolutions: StateFlow<Boolean>
|
||||
field = MutableStateFlow(
|
||||
settings.getBoolean(
|
||||
VideoAudioPreferences.KEY_SHOW_HIGHER_RESOLUTIONS,
|
||||
VideoAudioPreferences.DEFAULT_SHOW_HIGHER_RESOLUTIONS
|
||||
)
|
||||
)
|
||||
field = booleanFlow(VideoAudioPreferences.KEY_SHOW_HIGHER_RESOLUTIONS, VideoAudioPreferences.DEFAULT_SHOW_HIGHER_RESOLUTIONS)
|
||||
|
||||
val videoFormat: StateFlow<String>
|
||||
field = MutableStateFlow(
|
||||
settings.getString(
|
||||
VideoAudioPreferences.KEY_DEFAULT_VIDEO_FORMAT,
|
||||
VideoAudioPreferences.DEFAULT_VIDEO_FORMAT
|
||||
)
|
||||
)
|
||||
field = stringFlow(VideoAudioPreferences.KEY_DEFAULT_VIDEO_FORMAT, VideoAudioPreferences.DEFAULT_VIDEO_FORMAT)
|
||||
|
||||
val audioFormat: StateFlow<String>
|
||||
field = MutableStateFlow(
|
||||
settings.getString(
|
||||
VideoAudioPreferences.KEY_DEFAULT_AUDIO_FORMAT,
|
||||
VideoAudioPreferences.DEFAULT_AUDIO_FORMAT
|
||||
)
|
||||
)
|
||||
field = stringFlow(VideoAudioPreferences.KEY_DEFAULT_AUDIO_FORMAT, VideoAudioPreferences.DEFAULT_AUDIO_FORMAT)
|
||||
|
||||
val preferOriginalAudio: StateFlow<Boolean>
|
||||
field = MutableStateFlow(
|
||||
settings.getBoolean(
|
||||
VideoAudioPreferences.KEY_PREFER_ORIGINAL_AUDIO,
|
||||
VideoAudioPreferences.DEFAULT_PREFER_ORIGINAL_AUDIO
|
||||
)
|
||||
)
|
||||
field = booleanFlow(VideoAudioPreferences.KEY_PREFER_ORIGINAL_AUDIO, VideoAudioPreferences.DEFAULT_PREFER_ORIGINAL_AUDIO)
|
||||
|
||||
val preferDescriptiveAudio: StateFlow<Boolean>
|
||||
field = MutableStateFlow(
|
||||
settings.getBoolean(
|
||||
VideoAudioPreferences.KEY_PREFER_DESCRIPTIVE_AUDIO,
|
||||
VideoAudioPreferences.DEFAULT_PREFER_DESCRIPTIVE_AUDIO
|
||||
)
|
||||
)
|
||||
field = booleanFlow(VideoAudioPreferences.KEY_PREFER_DESCRIPTIVE_AUDIO, VideoAudioPreferences.DEFAULT_PREFER_DESCRIPTIVE_AUDIO)
|
||||
|
||||
fun setDefaultResolution(value: String) {
|
||||
settings.putString(VideoAudioPreferences.KEY_DEFAULT_RESOLUTION, value)
|
||||
defaultResolution.value = value
|
||||
}
|
||||
val useExternalVideoPlayer: StateFlow<Boolean>
|
||||
field = booleanFlow(VideoAudioPreferences.KEY_USE_EXTERNAL_VIDEO_PLAYER, VideoAudioPreferences.DEFAULT_USE_EXTERNAL_VIDEO_PLAYER)
|
||||
|
||||
fun setDefaultPopupResolution(value: String) {
|
||||
settings.putString(VideoAudioPreferences.KEY_DEFAULT_POPUP_RESOLUTION, value)
|
||||
defaultPopupResolution.value = value
|
||||
}
|
||||
val useExternalAudioPlayer: StateFlow<Boolean>
|
||||
field = booleanFlow(VideoAudioPreferences.KEY_USE_EXTERNAL_AUDIO_PLAYER, VideoAudioPreferences.DEFAULT_USE_EXTERNAL_AUDIO_PLAYER)
|
||||
|
||||
fun setMobileDataResolution(value: String) {
|
||||
settings.putString(VideoAudioPreferences.KEY_LIMIT_MOBILE_DATA_USAGE, value)
|
||||
mobileDataResolution.value = value
|
||||
}
|
||||
val showPlayWithKodi: StateFlow<Boolean>
|
||||
field = booleanFlow(VideoAudioPreferences.KEY_SHOW_PLAY_WITH_KODI, VideoAudioPreferences.DEFAULT_SHOW_PLAY_WITH_KODI)
|
||||
|
||||
val seekbarPreviewThumbnail: StateFlow<String>
|
||||
field = stringFlow(VideoAudioPreferences.KEY_SEEKBAR_PREVIEW_THUMBNAIL, VideoAudioPreferences.DEFAULT_SEEKBAR_PREVIEW_THUMBNAIL)
|
||||
|
||||
val preferredOpenAction: StateFlow<String>
|
||||
field = stringFlow(VideoAudioPreferences.KEY_PREFERRED_OPEN_ACTION, VideoAudioPreferences.DEFAULT_PREFERRED_OPEN_ACTION)
|
||||
|
||||
val minimizeOnExit: StateFlow<String>
|
||||
field = stringFlow(VideoAudioPreferences.KEY_MINIMIZE_ON_EXIT, VideoAudioPreferences.DEFAULT_MINIMIZE_ON_EXIT)
|
||||
|
||||
val startMainPlayerFullscreen: StateFlow<Boolean>
|
||||
field = booleanFlow(VideoAudioPreferences.KEY_START_MAIN_PLAYER_FULLSCREEN, VideoAudioPreferences.DEFAULT_START_MAIN_PLAYER_FULLSCREEN)
|
||||
|
||||
val autoplay: StateFlow<String>
|
||||
field = stringFlow(VideoAudioPreferences.KEY_AUTOPLAY, VideoAudioPreferences.DEFAULT_AUTOPLAY)
|
||||
|
||||
val autoQueue: StateFlow<Boolean>
|
||||
field = booleanFlow(VideoAudioPreferences.KEY_AUTO_QUEUE, VideoAudioPreferences.DEFAULT_AUTO_QUEUE)
|
||||
|
||||
val resumeOnAudioFocusGain: StateFlow<Boolean>
|
||||
field = booleanFlow(VideoAudioPreferences.KEY_RESUME_ON_AUDIO_FOCUS_GAIN, VideoAudioPreferences.DEFAULT_RESUME_ON_AUDIO_FOCUS_GAIN)
|
||||
|
||||
val leftGestureControl: StateFlow<String>
|
||||
field = stringFlow(VideoAudioPreferences.KEY_LEFT_GESTURE_CONTROL, VideoAudioPreferences.DEFAULT_LEFT_GESTURE_CONTROL)
|
||||
|
||||
val rightGestureControl: StateFlow<String>
|
||||
field = stringFlow(VideoAudioPreferences.KEY_RIGHT_GESTURE_CONTROL, VideoAudioPreferences.DEFAULT_RIGHT_GESTURE_CONTROL)
|
||||
|
||||
val popupRememberSizePos: StateFlow<Boolean>
|
||||
field = booleanFlow(VideoAudioPreferences.KEY_POPUP_REMEMBER_SIZE_POS, VideoAudioPreferences.DEFAULT_POPUP_REMEMBER_SIZE_POS)
|
||||
|
||||
val useInexactSeek: StateFlow<Boolean>
|
||||
field = booleanFlow(VideoAudioPreferences.KEY_USE_INEXACT_SEEK, VideoAudioPreferences.DEFAULT_USE_INEXACT_SEEK)
|
||||
|
||||
val seekDuration: StateFlow<String>
|
||||
field = stringFlow(VideoAudioPreferences.KEY_SEEK_DURATION, VideoAudioPreferences.DEFAULT_SEEK_DURATION_MS)
|
||||
|
||||
val clearQueueConfirmation: StateFlow<Boolean>
|
||||
field = booleanFlow(VideoAudioPreferences.KEY_CLEAR_QUEUE_CONFIRMATION, VideoAudioPreferences.DEFAULT_CLEAR_QUEUE_CONFIRMATION)
|
||||
|
||||
val ignoreHardwareMediaButtons: StateFlow<Boolean>
|
||||
field = booleanFlow(VideoAudioPreferences.KEY_IGNORE_HARDWARE_MEDIA_BUTTONS, VideoAudioPreferences.DEFAULT_IGNORE_HARDWARE_MEDIA_BUTTONS)
|
||||
|
||||
fun setDefaultResolution(value: String) = defaultResolution.persist(VideoAudioPreferences.KEY_DEFAULT_RESOLUTION, value)
|
||||
|
||||
fun setDefaultPopupResolution(value: String) = defaultPopupResolution.persist(VideoAudioPreferences.KEY_DEFAULT_POPUP_RESOLUTION, value)
|
||||
|
||||
fun setMobileDataResolution(value: String) = mobileDataResolution.persist(VideoAudioPreferences.KEY_LIMIT_MOBILE_DATA_USAGE, value)
|
||||
|
||||
fun setShowHigherResolutions(value: Boolean) {
|
||||
settings.putBoolean(VideoAudioPreferences.KEY_SHOW_HIGHER_RESOLUTIONS, value)
|
||||
showHigherResolutions.value = value
|
||||
showHigherResolutions.persist(VideoAudioPreferences.KEY_SHOW_HIGHER_RESOLUTIONS, value)
|
||||
|
||||
if (!value) {
|
||||
if (defaultResolution.value in VideoAudioPreferences.HIGH_RESOLUTIONS) {
|
||||
@@ -111,23 +112,67 @@ class VideoAudioSettingsViewModel(private val settings: Settings) : ViewModel()
|
||||
}
|
||||
}
|
||||
|
||||
fun setVideoFormat(value: String) {
|
||||
settings.putString(VideoAudioPreferences.KEY_DEFAULT_VIDEO_FORMAT, value)
|
||||
videoFormat.value = value
|
||||
fun setVideoFormat(value: String) = videoFormat.persist(VideoAudioPreferences.KEY_DEFAULT_VIDEO_FORMAT, value)
|
||||
|
||||
fun setAudioFormat(value: String) = audioFormat.persist(VideoAudioPreferences.KEY_DEFAULT_AUDIO_FORMAT, value)
|
||||
|
||||
fun setPreferOriginalAudio(value: Boolean) = preferOriginalAudio.persist(VideoAudioPreferences.KEY_PREFER_ORIGINAL_AUDIO, value)
|
||||
|
||||
fun setPreferDescriptiveAudio(value: Boolean) = preferDescriptiveAudio.persist(VideoAudioPreferences.KEY_PREFER_DESCRIPTIVE_AUDIO, value)
|
||||
|
||||
fun setUseExternalVideoPlayer(value: Boolean) = useExternalVideoPlayer.persist(VideoAudioPreferences.KEY_USE_EXTERNAL_VIDEO_PLAYER, value)
|
||||
|
||||
fun setUseExternalAudioPlayer(value: Boolean) = useExternalAudioPlayer.persist(VideoAudioPreferences.KEY_USE_EXTERNAL_AUDIO_PLAYER, value)
|
||||
|
||||
fun setShowPlayWithKodi(value: Boolean) = showPlayWithKodi.persist(VideoAudioPreferences.KEY_SHOW_PLAY_WITH_KODI, value)
|
||||
|
||||
fun setSeekbarPreviewThumbnail(value: String) = seekbarPreviewThumbnail.persist(VideoAudioPreferences.KEY_SEEKBAR_PREVIEW_THUMBNAIL, value)
|
||||
|
||||
fun setPreferredOpenAction(value: String) = preferredOpenAction.persist(VideoAudioPreferences.KEY_PREFERRED_OPEN_ACTION, value)
|
||||
|
||||
fun setMinimizeOnExit(value: String) = minimizeOnExit.persist(VideoAudioPreferences.KEY_MINIMIZE_ON_EXIT, value)
|
||||
|
||||
fun setStartMainPlayerFullscreen(value: Boolean) = startMainPlayerFullscreen.persist(VideoAudioPreferences.KEY_START_MAIN_PLAYER_FULLSCREEN, value)
|
||||
|
||||
fun setAutoplay(value: String) = autoplay.persist(VideoAudioPreferences.KEY_AUTOPLAY, value)
|
||||
|
||||
fun setAutoQueue(value: Boolean) = autoQueue.persist(VideoAudioPreferences.KEY_AUTO_QUEUE, value)
|
||||
|
||||
fun setResumeOnAudioFocusGain(value: Boolean) = resumeOnAudioFocusGain.persist(VideoAudioPreferences.KEY_RESUME_ON_AUDIO_FOCUS_GAIN, value)
|
||||
|
||||
fun setLeftGestureControl(value: String) = leftGestureControl.persist(VideoAudioPreferences.KEY_LEFT_GESTURE_CONTROL, value)
|
||||
|
||||
fun setRightGestureControl(value: String) = rightGestureControl.persist(VideoAudioPreferences.KEY_RIGHT_GESTURE_CONTROL, value)
|
||||
|
||||
fun setPopupRememberSizePos(value: Boolean) = popupRememberSizePos.persist(VideoAudioPreferences.KEY_POPUP_REMEMBER_SIZE_POS, value)
|
||||
|
||||
/**
|
||||
* Enabling inexact seek hides 5-second-step durations. If the current selection becomes
|
||||
* hidden it is bumped by 5 seconds, matching the legacy screen (which also showed a toast;
|
||||
* the screen shows a snackbar based on the same [VideoAudioPreferences.adjustedSeekDurationMs]).
|
||||
*/
|
||||
fun setUseInexactSeek(value: Boolean) {
|
||||
useInexactSeek.persist(VideoAudioPreferences.KEY_USE_INEXACT_SEEK, value)
|
||||
VideoAudioPreferences.adjustedSeekDurationMs(seekDuration.value, value)?.let(::setSeekDuration)
|
||||
}
|
||||
|
||||
fun setAudioFormat(value: String) {
|
||||
settings.putString(VideoAudioPreferences.KEY_DEFAULT_AUDIO_FORMAT, value)
|
||||
audioFormat.value = value
|
||||
fun setSeekDuration(value: String) = seekDuration.persist(VideoAudioPreferences.KEY_SEEK_DURATION, value)
|
||||
|
||||
fun setClearQueueConfirmation(value: Boolean) = clearQueueConfirmation.persist(VideoAudioPreferences.KEY_CLEAR_QUEUE_CONFIRMATION, value)
|
||||
|
||||
fun setIgnoreHardwareMediaButtons(value: Boolean) = ignoreHardwareMediaButtons.persist(VideoAudioPreferences.KEY_IGNORE_HARDWARE_MEDIA_BUTTONS, value)
|
||||
|
||||
private fun stringFlow(key: String, defaultValue: String) = MutableStateFlow(settings.getString(key, defaultValue))
|
||||
|
||||
private fun booleanFlow(key: String, defaultValue: Boolean) = MutableStateFlow(settings.getBoolean(key, defaultValue))
|
||||
|
||||
private fun MutableStateFlow<String>.persist(key: String, newValue: String) {
|
||||
settings.putString(key, newValue)
|
||||
value = newValue
|
||||
}
|
||||
|
||||
fun setPreferOriginalAudio(value: Boolean) {
|
||||
settings.putBoolean(VideoAudioPreferences.KEY_PREFER_ORIGINAL_AUDIO, value)
|
||||
preferOriginalAudio.value = value
|
||||
}
|
||||
|
||||
fun setPreferDescriptiveAudio(value: Boolean) {
|
||||
settings.putBoolean(VideoAudioPreferences.KEY_PREFER_DESCRIPTIVE_AUDIO, value)
|
||||
preferDescriptiveAudio.value = value
|
||||
private fun MutableStateFlow<Boolean>.persist(key: String, newValue: Boolean) {
|
||||
settings.putBoolean(key, newValue)
|
||||
value = newValue
|
||||
}
|
||||
}
|
||||
|
||||
+16
-1
@@ -8,6 +8,7 @@ package net.newpipe.app.screen.settings
|
||||
import androidx.compose.ui.test.ExperimentalTestApi
|
||||
import androidx.compose.ui.test.assertIsDisplayed
|
||||
import androidx.compose.ui.test.onNodeWithText
|
||||
import androidx.compose.ui.test.performScrollTo
|
||||
import androidx.compose.ui.test.v2.runComposeUiTest
|
||||
import com.russhwolf.settings.MapSettings
|
||||
import com.russhwolf.settings.Settings
|
||||
@@ -17,6 +18,7 @@ import net.newpipe.app.preferences.VideoAudioPreferences
|
||||
import newpipe.shared.generated.resources.Res
|
||||
import newpipe.shared.generated.resources.best_resolution
|
||||
import newpipe.shared.generated.resources.default_resolution_title
|
||||
import newpipe.shared.generated.resources.settings_category_player_title
|
||||
import newpipe.shared.generated.resources.settings_category_video_audio_title
|
||||
import org.jetbrains.compose.resources.getString
|
||||
import org.koin.dsl.module
|
||||
@@ -40,6 +42,19 @@ class VideoAudioSettingsScreenTest {
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun rendersPlayerCategoryHeader() = runComposeUiTest {
|
||||
withKoin(
|
||||
modules = listOf(emptySettings),
|
||||
content = { VideoAudioSettingsScreenContent() },
|
||||
onContent = {
|
||||
onNodeWithText(getString(Res.string.settings_category_player_title))
|
||||
.performScrollTo()
|
||||
.assertIsDisplayed()
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun bestResolutionShowsLocalizedLabelAsSummary() = runComposeUiTest {
|
||||
withKoin(
|
||||
@@ -52,4 +67,4 @@ class VideoAudioSettingsScreenTest {
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user