Dark Mode for Android App in Kotlin using DataStore Jetpack android
Dark Theme Night Mode implementation programmatically Android App Development Tutorial for beginners
- Dark Mode is an example of optimization of User Experience as well as the Battery.
- It can be implemented on any application a developer desires.
DataStore
- Jetpack DataStore is a data storage solution that allows you to store key-value pairs (Google’s new library).
- It aims to replace SharedPreferences.
- DataStore uses Kotlin coroutines and Flow to store data asynchronously, consistently, and transactionally.
Google Material Design Color
- Build a custom theme and export it to code.
..
How to implement Dark (Night) mode in Android using DataStore?
Step 1:
Add datastore dependency in build.gradle file of your app module
// Preference DataStore
implementation "androidx.datastore:datastore-preferences:1.0.0"
Step 2:
Create a Preferences DataStore
- The Preferences DataStore implementation uses the DataStore and Preferences classes to persist simple key-value pairs to disk.
- At the top level of your kotlin file
class UIModePreference(var context: Context) {
// At the top level of your kotlin file:
private val Context.dataStore: DataStore<Preferences> by preferencesDataStore(name = "ui_mode_preference")
}
Step 3:
Read from a Preferences DataStore
- To define a key for an int value, use intPreferencesKey().
- Use the DataStore.data property to expose the appropriate stored value using a Flow.
val uiMode: Flow<Boolean> = context.dataStore.data
.map { preferences ->
val uiMode = preferences[UI_MODE_KEY] ?: false
uiMode
}
..
Step 4:
Write to a Preferences DataStore
- Preferences DataStore provides an edit() function that transactionally updates the data in a DataStore
- The function's transform parameter accepts a block of code where you can update the values as needed. All of the code in the transform block is treated as a single transaction.
suspend fun saveToDataStore(isNightMode: Boolean) {
context.dataStore.edit { preferences ->
preferences[UI_MODE_KEY] = isNightMode
}
}
Get this code for the common class for the data store to read & write daylight mode switching boolean value UIModePreference.kt
Step 5:
Set the menu in our fragment to switch daylight mode in a toolbar menu item.
- Add menu/menu_main.xml in your res folder
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/action_night_mode"
android:checkable="true"
android:icon="@drawable/ic_day"
android:title="@string/text_ui_mode"
app:showAsAction="ifRoom" />
</menu>
- Add the following code in your fragment to handle the menu item
//'setHasOptionsMenu(Boolean): Unit' is deprecated. Deprecated in Java
//https://stackoverflow.com/questions/71917856/sethasoptionsmenuboolean-unit-is-deprecated-deprecated-in-java
// The usage of an interface lets you inject your own implementation
val menuHost: MenuHost = requireActivity()
// Add menu items without using the Fragment Menu APIs
// Note how we can tie the MenuProvider to the viewLifecycleOwner
// and an optional Lifecycle.State (here, RESUMED) to indicate when
// the menu should be visible
menuHost.addMenuProvider(object : MenuProvider {
override fun onCreateMenu(menu: Menu, menuInflater: MenuInflater) {
// Add menu items here
menuInflater.inflate(R.menu.menu_main, menu)
}
override fun onMenuItemSelected(menuItem: MenuItem): Boolean {
// Handle the menu selection
return when (menuItem.itemId) {
R.id.action_night_mode -> {
//..
true
}
else -> false
}
}
}, viewLifecycleOwner, Lifecycle.State.RESUMED)
...
Step 6:
Applying Dark modeAppCompatDelegate
.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES) // night mode
AppCompatDelegate
.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO) // day mode
//this will follow system settings (from notification bar)
AppCompatDelegate
.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM)
private fun setUIMode(item: MenuItem, isChecked: Boolean) {
if (isChecked) {
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES)
viewModelActivity.saveToDataStore(true)
item.setIcon(R.drawable.ic_night)
} else {
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO)
viewModelActivity.saveToDataStore(false)
item.setIcon(R.drawable.ic_day)
}
}
We use the view model to store and retrieve the mode value from the datastore.class NotesViewModel(application: Application) :
AndroidViewModel(application) {
// DataStore
private val uiDataStore = UIModePreference(application)
// get UI mode
val getUIMode = uiDataStore.uiMode
// save UI mode
fun saveToDataStore(isNightMode: Boolean) {
viewModelScope.launch(IO) {
uiDataStore.saveToDataStore(isNightMode)
}
}
..
GET source code on Github:
Comments
Post a Comment