Skip to content

Commit

Permalink
Add theming support
Browse files Browse the repository at this point in the history
  • Loading branch information
andraantariksa committed Apr 16, 2022
1 parent c28fb94 commit 62be178
Show file tree
Hide file tree
Showing 12 changed files with 183 additions and 6 deletions.
3 changes: 2 additions & 1 deletion .idea/misc.xml

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

3 changes: 3 additions & 0 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,9 @@ dependencies {

implementation "pub.devrel:easypermissions:3.0.0"

// Datastore
implementation "androidx.datastore:datastore-preferences:1.0.0"

implementation 'androidx.core:core-ktx:1.7.0'
implementation 'androidx.appcompat:appcompat:1.4.1'
implementation 'com.google.android.material:material:1.5.0'
Expand Down
47 changes: 47 additions & 0 deletions app/src/main/kotlin/id/shaderboi/koffie/KoffieApplication.kt
Original file line number Diff line number Diff line change
@@ -1,15 +1,28 @@
package id.shaderboi.koffie

import android.app.Application
import androidx.appcompat.app.AppCompatDelegate
import com.google.firebase.FirebaseApp
import com.google.firebase.appcheck.FirebaseAppCheck
import com.google.firebase.appcheck.safetynet.SafetyNetAppCheckProviderFactory
import dagger.hilt.android.HiltAndroidApp
import id.shaderboi.koffie.core.domain.model.theme.Theme
import id.shaderboi.koffie.core.domain.repository.AppSettingsRepository
import id.shaderboi.koffie.util.logger.ReleaseTree
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.firstOrNull
import kotlinx.coroutines.flow.singleOrNull
import timber.log.Timber
import javax.inject.Inject

@HiltAndroidApp
class KoffieApplication : Application() {
@Inject
lateinit var appSettingsRepository: AppSettingsRepository

val coroutineScope = MainScope()

override fun onCreate() {
super.onCreate()

Expand All @@ -24,5 +37,39 @@ class KoffieApplication : Application() {
firebaseAppCheck.installAppCheckProviderFactory(
SafetyNetAppCheckProviderFactory.getInstance()
)

runBlocking {
withTimeout(50) {
appSettingsRepository.flow.firstOrNull()?.let { appSettings ->
when (appSettings.theme) {
Theme.FollowSystem -> {
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_UNSPECIFIED)
}
Theme.Dark -> {
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES)
}
Theme.Light -> {
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO)
}
}
}
}
}

coroutineScope.launch {
appSettingsRepository.flow.collectLatest { appSettings ->
when (appSettings.theme) {
Theme.FollowSystem -> {
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_UNSPECIFIED)
}
Theme.Dark -> {
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES)
}
Theme.Light -> {
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO)
}
}
}
}
}
}
10 changes: 8 additions & 2 deletions app/src/main/kotlin/id/shaderboi/koffie/di/AppModule.kt
Original file line number Diff line number Diff line change
@@ -1,16 +1,22 @@
package id.shaderboi.koffie.di

import com.google.firebase.auth.FirebaseAuth
import android.content.Context
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.android.qualifiers.ApplicationContext
import dagger.hilt.components.SingletonComponent
import id.shaderboi.koffie.core.data.repository.AppSettingsRepositoryImpl
import id.shaderboi.koffie.core.domain.repository.AppSettingsRepository
import java.text.DecimalFormat
import javax.inject.Singleton

@Module
@InstallIn(SingletonComponent::class)
object AppModule {
@Provides
fun provideNumberFormatter(): DecimalFormat = DecimalFormat("#,###.00")

@Provides
fun provideAppSettingsRepository(@ApplicationContext context: Context): AppSettingsRepository =
AppSettingsRepositoryImpl(context)
}
Original file line number Diff line number Diff line change
@@ -1,14 +1,49 @@
package id.shaderboi.koffie.ui.main.misc

import android.os.Bundle
import android.view.View
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import androidx.preference.ListPreference
import androidx.preference.PreferenceFragmentCompat
import dagger.hilt.EntryPoint
import dagger.hilt.android.AndroidEntryPoint
import id.shaderboi.koffie.R
import id.shaderboi.koffie.core.domain.model.theme.Theme
import id.shaderboi.koffie.core.domain.repository.AppSettingsRepository
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.launch
import javax.inject.Inject

