diff --git a/app/src/main/java/live/mehiz/mpvkt/preferences/DecoderPreferences.kt b/app/src/main/java/live/mehiz/mpvkt/preferences/DecoderPreferences.kt index 3284132..6f06136 100644 --- a/app/src/main/java/live/mehiz/mpvkt/preferences/DecoderPreferences.kt +++ b/app/src/main/java/live/mehiz/mpvkt/preferences/DecoderPreferences.kt @@ -9,4 +9,10 @@ class DecoderPreferences(preferenceStore: PreferenceStore) { val gpuNext = preferenceStore.getBoolean("gpu_next", false) val debanding = preferenceStore.getEnum("debanding", Debanding.None) val useYUV420P = preferenceStore.getBoolean("use_yuv420p", true) + + val brightnessFilter = preferenceStore.getInt("filter_brightness") + val saturationFilter = preferenceStore.getInt("filter_saturation") + val gammaFilter = preferenceStore.getInt("filter_gamma") + val contrastFilter = preferenceStore.getInt("filter_contrast") + val hueFilter = preferenceStore.getInt("filter_hue") } diff --git a/app/src/main/java/live/mehiz/mpvkt/ui/player/PlayerActivity.kt b/app/src/main/java/live/mehiz/mpvkt/ui/player/PlayerActivity.kt index ae2bc41..b1bc59d 100644 --- a/app/src/main/java/live/mehiz/mpvkt/ui/player/PlayerActivity.kt +++ b/app/src/main/java/live/mehiz/mpvkt/ui/player/PlayerActivity.kt @@ -195,6 +195,11 @@ class PlayerActivity : AppCompatActivity() { if (decoderPreferences.useYUV420P.get()) { MPVLib.setPropertyString("vf", "format=yuv420p") } + + VideoFilters.entries.forEach { + MPVLib.setPropertyInt(it.mpvProperty, it.preference(decoderPreferences).get()) + } + player.playbackSpeed = playerPreferences.defaultSpeed.get().toDouble() MPVLib.setPropertyBoolean("keep-open", true) MPVLib.setPropertyBoolean("input-default-bindings", true) diff --git a/app/src/main/java/live/mehiz/mpvkt/ui/player/PlayerEnums.kt b/app/src/main/java/live/mehiz/mpvkt/ui/player/PlayerEnums.kt index d8150bf..2693e55 100644 --- a/app/src/main/java/live/mehiz/mpvkt/ui/player/PlayerEnums.kt +++ b/app/src/main/java/live/mehiz/mpvkt/ui/player/PlayerEnums.kt @@ -2,6 +2,8 @@ package live.mehiz.mpvkt.ui.player import androidx.annotation.StringRes import live.mehiz.mpvkt.R +import live.mehiz.mpvkt.preferences.DecoderPreferences +import live.mehiz.mpvkt.preferences.preference.Preference enum class PlayerOrientation(@StringRes val titleRes: Int) { Free(R.string.pref_player_orientation_free), @@ -52,6 +54,7 @@ enum class Panels { SubtitleSettings, SubtitleDelay, AudioDelay, + VideoFilters, } enum class PlayerUpdates { @@ -65,3 +68,35 @@ enum class EndPlaybackReason(val value: String) { PlaybackCompleted("playback_completion"), Error("error"), } + +enum class VideoFilters( + @StringRes val titleRes: Int, + val preference: (DecoderPreferences) -> Preference, + val mpvProperty: String, +) { + BRIGHTNESS( + R.string.player_sheets_filters_brightness, + { it.brightnessFilter }, + "brightness", + ), + SATURATION( + R.string.player_sheets_filters_Saturation, + { it.saturationFilter }, + "saturation", + ), + CONTRAST( + R.string.player_sheets_filters_contrast, + { it.contrastFilter }, + "contrast", + ), + GAMMA( + R.string.player_sheets_filters_gamma, + { it.gammaFilter }, + "gamma", + ), + HUE( + R.string.player_sheets_filters_hue, + { it.hueFilter }, + "hue", + ), +} diff --git a/app/src/main/java/live/mehiz/mpvkt/ui/player/controls/PlayerPanels.kt b/app/src/main/java/live/mehiz/mpvkt/ui/player/controls/PlayerPanels.kt index bb137ba..3d060c9 100644 --- a/app/src/main/java/live/mehiz/mpvkt/ui/player/controls/PlayerPanels.kt +++ b/app/src/main/java/live/mehiz/mpvkt/ui/player/controls/PlayerPanels.kt @@ -17,6 +17,7 @@ import live.mehiz.mpvkt.ui.player.PlayerViewModel import live.mehiz.mpvkt.ui.player.controls.components.panels.AudioDelayPanel import live.mehiz.mpvkt.ui.player.controls.components.panels.SubtitleDelayPanel import live.mehiz.mpvkt.ui.player.controls.components.panels.SubtitleSettingsPanel +import live.mehiz.mpvkt.ui.player.controls.components.panels.VideoFiltersPanel import org.koin.compose.koinInject @Composable @@ -50,6 +51,11 @@ fun PlayerPanels(modifier: Modifier = Modifier) { viewModel.hideControls() AudioDelayPanel(onDismissRequest) } + + Panels.VideoFilters -> { + viewModel.hideControls() + VideoFiltersPanel(onDismissRequest) + } } } } diff --git a/app/src/main/java/live/mehiz/mpvkt/ui/player/controls/PlayerSheets.kt b/app/src/main/java/live/mehiz/mpvkt/ui/player/controls/PlayerSheets.kt index af8b573..445e86c 100644 --- a/app/src/main/java/live/mehiz/mpvkt/ui/player/controls/PlayerSheets.kt +++ b/app/src/main/java/live/mehiz/mpvkt/ui/player/controls/PlayerSheets.kt @@ -69,9 +69,7 @@ fun PlayerSheets() { { viewModel.selectAudio(it) }, { audioPicker.launch(arrayOf("*/*")) }, onOpenDelayPanel = { - viewModel.panelShown.update { - Panels.AudioDelay - } + viewModel.panelShown.update { Panels.AudioDelay } onDismissRequest() }, onDismissRequest, @@ -101,7 +99,13 @@ fun PlayerSheets() { } Sheets.More -> { - MoreSheet(onDismissRequest) + MoreSheet( + onDismissRequest, + onEnterFiltersPanel = { + viewModel.panelShown.update { Panels.VideoFilters } + onDismissRequest() + } + ) } } } diff --git a/app/src/main/java/live/mehiz/mpvkt/ui/player/controls/components/panels/SubtitleDelayPanel.kt b/app/src/main/java/live/mehiz/mpvkt/ui/player/controls/components/panels/SubtitleDelayPanel.kt index cd5fa27..d2435d0 100644 --- a/app/src/main/java/live/mehiz/mpvkt/ui/player/controls/components/panels/SubtitleDelayPanel.kt +++ b/app/src/main/java/live/mehiz/mpvkt/ui/player/controls/components/panels/SubtitleDelayPanel.kt @@ -57,7 +57,7 @@ fun SubtitleDelayPanel( ConstraintLayout( modifier = modifier .fillMaxSize() - .padding(16.dp), + .padding(MaterialTheme.spacing.medium), ) { val delayControlCard = createRef() @@ -170,10 +170,14 @@ fun DelayCard( modifier = modifier .widthIn(max = CARDS_MAX_WIDTH) .animateContentSize(), - colors = SubtitleSettingsCardColors(), + colors = panelCardsColors(), ) { Column( - Modifier.padding(horizontal = MaterialTheme.spacing.medium, vertical = MaterialTheme.spacing.smaller), + Modifier + .padding( + horizontal = MaterialTheme.spacing.medium, + vertical = MaterialTheme.spacing.smaller + ), verticalArrangement = Arrangement.spacedBy(MaterialTheme.spacing.smaller), ) { title() diff --git a/app/src/main/java/live/mehiz/mpvkt/ui/player/controls/components/panels/SubtitleSettingsColorsCard.kt b/app/src/main/java/live/mehiz/mpvkt/ui/player/controls/components/panels/SubtitleSettingsColorsCard.kt index fccb6c7..4cdce7e 100644 --- a/app/src/main/java/live/mehiz/mpvkt/ui/player/controls/components/panels/SubtitleSettingsColorsCard.kt +++ b/app/src/main/java/live/mehiz/mpvkt/ui/player/controls/components/panels/SubtitleSettingsColorsCard.kt @@ -65,7 +65,7 @@ fun SubtitleSettingsColorsCard( } }, modifier = modifier.widthIn(max = CARDS_MAX_WIDTH), - colors = SubtitleSettingsCardColors(), + colors = panelCardsColors(), ) { Column { var currentColorType by remember { mutableStateOf(SubColorType.Text) } diff --git a/app/src/main/java/live/mehiz/mpvkt/ui/player/controls/components/panels/SubtitleSettingsMiscellaneousCard.kt b/app/src/main/java/live/mehiz/mpvkt/ui/player/controls/components/panels/SubtitleSettingsMiscellaneousCard.kt index 1ce7a64..31c5dec 100644 --- a/app/src/main/java/live/mehiz/mpvkt/ui/player/controls/components/panels/SubtitleSettingsMiscellaneousCard.kt +++ b/app/src/main/java/live/mehiz/mpvkt/ui/player/controls/components/panels/SubtitleSettingsMiscellaneousCard.kt @@ -39,7 +39,7 @@ fun SubtitlesMiscellaneousCard(modifier: Modifier = Modifier) { }, onExpand = { isExpanded = !isExpanded }, modifier.widthIn(max = CARDS_MAX_WIDTH), - colors = SubtitleSettingsCardColors(), + colors = panelCardsColors(), ) { ProvidePreferenceLocals { Column { diff --git a/app/src/main/java/live/mehiz/mpvkt/ui/player/controls/components/panels/SubtitleSettingsPanel.kt b/app/src/main/java/live/mehiz/mpvkt/ui/player/controls/components/panels/SubtitleSettingsPanel.kt index a1a14b0..7835f01 100644 --- a/app/src/main/java/live/mehiz/mpvkt/ui/player/controls/components/panels/SubtitleSettingsPanel.kt +++ b/app/src/main/java/live/mehiz/mpvkt/ui/player/controls/components/panels/SubtitleSettingsPanel.kt @@ -128,7 +128,7 @@ fun SubtitleSettingsPanel( } val CARDS_MAX_WIDTH = 420.dp -val SubtitleSettingsCardColors: @Composable () -> CardColors = { +val panelCardsColors: @Composable () -> CardColors = { val colors = CardDefaults.cardColors() colors.copy( containerColor = colors.containerColor.copy(0.6f), diff --git a/app/src/main/java/live/mehiz/mpvkt/ui/player/controls/components/panels/SubtitleSettingsTypographyCard.kt b/app/src/main/java/live/mehiz/mpvkt/ui/player/controls/components/panels/SubtitleSettingsTypographyCard.kt index e896a1f..3ccc049 100644 --- a/app/src/main/java/live/mehiz/mpvkt/ui/player/controls/components/panels/SubtitleSettingsTypographyCard.kt +++ b/app/src/main/java/live/mehiz/mpvkt/ui/player/controls/components/panels/SubtitleSettingsTypographyCard.kt @@ -97,7 +97,7 @@ fun SubtitleSettingsTypographyCard( } }, modifier = modifier.widthIn(max = CARDS_MAX_WIDTH), - colors = SubtitleSettingsCardColors(), + colors = panelCardsColors(), ) { Column { val isBold by preferences.bold.collectAsState() diff --git a/app/src/main/java/live/mehiz/mpvkt/ui/player/controls/components/panels/VideoFiltersPanel.kt b/app/src/main/java/live/mehiz/mpvkt/ui/player/controls/components/panels/VideoFiltersPanel.kt new file mode 100644 index 0000000..cbd6382 --- /dev/null +++ b/app/src/main/java/live/mehiz/mpvkt/ui/player/controls/components/panels/VideoFiltersPanel.kt @@ -0,0 +1,123 @@ +package live.mehiz.mpvkt.ui.player.controls.components.panels + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.widthIn +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Close +import androidx.compose.material3.Card +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.material3.TextButton +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import androidx.constraintlayout.compose.ConstraintLayout +import `is`.xyz.mpv.MPVLib +import live.mehiz.mpvkt.R +import live.mehiz.mpvkt.preferences.DecoderPreferences +import live.mehiz.mpvkt.preferences.preference.collectAsState +import live.mehiz.mpvkt.preferences.preference.deleteAndGet +import live.mehiz.mpvkt.presentation.components.SliderItem +import live.mehiz.mpvkt.ui.player.VideoFilters +import live.mehiz.mpvkt.ui.player.controls.components.ControlsButton +import live.mehiz.mpvkt.ui.theme.spacing +import me.zhanghai.compose.preference.FooterPreference +import me.zhanghai.compose.preference.ProvidePreferenceLocals +import org.koin.compose.koinInject + +@Composable +fun VideoFiltersPanel( + onDismissRequest: () -> Unit, + modifier: Modifier = Modifier, +) { + ConstraintLayout( + modifier = modifier + .fillMaxSize() + .padding(MaterialTheme.spacing.medium), + ) { + val filtersCard = createRef() + + FiltersCard( + Modifier.constrainAs(filtersCard) { + linkTo(parent.top, parent.bottom, bias = 0.8f) + end.linkTo(parent.end) + }, + onClose = onDismissRequest, + ) + } +} + +@Composable +fun FiltersCard( + modifier: Modifier = Modifier, + onClose: () -> Unit, +) { + val decoderPreferences = koinInject() + Card( + colors = panelCardsColors(), + modifier = modifier + .widthIn(max = CARDS_MAX_WIDTH), + ) { + Row( + Modifier + .fillMaxWidth() + .padding(start = MaterialTheme.spacing.medium), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.SpaceBetween, + ) { + Text( + stringResource(id = R.string.player_sheets_filters_title), + style = MaterialTheme.typography.headlineMedium, + ) + Row( + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.spacedBy(MaterialTheme.spacing.extraSmall), + ) { + TextButton( + onClick = { + VideoFilters.entries.forEach { + MPVLib.setPropertyInt(it.mpvProperty, it.preference(decoderPreferences).deleteAndGet()) + } + }, + ) { + Text(text = stringResource(id = R.string.generic_reset)) + } + ControlsButton(Icons.Default.Close, onClose) + } + } + LazyColumn { + items(VideoFilters.entries) { filter -> + val value by filter.preference(decoderPreferences).collectAsState() + SliderItem( + label = stringResource(filter.titleRes), + value = value, + valueText = value.toString(), + onChange = { + filter.preference(decoderPreferences).set(it) + MPVLib.setPropertyInt(filter.mpvProperty, it) + }, + max = 100, + min = -100, + ) + } + item { + if (decoderPreferences.gpuNext.get()) return@item + ProvidePreferenceLocals { + FooterPreference( + summary = { + Text(text = stringResource(id = R.string.player_sheets_filters_warning)) + }, + ) + } + } + } + } +} diff --git a/app/src/main/java/live/mehiz/mpvkt/ui/player/controls/components/sheets/MoreSheet.kt b/app/src/main/java/live/mehiz/mpvkt/ui/player/controls/components/sheets/MoreSheet.kt index 99e453b..6af74b4 100644 --- a/app/src/main/java/live/mehiz/mpvkt/ui/player/controls/components/sheets/MoreSheet.kt +++ b/app/src/main/java/live/mehiz/mpvkt/ui/player/controls/components/sheets/MoreSheet.kt @@ -2,14 +2,21 @@ package live.mehiz.mpvkt.ui.player.controls.components.sheets import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyRow import androidx.compose.foundation.lazy.items +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Tune import androidx.compose.material3.FilterChip +import androidx.compose.material3.Icon +import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text +import androidx.compose.material3.TextButton import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp @@ -20,29 +27,50 @@ import live.mehiz.mpvkt.preferences.AudioChannels import live.mehiz.mpvkt.preferences.AudioPreferences import live.mehiz.mpvkt.preferences.preference.collectAsState import live.mehiz.mpvkt.presentation.components.PlayerSheet +import live.mehiz.mpvkt.ui.theme.spacing import org.koin.compose.koinInject @Composable fun MoreSheet( onDismissRequest: () -> Unit, - modifier: Modifier = Modifier + onEnterFiltersPanel: () -> Unit, + modifier: Modifier = Modifier, ) { val advancedPreferences = koinInject() val audioPreferences = koinInject() val statisticsPage by advancedPreferences.enabledStatisticsPage.collectAsState() PlayerSheet( onDismissRequest, - modifier + modifier, ) { Column( modifier = Modifier .fillMaxWidth() - .padding(16.dp), - verticalArrangement = Arrangement.spacedBy(8.dp) + .padding(MaterialTheme.spacing.medium), + verticalArrangement = Arrangement.spacedBy(MaterialTheme.spacing.smaller), ) { + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically, + ) { + Text( + text = stringResource(id = R.string.player_sheets_more_title), + style = MaterialTheme.typography.headlineMedium, + ) + TextButton(onClick = onEnterFiltersPanel) { + Row( + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.spacedBy(4.dp), + ) { + Icon(imageVector = Icons.Default.Tune, contentDescription = null) + Text(text = stringResource(id = R.string.player_sheets_filters_title)) + } + } + } Text(stringResource(R.string.player_sheets_stats_page_title)) LazyRow( - horizontalArrangement = Arrangement.spacedBy(8.dp), + horizontalArrangement = Arrangement.spacedBy(MaterialTheme.spacing.smaller), ) { items(4) { page -> FilterChip( @@ -70,7 +98,7 @@ fun MoreSheet( Text(text = stringResource(id = R.string.pref_audio_channels)) val audioChannels by audioPreferences.audioChannels.collectAsState() LazyRow( - horizontalArrangement = Arrangement.spacedBy(8.dp) + horizontalArrangement = Arrangement.spacedBy(MaterialTheme.spacing.smaller), ) { items(AudioChannels.entries) { FilterChip( diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index f7e1630..e4e0673 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -119,9 +119,18 @@ Set as default Audio delay + Filters + Brightness + Contrast + Gamma + Saturation + Hue + Some filters may not work your current video driver + Value too big Value too small + More Default statistics page Page %d %d seconds