Skip to content

Commit

Permalink
✨ Add a Day/Night switch that doesn't depend on the System Theme (#610)
Browse files Browse the repository at this point in the history
Co-authored-by: gBL17 <[email protected]>
  • Loading branch information
LeoColman and gBL17 authored Jun 11, 2024
1 parent 5f6372f commit be4467e
Show file tree
Hide file tree
Showing 5 changed files with 72 additions and 12 deletions.
8 changes: 7 additions & 1 deletion app/src/main/kotlin/br/com/colman/petals/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ class MainActivity : ComponentActivity(), CoroutineScope by CoroutineScope(Dispa
}
}

MaterialTheme(if (isSystemInDarkTheme()) darkColors() else lightColors()) {
MaterialTheme(if (isDarkModeEnabled()) darkColors() else lightColors()) {
if (isAuthorized || correctPin == null) {
Surface {
Scaffold(
Expand Down Expand Up @@ -108,4 +108,10 @@ class MainActivity : ComponentActivity(), CoroutineScope by CoroutineScope(Dispa
OutlinedTextField(pin, { pin = it }, visualTransformation = PasswordVisualTransformation())
}
}

@Composable
fun isDarkModeEnabled(): Boolean {
val darkMode: Boolean by settingsRepository.isDarkModeEnabled.collectAsState(isSystemInDarkTheme())
return darkMode
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package br.com.colman.petals.settings

import androidx.datastore.core.DataStore
import androidx.datastore.preferences.core.Preferences
import androidx.datastore.preferences.core.booleanPreferencesKey
import androidx.datastore.preferences.core.edit
import androidx.datastore.preferences.core.intPreferencesKey
import androidx.datastore.preferences.core.stringPreferencesKey
Expand Down Expand Up @@ -35,6 +36,7 @@ class SettingsRepository(
val decimalPrecision = datastore.data.map { it[DecimalPrecision] ?: decimalPrecisionList[2] }
val extendedDayList = listOf("enabled", "disabled")
val extendedDay: Flow<String> = datastore.data.map { it[ExtendedDayEnabled] ?: extendedDayList[1] }
val isDarkModeEnabled: Flow<Boolean> = datastore.data.map { it[IsDarkModeOn] ?: true }

fun setCurrencyIcon(value: String): Unit = runBlocking {
datastore.edit { it[CurrencyIcon] = value }
Expand Down Expand Up @@ -64,6 +66,10 @@ class SettingsRepository(
datastore.edit { it[ExtendedDayEnabled] = value }
}

fun setDarkMode(value: Boolean): Unit = runBlocking {
datastore.edit { it[IsDarkModeOn] = value }
}

val pin: Flow<String?>
get() = datastore.data.map { it[Pin] }

Expand All @@ -82,5 +88,6 @@ class SettingsRepository(
val HitTimerMillisecondsEnabled = stringPreferencesKey("hit_timer_milliseconds_enabled")
val DecimalPrecision = intPreferencesKey("decimal_precision")
val ExtendedDayEnabled: Preferences.Key<String> = stringPreferencesKey("is_day_extended")
val IsDarkModeOn: Preferences.Key<Boolean> = booleanPreferencesKey("is_dark_mode_on")
}
}
42 changes: 33 additions & 9 deletions app/src/main/kotlin/br/com/colman/petals/use/LastUseDateTimer.kt
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,16 @@
package br.com.colman.petals.use

import androidx.annotation.StringRes
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.material.Icon
import androidx.compose.material.IconButton
import androidx.compose.material.LinearProgressIndicator
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
Expand Down Expand Up @@ -55,6 +60,9 @@ import br.com.colman.petals.use.TimeUnit.Month
import br.com.colman.petals.use.TimeUnit.Second
import br.com.colman.petals.use.TimeUnit.Year
import br.com.colman.petals.utils.truncatedToMinute
import compose.icons.TablerIcons
import compose.icons.tablericons.Moon
import compose.icons.tablericons.Sun
import kotlinx.coroutines.delay
import org.koin.compose.koinInject
import java.time.LocalDateTime
Expand All @@ -70,13 +78,9 @@ fun LastUseDateTimer(lastUseDate: LocalDateTime) {
val dateFormat by settingsRepository.dateFormat.collectAsState(settingsRepository.dateFormatList[0])
val timeFormat by settingsRepository.timeFormat.collectAsState(settingsRepository.timeFormatList[0])
val millisecondsEnabled by settingsRepository.millisecondsEnabled.collectAsState("disabled")
val darkMode: Boolean by settingsRepository.isDarkModeEnabled.collectAsState(isSystemInDarkTheme())
val dateString = DateTimeFormatter.ofPattern(
String.format(
Locale.US,
"%s %s",
dateFormat,
timeFormat
)
String.format(Locale.US, "%s %s", dateFormat, timeFormat)
).format(lastUseDate)

var millis by remember { mutableStateOf(ChronoUnit.MILLIS.between(lastUseDate, now())) }
Expand All @@ -100,9 +104,19 @@ fun LastUseDateTimer(lastUseDate: LocalDateTime) {

Column(Modifier.padding(16.dp), Arrangement.spacedBy(16.dp)) {
Column {
Text(stringResource(quit_date_text))
val dateStringWithExtras = if (!lastUseDate.is420()) dateString else "$dateString 🥦🥦"
Text(dateStringWithExtras, fontSize = 24.sp)
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween
) {
Column {
Text(stringResource(quit_date_text))
val dateStringWithExtras = if (!lastUseDate.is420()) dateString else "$dateString 🥦🥦"
Text(dateStringWithExtras, fontSize = 24.sp)
}
IconButton({ settingsRepository.setDarkMode(!darkMode) }) {
SetDarkModeIcon(darkMode)
}
}
}

Column(verticalArrangement = Arrangement.spacedBy(8.dp)) {
Expand Down Expand Up @@ -136,3 +150,13 @@ enum class TimeUnit(@StringRes val unitName: Int, val max: Long, val millis: Lon
}

private fun LocalDateTime.is420() = toLocalTime().truncatedToMinute() == LocalTime.of(16, 20)

@Composable
fun SetDarkModeIcon(isDarkModeOn: Boolean?) {
if (isDarkModeOn != null) {
val chosenIcon = if (isDarkModeOn) TablerIcons.Sun else TablerIcons.Moon
Icon(chosenIcon, null, Modifier.size(26.dp))
} else {
Icon(TablerIcons.Moon, null, Modifier.size(26.dp))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,24 +10,31 @@ import androidx.compose.material.Scaffold
import androidx.compose.material.Surface
import androidx.compose.material.darkColors
import androidx.compose.material.lightColors
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.navigation.compose.rememberNavController
import br.com.colman.petals.navigation.BottomNavigationBar
import br.com.colman.petals.navigation.MyTopAppBar
import br.com.colman.petals.navigation.NavHostContainer
import br.com.colman.petals.settings.SettingsRepository
import com.google.android.gms.ads.MobileAds
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import org.koin.android.ext.android.inject

@Suppress("FunctionName")
class MainActivity : ComponentActivity(), CoroutineScope by CoroutineScope(Dispatchers.Main) {

private val settingsRepository by inject<SettingsRepository>()

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
val navController = rememberNavController()

MaterialTheme(if (isSystemInDarkTheme()) darkColors() else lightColors()) {
MaterialTheme(if (isDarkModeEnabled()) darkColors() else lightColors()) {
Surface {
Scaffold(
topBar = { MyTopAppBar(navController) },
Expand All @@ -44,4 +51,10 @@ class MainActivity : ComponentActivity(), CoroutineScope by CoroutineScope(Dispa
}
launch { MobileAds.initialize(this@MainActivity) }
}
}

@Composable
fun isDarkModeEnabled(): Boolean {
val darkMode: Boolean? by settingsRepository.isDarkModeEnabled.collectAsState(null)
return darkMode ?: isSystemInDarkTheme()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -85,4 +85,14 @@ class SettingsRepositoryTest : FunSpec({
target.setExtendedDay("enabled")
datastore.data.first()[ExtendedDayEnabled] shouldBe "enabled"
}

test("Changes dark mode to true") {
target.setDarkMode(true)
target.isDarkModeEnabled.first() shouldBe true
}

test("Changes dark mode to false") {
target.setDarkMode(false)
target.isDarkModeEnabled.first() shouldBe false
}
})

0 comments on commit be4467e

Please sign in to comment.