Skip to content

Commit 9674f04

Browse files
committed
add dark mode settings
1 parent a83d2b6 commit 9674f04

11 files changed

Lines changed: 174 additions & 6 deletions

File tree

app/build.gradle

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,15 +48,33 @@ dependencies {
4848
implementation 'com.github.bumptech.glide:glide:4.12.0'
4949
implementation 'de.hdodenhof:circleimageview:3.1.0'
5050
implementation "androidx.viewpager2:viewpager2:1.0.0"
51+
implementation 'androidx.fragment:fragment-ktx:1.5.6'
52+
53+
// Room
5154
def room_version = '2.5.1'
5255
implementation "androidx.room:room-runtime:$room_version"
5356
annotationProcessor "androidx.room:room-compiler:$room_version"
5457
androidTestImplementation "androidx.room:room-testing:$room_version"
5558
implementation "androidx.room:room-ktx:$room_version"
5659
kapt "androidx.room:room-compiler:$room_version"
60+
61+
// Coroutines
5762
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4"
5863
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4"
5964

65+
// Lifecycle
66+
def lifecycle_version = "2.6.1"
67+
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version"
68+
implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version"
69+
implementation "androidx.lifecycle:lifecycle-runtime-ktx:$lifecycle_version"
70+
implementation "androidx.lifecycle:lifecycle-common-java8:$lifecycle_version"
71+
implementation "androidx.lifecycle:lifecycle-viewmodel-savedstate:$lifecycle_version"
72+
73+
// DataStore
74+
implementation "androidx.datastore:datastore-preferences-core:1.0.0"
75+
implementation "androidx.datastore:datastore-preferences:1.0.0"
76+
77+
6078
testImplementation 'junit:junit:4.13.2'
6179
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
6280
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'

app/src/main/AndroidManifest.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@
1313
android:supportsRtl="true"
1414
android:theme="@style/Theme.GithubUser"
1515
tools:targetApi="31">
16+
<activity
17+
android:name=".ui.setting.SettingActivity"
18+
android:exported="false" />
1619
<activity
1720
android:name=".ui.favorite.FavoriteActivity"
1821
android:exported="false" />
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package com.riyandifirman.githubuser.settings
2+
3+
import android.content.Context
4+
import androidx.datastore.preferences.core.booleanPreferencesKey
5+
import androidx.datastore.preferences.core.edit
6+
import androidx.datastore.preferences.preferencesDataStore
7+
import kotlinx.coroutines.flow.Flow
8+
import kotlinx.coroutines.flow.map
9+
10+
private val Context.prefDataStore by preferencesDataStore(name = "settings")
11+
12+
class SettingsPreferences(context: Context) {
13+
14+
private val settingsDataStore = context.prefDataStore
15+
private val themeKey = booleanPreferencesKey("theme")
16+
17+
fun getTheme(): Flow<Boolean> = settingsDataStore.data.map { preferences ->
18+
preferences[themeKey] ?: false
19+
}
20+
21+
suspend fun setTheme(isDarkMode: Boolean) {
22+
settingsDataStore.edit { preferences ->
23+
preferences[themeKey] = isDarkMode
24+
}
25+
}
26+
}

app/src/main/java/com/riyandifirman/githubuser/ui/main/MainActivity.kt

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,22 +8,27 @@ import android.os.Bundle
88
import android.view.Menu
99
import android.view.MenuItem
1010
import android.view.View
11+
import androidx.activity.viewModels
12+
import androidx.appcompat.app.AppCompatDelegate
1113
import androidx.appcompat.widget.SearchView
1214
import androidx.lifecycle.ViewModelProvider
1315
import androidx.recyclerview.widget.LinearLayoutManager
1416
import com.riyandifirman.githubuser.R
1517
import com.riyandifirman.githubuser.User
1618
import com.riyandifirman.githubuser.adapter.UserAdapter
1719
import com.riyandifirman.githubuser.databinding.ActivityMainBinding
20+
import com.riyandifirman.githubuser.settings.SettingsPreferences
1821
import com.riyandifirman.githubuser.ui.detail.DetailUserActivity
1922
import com.riyandifirman.githubuser.ui.favorite.FavoriteActivity
23+
import com.riyandifirman.githubuser.ui.setting.SettingActivity
2024
import com.riyandifirman.githubuser.viewmodel.MainViewModel
25+
import com.riyandifirman.githubuser.viewmodel.SettingsViewModel
2126

2227
class MainActivity : AppCompatActivity() {
2328

24-
private lateinit var viewModel: MainViewModel
2529
private lateinit var binding: ActivityMainBinding
2630
private lateinit var adapter: UserAdapter
31+
private lateinit var viewModel: MainViewModel
2732

2833
override fun onCreate(savedInstanceState: Bundle?) {
2934
super.onCreate(savedInstanceState)
@@ -47,7 +52,16 @@ class MainActivity : AppCompatActivity() {
4752
})
4853

4954
// inisialisasi MainViewModel
50-
viewModel = ViewModelProvider(this, ViewModelProvider.NewInstanceFactory()).get(MainViewModel::class.java)
55+
viewModel = ViewModelProvider(this, MainViewModel.Factory(SettingsPreferences(this))).get(MainViewModel::class.java)
56+
// viewModel = ViewModelProvider(this, ViewModelProvider.NewInstanceFactory()).get(MainViewModel::class.java)
57+
58+
viewModel.getTheme().observe(this) {
59+
if (it) {
60+
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES)
61+
} else {
62+
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO)
63+
}
64+
}
5165

