diff --git a/app/src/main/java/com/apkupdater/di/MainModule.kt b/app/src/main/java/com/apkupdater/di/MainModule.kt
index a421ceb5..0c3ffd7b 100644
--- a/app/src/main/java/com/apkupdater/di/MainModule.kt
+++ b/app/src/main/java/com/apkupdater/di/MainModule.kt
@@ -136,11 +136,11 @@ val mainModule = module {
viewModel { parameters -> AppsViewModel(parameters.get(), get(), get()) }
- viewModel { MainViewModel() }
+ viewModel { MainViewModel(get()) }
viewModel { parameters -> UpdatesViewModel(parameters.get(), get(), get(), get(), get()) }
- viewModel { SettingsViewModel(get(), get(), WorkManager.getInstance(get())) }
+ viewModel { parameters -> SettingsViewModel(parameters.get(), get(), get(), WorkManager.getInstance(get())) }
viewModel { parameters -> SearchViewModel(parameters.get(), get(), get(), get(), get()) }
diff --git a/app/src/main/java/com/apkupdater/prefs/Prefs.kt b/app/src/main/java/com/apkupdater/prefs/Prefs.kt
index d2bd4b0d..7f89637d 100644
--- a/app/src/main/java/com/apkupdater/prefs/Prefs.kt
+++ b/app/src/main/java/com/apkupdater/prefs/Prefs.kt
@@ -26,4 +26,5 @@ class Prefs(
val alarmFrequency = int("alarmFrequency", 0, backed = true)
val androidTvUi = boolean("androidTvUi", defValue = isAndroidTv, backed = true)
val rootInstall = boolean("rootInstall", defValue = false, backed = true)
+ val theme = int("theme", defValue = 0, backed = true)
}
diff --git a/app/src/main/java/com/apkupdater/ui/activity/MainActivity.kt b/app/src/main/java/com/apkupdater/ui/activity/MainActivity.kt
index 4aaf8895..9e92c296 100644
--- a/app/src/main/java/com/apkupdater/ui/activity/MainActivity.kt
+++ b/app/src/main/java/com/apkupdater/ui/activity/MainActivity.kt
@@ -4,12 +4,11 @@ import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import com.apkupdater.ui.screen.MainScreen
-import com.apkupdater.ui.theme.AppTheme
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
- setContent { AppTheme { MainScreen() } }
+ setContent { MainScreen() }
}
}
diff --git a/app/src/main/java/com/apkupdater/ui/component/Settings.kt b/app/src/main/java/com/apkupdater/ui/component/Settings.kt
index ddc556f9..8601a249 100644
--- a/app/src/main/java/com/apkupdater/ui/component/Settings.kt
+++ b/app/src/main/java/com/apkupdater/ui/component/Settings.kt
@@ -121,8 +121,9 @@ fun DropDownSetting(
@DrawableRes icon: Int
) = Box(
Modifier
- .padding(16.dp)
- .fillMaxWidth()) {
+ .padding(top = 16.dp, start = 16.dp, end = 16.dp, bottom = 8.dp)
+ .fillMaxWidth()
+) {
var expanded by remember { mutableStateOf(false) }
var selectedOptionText by remember { mutableStateOf(options[getValue()]) }
@@ -155,12 +156,13 @@ fun DropDownSetting(
expanded = expanded,
onDismissRequest = { expanded = false }
) {
- options.forEach { option ->
+ options.forEachIndexed { i, option ->
DropdownMenuItem(
text = { Text(text = option) },
onClick = {
selectedOptionText = option
expanded = false
+ setValue(i)
}
)
}
diff --git a/app/src/main/java/com/apkupdater/ui/screen/MainScreen.kt b/app/src/main/java/com/apkupdater/ui/screen/MainScreen.kt
index d443431b..6d75fd30 100644
--- a/app/src/main/java/com/apkupdater/ui/screen/MainScreen.kt
+++ b/app/src/main/java/com/apkupdater/ui/screen/MainScreen.kt
@@ -41,6 +41,7 @@ import androidx.navigation.compose.currentBackStackEntryAsState
import androidx.navigation.compose.rememberNavController
import com.apkupdater.data.ui.Screen
import com.apkupdater.ui.component.BadgeText
+import com.apkupdater.ui.theme.AppTheme
import com.apkupdater.viewmodel.AppsViewModel
import com.apkupdater.viewmodel.MainViewModel
import com.apkupdater.viewmodel.SearchViewModel
@@ -56,6 +57,7 @@ fun MainScreen(mainViewModel: MainViewModel = koinViewModel()) {
val appsViewModel: AppsViewModel = koinViewModel(parameters = { parametersOf(mainViewModel) })
val updatesViewModel: UpdatesViewModel = koinViewModel(parameters = { parametersOf(mainViewModel) })
val searchViewModel: SearchViewModel = koinViewModel(parameters = { parametersOf(mainViewModel) })
+ val settingsViewModel: SettingsViewModel = koinViewModel(parameters = { parametersOf(mainViewModel) })
// Navigation
val navController = rememberNavController()
@@ -80,15 +82,20 @@ fun MainScreen(mainViewModel: MainViewModel = koinViewModel()) {
// Check notification intent when hot starting
intentListener(mainViewModel, updatesViewModel, navController, launcher)
- Scaffold(bottomBar = { BottomBar(mainViewModel, navController) }) { padding ->
- Box(modifier = Modifier.pullRefresh(pullToRefresh)) {
- NavHost(navController, padding, appsViewModel, updatesViewModel, searchViewModel)
- PullRefreshIndicator(
- refreshing = isRefreshing.value,
- state = pullToRefresh,
- modifier = Modifier.align(Alignment.TopCenter),
- contentColor = MaterialTheme.colorScheme.primary
- )
+ // Theme
+ val theme = mainViewModel.theme.collectAsStateWithLifecycle().value
+
+ AppTheme(theme) {
+ Scaffold(bottomBar = { BottomBar(mainViewModel, navController) }) { padding ->
+ Box(modifier = Modifier.pullRefresh(pullToRefresh)) {
+ NavHost(navController, padding, appsViewModel, updatesViewModel, searchViewModel, settingsViewModel)
+ PullRefreshIndicator(
+ refreshing = isRefreshing.value,
+ state = pullToRefresh,
+ modifier = Modifier.align(Alignment.TopCenter),
+ contentColor = MaterialTheme.colorScheme.primary
+ )
+ }
}
}
}
@@ -167,7 +174,7 @@ fun NavHost(
appsViewModel: AppsViewModel,
updatesViewModel: UpdatesViewModel,
searchViewModel: SearchViewModel,
- settingsViewModel: SettingsViewModel = koinViewModel()
+ settingsViewModel: SettingsViewModel
) = NavHost(
navController = navController,
startDestination = Screen.Apps.route,
diff --git a/app/src/main/java/com/apkupdater/ui/screen/SettingsScreen.kt b/app/src/main/java/com/apkupdater/ui/screen/SettingsScreen.kt
index 61b7e8a7..00adaaf5 100644
--- a/app/src/main/java/com/apkupdater/ui/screen/SettingsScreen.kt
+++ b/app/src/main/java/com/apkupdater/ui/screen/SettingsScreen.kt
@@ -101,6 +101,17 @@ fun Settings(viewModel: SettingsViewModel) = LazyColumn {
6,
R.drawable.ic_landscape
)
+ DropDownSetting(
+ stringResource(R.string.theme),
+ listOf(
+ stringResource(R.string.theme_system),
+ stringResource(R.string.theme_dark),
+ stringResource(R.string.theme_light)
+ ),
+ { viewModel.getTheme() },
+ { viewModel.setTheme(it) },
+ R.drawable.ic_theme
+ )
}
item {
diff --git a/app/src/main/java/com/apkupdater/ui/theme/Theme.kt b/app/src/main/java/com/apkupdater/ui/theme/Theme.kt
index 0abfd0e6..8680f443 100644
--- a/app/src/main/java/com/apkupdater/ui/theme/Theme.kt
+++ b/app/src/main/java/com/apkupdater/ui/theme/Theme.kt
@@ -2,7 +2,6 @@ package com.apkupdater.ui.theme
import android.app.Activity
import android.os.Build
-import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.material3.ColorScheme
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.darkColorScheme
@@ -17,10 +16,12 @@ import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalView
import androidx.compose.ui.unit.dp
import androidx.core.view.WindowCompat
+import com.apkupdater.util.isDark
+
@Composable
fun AppTheme(
- darkTheme: Boolean = isSystemInDarkTheme(),
+ darkTheme: Boolean,
dynamicColor: Boolean = true,
content: @Composable () -> Unit
) {
@@ -60,3 +61,9 @@ fun AppTheme(
}
fun ColorScheme.statusBarColor() = surfaceColorAtElevation(3.dp)
+
+fun isDarkTheme(theme: Int): Boolean {
+ if (theme == 1) return true
+ if (theme == 2) return false
+ return isDark()
+}
diff --git a/app/src/main/java/com/apkupdater/util/Extensions.kt b/app/src/main/java/com/apkupdater/util/Extensions.kt
index e048caf6..c90cfb19 100644
--- a/app/src/main/java/com/apkupdater/util/Extensions.kt
+++ b/app/src/main/java/com/apkupdater/util/Extensions.kt
@@ -4,6 +4,8 @@ import android.content.Context
import android.content.Intent
import android.content.pm.PackageInfo
import android.content.pm.PackageManager
+import android.content.res.Configuration
+import android.content.res.Resources
import android.os.Build
import androidx.compose.foundation.clickable
import androidx.compose.foundation.interaction.MutableInteractionSource
@@ -93,3 +95,5 @@ fun PackageManager.isAndroidTv() = hasSystemFeature(PackageManager.FEATURE_LEANB
fun Context.isAndroidTv() = packageManager.isAndroidTv()
fun randomUUID() = UUID.randomUUID().toString()
+
+fun isDark() = Resources.getSystem().configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK == Configuration.UI_MODE_NIGHT_YES
diff --git a/app/src/main/java/com/apkupdater/viewmodel/MainViewModel.kt b/app/src/main/java/com/apkupdater/viewmodel/MainViewModel.kt
index 2c6765af..b755796e 100644
--- a/app/src/main/java/com/apkupdater/viewmodel/MainViewModel.kt
+++ b/app/src/main/java/com/apkupdater/viewmodel/MainViewModel.kt
@@ -11,6 +11,8 @@ import androidx.navigation.NavController
import androidx.navigation.NavGraph.Companion.findStartDestination
import com.apkupdater.data.ui.AppInstallStatus
import com.apkupdater.data.ui.Screen
+import com.apkupdater.prefs.Prefs
+import com.apkupdater.ui.theme.isDarkTheme
import com.apkupdater.util.SessionInstaller
import com.apkupdater.util.UpdatesNotification
import com.apkupdater.util.getAppId
@@ -22,10 +24,12 @@ import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.launch
-class MainViewModel : ViewModel() {
+class MainViewModel(prefs: Prefs) : ViewModel() {
val screens = listOf(Screen.Apps, Screen.Search, Screen.Updates, Screen.Settings)
+ val theme = MutableStateFlow(isDarkTheme(prefs.theme.get()))
+
val badges = MutableStateFlow(mapOf(
Screen.Apps.route to "",
Screen.Search.route to "",
@@ -48,6 +52,8 @@ class MainViewModel : ViewModel() {
}
}
+ fun setTheme(theme: Boolean) = this.theme.apply { value = theme }
+
fun changeSearchBadge(number: String) = changeBadge(Screen.Search.route, number)
fun changeAppsBadge(number: String) = changeBadge(Screen.Apps.route, number)
diff --git a/app/src/main/java/com/apkupdater/viewmodel/SettingsViewModel.kt b/app/src/main/java/com/apkupdater/viewmodel/SettingsViewModel.kt
index ae0d16a3..0fa72e02 100644
--- a/app/src/main/java/com/apkupdater/viewmodel/SettingsViewModel.kt
+++ b/app/src/main/java/com/apkupdater/viewmodel/SettingsViewModel.kt
@@ -5,6 +5,7 @@ import androidx.lifecycle.ViewModel
import androidx.work.WorkManager
import com.apkupdater.data.ui.SettingsUiState
import com.apkupdater.prefs.Prefs
+import com.apkupdater.ui.theme.isDarkTheme
import com.apkupdater.util.UpdatesNotification
import com.apkupdater.worker.UpdatesWorker
import eu.chainfire.libsuperuser.Shell
@@ -12,6 +13,7 @@ import kotlinx.coroutines.flow.MutableStateFlow
class SettingsViewModel(
+ private val mainViewModel: MainViewModel,
private val prefs: Prefs,
private val notification: UpdatesNotification,
private val workManager: WorkManager
@@ -41,6 +43,12 @@ class SettingsViewModel(
fun getRootInstall() = prefs.rootInstall.get()
fun getAlarmHour() = prefs.alarmHour.get()
fun getAlarmFrequency() = prefs.alarmFrequency.get()
+ fun getTheme() = prefs.theme.get()
+
+ fun setTheme(theme: Int) {
+ prefs.theme.put(theme)
+ mainViewModel.setTheme(isDarkTheme(theme))
+ }
fun setRootInstall(b: Boolean) {
if (b && Shell.SU.available()) {
diff --git a/app/src/main/res/drawable/ic_theme.xml b/app/src/main/res/drawable/ic_theme.xml
new file mode 100644
index 00000000..cac8de55
--- /dev/null
+++ b/app/src/main/res/drawable/ic_theme.xml
@@ -0,0 +1,5 @@
+
+
+
diff --git a/app/src/main/res/values-ro/strings.xml b/app/src/main/res/values-ro/strings.xml
index 9983e2e4..2c2b3a73 100644
--- a/app/src/main/res/values-ro/strings.xml
+++ b/app/src/main/res/values-ro/strings.xml
@@ -46,7 +46,7 @@
updateChannel
Actualizări
- - TODO
+ - Au fost găsite %1$d actualizări.
- Nicio actualizare găsită.
- A fost găsită %1$d actualizare.
- Au fost găsite %1$d actualizări.
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 0d75ead1..8e7cff56 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -39,6 +39,10 @@
GitHub
About
Frequency
+ Theme
+ System
+ Dark
+ Light
// Notifications
Updates