About
Introduction
This library is based on Flows
and Coroutines
and works with the provided DataStore Storage or even with a custom storage implementation. It supports LiveData
by default as Flows
can easily be converted to LiveData
. Preferences are elegantly declared via delegates
. Additionally the preference-screen module provides a DSL to easily set up RecyclerView
based preference screens. It also supports custom extensions for custom preference screens.
Following are the key features:
- define preferences elegantly via delegates
- flow and coroutine based
- allows to observe single / some / all preferences
- provides suspending update functions
- provides a DSL for a
RecyclerView
based setting screen
Core
With this library you can declare preferences via kotlin delegates
,and observe and update them via kotlin Flows
. This works with any storage implementation, an implementation for JetPack DataStore is provided already.
1/4 Define preferences:
object UserSettingsModel : SettingsModel(DataStoreStorage(name = "user")) {
// Basic
val name by stringPref("User")
val alive by boolPref(true)
val hairColor by intPref(Color.parseColor("#A52A2A"))
val age by intPref(40)
val income by floatPref(50000f)
val dayOfBirth by longPref(0L)
val doubleTest by doublePref(0.0)
// Sets
val childrenAges by intSetPref(setOf(20, 18, 16))
val childrenIncomes by floatSetPref(setOf(30000f, 10000f, 0f))
val childrenDaysOfBirth by longSetPref(setOf(0L, 0L, 0L))
// Enum
val car by enumPref(Car.Tesla)
// custom class - provide a custom converter (String <=> Class)
val testClass by anyPref(TestClass.CONVERTER, TestClass())
// NULLABLE variants
val nullableString by nullableStringPref()
val nullableInt by nullableIntPref()
val nullableFloat by nullableFloatPref()
val nullableDouble by nullableDoublePref()
val nullableLong by nullableLongPref()
val nullableBool by nullableBoolPref()
}
2/4 Observe/Read preferences:
// 1) simply observe a setting
UserSettingsModel.name.observe(lifecycleScope) {
L.d { "name = $it"}
}
// 2) direct read (not recommended if not necessary but may be useful in many cases => simply returns flow.first() in a blocking way)
val name = UserSettingsModel.name.value
// 3) observe a setting once
UserSettingsModel.name.observeOnce(lifecycleScope) {
L.d { "name = $it"}
}
// 4) observe ALL settings
UserSettingsModel.changes.onEach {
L.d { "[ALL SETTINGS OBSERVER] Setting '${it.setting.key}' changed its value to ${it.value}" }
}.launchIn(lifecycleScope)
// 5) observe SOME settings
UserSettingsModel.changes´
.filter {
it.setting == UserSettingsModel.name ||
it.setting == UserSettingsModel.age
}.onEach {
// we know that either the name or the age changes
L.d { "[SOME SETTINGS OBSERVER] Setting '${it.setting.key}' changed its value to ${it.value}" }
}.launchIn(lifecycleScope)
// 6) read multiple settings in a suspending way
lifecycleScope.launch(Dispatchers.IO) {
val name = UserSettingsModel.childName1.flow.first()
val alive = DemoSettingsModel.alive.flow.first()
val hairColor = DemoSettingsModel.hairColor.flow.first()
withContext(Dispatchers.Main) {
textView.text = "Informations: $name, $alive, $hairColor"
}
}
3/4 Lifedata:
val lifedata = UserSettingsModel.name.flow.asLiveData()
4/4 Update preferences:
lifecycleScope.launch(Dispatchers.IO) {
UserSettingsModel.name.update("Some new name")
UserSettingsModel.age.update(30)
}
Storage
The Storage
is an abstraction to support any storage implementation. The datastore
module provides an implementation based on the Android JetPack DataStore.
Check out the corresponding readme here: DataStore Module README
Preference Screen
The preference-screen* modules allow you to create preference screens like following easily via DSL.
Explanations, code examples and more be found here: Preference Screen Modules README
JitPack.io)
Gradle (via- add jitpack to your project's
build.gradle
:
repositories {
maven { url "https://jitpack.io" }
}
- add the compile statement to your module's
build.gradle
:
dependencies { // core module implementation "com.github.MFlisar.MaterialPreferences:core:" // data store module implementation "com.github.MFlisar.MaterialPreferences:datastore:" // screen modules implementation "com.github.MFlisar.MaterialPreferences:screen:" implementation "com.github.MFlisar.MaterialPreferences:screen-input:" implementation "com.github.MFlisar.MaterialPreferences:screen-choice:" implementation "com.github.MFlisar.MaterialPreferences:screen-color:" }
TODO
- Preference Types
- SeekBar Preference
- Collapse Preference - add sub items ONCE on click
- Dropdown Preference
- Spacer Preference
- Others
- Global Setting - enable title numbering (Count numbers of categories yes/no)
- use MaterialDialogFragments dialog fragments so that even the dialogs restore their state and remember temporary user changes inside the dialogs