5266
// inisialisasi recycle view
5367
binding.apply {
@@ -120,6 +134,10 @@ class MainActivity : AppCompatActivity() {
120134
val intent = Intent(this, FavoriteActivity::class.java)
121135
startActivity(intent)
122136
}
137+
R.id.settings -> {
138+
val intent = Intent(this, SettingActivity::class.java)
139+
startActivity(intent)
140+
}
123141
}
124142
return super.onOptionsItemSelected(item)
125143
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package com.riyandifirman.githubuser.ui.setting
2+
3+
import androidx.appcompat.app.AppCompatActivity
4+
import android.os.Bundle
5+
import androidx.appcompat.app.AppCompatDelegate
6+
import androidx.lifecycle.ViewModelProvider
7+
import com.riyandifirman.githubuser.R
8+
import com.riyandifirman.githubuser.databinding.ActivitySettingBinding
9+
import com.riyandifirman.githubuser.settings.SettingsPreferences
10+
import com.riyandifirman.githubuser.viewmodel.SettingsViewModel
11+
12+
class SettingActivity : AppCompatActivity() {
13+
14+
private lateinit var binding: ActivitySettingBinding
15+
private lateinit var viewModel: SettingsViewModel
16+
17+
override fun onCreate(savedInstanceState: Bundle?) {
18+
super.onCreate(savedInstanceState)
19+
binding = ActivitySettingBinding.inflate(layoutInflater)
20+
setContentView(binding.root)
21+
22+
viewModel = ViewModelProvider(this, SettingsViewModel.Factory(SettingsPreferences(this))).get(SettingsViewModel::class.java)
23+
24+
viewModel.getTheme().observe(this) {
25+
if (it) {
26+
binding.switchTheme.text = getString(R.string.dark_mode)
27+
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES)
28+
} else {
29+
binding.switchTheme.text = getString(R.string.light_mode)
30+
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO)
31+
}
32+
binding.switchTheme.isChecked = it
33+
}
34+
35+
binding.switchTheme.setOnCheckedChangeListener { _, isChecked ->
36+
viewModel.setTheme(isChecked)
37+
}
38+
}
39+
}

app/src/main/java/com/riyandifirman/githubuser/viewmodel/MainViewModel.kt

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,17 @@
11
package com.riyandifirman.githubuser.viewmodel
22

33
import android.util.Log
4-
import androidx.lifecycle.LiveData
5-
import androidx.lifecycle.MutableLiveData
6-
import androidx.lifecycle.ViewModel
4+
import androidx.lifecycle.*
75
import com.riyandifirman.githubuser.ApiConfig
86
import com.riyandifirman.githubuser.User
97
import com.riyandifirman.githubuser.response.GithubResponse
108
import com.riyandifirman.githubuser.response.SearchResponse
9+
import com.riyandifirman.githubuser.settings.SettingsPreferences
1110
import retrofit2.Call
1211
import retrofit2.Callback
1312
import retrofit2.Response
1413

