Skip to content

Commit

Permalink
Example Settings Screen with variants of each Preference
Browse files Browse the repository at this point in the history
  • Loading branch information
JamalMulla committed Dec 27, 2021
1 parent bfb5002 commit b12ef11
Show file tree
Hide file tree
Showing 17 changed files with 358 additions and 93 deletions.
6 changes: 6 additions & 0 deletions .idea/vcs.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion ComposePrefs/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ afterEvaluate {
from components.release

groupId = 'com.github.jamalmulla'
artifactId = 'Compose Prefs'
artifactId = 'ComposePrefs'
version = '1.0'
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ fun PrefsCategoryHeader(
) {
Text(
title,
color = MaterialTheme.colors.secondary,
color = MaterialTheme.colors.primary,
fontSize = LocalTextStyle.current.fontSize.times(FontSizeMultiplier),
fontWeight = FontWeight.SemiBold
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ fun PrefsListItem(
icon: @Composable (() -> Unit)? = null,
secondaryText: @Composable (() -> Unit)? = null,
trailing: @Composable (() -> Unit)? = null,
textColor: Color = LocalTextStyle.current.color,
textColor: Color = MaterialTheme.colors.onBackground,
minimalHeight: Boolean = false,
text: @Composable () -> Unit
) {
Expand Down Expand Up @@ -69,6 +69,8 @@ private object AnyLine {
private val MinHeightSmaller = 32.dp
private val IconMinPaddedWidth = 40.dp
private val ContentPadding = 16.dp
private val VerticalPadding = 12.dp
private val SingleLinePadding = 4.dp //used when no secondary text is supplied

@Composable
fun CustomListItem(
Expand All @@ -85,8 +87,15 @@ private object AnyLine {
.padding(
start = ContentPadding,
end = ContentPadding,
top = ContentPadding,
bottom = if (minimalHeight) 0.dp else ContentPadding
top = when {
secondaryText == null && !minimalHeight -> SingleLinePadding
else -> VerticalPadding
},
bottom = when {
minimalHeight -> 0.dp
secondaryText == null -> SingleLinePadding
else -> VerticalPadding
}
)
.fillMaxWidth(),
verticalAlignment = Alignment.CenterVertically,
Expand All @@ -102,7 +111,7 @@ private object AnyLine {

Column(
verticalArrangement = Arrangement.Center,
modifier = Modifier.weight(0.8f)
modifier = Modifier.weight(1f)
) {
text()
secondaryText?.invoke()
Expand Down
33 changes: 19 additions & 14 deletions ComposePrefs/src/main/java/com/jamal/composeprefs/ui/PrefScreen.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package com.jamal.composeprefs.ui

import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
Expand All @@ -27,26 +30,28 @@ fun PrefsScreen(
content: PrefsScope.() -> Unit
) {
LocalPrefsDataStore = staticCompositionLocalOf { dataStore }
// basically call prefsItem/prefsItems() on each thing that was passed
val prefsScope = PrefsScopeImpl().apply(content)

// Now the dataStore can be accessed by calling LocalPrefsDataStore.current from any child Pref
CompositionLocalProvider(LocalPrefsDataStore provides dataStore) {
LazyColumn(modifier = modifier.fillMaxSize()) {
Column {
Spacer(modifier = Modifier.height(12.dp))
LazyColumn(modifier = modifier.fillMaxSize()) {

items(prefsScope.prefsItems.size) { index ->
prefsScope.getPrefsItem(index)()
items(prefsScope.prefsItems.size) { index ->
prefsScope.getPrefsItem(index)()

if (dividerThickness != 0.dp
&& index != prefsScope.prefsItems.size - 1
&& !prefsScope.headerIndexes.contains(index)
&& !prefsScope.headerIndexes.contains(index + 1)
&& !prefsScope.footerIndexes.contains(index)
) {
Divider(
thickness = dividerThickness,
indent = dividerIndent
)
if (dividerThickness != 0.dp
&& index != prefsScope.prefsItems.size - 1
&& !prefsScope.headerIndexes.contains(index)
&& !prefsScope.headerIndexes.contains(index + 1)
&& !prefsScope.footerIndexes.contains(index)
) {
Divider(
thickness = dividerThickness,
indent = dividerIndent
)
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
package com.jamal.composeprefs.ui.prefs

import android.util.Log
import androidx.compose.material.Checkbox
import androidx.compose.material.ExperimentalMaterialApi
import androidx.compose.material.MaterialTheme
import androidx.compose.material.*
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
Expand Down Expand Up @@ -73,6 +71,7 @@ fun CheckBoxPref(
summary = summary,
leadingIcon = leadingIcon,
enabled = enabled,
darkenOnDisable = true,
onClick = {
checked = !checked
edit(checked)
Expand All @@ -81,6 +80,7 @@ fun CheckBoxPref(
Checkbox(
checked = checked,
enabled = enabled,
colors = CheckboxDefaults.colors(checkedColor = MaterialTheme.colors.primary),
onCheckedChange = {
edit(it)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import java.lang.Exception
* @param summary Used to give some more information about what this Pref is for
* @param defaultValue Default selected key if this Pref hasn't been saved already. Otherwise the value from the dataStore is used.
* @param onValueChange Will be called with the selected key when an item is selected
* @param useCurrentValueAsSummary If true, uses the current selected item as the summary. Equivalent of useSimpleSummaryProvider in androidx.
* @param useSelectedAsSummary If true, uses the current selected item as the summary. Equivalent of useSimpleSummaryProvider in androidx.
* @param dropdownBackgroundColor Color of the dropdown menu
* @param textColor Text colour of the [title] and [summary]
* @param enabled If false, this Pref cannot be clicked and the dropdown menu will not show.
Expand All @@ -41,9 +41,9 @@ fun DropDownPref(
summary: String? = null,
defaultValue: String? = null,
onValueChange: ((String) -> Unit)? = null,
useCurrentValueAsSummary: Boolean = false,
useSelectedAsSummary: Boolean = false,
dropdownBackgroundColor: Color? = null,
textColor: Color = contentColorFor(backgroundColor = MaterialTheme.colors.surface),
textColor: Color = MaterialTheme.colors.onBackground,
enabled: Boolean = true,
entries: Map<String, String> = mapOf()
) {
Expand Down Expand Up @@ -76,7 +76,11 @@ fun DropDownPref(
TextPref(
title = title,
modifier = modifier,
summary = if (useCurrentValueAsSummary) entries[value] else summary,
summary = when {
useSelectedAsSummary && value != null -> entries[value]
useSelectedAsSummary && value == null -> "Not Set"
else -> summary
},
textColor = textColor,
enabled = enabled,
onClick = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,8 @@ fun EditTextPref(
defaultValue: String = "",
onValueSaved: ((String) -> Unit) = {},
onValueChange: ((String) -> Unit) = {},
dialogBackgroundColor: Color = MaterialTheme.colors.surface,
textColor: Color = contentColorFor(backgroundColor = MaterialTheme.colors.surface),
dialogBackgroundColor: Color = MaterialTheme.colors.background,
textColor: Color = MaterialTheme.colors.onBackground,
enabled: Boolean = true,
) {

Expand Down Expand Up @@ -149,8 +149,7 @@ fun EditTextPref(
) {
TextButton(
modifier = Modifier.padding(end = 16.dp),
onClick = { showDialog = false },
colors = ButtonDefaults.textButtonColors(contentColor = MaterialTheme.colors.secondary),
onClick = { showDialog = false }
) {
Text("Cancel", style = MaterialTheme.typography.body1)
}
Expand All @@ -160,8 +159,7 @@ fun EditTextPref(
onClick = {
edit()
showDialog = false
},
colors = ButtonDefaults.textButtonColors(contentColor = MaterialTheme.colors.secondary),
}
) {
Text("Save", style = MaterialTheme.typography.body1)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ import com.jamal.composeprefs.ui.LocalPrefsDataStore
import kotlinx.coroutines.launch
import java.lang.Exception

//TODO useSelectedAsSummary

/**
* Preference that shows a list of entries in a Dialog where a single entry can be selected at one time.
*
Expand All @@ -28,6 +30,7 @@ import java.lang.Exception
* @param summary Used to give some more information about what this Pref is for
* @param defaultValue Default selected key if this Pref hasn't been saved already. Otherwise the value from the dataStore is used.
* @param onValueChange Will be called with the selected key when an item is selected
* @param useSelectedAsSummary If true, uses the current selected item as the summary
* @param dialogBackgroundColor Background color of the Dialog
* @param textColor Text colour of the [title] and [summary]
* @param enabled If false, this Pref cannot be clicked and the Dialog cannot be shown.
Expand All @@ -38,13 +41,14 @@ import java.lang.Exception
@Composable
fun ListPref(
key: String,
title: String, // Title is shown above summary and with the dialog
title: String,
modifier: Modifier = Modifier,
summary: String? = null,
defaultValue: String? = null, // default selected key if this hasn't been saved already. otherwise the value from the datastore is used
defaultValue: String? = null,
onValueChange: ((String) -> Unit)? = null,
useSelectedAsSummary: Boolean = false,
dialogBackgroundColor: Color = MaterialTheme.colors.surface,
textColor: Color = contentColorFor(backgroundColor = MaterialTheme.colors.surface),
textColor: Color = MaterialTheme.colors.onBackground,
enabled: Boolean = true,
entries: Map<String, String> = mapOf()
) {
Expand Down Expand Up @@ -75,7 +79,11 @@ fun ListPref(

TextPref(
title = title,
summary = summary,
summary = when {
useSelectedAsSummary && selected != null -> entries[selected]
useSelectedAsSummary && selected == null -> "Not Set"
else -> summary
},
modifier = modifier,
textColor = textColor,
enabled = true,
Expand Down Expand Up @@ -104,7 +112,8 @@ fun ListPref(
) {
RadioButton(
selected = isSelected,
onClick = { if (!isSelected) onSelected() }
onClick = { if (!isSelected) onSelected() },
colors = RadioButtonDefaults.colors(selectedColor = MaterialTheme.colors.primary)
)
Text(
text = current.value,
Expand All @@ -118,7 +127,6 @@ fun ListPref(
confirmButton = {
TextButton(
onClick = { showDialog = false },
colors = ButtonDefaults.textButtonColors(contentColor = MaterialTheme.colors.secondary),
) {
Text("Cancel", style = MaterialTheme.typography.body1)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,21 +38,20 @@ import java.lang.Exception
@Composable
fun MultiSelectListPref(
key: String,
title: String, // Title is shown above summary and with the dialog
title: String,
modifier: Modifier = Modifier,
summary: String? = null,
defaultValue: Set<String> = setOf(), // default selected keys if this hasn't been saved already. otherwise the value from the datastore is used
defaultValue: Set<String> = setOf(),
onValuesChange: ((Set<String>) -> Unit)? = null,
dialogBackgroundColor: Color = MaterialTheme.colors.surface,
textColor: Color = contentColorFor(backgroundColor = MaterialTheme.colors.surface),
textColor: Color = MaterialTheme.colors.onBackground,
enabled: Boolean = true,
entries: Map<String, String> = mapOf()
) {
var showDialog by rememberSaveable { mutableStateOf(false) }
val selectionKey = stringSetPreferencesKey(key)
val scope = rememberCoroutineScope()

// need to observe state with some sort of flow maybe? this also works
val datastore = LocalPrefsDataStore.current
val prefs by remember { datastore.data }.collectAsState(initial = null)

Expand Down Expand Up @@ -112,7 +111,8 @@ fun MultiSelectListPref(
) {
Checkbox(
checked = isSelected,
onCheckedChange = { onSelectionChanged() }
onCheckedChange = { onSelectionChanged() },
colors = CheckboxDefaults.colors(checkedColor = MaterialTheme.colors.primary)
)
Text(
text = current.value,
Expand All @@ -127,7 +127,6 @@ fun MultiSelectListPref(
confirmButton = {
TextButton(
onClick = { showDialog = false },
colors = ButtonDefaults.textButtonColors(contentColor = MaterialTheme.colors.secondary),
) {
Text(text = "Select", style = MaterialTheme.typography.body1)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,6 @@ fun SliderPref(
leadingIcon: @Composable (() -> Unit)? = null,
) {

//todo overlapping with long title
val selectionKey = floatPreferencesKey(key)
val scope = rememberCoroutineScope()

Expand Down Expand Up @@ -112,16 +111,7 @@ fun SliderPref(
valueRange = valueRange,
steps = steps,
onValueChangeFinished = { edit() },
enabled = enabled,
colors = SliderDefaults.colors(
thumbColor = MaterialTheme.colors.secondary,
disabledThumbColor = MaterialTheme.colors.onSurface
.copy(alpha = ContentAlpha.disabled)
.compositeOver(MaterialTheme.colors.surface),
activeTrackColor = MaterialTheme.colors.secondary,
disabledActiveTrackColor =
MaterialTheme.colors.onSurface.copy(alpha = SliderDefaults.DisabledActiveTrackAlpha)
)
enabled = enabled
)

if (showValue) {
Expand All @@ -130,7 +120,7 @@ fun SliderPref(
color = textColor,
modifier = Modifier
.weight(0.5f)
.padding(start = 16.dp)
.padding(start = 8.dp)
)
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
package com.jamal.composeprefs.ui.prefs

import android.util.Log
import androidx.compose.material.ExperimentalMaterialApi
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Switch
import androidx.compose.material.*
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
Expand Down Expand Up @@ -67,6 +65,7 @@ fun SwitchPref(
modifier = modifier,
textColor = textColor,
summary = summary,
darkenOnDisable = true,
leadingIcon = leadingIcon,
enabled = enabled,
onClick = {
Expand All @@ -77,6 +76,7 @@ fun SwitchPref(
Switch(
checked = checked,
enabled = enabled,
colors = SwitchDefaults.colors(checkedThumbColor = MaterialTheme.colors.primary),
onCheckedChange = {
edit(it)
}
Expand Down
4 changes: 4 additions & 0 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -62,4 +62,8 @@ dependencies {
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
androidTestImplementation "androidx.compose.ui:ui-test-junit4:$compose_version"
debugImplementation "androidx.compose.ui:ui-tooling:$compose_version"

// ComposePrefs library
implementation project(':ComposePrefs')
implementation "androidx.datastore:datastore-preferences:1.0.0"
}
Loading

0 comments on commit b12ef11

Please sign in to comment.