Skip to content

Commit

Permalink
feat: Move player preferences into their own menu (#1819)
Browse files Browse the repository at this point in the history
  • Loading branch information
Secozzi authored Nov 9, 2024
1 parent 37e1834 commit 33c8137
Show file tree
Hide file tree
Showing 22 changed files with 1,167 additions and 314 deletions.
9 changes: 9 additions & 0 deletions app/src/main/java/eu/kanade/presentation/more/MoreScreen.kt
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import androidx.compose.material.icons.outlined.Info
import androidx.compose.material.icons.outlined.QueryStats
import androidx.compose.material.icons.outlined.Settings
import androidx.compose.material.icons.outlined.Storage
import androidx.compose.material.icons.outlined.VideoSettings
import androidx.compose.material3.HorizontalDivider
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
Expand Down Expand Up @@ -51,6 +52,7 @@ fun MoreScreen(
onClickStats: () -> Unit,
onClickStorage: () -> Unit,
onClickDataAndStorage: () -> Unit,
onClickPlayerSettings: () -> Unit,
onClickSettings: () -> Unit,
onClickAbout: () -> Unit,
) {
Expand Down Expand Up @@ -178,6 +180,13 @@ fun MoreScreen(
onPreferenceClick = onClickSettings,
)
}
item {
TextPreferenceWidget(
title = stringResource(MR.strings.label_player_settings),
icon = Icons.Outlined.VideoSettings,
onPreferenceClick = onClickPlayerSettings,
)
}
item {
TextPreferenceWidget(
title = stringResource(MR.strings.pref_category_about),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.graphics.vector.ImageVector
import eu.kanade.core.preference.asState
import eu.kanade.presentation.more.settings.Preference.PreferenceItem
import eu.kanade.tachiyomi.data.track.Tracker
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.ImmutableMap
Expand Down Expand Up @@ -199,6 +200,20 @@ sealed class Preference {
val canBeBlank: Boolean = true,
) : PreferenceItem<String>()

/**
* A [PreferenceItem] that shows a EditText with a subtitle in the dialog.
* Unlike [EditTextPreference], empty values can be set and a subtitle in the dialog can be show.
*/
data class EditTextInfoPreference(
val pref: PreferenceData<String>,
val dialogSubtitle: String?,
override val title: String,
override val subtitle: String? = "%s",
override val icon: ImageVector? = null,
override val enabled: Boolean = true,
override val onValueChanged: suspend (newValue: String) -> Boolean = { true },
) : PreferenceItem<String>()

/**
* A [PreferenceItem] for individual tracker.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,23 @@ internal fun PreferenceItem(
canBeBlank = item.canBeBlank,
)
}
is Preference.PreferenceItem.EditTextInfoPreference -> {
val values by item.pref.collectAsState()
EditTextPreferenceWidget(
title = item.title,
subtitle = item.subtitle,
dialogSubtitle = item.dialogSubtitle,
icon = item.icon,
value = values,
onConfirm = {
val accepted = item.onValueChanged(it)
if (accepted) item.pref.set(it)
accepted
},
singleLine = true,
canBeBlank = true,
)
}
is Preference.PreferenceItem.TrackerPreference -> {
val isLoggedIn by item.tracker.let { tracker ->
tracker.isLoggedInFlow.collectAsState(tracker.isLoggedIn)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import androidx.compose.material.icons.outlined.Explore
import androidx.compose.material.icons.outlined.GetApp
import androidx.compose.material.icons.outlined.Info
import androidx.compose.material.icons.outlined.Palette
import androidx.compose.material.icons.outlined.PlayCircleOutline
import androidx.compose.material.icons.outlined.Search
import androidx.compose.material.icons.outlined.Security
import androidx.compose.material.icons.outlined.Storage
Expand Down Expand Up @@ -186,12 +185,6 @@ object SettingsMainScreen : Screen() {
icon = Icons.Outlined.CollectionsBookmark,
screen = SettingsLibraryScreen,
),
Item(
titleRes = MR.strings.pref_category_player,
subtitleRes = MR.strings.pref_player_summary,
icon = Icons.Outlined.PlayCircleOutline,
screen = SettingsPlayerScreen,
),
Item(
titleRes = MR.strings.pref_category_reader,
subtitleRes = MR.strings.pref_reader_summary,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,12 @@ import cafe.adriel.voyager.navigator.LocalNavigator
import cafe.adriel.voyager.navigator.currentOrThrow
import eu.kanade.presentation.components.UpIcon
import eu.kanade.presentation.more.settings.Preference
import eu.kanade.presentation.more.settings.screen.player.PlayerSettingsAdvancedScreen
import eu.kanade.presentation.more.settings.screen.player.PlayerSettingsAudioScreen
import eu.kanade.presentation.more.settings.screen.player.PlayerSettingsDecoderScreen
import eu.kanade.presentation.more.settings.screen.player.PlayerSettingsGesturesScreen
import eu.kanade.presentation.more.settings.screen.player.PlayerSettingsPlayerScreen
import eu.kanade.presentation.more.settings.screen.player.PlayerSettingsSubtitleScreen
import eu.kanade.presentation.util.Screen
import tachiyomi.i18n.MR
import tachiyomi.presentation.core.components.material.Scaffold
Expand All @@ -58,7 +64,9 @@ import tachiyomi.presentation.core.screens.EmptyScreen
import tachiyomi.presentation.core.util.runOnEnterKeyPressed
import cafe.adriel.voyager.core.screen.Screen as VoyagerScreen

class SettingsSearchScreen : Screen() {
class SettingsSearchScreen(
val isPlayer: Boolean = false,
) : Screen() {
@Composable
override fun Content() {
val navigator = LocalNavigator.currentOrThrow
Expand Down Expand Up @@ -115,7 +123,13 @@ class SettingsSearchScreen : Screen() {
decorator = {
if (textFieldState.text.isEmpty()) {
Text(
text = stringResource(MR.strings.action_search_settings),
text = stringResource(
resource = if (isPlayer) {
MR.strings.action_search_player_settings
} else {
MR.strings.action_search_settings
},
),
color = MaterialTheme.colorScheme.onSurfaceVariant,
style = MaterialTheme.typography.bodyLarge,
)
Expand All @@ -142,6 +156,7 @@ class SettingsSearchScreen : Screen() {
) { contentPadding ->
SearchResult(
searchKey = textFieldState.text.toString(),
isPlayer = isPlayer,
listState = listState,
contentPadding = contentPadding,
) { result ->
Expand All @@ -155,6 +170,7 @@ class SettingsSearchScreen : Screen() {
@Composable
private fun SearchResult(
searchKey: String,
isPlayer: Boolean,
modifier: Modifier = Modifier,
listState: LazyListState = rememberLazyListState(),
contentPadding: PaddingValues = PaddingValues(),
Expand All @@ -164,7 +180,7 @@ private fun SearchResult(

val isLtr = LocalLayoutDirection.current == LayoutDirection.Ltr

val index = getIndex()
val index = if (isPlayer) getPlayerIndex() else getIndex()
val result by produceState<List<SearchResultItem>?>(initialValue = null, searchKey) {
value = index.asSequence()
.flatMap { settingsData ->
Expand Down Expand Up @@ -271,6 +287,17 @@ private fun getIndex() = settingScreens
)
}

@Composable
@NonRestartableComposable
private fun getPlayerIndex() = playerSettingScreens
.map { screen ->
SettingsData(
title = stringResource(screen.getTitleRes()),
route = screen,
contents = screen.getPreferences(),
)
}

private fun getLocalizedBreadcrumb(path: String, node: String?, isLtr: Boolean): String {
return if (node == null) {
path
Expand All @@ -285,11 +312,19 @@ private fun getLocalizedBreadcrumb(path: String, node: String?, isLtr: Boolean):
}
}

private val playerSettingScreens = listOf(
PlayerSettingsPlayerScreen,
PlayerSettingsGesturesScreen,
PlayerSettingsDecoderScreen,
PlayerSettingsSubtitleScreen,
PlayerSettingsAudioScreen,
PlayerSettingsAdvancedScreen,
)

private val settingScreens = listOf(
SettingsAppearanceScreen,
SettingsLibraryScreen,
SettingsReaderScreen,
SettingsPlayerScreen,
SettingsDownloadScreen,
SettingsTrackingScreen,
SettingsBrowseScreen,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package eu.kanade.presentation.more.settings.screen.player

import android.content.Intent
import android.net.Uri
import android.os.Build
import android.os.Environment
import android.provider.Settings
import androidx.compose.runtime.Composable
import androidx.compose.runtime.ReadOnlyComposable
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.platform.LocalContext
import eu.kanade.presentation.more.settings.Preference
import eu.kanade.presentation.more.settings.screen.SearchableSettings
import eu.kanade.tachiyomi.ui.player.settings.PlayerPreferences
import tachiyomi.i18n.MR
import tachiyomi.presentation.core.i18n.stringResource
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get

object PlayerSettingsAdvancedScreen : SearchableSettings {

@ReadOnlyComposable
@Composable
override fun getTitleRes() = MR.strings.pref_player_advanced

@Composable
override fun getPreferences(): List<Preference> {
val playerPreferences = remember { Injekt.get<PlayerPreferences>() }
val scope = rememberCoroutineScope()
val context = LocalContext.current

val enableScripts = playerPreferences.mpvScripts()
val mpvConf = playerPreferences.mpvConf()
val mpvInput = playerPreferences.mpvInput()

return listOf(
Preference.PreferenceItem.SwitchPreference(
title = stringResource(MR.strings.pref_mpv_scripts),
subtitle = stringResource(MR.strings.pref_mpv_scripts_summary),
pref = enableScripts,
onValueChanged = {
// Ask for external storage permission
if (it) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R && !Environment.isExternalStorageManager()) {
val intent = Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION)
intent.data = Uri.fromParts("package", context.packageName, null)
context.startActivity(intent)
}
}
true
},
),
Preference.PreferenceItem.MPVConfPreference(
pref = mpvConf,
title = stringResource(MR.strings.pref_mpv_conf),
fileName = "mpv.conf",
scope = scope,
context = context,
),
Preference.PreferenceItem.MPVConfPreference(
pref = mpvInput,
title = stringResource(MR.strings.pref_mpv_input),
fileName = "input.conf",
scope = scope,
context = context,
),
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package eu.kanade.presentation.more.settings.screen.player

import androidx.compose.runtime.Composable
import androidx.compose.runtime.ReadOnlyComposable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import eu.kanade.presentation.more.settings.Preference
import eu.kanade.presentation.more.settings.screen.SearchableSettings
import eu.kanade.tachiyomi.ui.player.settings.PlayerPreferences
import eu.kanade.tachiyomi.ui.player.viewer.AudioChannels
import kotlinx.collections.immutable.toImmutableMap
import tachiyomi.i18n.MR
import tachiyomi.presentation.core.i18n.stringResource
import tachiyomi.presentation.core.util.collectAsState
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get

object PlayerSettingsAudioScreen : SearchableSettings {

@ReadOnlyComposable
@Composable
override fun getTitleRes() = MR.strings.pref_player_audio

@Composable
override fun getPreferences(): List<Preference> {
val playerPreferences = remember { Injekt.get<PlayerPreferences>() }

val prefLangs = playerPreferences.preferredAudioLanguages()
val pitchCorrection = playerPreferences.enablePitchCorrection()
val audioChannels = playerPreferences.audioChannels()
val boostCapPref = playerPreferences.volumeBoostCap()
val boostCap by boostCapPref.collectAsState()

return listOf(
Preference.PreferenceItem.EditTextInfoPreference(
pref = prefLangs,
title = stringResource(MR.strings.pref_player_audio_lang),
dialogSubtitle = stringResource(MR.strings.pref_player_audio_lang_info),
),
Preference.PreferenceItem.SwitchPreference(
pref = pitchCorrection,
title = stringResource(MR.strings.pref_player_audio_pitch_correction),
subtitle = stringResource(MR.strings.pref_player_audio_pitch_correction_summary),
),
Preference.PreferenceItem.ListPreference(
pref = audioChannels,
title = stringResource(MR.strings.pref_player_audio_channels),
entries = AudioChannels.entries.associateWith {
stringResource(it.textRes)
}.toImmutableMap(),
),
Preference.PreferenceItem.SliderPreference(
value = boostCap,
title = stringResource(MR.strings.pref_player_audio_boost_cap),
subtitle = boostCap.toString(),
min = 0,
max = 200,
onValueChanged = {
boostCapPref.set(it)
true
},
),
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package eu.kanade.presentation.more.settings.screen.player

import androidx.compose.runtime.Composable
import androidx.compose.runtime.ReadOnlyComposable
import androidx.compose.runtime.remember
import eu.kanade.presentation.more.settings.Preference
import eu.kanade.presentation.more.settings.screen.SearchableSettings
import eu.kanade.tachiyomi.ui.player.settings.PlayerPreferences
import eu.kanade.tachiyomi.ui.player.viewer.VideoDebanding
import kotlinx.collections.immutable.toImmutableMap
import tachiyomi.i18n.MR
import tachiyomi.presentation.core.i18n.stringResource
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get

object PlayerSettingsDecoderScreen : SearchableSettings {

@ReadOnlyComposable
@Composable
override fun getTitleRes() = MR.strings.pref_player_decoder

@Composable
override fun getPreferences(): List<Preference> {
val playerPreferences = remember { Injekt.get<PlayerPreferences>() }

val tryHw = playerPreferences.tryHWDecoding()
val useGpuNext = playerPreferences.gpuNext()
val debanding = playerPreferences.videoDebanding()
val yuv420p = playerPreferences.useYUV420P()

return listOf(
Preference.PreferenceItem.SwitchPreference(
pref = tryHw,
title = stringResource(MR.strings.pref_try_hw),
),
Preference.PreferenceItem.SwitchPreference(
pref = useGpuNext,
title = stringResource(MR.strings.pref_gpu_next_title),
subtitle = stringResource(MR.strings.pref_gpu_next_subtitle),
),
Preference.PreferenceItem.ListPreference(
pref = debanding,
title = stringResource(MR.strings.pref_debanding_title),
entries = VideoDebanding.entries.associateWith {
stringResource(it.stringRes)
}.toImmutableMap(),
),
Preference.PreferenceItem.SwitchPreference(
pref = yuv420p,
title = stringResource(MR.strings.pref_use_yuv420p_title),
subtitle = stringResource(MR.strings.pref_use_yuv420p_subtitle),
),
)
}
}
Loading

0 comments on commit 33c8137

Please sign in to comment.