15-
class MainViewModel : ViewModel() {
14+
class MainViewModel(private val preferences: SettingsPreferences) : ViewModel() {
1615

1716
// companion object digunakan untuk membuat variabel yang dapat diakses tanpa harus membuat objek
1817
companion object {
@@ -76,4 +75,10 @@ class MainViewModel : ViewModel() {
7675
}
7776
})
7877
}
78+
79+
fun getTheme() = preferences.getTheme().asLiveData()
80+
81+
class Factory(private val preferences: SettingsPreferences) : ViewModelProvider.NewInstanceFactory() {
82+
override fun <T : ViewModel> create(modelClass: Class<T>): T = MainViewModel(preferences) as T
83+
}
7984
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package com.riyandifirman.githubuser.viewmodel
2+
3+
import androidx.lifecycle.ViewModel
4+
import androidx.lifecycle.ViewModelProvider
5+
import androidx.lifecycle.asLiveData
6+
import androidx.lifecycle.viewModelScope
7+
import androidx.lifecycle.viewmodel.viewModelFactory
8+
import com.riyandifirman.githubuser.settings.SettingsPreferences
9+
import kotlinx.coroutines.launch
10+
11+
class SettingsViewModel(private val pref : SettingsPreferences) : ViewModel() {
12+
13+
fun getTheme() = pref.getTheme().asLiveData()
14+
15+
fun setTheme(isDarkMode: Boolean) {
16+
viewModelScope.launch {
17+
pref.setTheme(isDarkMode)
18+
}
19+
}
20+
21+
class Factory(private val pref: SettingsPreferences) : ViewModelProvider.NewInstanceFactory() {
22+
override fun <T : ViewModel> create(modelClass: Class<T>): T = SettingsViewModel(pref) as T
23+
}
24+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<vector android:height="24dp" android:tint="#FFFFFF"
2+
android:viewportHeight="24" android:viewportWidth="24"
3+
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
4+
<path android:fillColor="@android:color/white" android:pathData="M19.14,12.94c0.04,-0.3 0.06,-0.61 0.06,-0.94c0,-0.32 -0.02,-0.64 -0.07,-0.94l2.03,-1.58c0.18,-0.14 0.23,-0.41 0.12,-0.61l-1.92,-3.32c-0.12,-0.22 -0.37,-0.29 -0.59,-0.22l-2.39,0.96c-0.5,-0.38 -1.03,-0.7 -1.62,-0.94L14.4,2.81c-0.04,-0.24 -0.24,-0.41 -0.48,-0.41h-3.84c-0.24,0 -0.43,0.17 -0.47,0.41L9.25,5.35C8.66,5.59 8.12,5.92 7.63,6.29L5.24,5.33c-0.22,-0.08 -0.47,0 -0.59,0.22L2.74,8.87C2.62,9.08 2.66,9.34 2.86,9.48l2.03,1.58C4.84,11.36 4.8,11.69 4.8,12s0.02,0.64 0.07,0.94l-2.03,1.58c-0.18,0.14 -0.23,0.41 -0.12,0.61l1.92,3.32c0.12,0.22 0.37,0.29 0.59,0.22l2.39,-0.96c0.5,0.38 1.03,0.7 1.62,0.94l0.36,2.54c0.05,0.24 0.24,0.41 0.48,0.41h3.84c0.24,0 0.44,-0.17 0.47,-0.41l0.36,-2.54c0.59,-0.24 1.13,-0.56 1.62,-0.94l2.39,0.96c0.22,0.08 0.47,0 0.59,-0.22l1.92,-3.32c0.12,-0.22 0.07,-0.47 -0.12,-0.61L19.14,12.94zM12,15.6c-1.98,0 -3.6,-1.62 -3.6,-3.6s1.62,-3.6 3.6,-3.6s3.6,1.62 3.6,3.6S13.98,15.6 12,15.6z"/>
5+
</vector>
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
3+
xmlns:app="http://schemas.android.com/apk/res-auto"
4+
xmlns:tools="http://schemas.android.com/tools"
5+
android:layout_width="match_parent"
6+
android:layout_height="match_parent"
7+
tools:context=".ui.setting.SettingActivity">
8+
9+
<com.google.android.material.switchmaterial.SwitchMaterial
10+
android:id="@+id/switch_theme"
11+
android:layout_width="wrap_content"
12+
android:layout_height="wrap_content"
13+
android:text="@string/light_mode"
14+
android:textOff="@string/dark_mode"
15+
android:textOn="@string/light_mode"
16+
android:textSize="20sp"
17+
app:layout_constraintBottom_toBottomOf="parent"
18+
app:layout_constraintEnd_toEndOf="parent"
19+
app:layout_constraintStart_toStartOf="parent"
20+
app:layout_constraintTop_toTopOf="parent" />
21+
22+
</androidx.constraintlayout.widget.ConstraintLayout>

app/src/main/res/menu/option_menu.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,9 @@
1212
android:icon="@drawable/ic_baseline_menu_favorite_24"
1313
android:title="@string/favorite"
1414
app:showAsAction="collapseActionView|always" />
15+
<item
16+
android:id="@+id/settings"
17+
android:icon="@drawable/ic_baseline_settings_24"
18+
android:title="@string/settings"
19+
app:showAsAction="collapseActionView|always" />
1520
</menu>

0 commit comments

Comments
 (0)