mirror of
https://github.com/JustinZeus/Wholphin.git
synced 2026-07-09 16:11:20 +02:00
Rebrand
This commit is contained in:
parent
aabd8462dc
commit
d39ed721d5
138 changed files with 738 additions and 738 deletions
|
|
@ -0,0 +1,650 @@
|
|||
package com.github.damontecres.wholphin.preferences
|
||||
|
||||
import android.content.Context
|
||||
import androidx.annotation.ArrayRes
|
||||
import androidx.annotation.StringRes
|
||||
import com.github.damontecres.wholphin.R
|
||||
import com.github.damontecres.wholphin.ui.nav.Destination
|
||||
import com.github.damontecres.wholphin.ui.preferences.PreferenceGroup
|
||||
import com.github.damontecres.wholphin.ui.preferences.PreferenceScreenOption
|
||||
import com.github.damontecres.wholphin.ui.preferences.PreferenceValidation
|
||||
import kotlin.time.Duration.Companion.milliseconds
|
||||
import kotlin.time.Duration.Companion.minutes
|
||||
import kotlin.time.Duration.Companion.seconds
|
||||
|
||||
/**
|
||||
* A preference that can be stored in [AppPreferences].
|
||||
*
|
||||
* @param T The type of the preference value.
|
||||
*/
|
||||
sealed interface AppPreference<T> {
|
||||
/**
|
||||
* String resource ID for the title of the preference
|
||||
*/
|
||||
@get:StringRes
|
||||
val title: Int
|
||||
|
||||
/**
|
||||
* Default value for the preference for UI purposes
|
||||
*/
|
||||
val defaultValue: T
|
||||
|
||||
/**
|
||||
* A function that gets the value from the [AppPreferences] object for UI purposes. This means
|
||||
* that it should return the value that is displayed in the UI, which isn't necessarily the raw value
|
||||
*/
|
||||
val getter: (prefs: AppPreferences) -> T
|
||||
|
||||
/**
|
||||
* A function that sets the value in the [AppPreferences] object from the UI. It should convert the value if needed
|
||||
*/
|
||||
val setter: (prefs: AppPreferences, value: T) -> AppPreferences
|
||||
|
||||
fun summary(
|
||||
context: Context,
|
||||
value: T?,
|
||||
): String? = null
|
||||
|
||||
fun validate(value: T): PreferenceValidation = PreferenceValidation.Valid
|
||||
|
||||
companion object {
|
||||
val SkipForward =
|
||||
AppSliderPreference(
|
||||
title = R.string.skip_forward_preference,
|
||||
defaultValue = 30,
|
||||
min = 10,
|
||||
max = 5.minutes.inWholeSeconds,
|
||||
interval = 5,
|
||||
getter = {
|
||||
it.playbackPreferences.skipForwardMs
|
||||
.milliseconds.inWholeSeconds
|
||||
},
|
||||
setter = { prefs, value ->
|
||||
prefs.updatePlaybackPreferences {
|
||||
skipForwardMs = value.seconds.inWholeMilliseconds
|
||||
}
|
||||
},
|
||||
summarizer = { value ->
|
||||
if (value != null) {
|
||||
"$value seconds"
|
||||
} else {
|
||||
null
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
val SkipBack =
|
||||
AppSliderPreference(
|
||||
title = R.string.skip_back_preference,
|
||||
defaultValue = 10,
|
||||
min = 5,
|
||||
max = 5.minutes.inWholeSeconds,
|
||||
interval = 5,
|
||||
getter = {
|
||||
it.playbackPreferences.skipBackMs
|
||||
.milliseconds.inWholeSeconds
|
||||
},
|
||||
setter = { prefs, value ->
|
||||
prefs.updatePlaybackPreferences {
|
||||
skipBackMs = value.seconds.inWholeMilliseconds
|
||||
}
|
||||
},
|
||||
summarizer = { value ->
|
||||
if (value != null) {
|
||||
"$value seconds"
|
||||
} else {
|
||||
null
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
// val GridJumpButtons =
|
||||
// AppSwitchPreference(
|
||||
// title = R.string.show_grid_jump_buttons,
|
||||
// defaultValue = true,
|
||||
// getter = { it.interfacePreferences.showGridJumpButtons },
|
||||
// setter = { prefs, value ->
|
||||
// prefs.updateInterfacePreferences { showGridJumpButtons = value }
|
||||
// },
|
||||
// summaryOn = R.string.enabled,
|
||||
// summaryOff = R.string.disabled,
|
||||
// )
|
||||
|
||||
// val ShowGridFooter =
|
||||
// AppSwitchPreference(
|
||||
// title = R.string.grid_position_footer,
|
||||
// defaultValue = true,
|
||||
// getter = { it.interfacePreferences.showPositionFooter },
|
||||
// setter = { prefs, value ->
|
||||
// prefs.updateInterfacePreferences { showPositionFooter = value }
|
||||
// },
|
||||
// summaryOn = R.string.show,
|
||||
// summaryOff = R.string.hide,
|
||||
// )
|
||||
|
||||
val ControllerTimeout =
|
||||
AppSliderPreference(
|
||||
title = R.string.hide_controller_timeout,
|
||||
defaultValue = 5000,
|
||||
min = 500,
|
||||
max = 15.seconds.inWholeMilliseconds,
|
||||
interval = 100,
|
||||
getter = { it.playbackPreferences.controllerTimeoutMs },
|
||||
setter = { prefs, value ->
|
||||
prefs.updatePlaybackPreferences { controllerTimeoutMs = value }
|
||||
},
|
||||
summarizer = { value -> value?.let { "${value / 1000.0} seconds" } },
|
||||
)
|
||||
|
||||
val SeekBarSteps =
|
||||
AppSliderPreference(
|
||||
title = R.string.seek_bar_steps,
|
||||
defaultValue = 16,
|
||||
min = 4,
|
||||
max = 64,
|
||||
interval = 1,
|
||||
getter = { it.playbackPreferences.seekBarSteps.toLong() },
|
||||
setter = { prefs, value ->
|
||||
prefs.updatePlaybackPreferences { seekBarSteps = value.toInt() }
|
||||
},
|
||||
summarizer = { value -> value?.toString() },
|
||||
)
|
||||
|
||||
val HomePageItems =
|
||||
AppSliderPreference(
|
||||
title = R.string.max_homepage_items,
|
||||
defaultValue = 25,
|
||||
min = 5,
|
||||
max = 50,
|
||||
interval = 1,
|
||||
getter = { it.homePagePreferences.maxItemsPerRow.toLong() },
|
||||
setter = { prefs, value ->
|
||||
prefs.updateHomePagePreferences { maxItemsPerRow = value.toInt() }
|
||||
},
|
||||
summarizer = { value -> value?.toString() },
|
||||
)
|
||||
|
||||
val CombineContinueNext =
|
||||
AppSwitchPreference(
|
||||
title = R.string.combine_continue_next,
|
||||
defaultValue = false,
|
||||
getter = { it.homePagePreferences.combineContinueNext },
|
||||
setter = { prefs, value ->
|
||||
prefs.updateHomePagePreferences { combineContinueNext = value }
|
||||
},
|
||||
summaryOn = R.string.enabled,
|
||||
summaryOff = R.string.disabled,
|
||||
)
|
||||
|
||||
val RewatchNextUp =
|
||||
AppSwitchPreference(
|
||||
title = R.string.rewatch_next_up,
|
||||
defaultValue = false,
|
||||
getter = { it.homePagePreferences.enableRewatchingNextUp },
|
||||
setter = { prefs, value ->
|
||||
prefs.updateHomePagePreferences { enableRewatchingNextUp = value }
|
||||
},
|
||||
summaryOn = R.string.enabled,
|
||||
summaryOff = R.string.disabled,
|
||||
)
|
||||
|
||||
val PlayThemeMusic =
|
||||
AppChoicePreference<ThemeSongVolume>(
|
||||
title = R.string.play_theme_music,
|
||||
defaultValue = ThemeSongVolume.MEDIUM,
|
||||
getter = { it.interfacePreferences.playThemeSongs },
|
||||
setter = { prefs, value ->
|
||||
prefs.updateInterfacePreferences { playThemeSongs = value }
|
||||
},
|
||||
displayValues = R.array.theme_song_volume,
|
||||
indexToValue = { ThemeSongVolume.forNumber(it) },
|
||||
valueToIndex = { it.number },
|
||||
)
|
||||
|
||||
val PlaybackDebugInfo =
|
||||
AppSwitchPreference(
|
||||
title = R.string.playback_debug_info,
|
||||
defaultValue = false,
|
||||
getter = { it.playbackPreferences.showDebugInfo },
|
||||
setter = { prefs, value ->
|
||||
prefs.updatePlaybackPreferences { showDebugInfo = value }
|
||||
},
|
||||
summaryOn = R.string.show,
|
||||
summaryOff = R.string.hide,
|
||||
)
|
||||
|
||||
val AutoPlayNextUp =
|
||||
AppSwitchPreference(
|
||||
title = R.string.auto_play_next,
|
||||
defaultValue = true,
|
||||
getter = { it.playbackPreferences.autoPlayNext },
|
||||
setter = { prefs, value ->
|
||||
prefs.updatePlaybackPreferences { autoPlayNext = value }
|
||||
},
|
||||
summaryOn = R.string.enabled,
|
||||
summaryOff = R.string.disabled,
|
||||
)
|
||||
|
||||
val SkipBackOnResume =
|
||||
AppSliderPreference(
|
||||
title = R.string.skip_back_on_resume_preference,
|
||||
defaultValue = 0,
|
||||
min = 0,
|
||||
max = 10,
|
||||
interval = 1,
|
||||
getter = { it.playbackPreferences.skipBackOnResumeSeconds.milliseconds.inWholeSeconds },
|
||||
setter = { prefs, value ->
|
||||
prefs.updatePlaybackPreferences {
|
||||
skipBackOnResumeSeconds = value.seconds.inWholeMilliseconds
|
||||
}
|
||||
},
|
||||
summarizer = { value ->
|
||||
if (value == 0L) {
|
||||
"Disabled"
|
||||
} else {
|
||||
"${value}s"
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
val AutoPlayNextDelay =
|
||||
AppSliderPreference(
|
||||
title = R.string.auto_play_next_delay,
|
||||
defaultValue = 15,
|
||||
min = 0,
|
||||
max = 60,
|
||||
interval = 5,
|
||||
getter = { it.playbackPreferences.autoPlayNextDelaySeconds },
|
||||
setter = { prefs, value ->
|
||||
prefs.updatePlaybackPreferences { autoPlayNextDelaySeconds = value }
|
||||
},
|
||||
summarizer = { value ->
|
||||
if (value == 0L) {
|
||||
"Immediate"
|
||||
} else {
|
||||
"$value seconds"
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
private const val MEGA_BIT = 1024 * 1024L
|
||||
const val DEFAULT_BITRATE = 20 * MEGA_BIT
|
||||
private val bitrateValues =
|
||||
listOf(
|
||||
500 * 1024L,
|
||||
750 * 1024L,
|
||||
1 * MEGA_BIT,
|
||||
2 * MEGA_BIT,
|
||||
3 * MEGA_BIT,
|
||||
5 * MEGA_BIT,
|
||||
8 * MEGA_BIT,
|
||||
10 * MEGA_BIT,
|
||||
15 * MEGA_BIT,
|
||||
DEFAULT_BITRATE,
|
||||
*(30..100 step 10).map { it * MEGA_BIT }.toTypedArray(),
|
||||
*(120..200 step 20).map { it * MEGA_BIT }.toTypedArray(),
|
||||
)
|
||||
val MaxBitrate =
|
||||
AppSliderPreference(
|
||||
title = R.string.max_bitrate,
|
||||
defaultValue = bitrateValues.indexOf(DEFAULT_BITRATE).toLong(),
|
||||
min = 0,
|
||||
max = bitrateValues.size - 1L,
|
||||
interval = 1,
|
||||
getter = {
|
||||
bitrateValues.indexOf(it.playbackPreferences.maxBitrate).toLong()
|
||||
},
|
||||
setter = { prefs, value ->
|
||||
prefs.updatePlaybackPreferences {
|
||||
maxBitrate = bitrateValues[value.toInt()]
|
||||
}
|
||||
},
|
||||
summarizer = { value ->
|
||||
if (value != null) {
|
||||
val v = bitrateValues.getOrNull(value.toInt()) ?: DEFAULT_BITRATE
|
||||
if (v < MEGA_BIT) {
|
||||
"${v / 1024} kbps"
|
||||
} else {
|
||||
"${v / MEGA_BIT} Mbps"
|
||||
}
|
||||
} else {
|
||||
null
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
val RememberSelectedTab =
|
||||
AppSwitchPreference(
|
||||
title = R.string.remember_selected_tab,
|
||||
defaultValue = false,
|
||||
getter = { it.interfacePreferences.rememberSelectedTab },
|
||||
setter = { prefs, value ->
|
||||
prefs.updateInterfacePreferences { rememberSelectedTab = value }
|
||||
},
|
||||
summaryOn = R.string.enabled,
|
||||
summaryOff = R.string.disabled,
|
||||
)
|
||||
|
||||
val ThemeColors =
|
||||
AppChoicePreference<AppThemeColors>(
|
||||
title = R.string.app_theme,
|
||||
defaultValue = AppThemeColors.PURPLE,
|
||||
getter = { it.interfacePreferences.appThemeColors },
|
||||
setter = { prefs, value ->
|
||||
prefs.updateInterfacePreferences { appThemeColors = value }
|
||||
},
|
||||
displayValues = R.array.app_theme_colors,
|
||||
indexToValue = { AppThemeColors.forNumber(it) },
|
||||
valueToIndex = { it.number },
|
||||
)
|
||||
|
||||
val InstalledVersion =
|
||||
AppClickablePreference(
|
||||
title = R.string.installed_version,
|
||||
getter = { },
|
||||
setter = { prefs, _ -> prefs },
|
||||
)
|
||||
|
||||
val Update =
|
||||
AppClickablePreference(
|
||||
title = R.string.check_for_updates,
|
||||
getter = { },
|
||||
setter = { prefs, _ -> prefs },
|
||||
)
|
||||
|
||||
val AutoCheckForUpdates =
|
||||
AppSwitchPreference(
|
||||
title = R.string.auto_check_for_updates,
|
||||
defaultValue = true,
|
||||
getter = { it.autoCheckForUpdates },
|
||||
setter = { prefs, value ->
|
||||
prefs.update { autoCheckForUpdates = value }
|
||||
},
|
||||
summaryOn = R.string.enabled,
|
||||
summaryOff = R.string.disabled,
|
||||
)
|
||||
|
||||
val UpdateUrl =
|
||||
AppStringPreference(
|
||||
title = R.string.update_url,
|
||||
defaultValue = "", // TODO
|
||||
getter = { it.updateUrl },
|
||||
setter = { prefs, value ->
|
||||
prefs.update { updateUrl = value }
|
||||
},
|
||||
summary = R.string.update_url_summary,
|
||||
)
|
||||
|
||||
val OssLicenseInfo =
|
||||
AppDestinationPreference(
|
||||
title = R.string.license_info,
|
||||
destination = Destination.License,
|
||||
)
|
||||
|
||||
val AdvancedSettings =
|
||||
AppDestinationPreference(
|
||||
title = R.string.advanced_settings,
|
||||
destination = Destination.Settings(PreferenceScreenOption.ADVANCED),
|
||||
)
|
||||
|
||||
val SkipIntros =
|
||||
AppChoicePreference<SkipSegmentBehavior>(
|
||||
title = R.string.skip_intro_behavior,
|
||||
defaultValue = SkipSegmentBehavior.ASK_TO_SKIP,
|
||||
getter = { it.playbackPreferences.skipIntros },
|
||||
setter = { prefs, value ->
|
||||
prefs.updatePlaybackPreferences { skipIntros = value }
|
||||
},
|
||||
displayValues = R.array.skip_behaviors,
|
||||
indexToValue = { SkipSegmentBehavior.forNumber(it) },
|
||||
valueToIndex = { it.number },
|
||||
)
|
||||
|
||||
val SkipOutros =
|
||||
AppChoicePreference<SkipSegmentBehavior>(
|
||||
title = R.string.skip_outro_behavior,
|
||||
defaultValue = SkipSegmentBehavior.ASK_TO_SKIP,
|
||||
getter = { it.playbackPreferences.skipOutros },
|
||||
setter = { prefs, value ->
|
||||
prefs.updatePlaybackPreferences { skipOutros = value }
|
||||
},
|
||||
displayValues = R.array.skip_behaviors,
|
||||
indexToValue = { SkipSegmentBehavior.forNumber(it) },
|
||||
valueToIndex = { it.number },
|
||||
)
|
||||
|
||||
val SkipCommercials =
|
||||
AppChoicePreference<SkipSegmentBehavior>(
|
||||
title = R.string.skip_comercials_behavior,
|
||||
defaultValue = SkipSegmentBehavior.ASK_TO_SKIP,
|
||||
getter = { it.playbackPreferences.skipCommercials },
|
||||
setter = { prefs, value ->
|
||||
prefs.updatePlaybackPreferences { skipCommercials = value }
|
||||
},
|
||||
displayValues = R.array.skip_behaviors,
|
||||
indexToValue = { SkipSegmentBehavior.forNumber(it) },
|
||||
valueToIndex = { it.number },
|
||||
)
|
||||
|
||||
val SkipPreviews =
|
||||
AppChoicePreference<SkipSegmentBehavior>(
|
||||
title = R.string.skip_previews_behavior,
|
||||
defaultValue = SkipSegmentBehavior.IGNORE,
|
||||
getter = { it.playbackPreferences.skipPreviews },
|
||||
setter = { prefs, value ->
|
||||
prefs.updatePlaybackPreferences { skipPreviews = value }
|
||||
},
|
||||
displayValues = R.array.skip_behaviors,
|
||||
indexToValue = { SkipSegmentBehavior.forNumber(it) },
|
||||
valueToIndex = { it.number },
|
||||
)
|
||||
|
||||
val SkipRecaps =
|
||||
AppChoicePreference<SkipSegmentBehavior>(
|
||||
title = R.string.skip_recap_behavior,
|
||||
defaultValue = SkipSegmentBehavior.IGNORE,
|
||||
getter = { it.playbackPreferences.skipRecaps },
|
||||
setter = { prefs, value ->
|
||||
prefs.updatePlaybackPreferences { skipRecaps = value }
|
||||
},
|
||||
displayValues = R.array.skip_behaviors,
|
||||
indexToValue = { SkipSegmentBehavior.forNumber(it) },
|
||||
valueToIndex = { it.number },
|
||||
)
|
||||
|
||||
val ClearImageCache =
|
||||
AppClickablePreference(
|
||||
title = R.string.clear_image_cache,
|
||||
getter = { },
|
||||
setter = { prefs, _ -> prefs },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
val basicPreferences =
|
||||
listOf(
|
||||
PreferenceGroup(
|
||||
title = R.string.basic_interface,
|
||||
preferences =
|
||||
listOf(
|
||||
AppPreference.HomePageItems,
|
||||
AppPreference.RewatchNextUp,
|
||||
AppPreference.CombineContinueNext,
|
||||
AppPreference.PlayThemeMusic,
|
||||
AppPreference.RememberSelectedTab,
|
||||
AppPreference.ThemeColors,
|
||||
),
|
||||
),
|
||||
PreferenceGroup(
|
||||
title = R.string.playback,
|
||||
preferences =
|
||||
listOf(
|
||||
AppPreference.SkipForward,
|
||||
AppPreference.SkipBack,
|
||||
AppPreference.ControllerTimeout,
|
||||
AppPreference.AutoPlayNextUp,
|
||||
AppPreference.AutoPlayNextDelay,
|
||||
AppPreference.SkipBackOnResume,
|
||||
),
|
||||
),
|
||||
PreferenceGroup(
|
||||
title = R.string.about,
|
||||
preferences =
|
||||
listOf(
|
||||
AppPreference.InstalledVersion,
|
||||
AppPreference.Update,
|
||||
),
|
||||
),
|
||||
PreferenceGroup(
|
||||
title = R.string.more,
|
||||
preferences =
|
||||
listOf(
|
||||
AppPreference.AdvancedSettings,
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
val uiPreferences = listOf<PreferenceGroup>()
|
||||
|
||||
val advancedPreferences =
|
||||
listOf(
|
||||
PreferenceGroup(
|
||||
title = R.string.playback,
|
||||
preferences =
|
||||
listOf(
|
||||
AppPreference.SkipIntros,
|
||||
AppPreference.SkipOutros,
|
||||
AppPreference.SkipCommercials,
|
||||
AppPreference.SkipPreviews,
|
||||
AppPreference.SkipRecaps,
|
||||
AppPreference.MaxBitrate,
|
||||
AppPreference.PlaybackDebugInfo,
|
||||
),
|
||||
),
|
||||
PreferenceGroup(
|
||||
title = R.string.updates,
|
||||
preferences =
|
||||
listOf(
|
||||
AppPreference.AutoCheckForUpdates,
|
||||
AppPreference.UpdateUrl,
|
||||
),
|
||||
),
|
||||
PreferenceGroup(
|
||||
title = R.string.more,
|
||||
preferences =
|
||||
listOf(
|
||||
AppPreference.ClearImageCache,
|
||||
AppPreference.OssLicenseInfo,
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
data class AppSwitchPreference(
|
||||
@get:StringRes override val title: Int,
|
||||
override val defaultValue: Boolean,
|
||||
override val getter: (prefs: AppPreferences) -> Boolean,
|
||||
override val setter: (prefs: AppPreferences, value: Boolean) -> AppPreferences,
|
||||
val validator: (value: Boolean) -> PreferenceValidation = { PreferenceValidation.Valid },
|
||||
@param:StringRes val summary: Int? = null,
|
||||
@param:StringRes val summaryOn: Int? = null,
|
||||
@param:StringRes val summaryOff: Int? = null,
|
||||
) : AppPreference<Boolean> {
|
||||
override fun summary(
|
||||
context: Context,
|
||||
value: Boolean?,
|
||||
): String? =
|
||||
when {
|
||||
summaryOn != null && value == true -> context.getString(summaryOn)
|
||||
summaryOff != null && value == false -> context.getString(summaryOff)
|
||||
else -> summary?.let { context.getString(summary) }
|
||||
}
|
||||
}
|
||||
|
||||
open class AppStringPreference(
|
||||
@param:StringRes override val title: Int,
|
||||
override val defaultValue: String,
|
||||
override val getter: (AppPreferences) -> String,
|
||||
override val setter: (AppPreferences, String) -> AppPreferences,
|
||||
@param:StringRes val summary: Int?,
|
||||
) : AppPreference<String> {
|
||||
override fun summary(
|
||||
context: Context,
|
||||
value: String?,
|
||||
): String? = summary?.let { context.getString(it) } ?: value
|
||||
}
|
||||
|
||||
data class AppChoicePreference<T>(
|
||||
@param:StringRes override val title: Int,
|
||||
override val defaultValue: T,
|
||||
@param:ArrayRes val displayValues: Int,
|
||||
val indexToValue: (index: Int) -> T,
|
||||
val valueToIndex: (T) -> Int,
|
||||
override val getter: (prefs: AppPreferences) -> T,
|
||||
override val setter: (prefs: AppPreferences, value: T) -> AppPreferences,
|
||||
@param:StringRes val summary: Int? = null,
|
||||
) : AppPreference<T>
|
||||
|
||||
data class AppMultiChoicePreference<T>(
|
||||
@param:StringRes override val title: Int,
|
||||
override val defaultValue: List<T>,
|
||||
val allValues: List<T>,
|
||||
@param:ArrayRes val displayValues: Int,
|
||||
override val getter: (prefs: AppPreferences) -> List<T>,
|
||||
override val setter: (prefs: AppPreferences, value: List<T>) -> AppPreferences,
|
||||
@param:StringRes val summary: Int? = null,
|
||||
val toSharedPrefs: (T) -> String,
|
||||
val fromSharedPrefs: (String) -> T?,
|
||||
) : AppPreference<List<T>>
|
||||
|
||||
data class AppClickablePreference(
|
||||
@param:StringRes override val title: Int,
|
||||
override val defaultValue: Unit = Unit,
|
||||
override val getter: (prefs: AppPreferences) -> Unit = { },
|
||||
override val setter: (prefs: AppPreferences, value: Unit) -> AppPreferences = { prefs, _ -> prefs },
|
||||
@param:StringRes val summary: Int? = null,
|
||||
) : AppPreference<Unit> {
|
||||
override fun summary(
|
||||
context: Context,
|
||||
value: Unit?,
|
||||
): String? = summary?.let { context.getString(it) }
|
||||
}
|
||||
|
||||
data class AppDestinationPreference(
|
||||
@param:StringRes override val title: Int,
|
||||
override val defaultValue: Unit = Unit,
|
||||
override val getter: (prefs: AppPreferences) -> Unit = { },
|
||||
override val setter: (prefs: AppPreferences, value: Unit) -> AppPreferences = { prefs, _ -> prefs },
|
||||
@param:StringRes val summary: Int? = null,
|
||||
val destination: Destination,
|
||||
) : AppPreference<Unit> {
|
||||
override fun summary(
|
||||
context: Context,
|
||||
value: Unit?,
|
||||
): String? = summary?.let { context.getString(it) }
|
||||
}
|
||||
|
||||
class AppSliderPreference(
|
||||
@param:StringRes override val title: Int,
|
||||
override val defaultValue: Long,
|
||||
/**
|
||||
* Minimum value for the slider. Similar to [defaultValue], this is for UI purposes only
|
||||
*/
|
||||
val min: Long = 0,
|
||||
/**
|
||||
* Max value for the slider. Similar to [defaultValue], this is for UI purposes only
|
||||
*/
|
||||
val max: Long = 100,
|
||||
val interval: Int = 1,
|
||||
override val getter: (prefs: AppPreferences) -> Long,
|
||||
override val setter: (prefs: AppPreferences, value: Long) -> AppPreferences,
|
||||
@param:StringRes val summary: Int? = null,
|
||||
val summarizer: ((Long?) -> String?)? = null,
|
||||
) : AppPreference<Long> {
|
||||
override fun summary(
|
||||
context: Context,
|
||||
value: Long?,
|
||||
): String? =
|
||||
summarizer?.invoke(value)
|
||||
?: summary?.let { context.getString(it) }
|
||||
?: value?.toString()
|
||||
}
|
||||
|
|
@ -0,0 +1,102 @@
|
|||
package com.github.damontecres.wholphin.preferences
|
||||
|
||||
import androidx.datastore.core.CorruptionException
|
||||
import androidx.datastore.core.Serializer
|
||||
import com.google.protobuf.InvalidProtocolBufferException
|
||||
import timber.log.Timber
|
||||
import java.io.InputStream
|
||||
import java.io.OutputStream
|
||||
import java.util.UUID
|
||||
import javax.inject.Inject
|
||||
import kotlin.time.Duration.Companion.seconds
|
||||
|
||||
class AppPreferencesSerializer
|
||||
@Inject
|
||||
constructor() : Serializer<AppPreferences> {
|
||||
override val defaultValue: AppPreferences =
|
||||
AppPreferences
|
||||
.newBuilder()
|
||||
.apply {
|
||||
updateUrl = AppPreference.UpdateUrl.defaultValue
|
||||
autoCheckForUpdates = AppPreference.AutoCheckForUpdates.defaultValue
|
||||
|
||||
playbackPreferences =
|
||||
PlaybackPreferences
|
||||
.newBuilder()
|
||||
.apply {
|
||||
skipForwardMs =
|
||||
AppPreference.SkipForward.defaultValue.seconds.inWholeMilliseconds
|
||||
skipBackMs =
|
||||
AppPreference.SkipBack.defaultValue.seconds.inWholeMilliseconds
|
||||
controllerTimeoutMs = AppPreference.ControllerTimeout.defaultValue
|
||||
seekBarSteps = AppPreference.SeekBarSteps.defaultValue.toInt()
|
||||
showDebugInfo = AppPreference.PlaybackDebugInfo.defaultValue
|
||||
autoPlayNext = AppPreference.AutoPlayNextUp.defaultValue
|
||||
autoPlayNextDelaySeconds =
|
||||
AppPreference.AutoPlayNextDelay.defaultValue
|
||||
skipBackOnResumeSeconds =
|
||||
AppPreference.SkipBackOnResume.defaultValue.seconds.inWholeMilliseconds
|
||||
maxBitrate = AppPreference.DEFAULT_BITRATE
|
||||
skipIntros = AppPreference.SkipIntros.defaultValue
|
||||
skipOutros = AppPreference.SkipOutros.defaultValue
|
||||
skipCommercials = AppPreference.SkipCommercials.defaultValue
|
||||
skipPreviews = AppPreference.SkipPreviews.defaultValue
|
||||
skipRecaps = AppPreference.SkipRecaps.defaultValue
|
||||
}.build()
|
||||
homePagePreferences =
|
||||
HomePagePreferences
|
||||
.newBuilder()
|
||||
.apply {
|
||||
maxItemsPerRow = AppPreference.HomePageItems.defaultValue.toInt()
|
||||
enableRewatchingNextUp = AppPreference.RewatchNextUp.defaultValue
|
||||
combineContinueNext = AppPreference.CombineContinueNext.defaultValue
|
||||
}.build()
|
||||
interfacePreferences =
|
||||
InterfacePreferences
|
||||
.newBuilder()
|
||||
.apply {
|
||||
playThemeSongs = AppPreference.PlayThemeMusic.defaultValue
|
||||
appThemeColors = AppPreference.ThemeColors.defaultValue
|
||||
}.build()
|
||||
}.build()
|
||||
|
||||
override suspend fun readFrom(input: InputStream): AppPreferences {
|
||||
try {
|
||||
return AppPreferences.parseFrom(input)
|
||||
} catch (exception: InvalidProtocolBufferException) {
|
||||
throw CorruptionException("Cannot read proto.", exception)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun writeTo(
|
||||
t: AppPreferences,
|
||||
output: OutputStream,
|
||||
) = t.writeTo(output)
|
||||
}
|
||||
|
||||
inline fun AppPreferences.update(block: AppPreferences.Builder.() -> Unit): AppPreferences = toBuilder().apply(block).build()
|
||||
|
||||
inline fun AppPreferences.updatePlaybackPreferences(block: PlaybackPreferences.Builder.() -> Unit): AppPreferences =
|
||||
update {
|
||||
playbackPreferences = playbackPreferences.toBuilder().apply(block).build()
|
||||
}
|
||||
|
||||
inline fun AppPreferences.updateHomePagePreferences(block: HomePagePreferences.Builder.() -> Unit): AppPreferences =
|
||||
update {
|
||||
homePagePreferences = homePagePreferences.toBuilder().apply(block).build()
|
||||
}
|
||||
|
||||
inline fun AppPreferences.updateInterfacePreferences(block: InterfacePreferences.Builder.() -> Unit): AppPreferences =
|
||||
update {
|
||||
interfacePreferences = interfacePreferences.toBuilder().apply(block).build()
|
||||
}
|
||||
|
||||
fun AppPreferences.rememberTab(
|
||||
itemId: UUID,
|
||||
index: Int,
|
||||
): AppPreferences {
|
||||
Timber.v("Updating $itemId tab to $index")
|
||||
return updateInterfacePreferences {
|
||||
putRememberedTabs(itemId.toString(), index)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
package com.github.damontecres.wholphin.preferences
|
||||
|
||||
import kotlin.time.Duration
|
||||
import kotlin.time.Duration.Companion.milliseconds
|
||||
|
||||
val PlaybackPreferences.skipBackOnResume: Duration?
|
||||
get() =
|
||||
if (skipBackOnResumeSeconds > 0) {
|
||||
skipBackOnResumeSeconds.milliseconds
|
||||
} else {
|
||||
null
|
||||
}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
package com.github.damontecres.wholphin.preferences
|
||||
|
||||
import org.jellyfin.sdk.model.api.SubtitlePlaybackMode
|
||||
import org.jellyfin.sdk.model.api.UserConfiguration
|
||||
|
||||
/**
|
||||
* A combination of the app-specific preferences and server-side user configuration
|
||||
*/
|
||||
data class UserPreferences(
|
||||
val appPreferences: AppPreferences,
|
||||
val userConfig: UserConfiguration,
|
||||
)
|
||||
|
||||
val DefaultUserConfiguration =
|
||||
UserConfiguration(
|
||||
playDefaultAudioTrack = true,
|
||||
displayMissingEpisodes = false,
|
||||
groupedFolders = listOf(),
|
||||
subtitleMode = SubtitlePlaybackMode.DEFAULT,
|
||||
displayCollectionsView = false,
|
||||
enableLocalPassword = false,
|
||||
orderedViews = listOf(),
|
||||
latestItemsExcludes = listOf(),
|
||||
myMediaExcludes = listOf(),
|
||||
hidePlayedInLatest = true,
|
||||
rememberAudioSelections = true,
|
||||
rememberSubtitleSelections = true,
|
||||
enableNextEpisodeAutoPlay = true,
|
||||
)
|
||||
Loading…
Add table
Add a link
Reference in a new issue