I added a feature where I can change the theme of the app from the application. It seems to work fine for now, but there is a problem. Even though I specify two icons as light and dark, the color of the icons does not change even if I change the theme. What could be the problem?
Hear is my code:
MainActivity.kt
@AndroidEntryPoint
class MainActivity : ComponentActivity() {
private val themeViewModel: ThemeViewModel by viewModels()
private lateinit var dataStoreUtil: DataStoreUtil
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
dataStoreUtil = DataStoreUtil(applicationContext)
val systemTheme = when (resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK) {
Configuration.UI_MODE_NIGHT_YES -> { true }
Configuration.UI_MODE_NIGHT_NO -> { false }
else -> { false }
}
setContent {
val theme = dataStoreUtil.getTheme(systemTheme).collectAsState(initial = systemTheme)
DiyetkolikTheme(darkTheme = theme.value) {
...
ThemeScreen.kt
@Composable
fun ThemeScreenRoute(
navHostController: NavHostController,
viewModel: ThemeViewModel = hiltViewModel()
) {
val state by viewModel.state.collectAsState()
ThemeScreen(
navHostController,
saveDarkTheme = viewModel::saveDarkTheme,
saveThemeChoose = viewModel::saveThemeChoose,
onChangeThemeType = viewModel::onChangeThemeType,
state
)
}
@Composable
fun ThemeScreen(
navHostController: NavHostController,
saveDarkTheme: (Boolean) -> Unit,
saveThemeChoose:(ThemeType)->Unit,
onChangeThemeType:(ThemeType)->Unit,
state:ThemeScreenState
) {
Scaffold(
topBar = {
ScreenTopBar(
title = stringResource(id = R.string.title),
img = painterResource(id = R.drawable.ic_back),
onBackClick = { }
)
}
) { it
val isSystemDarkTheme = isSystemInDarkTheme()
Column(
modifier = Modifier.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally
) {
SelectableTitleWithIcon(
title = "Dark mode",
shouldShowImage = state.selectedThemeType == ThemeType.DarkTheme,
onClick = {
onChangeThemeType(ThemeType.DarkTheme)
saveThemeChoose(ThemeType.DarkTheme)
saveDarkTheme(true)
})
CustomDivider(startPadding = 15.dp, endPadding = 15.dp)
SelectableTitleWithIcon(
title = "Light Mode",
shouldShowImage = state.selectedThemeType == ThemeType.LightTheme,
onClick = {
onChangeThemeType(ThemeType.LightTheme)
saveThemeChoose(ThemeType.LightTheme)
saveDarkTheme(false)
})
CustomDivider(startPadding = 15.dp, endPadding = 15.dp)
SelectableTitleWithIcon(
title = "System Mode",
shouldShowImage = state.selectedThemeType == ThemeType.SystemTheme,
onClick = {
onChangeThemeType(ThemeType.SystemTheme)
saveThemeChoose(ThemeType.SystemTheme)
if (isSystemDarkTheme) saveDarkTheme(true) else saveDarkTheme(false)
})
CustomDivider(startPadding = 15.dp, endPadding = 15.dp)
}
}
}
ThemeViewModel.kt
@HiltViewModel
class ThemeViewModel @Inject constructor(
private val dataStoreUtil: DataStoreUtil,
private val dataStoreHelper: PreferenceDataStoreHelper
) : ViewModel() {
private val _state = MutableStateFlow(ThemeScreenState())
val state: StateFlow<ThemeScreenState> = _state.asStateFlow()
init {
getThemeChoose()
}
private fun getThemeChoose() {
viewModelScope.launch {
val themeName = dataStoreHelper.getFirstPreference(PreferenceDataStoreConstants.THEME_CHOOSE, ThemeType.SystemTheme.name)
_state.update {
it.copy(
selectedThemeType = ThemeType.fromName(themeName)
)
}
}
}
fun onChangeThemeType(themeType: ThemeType){
_state.update {
it.copy(
selectedThemeType = themeType
)
}
}
fun saveThemeChoose(themeType: ThemeType) {
viewModelScope.launch {
dataStoreHelper.putPreference(PreferenceDataStoreConstants.THEME_CHOOSE, themeType.name)
}
}
fun saveDarkTheme(isDarkTheme: Boolean) {
viewModelScope.launch {
dataStoreUtil.saveTheme(isDarkTheme)
}
}
}
sealed class ThemeType(val name: String) {
object DarkTheme : ThemeType("dark_theme")
object LightTheme : ThemeType("light_theme")
object SystemTheme : ThemeType("system_theme")
object Default : ThemeType("default")
companion object {
fun fromName(name: String): ThemeType {
return when (name) {
DarkTheme.name -> DarkTheme
LightTheme.name -> LightTheme
SystemTheme.name -> SystemTheme
Default.name -> Default
else -> SystemTheme
}
}
}
}
data class ThemeScreenState(
val selectedThemeType: ThemeType = ThemeType.Default,
)
AppTheme
@Composable
fun DiyetkolikTheme(
darkTheme: Boolean = isSystemInDarkTheme(),
dynamicColor: Boolean = true,
content: @Composable () -> Unit
) {
val colors = if (darkTheme) DarkColors else LightColors
MaterialTheme(
colors = colors,
typography = MontSerratTypography(colors),
content = content,
)
}
However, I noticed that if it works according to the theme of the emulator. In other words, the icons do not change according to the theme I choose programmatically from my app, for example, if the emulator's theme is dark, the night/icons are displayed. However, if I make the theme light from the app, the system does not work properly because it will still be in dark mode. How can I solve this problem?