@AndroidEntryPoint
class PreferenceFragment: PreferenceFragmentCompat() {
class PreferenceFragment : PreferenceFragmentCompat() {
@Inject
lateinit var appSettingsRepository: AppSettingsRepository

override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
setPreferencesFromResource(R.xml.profile_preference, rootKey)
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)

val themeList = findPreference<ListPreference>("theme")!!

viewLifecycleOwner.lifecycleScope.launch {
viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
themeList.setOnPreferenceChangeListener { preference, newValue ->
launch {
appSettingsRepository.setTheme(Theme.valueOf(newValue as String))
}
true
}

launch {
appSettingsRepository.flow.collectLatest { appSettings ->
themeList.value = appSettings.theme.name
}
}
}
}
}
}
10 changes: 10 additions & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,16 @@
<item>Female</item>
<item>Prefer not to say</item>
</string-array>
<string-array name="theme">
<item>Follow system</item>
<item>Dark</item>
<item>Light</item>
</string-array>
<string-array name="themeValues">
<item>FollowSystem</item>
<item>Dark</item>
<item>Light</item>
</string-array>

<string name="app_name">Koffie</string>
<string name="explore">Explore</string>
Expand Down
10 changes: 9 additions & 1 deletion app/src/main/res/xml/profile_preference.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:app="http:https://schemas.android.com/apk/res-auto">
<PreferenceScreen xmlns:android="http:https://schemas.android.com/apk/res/android"
xmlns:app="http:https://schemas.android.com/apk/res-auto">

<SwitchPreferenceCompat
app:key="notifications"
Expand All @@ -10,5 +11,12 @@
app:title="Send feedback"
app:summary="Report technical issues or suggest new features"/>

<ListPreference
android:entries="@array/theme"
android:entryValues="@array/themeValues"
app:key="theme"
app:summary="For those of you who only like to be one sided"
app:title="App theme" />


</PreferenceScreen>
3 changes: 3 additions & 0 deletions core/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,9 @@ dependencies {
// Datetime
implementation "org.jetbrains.kotlinx:kotlinx-datetime:0.3.2"

// Datastore
implementation "androidx.datastore:datastore-preferences:1.0.0"

implementation 'androidx.core:core-ktx:1.7.0'
implementation 'androidx.appcompat:appcompat:1.4.1'
implementation 'com.google.android.material:material:1.5.0'
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package id.shaderboi.koffie.core.data.data_source.local.datastore

import android.content.Context
import androidx.datastore.core.DataStore
import androidx.datastore.preferences.core.Preferences
import androidx.datastore.preferences.core.intPreferencesKey
import androidx.datastore.preferences.preferencesDataStore
import id.shaderboi.koffie.core.domain.model.theme.Theme

val Context.settingsDataStore: DataStore<Preferences> by preferencesDataStore(name = "app_settings")

data class AppSettings(
val theme: Theme
)

val APP_THEME = intPreferencesKey("APP_THEME")
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package id.shaderboi.koffie.core.data.repository

import android.content.Context
import androidx.datastore.preferences.core.edit
import id.shaderboi.koffie.core.data.data_source.local.datastore.APP_THEME
import id.shaderboi.koffie.core.data.data_source.local.datastore.AppSettings
import id.shaderboi.koffie.core.data.data_source.local.datastore.settingsDataStore
import id.shaderboi.koffie.core.domain.model.theme.Theme
import id.shaderboi.koffie.core.domain.repository.AppSettingsRepository
import kotlinx.coroutines.flow.map
import javax.inject.Inject

class AppSettingsRepositoryImpl @Inject constructor(
context: Context
): AppSettingsRepository {
private val settingsDataStore = context.settingsDataStore
override val flow = settingsDataStore.data.map { pref ->
val theme = Theme.values()[pref[APP_THEME] ?: Theme.FollowSystem.ordinal]
AppSettings(theme)
}

override suspend fun setTheme(theme: Theme) {
settingsDataStore.edit { pref ->
pref[APP_THEME] = theme.ordinal
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package id.shaderboi.koffie.core.domain.model.theme

enum class Theme {
FollowSystem,
Dark,
Light
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package id.shaderboi.koffie.core.domain.repository

import androidx.datastore.preferences.core.edit
import id.shaderboi.koffie.core.data.data_source.local.datastore.APP_THEME
import id.shaderboi.koffie.core.data.data_source.local.datastore.AppSettings
import id.shaderboi.koffie.core.domain.model.theme.Theme
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map

interface AppSettingsRepository {
val flow: Flow<AppSettings>

suspend fun setTheme(theme: Theme)
}

0 comments on commit 62be178

Please sign in to comment.