mirror of
https://github.com/TeamNewPipe/NewPipe
synced 2026-10-10 17:51:48 +00:00
add exoplayer settings
This commit is contained in:
committed by
Aayush Gupta
parent
561afbf5a6
commit
a663449f05
@@ -23,7 +23,7 @@
|
||||
<string name="website_title">Website</string>
|
||||
<string name="website_encouragement">Visit the NewPipe Website for more info and news.</string>
|
||||
<string name="privacy_policy_title">NewPipe's Privacy Policy</string>
|
||||
<string name="privacy_policy_encouragement">The NewPipe project takes your privacy very seriously. Therefore, the app does not collect any data without your consent.\nNewPipe\'s privacy policy explains in detail what data is sent and stored when you send a crash report.</string>
|
||||
<string name="privacy_policy_encouragement">The NewPipe project takes your privacy very seriously. Therefore, the app does not collect any data without your consent.\nNewPipe's privacy policy explains in detail what data is sent and stored when you send a crash report.</string>
|
||||
<string name="read_privacy_policy">Read privacy policy</string>
|
||||
<string name="app_license_title">NewPipe's License</string>
|
||||
<string name="app_license">NewPipe is copyleft libre software: You can use, study, share, and improve it at will. Specifically you can redistribute and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.</string>
|
||||
@@ -59,7 +59,7 @@
|
||||
<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_summary">Show tip when pressing the background or the popup button in video \"Details:\"</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>
|
||||
<string name="caption_setting_title">Captions</string>
|
||||
@@ -99,7 +99,7 @@
|
||||
<string name="seekbar_preview_thumbnail_title">Seekbar thumbnail preview</string>
|
||||
<string name="high_quality_larger">High quality (larger)</string>
|
||||
<string name="low_quality_smaller">Low quality (smaller)</string>
|
||||
<string name="dont_show">Don\'t show</string>
|
||||
<string name="dont_show">Don't show</string>
|
||||
|
||||
<!-- Video/Audio Settings: Behavior section -->
|
||||
<string name="settings_category_player_behavior_title">Behavior</string>
|
||||
@@ -139,7 +139,7 @@
|
||||
<string name="popup_remember_size_pos_title">Remember popup properties</string>
|
||||
<string name="popup_remember_size_pos_summary">Remember last size and position of popup</string>
|
||||
<string name="use_inexact_seek_title">Use fast inexact seek</string>
|
||||
<string name="use_inexact_seek_summary">Inexact seek allows the player to seek to positions faster with reduced precision. Seeking for 5, 15 or 25 seconds doesn\'t work with this</string>
|
||||
<string name="use_inexact_seek_summary">Inexact seek allows the player to seek to positions faster with reduced precision. Seeking for 5, 15 or 25 seconds doesn't work with this</string>
|
||||
<string name="seek_duration_title">Fast-forward/-rewind seek duration</string>
|
||||
<string name="new_seek_duration_toast">Due to ExoPlayer constraints the seek duration was set to %1$d seconds</string>
|
||||
<string name="clear_queue_confirmation_title">Ask for confirmation before clearing a queue</string>
|
||||
@@ -151,5 +151,19 @@
|
||||
<item quantity="other">%1$d seconds</item>
|
||||
</plurals>
|
||||
|
||||
<!-- ExoPlayer Settings -->
|
||||
<string name="settings_category_exoplayer_title">ExoPlayer settings</string>
|
||||
<string name="settings_category_exoplayer_summary">Manage some ExoPlayer settings. These changes require a player restart to take effect</string>
|
||||
<string name="progressive_load_interval_title">Playback load interval size</string>
|
||||
<string name="progressive_load_interval_summary">Change the load interval size on progressive contents (currently %1$s). A lower value may speed up their initial loading</string>
|
||||
<string name="progressive_load_interval_exoplayer_default">ExoPlayer default</string>
|
||||
<string name="use_exoplayer_decoder_fallback_title">Use ExoPlayer's decoder fallback feature</string>
|
||||
<string name="use_exoplayer_decoder_fallback_summary">Enable this option if you have decoder initialization issues, which falls back to lower-priority decoders if primary decoders initialization fail. This may result in poor playback performance than when using primary decoders</string>
|
||||
<string name="disable_media_tunneling_title">Disable media tunneling</string>
|
||||
<string name="disable_media_tunneling_summary">Disable media tunneling if you experience a black screen or stuttering on video playback.</string>
|
||||
<string name="disable_media_tunneling_automatic_info">Media tunneling was disabled by default on your device because your device model is known to not support it.</string>
|
||||
<string name="always_use_exoplayer_set_output_surface_workaround_title">Always use ExoPlayer's video output surface setting workaround</string>
|
||||
<string name="always_use_exoplayer_set_output_surface_workaround_summary">This workaround releases and re-instantiates video codecs when a surface change occurs, instead of setting the surface to the codec directly. Already used by ExoPlayer on some devices with this issue, this setting has only an effect on Android 6 and higher\n\nEnabling this option may prevent playback errors when switching the current video player or switching to fullscreen</string>
|
||||
|
||||
|
||||
</resources>
|
||||
|
||||
@@ -15,6 +15,9 @@ import net.newpipe.app.model.License
|
||||
@Serializable
|
||||
sealed interface Destination : NavKey {
|
||||
|
||||
@Serializable
|
||||
data object ExoPlayerSettings : Destination
|
||||
|
||||
@Serializable
|
||||
data object VideoAudioSettings : Destination
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ import androidx.compose.runtime.mutableStateListOf
|
||||
import co.touchlab.kermit.Logger
|
||||
import net.newpipe.app.screen.about.AboutScreen
|
||||
import net.newpipe.app.screen.settings.AppearanceSettingsScreen
|
||||
import net.newpipe.app.screen.settings.ExoPlayerSettingsScreen
|
||||
import net.newpipe.app.screen.settings.SettingsHomeScreen
|
||||
import net.newpipe.app.screen.settings.VideoAudioSettingsScreen
|
||||
import org.koin.core.annotation.KoinExperimentalAPI
|
||||
@@ -42,6 +43,10 @@ fun navModule() = module {
|
||||
navigation<Destination.VideoAudioSettings> {
|
||||
VideoAudioSettingsScreen()
|
||||
}
|
||||
|
||||
navigation<Destination.ExoPlayerSettings> {
|
||||
ExoPlayerSettingsScreen()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2026 NewPipe e.V. <https://newpipe-ev.de>
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
package net.newpipe.app.preferences
|
||||
|
||||
object ExoPlayerPreferences {
|
||||
const val KEY_PROGRESSIVE_LOAD_INTERVAL = "progressive_load_interval"
|
||||
const val KEY_USE_EXOPLAYER_DECODER_FALLBACK = "use_exoplayer_decoder_fallback_key"
|
||||
const val KEY_DISABLE_MEDIA_TUNNELING = "disable_media_tunneling_key"
|
||||
const val KEY_DISABLED_MEDIA_TUNNELING_AUTOMATICALLY = "disabled_media_tunneling_automatically_key"
|
||||
const val KEY_ALWAYS_USE_SET_OUTPUT_SURFACE_WORKAROUND = "always_use_exoplayer_set_output_surface_workaround_key"
|
||||
|
||||
const val PROGRESSIVE_LOAD_INTERVAL_EXOPLAYER_DEFAULT = "exoplayer_default"
|
||||
|
||||
const val DEFAULT_PROGRESSIVE_LOAD_INTERVAL = "64"
|
||||
const val DEFAULT_USE_EXOPLAYER_DECODER_FALLBACK = false
|
||||
const val DEFAULT_DISABLE_MEDIA_TUNNELING = false
|
||||
const val DEFAULT_ALWAYS_USE_SET_OUTPUT_SURFACE_WORKAROUND = false
|
||||
|
||||
const val MEDIA_TUNNELING_AUTO_DISABLED = 1
|
||||
const val MEDIA_TUNNELING_USER_MANAGED = 0
|
||||
const val MEDIA_TUNNELING_FLAG_UNSET = -1
|
||||
|
||||
val PROGRESSIVE_LOAD_INTERVALS = listOf("1", "16", "64", "256", PROGRESSIVE_LOAD_INTERVAL_EXOPLAYER_DEFAULT)
|
||||
}
|
||||
+151
@@ -0,0 +1,151 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2026 NewPipe e.V. <https://newpipe-ev.de>
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
package net.newpipe.app.screen.settings
|
||||
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.WindowInsets
|
||||
import androidx.compose.foundation.layout.asPaddingValues
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.navigationBars
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
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 net.newpipe.app.composable.ListPreference
|
||||
import net.newpipe.app.composable.ListPreferenceEntry
|
||||
import net.newpipe.app.composable.SwitchPreference
|
||||
import net.newpipe.app.composable.TopAppBar
|
||||
import net.newpipe.app.navigation.Navigator
|
||||
import net.newpipe.app.preferences.ExoPlayerPreferences
|
||||
import net.newpipe.app.preview.ThemePreviewProvider
|
||||
import net.newpipe.app.viewmodel.settings.ExoPlayerSettingsViewModel
|
||||
import newpipe.shared.generated.resources.Res
|
||||
import newpipe.shared.generated.resources.always_use_exoplayer_set_output_surface_workaround_summary
|
||||
import newpipe.shared.generated.resources.always_use_exoplayer_set_output_surface_workaround_title
|
||||
import newpipe.shared.generated.resources.disable_media_tunneling_automatic_info
|
||||
import newpipe.shared.generated.resources.disable_media_tunneling_summary
|
||||
import newpipe.shared.generated.resources.disable_media_tunneling_title
|
||||
import newpipe.shared.generated.resources.progressive_load_interval_exoplayer_default
|
||||
import newpipe.shared.generated.resources.progressive_load_interval_summary
|
||||
import newpipe.shared.generated.resources.progressive_load_interval_title
|
||||
import newpipe.shared.generated.resources.settings_category_exoplayer_title
|
||||
import newpipe.shared.generated.resources.use_exoplayer_decoder_fallback_summary
|
||||
import newpipe.shared.generated.resources.use_exoplayer_decoder_fallback_title
|
||||
import org.jetbrains.compose.resources.stringResource
|
||||
import org.koin.compose.koinInject
|
||||
import org.koin.compose.viewmodel.koinViewModel
|
||||
|
||||
@Composable
|
||||
fun ExoPlayerSettingsScreen(
|
||||
navigator: Navigator = koinInject(),
|
||||
viewModel: ExoPlayerSettingsViewModel = koinViewModel()
|
||||
) {
|
||||
val progressiveLoadInterval by viewModel.progressiveLoadInterval.collectAsStateWithLifecycle()
|
||||
val useExoplayerDecoderFallback by viewModel.useExoplayerDecoderFallback.collectAsStateWithLifecycle()
|
||||
val disableMediaTunneling by viewModel.disableMediaTunneling.collectAsStateWithLifecycle()
|
||||
val mediaTunnelingAutoDisabled by viewModel.mediaTunnelingAutoDisabled.collectAsStateWithLifecycle()
|
||||
val alwaysUseSetOutputSurfaceWorkaround by viewModel.alwaysUseSetOutputSurfaceWorkaround.collectAsStateWithLifecycle()
|
||||
|
||||
ExoPlayerSettingsScreenContent(
|
||||
progressiveLoadInterval = progressiveLoadInterval,
|
||||
useExoplayerDecoderFallback = useExoplayerDecoderFallback,
|
||||
disableMediaTunneling = disableMediaTunneling,
|
||||
mediaTunnelingAutoDisabled = mediaTunnelingAutoDisabled,
|
||||
alwaysUseSetOutputSurfaceWorkaround = alwaysUseSetOutputSurfaceWorkaround,
|
||||
onProgressiveLoadIntervalChange = viewModel::setProgressiveLoadInterval,
|
||||
onUseExoplayerDecoderFallbackChange = viewModel::setUseExoplayerDecoderFallback,
|
||||
onDisableMediaTunnelingChange = viewModel::setDisableMediaTunneling,
|
||||
onAlwaysUseSetOutputSurfaceWorkaroundChange = viewModel::setAlwaysUseSetOutputSurfaceWorkaround,
|
||||
onNavigateUp = { navigator.navigateUp() }
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun ExoPlayerSettingsScreenContent(
|
||||
progressiveLoadInterval: String = ExoPlayerPreferences.DEFAULT_PROGRESSIVE_LOAD_INTERVAL,
|
||||
useExoplayerDecoderFallback: Boolean = ExoPlayerPreferences.DEFAULT_USE_EXOPLAYER_DECODER_FALLBACK,
|
||||
disableMediaTunneling: Boolean = ExoPlayerPreferences.DEFAULT_DISABLE_MEDIA_TUNNELING,
|
||||
mediaTunnelingAutoDisabled: Boolean = false,
|
||||
alwaysUseSetOutputSurfaceWorkaround: Boolean = ExoPlayerPreferences.DEFAULT_ALWAYS_USE_SET_OUTPUT_SURFACE_WORKAROUND,
|
||||
onProgressiveLoadIntervalChange: (String) -> Unit = {},
|
||||
onUseExoplayerDecoderFallbackChange: (Boolean) -> Unit = {},
|
||||
onDisableMediaTunnelingChange: (Boolean) -> Unit = {},
|
||||
onAlwaysUseSetOutputSurfaceWorkaroundChange: (Boolean) -> Unit = {},
|
||||
onNavigateUp: () -> Unit = {}
|
||||
) {
|
||||
val exoPlayerDefaultLabel = stringResource(Res.string.progressive_load_interval_exoplayer_default)
|
||||
|
||||
val loadIntervalEntries = ExoPlayerPreferences.PROGRESSIVE_LOAD_INTERVALS.map { value ->
|
||||
ListPreferenceEntry(
|
||||
value = value,
|
||||
title = if (value == ExoPlayerPreferences.PROGRESSIVE_LOAD_INTERVAL_EXOPLAYER_DEFAULT) exoPlayerDefaultLabel else "$value KiB"
|
||||
)
|
||||
}
|
||||
val selectedLoadIntervalTitle = loadIntervalEntries.firstOrNull { it.value == progressiveLoadInterval }?.title.orEmpty()
|
||||
|
||||
val tunnelingBaseSummary = stringResource(Res.string.disable_media_tunneling_summary)
|
||||
val tunnelingSummary = if (mediaTunnelingAutoDisabled) {
|
||||
tunnelingBaseSummary + " " + stringResource(Res.string.disable_media_tunneling_automatic_info)
|
||||
} else {
|
||||
tunnelingBaseSummary
|
||||
}
|
||||
|
||||
Scaffold(
|
||||
topBar = {
|
||||
TopAppBar(
|
||||
title = stringResource(Res.string.settings_category_exoplayer_title),
|
||||
onNavigateUp = onNavigateUp
|
||||
)
|
||||
}
|
||||
) { paddingValues ->
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.padding(top = paddingValues.calculateTopPadding())
|
||||
.verticalScroll(rememberScrollState())
|
||||
.padding(WindowInsets.navigationBars.asPaddingValues())
|
||||
) {
|
||||
ListPreference(
|
||||
title = stringResource(Res.string.progressive_load_interval_title),
|
||||
entries = loadIntervalEntries,
|
||||
selectedValue = progressiveLoadInterval,
|
||||
onValueSelected = onProgressiveLoadIntervalChange,
|
||||
summary = stringResource(Res.string.progressive_load_interval_summary, selectedLoadIntervalTitle)
|
||||
)
|
||||
SwitchPreference(
|
||||
title = stringResource(Res.string.use_exoplayer_decoder_fallback_title),
|
||||
summary = stringResource(Res.string.use_exoplayer_decoder_fallback_summary),
|
||||
checked = useExoplayerDecoderFallback,
|
||||
onCheckedChange = onUseExoplayerDecoderFallbackChange
|
||||
)
|
||||
SwitchPreference(
|
||||
title = stringResource(Res.string.disable_media_tunneling_title),
|
||||
summary = tunnelingSummary,
|
||||
checked = disableMediaTunneling,
|
||||
onCheckedChange = onDisableMediaTunnelingChange
|
||||
)
|
||||
SwitchPreference(
|
||||
title = stringResource(Res.string.always_use_exoplayer_set_output_surface_workaround_title),
|
||||
summary = stringResource(Res.string.always_use_exoplayer_set_output_surface_workaround_summary),
|
||||
checked = alwaysUseSetOutputSurfaceWorkaround,
|
||||
onCheckedChange = onAlwaysUseSetOutputSurfaceWorkaroundChange
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@PreviewWrapper(ThemePreviewProvider::class)
|
||||
@PreviewLightDark
|
||||
@Composable
|
||||
private fun ExoPlayerSettingsScreenPreview() {
|
||||
ExoPlayerSettingsScreenContent()
|
||||
}
|
||||
+11
-3
@@ -28,8 +28,10 @@ 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.PreferenceRow
|
||||
import net.newpipe.app.composable.SwitchPreference
|
||||
import net.newpipe.app.composable.TopAppBar
|
||||
import net.newpipe.app.navigation.Destination
|
||||
import net.newpipe.app.navigation.Navigator
|
||||
import net.newpipe.app.preferences.VideoAudioPreferences
|
||||
import net.newpipe.app.preview.ThemePreviewProvider
|
||||
@@ -86,6 +88,8 @@ 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_exoplayer_summary
|
||||
import newpipe.shared.generated.resources.settings_category_exoplayer_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
|
||||
@@ -206,6 +210,7 @@ fun VideoAudioSettingsScreen(
|
||||
onSeekDurationChange = viewModel::setSeekDuration,
|
||||
onClearQueueConfirmationChange = viewModel::setClearQueueConfirmation,
|
||||
onIgnoreHardwareMediaButtonsChange = viewModel::setIgnoreHardwareMediaButtons,
|
||||
onOpenExoPlayerSettings = { navigator.navigateTo(Destination.ExoPlayerSettings) },
|
||||
onNavigateUp = { navigator.navigateUp() }
|
||||
)
|
||||
}
|
||||
@@ -265,6 +270,7 @@ fun VideoAudioSettingsScreenContent(
|
||||
onSeekDurationChange: (String) -> Unit = {},
|
||||
onClearQueueConfirmationChange: (Boolean) -> Unit = {},
|
||||
onIgnoreHardwareMediaButtonsChange: (Boolean) -> Unit = {},
|
||||
onOpenExoPlayerSettings: () -> Unit = {},
|
||||
onNavigateUp: () -> Unit = {}
|
||||
) {
|
||||
val scope = rememberCoroutineScope()
|
||||
@@ -393,7 +399,11 @@ fun VideoAudioSettingsScreenContent(
|
||||
onCheckedChange = onPreferDescriptiveAudioChange
|
||||
)
|
||||
|
||||
// TODO: ExoPlayer settings sub-screen link goes here once that screen is migrated.
|
||||
PreferenceRow(
|
||||
title = stringResource(Res.string.settings_category_exoplayer_title),
|
||||
summary = stringResource(Res.string.settings_category_exoplayer_summary),
|
||||
onClick = onOpenExoPlayerSettings
|
||||
)
|
||||
|
||||
PreferenceCategoryTitle(title = stringResource(Res.string.settings_category_player_title))
|
||||
SwitchPreference(
|
||||
@@ -497,8 +507,6 @@ fun VideoAudioSettingsScreenContent(
|
||||
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 {
|
||||
|
||||
+68
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2026 NewPipe e.V. <https://newpipe-ev.de>
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
package net.newpipe.app.viewmodel.settings
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import com.russhwolf.settings.Settings
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import net.newpipe.app.preferences.ExoPlayerPreferences
|
||||
import org.koin.core.annotation.KoinViewModel
|
||||
|
||||
@KoinViewModel
|
||||
class ExoPlayerSettingsViewModel(private val settings: Settings) : ViewModel() {
|
||||
|
||||
val progressiveLoadInterval: StateFlow<String>
|
||||
field = stringFlow(ExoPlayerPreferences.KEY_PROGRESSIVE_LOAD_INTERVAL, ExoPlayerPreferences.DEFAULT_PROGRESSIVE_LOAD_INTERVAL)
|
||||
|
||||
val useExoplayerDecoderFallback: StateFlow<Boolean>
|
||||
field = booleanFlow(ExoPlayerPreferences.KEY_USE_EXOPLAYER_DECODER_FALLBACK, ExoPlayerPreferences.DEFAULT_USE_EXOPLAYER_DECODER_FALLBACK)
|
||||
|
||||
val disableMediaTunneling: StateFlow<Boolean>
|
||||
field = booleanFlow(ExoPlayerPreferences.KEY_DISABLE_MEDIA_TUNNELING, ExoPlayerPreferences.DEFAULT_DISABLE_MEDIA_TUNNELING)
|
||||
|
||||
val alwaysUseSetOutputSurfaceWorkaround: StateFlow<Boolean>
|
||||
field = booleanFlow(ExoPlayerPreferences.KEY_ALWAYS_USE_SET_OUTPUT_SURFACE_WORKAROUND, ExoPlayerPreferences.DEFAULT_ALWAYS_USE_SET_OUTPUT_SURFACE_WORKAROUND)
|
||||
|
||||
val mediaTunnelingAutoDisabled: StateFlow<Boolean>
|
||||
field = MutableStateFlow(
|
||||
settings.getInt(
|
||||
ExoPlayerPreferences.KEY_DISABLED_MEDIA_TUNNELING_AUTOMATICALLY,
|
||||
ExoPlayerPreferences.MEDIA_TUNNELING_FLAG_UNSET
|
||||
) == ExoPlayerPreferences.MEDIA_TUNNELING_AUTO_DISABLED
|
||||
)
|
||||
|
||||
fun setProgressiveLoadInterval(value: String) = progressiveLoadInterval.persist(ExoPlayerPreferences.KEY_PROGRESSIVE_LOAD_INTERVAL, value)
|
||||
|
||||
fun setUseExoplayerDecoderFallback(value: Boolean) = useExoplayerDecoderFallback.persist(ExoPlayerPreferences.KEY_USE_EXOPLAYER_DECODER_FALLBACK, value)
|
||||
|
||||
fun setDisableMediaTunneling(value: Boolean) {
|
||||
disableMediaTunneling.persist(ExoPlayerPreferences.KEY_DISABLE_MEDIA_TUNNELING, value)
|
||||
if (!value) {
|
||||
settings.putInt(
|
||||
ExoPlayerPreferences.KEY_DISABLED_MEDIA_TUNNELING_AUTOMATICALLY,
|
||||
ExoPlayerPreferences.MEDIA_TUNNELING_USER_MANAGED
|
||||
)
|
||||
mediaTunnelingAutoDisabled.value = false
|
||||
}
|
||||
}
|
||||
|
||||
fun setAlwaysUseSetOutputSurfaceWorkaround(value: Boolean) = alwaysUseSetOutputSurfaceWorkaround.persist(ExoPlayerPreferences.KEY_ALWAYS_USE_SET_OUTPUT_SURFACE_WORKAROUND, 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
|
||||
}
|
||||
|
||||
private fun MutableStateFlow<Boolean>.persist(key: String, newValue: Boolean) {
|
||||
settings.putBoolean(key, newValue)
|
||||
value = newValue
|
||||
}
|
||||
}
|
||||
+67
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2026 NewPipe e.V. <https://newpipe-ev.de>
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
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
|
||||
import kotlin.test.Test
|
||||
import net.newpipe.app.extensions.withKoin
|
||||
import newpipe.shared.generated.resources.Res
|
||||
import newpipe.shared.generated.resources.disable_media_tunneling_automatic_info
|
||||
import newpipe.shared.generated.resources.progressive_load_interval_summary
|
||||
import newpipe.shared.generated.resources.progressive_load_interval_title
|
||||
import newpipe.shared.generated.resources.settings_category_exoplayer_title
|
||||
import org.jetbrains.compose.resources.getString
|
||||
import org.koin.dsl.module
|
||||
|
||||
@OptIn(ExperimentalTestApi::class)
|
||||
class ExoPlayerSettingsScreenTest {
|
||||
|
||||
private val emptySettings = module {
|
||||
single<Settings> { MapSettings() }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun rendersTitleAndLoadIntervalRow() = runComposeUiTest {
|
||||
withKoin(
|
||||
modules = listOf(emptySettings),
|
||||
content = { ExoPlayerSettingsScreenContent() },
|
||||
onContent = {
|
||||
onNodeWithText(getString(Res.string.settings_category_exoplayer_title)).assertIsDisplayed()
|
||||
onNodeWithText(getString(Res.string.progressive_load_interval_title)).assertIsDisplayed()
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun loadIntervalSummaryShowsSelectedEntryLabel() = runComposeUiTest {
|
||||
withKoin(
|
||||
modules = listOf(emptySettings),
|
||||
content = { ExoPlayerSettingsScreenContent() },
|
||||
onContent = {
|
||||
onNodeWithText(getString(Res.string.progressive_load_interval_summary, "64 KiB")).assertIsDisplayed()
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun mediaTunnelingInfoShownOnlyWhenAutoDisabled() = runComposeUiTest {
|
||||
withKoin(
|
||||
modules = listOf(emptySettings),
|
||||
content = { ExoPlayerSettingsScreenContent(mediaTunnelingAutoDisabled = true) },
|
||||
onContent = {
|
||||
onNodeWithText(getString(Res.string.disable_media_tunneling_automatic_info), substring = true)
|
||||
.performScrollTo()
|
||||
.assertIsDisplayed()
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
+14
@@ -18,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_exoplayer_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
|
||||
@@ -67,4 +68,17 @@ class VideoAudioSettingsScreenTest {
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun rendersExoPlayerSettingsLink() = runComposeUiTest {
|
||||
withKoin(
|
||||
modules = listOf(emptySettings),
|
||||
content = { VideoAudioSettingsScreenContent() },
|
||||
onContent = {
|
||||
onNodeWithText(getString(Res.string.settings_category_exoplayer_title))
|
||||
.performScrollTo()
|
||||
.assertIsDisplayed()
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user