ComposePreferences#
This library offers you preference screens for compose including the ability of endless nesting subscreens as well as simple integration of custom preferences.
Screenshots#
Screenshots | ||
---|---|---|
Features#
- offers a simple
PreferenceScreen
composable - does offer all common used preferences
- manages nesting, visibilities and dependencies for you
- can be easily extended
All features are splitted into separate modules, just include the modules you want to use!
Dependencies#
Compose
Dependency | Version | Infos |
---|---|---|
Compose BOM | 2024.04.00 | Mapping |
Material3 | 1.2.1 |
Library
Module | Dependency | Version | ||
---|---|---|---|---|
core | - | |||
Screens | | | ||
screen-bool | - | |||
screen-button | - | |||
screen-input | ComposeDialogs | 1.0.8 | ||
screen-color | ComposeDialogs | 1.0.8 | ||
screen-date | ComposeDialogs | 1.0.8 | ||
screen-time | ComposeDialogs | 1.0.8 | ||
screen-list | ComposeDialogs | 1.0.8 | ||
screen-number | ComposeDialogs | 1.0.8 | ||
Extensions | | | ||
extension-kotpreferences | KotPreferences | 0.5.1 |
Setup Gradle#
This library is distributed via JitPack.io.
2/2: Add dependencies to your module's build.gradle
// use the latest version of the library
val composepreferences = "<LATEST-VERSION>"
// include necessary modules
// core module
implementation("com.github.MFlisar.ComposePreferences:core:$composepreferences")
// screen module
implementation("com.github.MFlisar.ComposePreferences:screen-bool:$composepreferences")
implementation("com.github.MFlisar.ComposePreferences:screen-button:$composepreferences")
implementation("com.github.MFlisar.ComposePreferences:screen-input:$composepreferences")
implementation("com.github.MFlisar.ComposePreferences:screen-color:$composepreferences")
implementation("com.github.MFlisar.ComposePreferences:screen-date:$composepreferences")
implementation("com.github.MFlisar.ComposePreferences:screen-time:$composepreferences")
implementation("com.github.MFlisar.ComposePreferences:screen-list:$composepreferences")
implementation("com.github.MFlisar.ComposePreferences:screen-number:$composepreferences")
// extension module
implementation("com.github.MFlisar.ComposePreferences:extension-kotpreferences:$composepreferences")
Usage#
It works as simple as following:
// Preferences must be wrapped in a screen
// => this allows to manage internal hierarchy and screen nesting and everything is managed automatically
// => this also enables internal scrolling
PreferenceScreen(
// optional parameters to customise this screen
settings = PreferenceSettingsDefaults.settings(),
scrollable = true
) {
// Preferences at root level
PreferenceInfo(
title = { Text("Info 1") }
)
PreferenceBool(
style = PreferenceBool.Style.Switch,
value = <value>,
onValueChange = {
// update value here
},
title = { Text("Bool") }
)
// Sub Preference - all nested preferences will show if you click the sub preference (and all preferences from other levels will be hidden automatically)
// + back press + state saving will be handled automatically
PreferenceSubScreen(
title = { Text("Menu") }
) {
// sub preferences must be placed here
// you can even nest another PreferenceSubScreen here - any nesting depth is supported!
}
// IMPORTANT:
// don't place any non preference composables here, they won't be correctly shown/hidden and managed by the preference screen because they don't hold any hierarchical data!
// also gray out and enabled states won't work
// if you want to place some custom content wrap it inside a `BasePreference` (if you want the default title/subtitle/icon/content layout)
// or inside a `BasePreferenceContainer` if you want to place plain content
// Custom 1 - default button inside the content area wrapped as preference => this will work correctly even if used in sub preferences and it will automatically support enabled/disabling
BasePreference(
title = { Text("A custom preference") },
subtitle = { Text("Showing a button") },
icon = { Icon(Icons.Default.Android, null) }
) {
Button(onClick = {
// ...
}) {
Icon(Icons.Default.Android, null)
}
}
// Custom 2 - completely free content => this will also work correctly even if used in sub preferences and it will automatically support enabled/disabling
// but it allows you to wrap ANY composable inside it
BasePreferenceContainer(
modifier = Modifier.padding(16.dp),
preferenceStyle = PreferenceStyleDefaults.item()
) { modifier ->
Button(
onClick = {
// ...
}) {
Text("Button")
}
}
}
Demo#
A full demo is included inside the demo module, it shows nearly every usage with working examples.
Modules and Extensions#
Info Preference
Preview | Module |
---|---|
core |
PreferenceInfo.kt
fun PreferenceScope.PreferenceInfo(
// Special
onLongClick: (() -> Unit)? = null,
ignoreMinItemHeight: Boolean = false,
alignment: Alignment.Vertical = Alignment.CenterVertically,
// Base Preference
title: @Composable () -> Unit,
enabled: Dependency = Dependency.Enabled,
visible: Dependency = Dependency.Enabled,
subtitle: @Composable (() -> Unit)? = null,
icon: (@Composable () -> Unit)? = null,
preferenceStyle: PreferenceStyle = LocalPreferenceSettings.current.itemStyle
) {
Section Header Preference
Preview | Module |
---|---|
core |
PreferenceSectionHeader.kt
fun PreferenceScope.PreferenceSectionHeader(
// Special
// Base Preference
enabled: Dependency = Dependency.Enabled,
visible: Dependency = Dependency.Enabled,
title: @Composable () -> Unit,
subtitle: @Composable (() -> Unit)? = null,
icon: (@Composable () -> Unit)? = null,
preferenceStyle: PreferenceStyle = PreferenceStyleDefaults.header()
) {
Bool Preference
Preview | Module | |
---|---|---|
bool |
PreferenceBool.kt
fun PreferenceScope.PreferenceBool(
style: PreferenceBool.Style = PreferenceBool.Style.Switch,
// Special
value: Boolean,
onValueChange: (selected: Boolean) -> Unit,
// Base Preference
title: @Composable () -> Unit,
enabled: Dependency = Dependency.Enabled,
visible: Dependency = Dependency.Enabled,
subtitle: @Composable (() -> Unit)? = null,
icon: (@Composable () -> Unit)? = null,
preferenceStyle: PreferenceStyle = LocalPreferenceSettings.current.itemStyle
) {
Button Preference
Preview | Module |
---|---|
button |
PreferenceButton.kt
fun PreferenceScope.PreferenceButton(
// Special
onClick: (() -> Unit),
// Base Preference
title: @Composable () -> Unit,
enabled: Dependency = Dependency.Enabled,
visible: Dependency = Dependency.Enabled,
subtitle: @Composable (() -> Unit)? = null,
icon: (@Composable () -> Unit)? = null,
preferenceStyle: PreferenceStyle = LocalPreferenceSettings.current.itemStyle
) {
Color Preference
Preview | Module | |
---|---|---|
color |
PreferenceColor.kt
fun PreferenceScope.PreferenceColor(
// Special
value: Color,
onValueChange: (value: Color) -> Unit,
alphaSupported: Boolean = true,
// Base Preference
title: @Composable () -> Unit,
enabled: Dependency = Dependency.Enabled,
visible: Dependency = Dependency.Enabled,
subtitle: @Composable (() -> Unit)? = null,
icon: (@Composable () -> Unit)? = null,
preferenceStyle: PreferenceStyle = LocalPreferenceSettings.current.itemStyle
) {
Date Preference
Preview | Module |
---|---|
date |
PreferenceDate.kt
fun PreferenceScope.PreferenceDate(
// Special
value: LocalDate,
onValueChange: (date: LocalDate) -> Unit,
firstDayOfWeek: DayOfWeek = DayOfWeek.MONDAY,
formatter: (date: LocalDate) -> String = {
it.format(DateTimeFormatter.ofLocalizedDate(FormatStyle.LONG))
},
// Base Preference
title: @Composable () -> Unit,
enabled: Dependency = Dependency.Enabled,
visible: Dependency = Dependency.Enabled,
subtitle: @Composable (() -> Unit)? = null,
icon: (@Composable () -> Unit)? = null,
preferenceStyle: PreferenceStyle = LocalPreferenceSettings.current.itemStyle
) {
Input Preference
Preview | Module | |
---|---|---|
input | ||
input |
PreferenceInputText.kt
fun PreferenceScope.PreferenceInputText(
// Special
value: String,
onValueChange: (value: String) -> Unit,
// Base Preference
title: @Composable () -> Unit,
enabled: Dependency = Dependency.Enabled,
visible: Dependency = Dependency.Enabled,
subtitle: @Composable (() -> Unit)? = null,
icon: (@Composable () -> Unit)? = null,
preferenceStyle: PreferenceStyle = LocalPreferenceSettings.current.itemStyle
) {
PreferenceInputNumber.kt
fun <T : Number> PreferenceScope.PreferenceInputNumber(
// Special
value: T,
onValueChange: (value: T) -> Unit,
// Base Preference
title: @Composable () -> Unit,
enabled: Dependency = Dependency.Enabled,
visible: Dependency = Dependency.Enabled,
subtitle: @Composable (() -> Unit)? = null,
icon: (@Composable () -> Unit)? = null,
preferenceStyle: PreferenceStyle = LocalPreferenceSettings.current.itemStyle
) {
Input List
Preview | Module | |
---|---|---|
list | ||
list |
This preference does offer 2 different options, one that allows you to only select a single item and one that allows to select mutliple items.
PreferenceList.kt
fun <T> PreferenceScope.PreferenceList(
style: PreferenceList.Style = PreferenceList.Style.Dialog,
// Special
value: T,
onValueChange: (value: T) -> Unit,
items: List<T>,
itemTextProvider: @Composable (item: T) -> String,
itemIconProvider: (@Composable (item: T) -> Unit)? = null,
// Base Preference
title: @Composable () -> Unit,
enabled: Dependency = Dependency.Enabled,
visible: Dependency = Dependency.Enabled,
subtitle: @Composable (() -> Unit)? = null,
icon: (@Composable () -> Unit)? = null,
preferenceStyle: PreferenceStyle = LocalPreferenceSettings.current.itemStyle
) {
PreferenceListMulti.kt
fun <T> PreferenceScope.PreferenceListMulti(
// Special
value: List<T>,
onValueChange: (value: List<T>) -> Unit,
items: List<T>,
itemTextProvider: @Composable (item: T) -> String,
itemIconProvider: (@Composable (item: T) -> Unit)? = null,
formatter: @Composable (selected: List<T>) -> String = { selected ->
selected.map {
itemTextProvider(it)
}.joinToString(";")
},
// Base Preference
title: @Composable () -> Unit,
enabled: Dependency = Dependency.Enabled,
visible: Dependency = Dependency.Enabled,
subtitle: @Composable (() -> Unit)? = null,
icon: (@Composable () -> Unit)? = null,
preferenceStyle: PreferenceStyle = LocalPreferenceSettings.current.itemStyle
) {
Number Preference
Preview | Module |
---|---|
number |
PreferenceNumber.kt
fun <T : Number> PreferenceScope.PreferenceNumber(
style: PreferenceNumber.Style = PreferenceNumber.Style.Picker,
// Special
value: T,
onValueChange: (value: T) -> Unit,
min: T,
max: T,
stepSize: T,
formatter: (value: T) -> String = { it.toString() },
// Base Preference
title: @Composable () -> Unit,
enabled: Dependency = Dependency.Enabled,
visible: Dependency = Dependency.Enabled,
subtitle: @Composable (() -> Unit)? = null,
icon: (@Composable () -> Unit)? = null,
preferenceStyle: PreferenceStyle = LocalPreferenceSettings.current.itemStyle
) {
Time Preference
Preview | Module |
---|---|
time |
PreferenceTime.kt
fun PreferenceScope.PreferenceTime(
// Special
value: LocalTime,
onValueChange: (value: LocalTime) -> Unit,
is24Hours: Boolean = DateFormat.is24HourFormat(LocalContext.current),
formatter: (time: LocalTime) -> String = getDefaultTimeFormatter(is24Hours),
// Base Preference
title: @Composable () -> Unit,
enabled: Dependency = Dependency.Enabled,
visible: Dependency = Dependency.Enabled,
subtitle: @Composable (() -> Unit)? = null,
icon: (@Composable () -> Unit)? = null,
preferenceStyle: PreferenceStyle = LocalPreferenceSettings.current.itemStyle
) {