Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ object Data
const val KEY_FANCY_BACKGROUND = "fancy_background"
const val KEY_FASTING_NOTIFICATION = "fasting_notification"
const val KEY_METRIC_SYSTEM = "metric_system"
const val KEY_THEME_MODE = "theme_mode"

private const val CM_INCH_RATIO = 2.54
fun inchToCm(inches: Int): Double = inches.toDouble() * CM_INCH_RATIO
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,7 @@ interface SettingsDatasource {
fun setUseMetricSystem(enabled: Boolean)

fun useMetricSystemFlow(default: Boolean): Flow<Boolean>

fun getThemeMode(): ThemeMode
fun setThemeMode(mode: ThemeMode)
}
Original file line number Diff line number Diff line change
Expand Up @@ -80,4 +80,11 @@ class SettingsPreferencesDatasource(
storage.registerOnSharedPreferenceChangeListener(listener)
awaitClose { storage.unregisterOnSharedPreferenceChangeListener(listener) }
}

override fun getThemeMode(): ThemeMode =
ThemeMode.fromName(storage.getString(Data.KEY_THEME_MODE, null))

override fun setThemeMode(mode: ThemeMode) {
storage.edit { putString(Data.KEY_THEME_MODE, mode.name) }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.darkrockstudios.apps.fasttrack.data.settings

enum class ThemeMode {
SYSTEM,
LIGHT,
DARK;

companion object {
fun fromName(name: String?): ThemeMode =
entries.firstOrNull { it.name == name } ?: SYSTEM
}
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
package com.darkrockstudios.apps.fasttrack.screens.fasting

import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.runtime.staticCompositionLocalOf
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import com.darkrockstudios.apps.fasttrack.ui.theme.LocalDarkTheme
import com.darkrockstudios.apps.fasttrack.ui.theme.Purple100
import com.darkrockstudios.apps.fasttrack.ui.theme.Purple700

Expand All @@ -16,7 +16,7 @@ val phaseTextColor_Dark = Purple100

@Composable
fun phaseTextColor(): Color {
val isDark: Boolean = isSystemInDarkTheme()
val isDark: Boolean = LocalDarkTheme.current
return if (isDark) {
phaseTextColor_Dark
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,20 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.core.view.WindowCompat
import com.darkrockstudios.apps.fasttrack.R
import com.darkrockstudios.apps.fasttrack.data.settings.SettingsDatasource
import com.darkrockstudios.apps.fasttrack.ui.theme.FastTrackTheme
import org.koin.android.ext.android.inject

class InfoActivity : AppCompatActivity() {
private val settings by inject<SettingsDatasource>()

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
WindowCompat.getInsetsController(window, window.decorView).isAppearanceLightStatusBars = false

setContent {
FastTrackTheme {
FastTrackTheme(themeMode = settings.getThemeMode()) {
Scaffold(
topBar = {
TopAppBar(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,15 @@ import androidx.core.content.edit
import androidx.core.view.WindowCompat
import com.darkrockstudios.apps.fasttrack.R
import com.darkrockstudios.apps.fasttrack.data.Data
import com.darkrockstudios.apps.fasttrack.data.settings.SettingsDatasource
import com.darkrockstudios.apps.fasttrack.ui.theme.FastTrackTheme
import io.github.aakira.napier.Napier
import kotlinx.coroutines.launch
import org.koin.android.ext.android.inject

class IntroActivity : AppCompatActivity() {
private val storage by lazy { PreferenceManager.getDefaultSharedPreferences(this) }
private val settings by inject<SettingsDatasource>()
private lateinit var requestNotificationPermission: ActivityResultLauncher<String>
private var shouldRequestPermission by mutableStateOf(false)

Expand All @@ -53,7 +56,7 @@ class IntroActivity : AppCompatActivity() {
registerNotificationPermissionCallback()

setContent {
FastTrackTheme {
FastTrackTheme(themeMode = settings.getThemeMode()) {
IntroScreen(
onComplete = { complete() },
onNotificationSlideExited = { requestNotificationPermissionIfNeeded() }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import com.darkrockstudios.apps.fasttrack.R
import com.darkrockstudios.apps.fasttrack.data.Stages
import com.darkrockstudios.apps.fasttrack.data.activefast.ActiveFastRepository
import com.darkrockstudios.apps.fasttrack.data.settings.SettingsDatasource
import com.darkrockstudios.apps.fasttrack.data.settings.ThemeMode
import com.darkrockstudios.apps.fasttrack.screens.fasting.ExternalRequests
import com.darkrockstudios.apps.fasttrack.screens.fasting.StartFastRequest
import com.darkrockstudios.apps.fasttrack.screens.info.InfoActivity
Expand All @@ -33,6 +34,7 @@ import kotlin.time.ExperimentalTime
class MainActivity : AppCompatActivity() {
private var startFastRequestState by mutableStateOf<StartFastRequest?>(null)
private var stopFastRequestState by mutableStateOf(false)
private var themeModeState by mutableStateOf(ThemeMode.SYSTEM)
private val settings by inject<SettingsDatasource>()
private val fastingRepository by inject<ActiveFastRepository>()

Expand All @@ -43,14 +45,15 @@ class MainActivity : AppCompatActivity() {
WindowCompat.getInsetsController(window, window.decorView)
.isAppearanceLightStatusBars = false

themeModeState = settings.getThemeMode()
handleStartFastExtra(intent)

if (!settings.getIntroSeen()) {
startActivity(Intent(this, IntroActivity::class.java))
}

setContent {
FastTrackTheme {
FastTrackTheme(themeMode = themeModeState) {
MainScreen(
repository = fastingRepository,
onShareClick = { shareText() },
Expand All @@ -70,6 +73,10 @@ class MainActivity : AppCompatActivity() {

override fun onStart() {
super.onStart()
val currentMode = settings.getThemeMode()
if (currentMode != themeModeState) {
themeModeState = currentMode
}
setupFastingNotification()
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.darkrockstudios.apps.fasttrack.screens.preview

import com.darkrockstudios.apps.fasttrack.data.settings.SettingsDatasource
import com.darkrockstudios.apps.fasttrack.data.settings.ThemeMode
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flowOf

Expand Down Expand Up @@ -33,4 +34,8 @@ class DummySettingsDatasource(
override fun setUseMetricSystem(enabled: Boolean) {}

override fun useMetricSystemFlow(default: Boolean): Flow<Boolean> = flowOf(default)

override fun getThemeMode(): ThemeMode = ThemeMode.SYSTEM

override fun setThemeMode(mode: ThemeMode) {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import com.darkrockstudios.apps.fasttrack.R
import com.darkrockstudios.apps.fasttrack.data.activefast.ActiveFastRepository
import com.darkrockstudios.apps.fasttrack.data.log.FastingLogRepository
import com.darkrockstudios.apps.fasttrack.data.settings.SettingsDatasource
import com.darkrockstudios.apps.fasttrack.data.settings.ThemeMode
import com.darkrockstudios.apps.fasttrack.ui.theme.FastTrackTheme
import io.github.aakira.napier.Napier
import kotlinx.coroutines.Dispatchers
Expand All @@ -44,6 +45,7 @@ class SettingsActivity : AppCompatActivity() {
private var notificationSettingState by mutableStateOf(false)
private var stageAlertsSettingState by mutableStateOf(false)
private var metricSystemSettingState by mutableStateOf(false)
private var themeModeState by mutableStateOf(ThemeMode.SYSTEM)

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
Expand All @@ -54,11 +56,12 @@ class SettingsActivity : AppCompatActivity() {
notificationSettingState = settings.getShowFastingNotification()
stageAlertsSettingState = settings.getFastingAlerts()
metricSystemSettingState = settings.getUseMetricSystem(default = isMetricSystemLocale())
themeModeState = settings.getThemeMode()
registerNotificationPermissionCallback()
registerImportCallback()

setContent {
FastTrackTheme {
FastTrackTheme(themeMode = themeModeState) {
SettingsScreen(
onBack = { finish() },
settings = settings,
Expand All @@ -68,6 +71,8 @@ class SettingsActivity : AppCompatActivity() {
onStageAlertsSettingChanged = { enabled -> handleStageAlertsSettingChange(enabled) },
metricSystemSettingState = metricSystemSettingState,
onMetricSystemSettingChanged = { enabled -> handleMetricSystemSettingChange(enabled) },
themeModeState = themeModeState,
onThemeModeChanged = { mode -> handleThemeModeChange(mode) },
onExportClick = { onExportLogBook() },
onImportClick = { onImportLogBook() }
)
Expand Down Expand Up @@ -154,6 +159,13 @@ class SettingsActivity : AppCompatActivity() {
metricSystemSettingState = enabled
}

private fun handleThemeModeChange(mode: ThemeMode) {
if (mode == themeModeState) return
settings.setThemeMode(mode)
themeModeState = mode
recreate()
}

private fun isMetricSystemLocale(): Boolean {
val locale: Locale = LocaleList.getDefault()[0]
val imperialCountries = listOf("US", "LR", "MM")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowBack
import androidx.compose.material.icons.filled.ArrowDropDown
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
Expand All @@ -14,6 +15,7 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
import com.darkrockstudios.apps.fasttrack.R
import com.darkrockstudios.apps.fasttrack.data.settings.SettingsDatasource
import com.darkrockstudios.apps.fasttrack.data.settings.ThemeMode
import com.darkrockstudios.apps.fasttrack.utils.MAX_COLUMN_WIDTH


Expand All @@ -27,6 +29,8 @@ fun SettingsScreen(
onStageAlertsSettingChanged: (Boolean) -> Unit,
metricSystemSettingState: Boolean,
onMetricSystemSettingChanged: (Boolean) -> Unit,
themeModeState: ThemeMode,
onThemeModeChanged: (ThemeMode) -> Unit,
onExportClick: () -> Unit,
onImportClick: () -> Unit
) {
Expand Down Expand Up @@ -59,6 +63,8 @@ fun SettingsScreen(
onStageAlertsSettingChanged = onStageAlertsSettingChanged,
metricSystemSettingState = metricSystemSettingState,
onMetricSystemSettingChanged = onMetricSystemSettingChanged,
themeModeState = themeModeState,
onThemeModeChanged = onThemeModeChanged,
onExportClick = onExportClick,
onImportClick = onImportClick
)
Expand All @@ -75,6 +81,8 @@ private fun SettingsList(
onStageAlertsSettingChanged: (Boolean) -> Unit,
metricSystemSettingState: Boolean,
onMetricSystemSettingChanged: (Boolean) -> Unit,
themeModeState: ThemeMode,
onThemeModeChanged: (ThemeMode) -> Unit,
onExportClick: () -> Unit,
onImportClick: () -> Unit
) {
Expand Down Expand Up @@ -133,6 +141,12 @@ private fun SettingsList(
onChange = onMetricSystemSettingChanged
)
}
item(key = "theme_mode") {
ThemeModeSettingsItem(
themeMode = themeModeState,
onThemeModeChanged = onThemeModeChanged
)
}
item(key = "logbook_header") {
SettingsSectionHeader(title = R.string.settings_section_logbook)
}
Expand Down Expand Up @@ -200,6 +214,65 @@ private fun SettingsItem(
)
}

@Composable
private fun ThemeModeSettingsItem(
themeMode: ThemeMode,
onThemeModeChanged: (ThemeMode) -> Unit
) {
var expanded by remember { mutableStateOf(false) }
val labelRes = when (themeMode) {
ThemeMode.SYSTEM -> R.string.settings_theme_mode_system
ThemeMode.LIGHT -> R.string.settings_theme_mode_light
ThemeMode.DARK -> R.string.settings_theme_mode_dark
}

ListItem(
headlineContent = {
Text(
text = stringResource(id = R.string.settings_theme_mode_title),
style = MaterialTheme.typography.labelLarge,
fontWeight = FontWeight.Bold
)
},
supportingContent = {
Text(
text = stringResource(id = R.string.settings_theme_mode_subtitle),
style = MaterialTheme.typography.bodySmall
)
},
trailingContent = {
Box {
TextButton(onClick = { expanded = true }) {
Text(stringResource(id = labelRes))
Icon(
imageVector = Icons.Filled.ArrowDropDown,
contentDescription = null
)
}
DropdownMenu(
expanded = expanded,
onDismissRequest = { expanded = false }
) {
ThemeMode.entries.forEach { mode ->
val itemLabel = when (mode) {
ThemeMode.SYSTEM -> R.string.settings_theme_mode_system
ThemeMode.LIGHT -> R.string.settings_theme_mode_light
ThemeMode.DARK -> R.string.settings_theme_mode_dark
}
DropdownMenuItem(
text = { Text(stringResource(id = itemLabel)) },
onClick = {
expanded = false
onThemeModeChanged(mode)
}
)
}
}
}
}
)
}

@Composable
private fun SettingsActionItem(
@StringRes headline: Int,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package com.darkrockstudios.apps.fasttrack.ui.theme

import androidx.compose.foundation.background
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.ui.Modifier
import androidx.compose.ui.composed
import androidx.compose.ui.graphics.Brush
Expand All @@ -11,9 +10,9 @@ import androidx.compose.ui.graphics.Color
val LightGradientStartColor = Color(0xFFE9DBFF) // #E9DBFF
val LightGradientEndColor = Color(0xFFC2D7FF) // #C2D7FF

// Colors from fast_background.xml (dark mode)
val DarkGradientStartColor = Color(0xFF4E447A) // #4E447A
val DarkGradientEndColor = Color(0xFF8E8E8E) // #8E8E8E
// Dark mode gradient
val DarkGradientStartColor = Color(0xFF2A1F3D)
val DarkGradientEndColor = Color(0xFF1A1A1A)

/**
* Extension function to apply the fast background gradient to a Modifier.
Expand All @@ -31,7 +30,7 @@ val DarkGradientEndColor = Color(0xFF8E8E8E) // #8E8E8E
*/
fun Modifier.fastBackgroundGradient(show: Boolean): Modifier = composed {
if (show) {
val isDarkTheme = isSystemInDarkTheme()
val isDarkTheme = LocalDarkTheme.current

val startColor = if (isDarkTheme) DarkGradientStartColor else LightGradientStartColor
val endColor = if (isDarkTheme) DarkGradientEndColor else LightGradientEndColor
Expand Down
Loading
Loading