package com.gigaprojects.gigaweather
import android.content.Context
import android.content.SharedPreferences
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.core.view.WindowCompat
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.WindowInsetsControllerCompat
import com.gigaprojects.gigaweather.ui.theme.GigaWeatherTheme
class SettingsActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
hideSystemBars()
setContent {
val sharedPreferences = remember { getSharedPreferences("geo_weather_prefs", Context.MODE_PRIVATE) }
val useSystemTheme = sharedPreferences.collectAsState(key = "use_system_theme", defaultValue = true)
val darkModeEnabled = sharedPreferences.collectAsState(key = "dark_mode_enabled", defaultValue = false)
val dynamicColor = sharedPreferences.collectAsState(key = "dynamic_color", defaultValue = true)
val darkTheme = if (useSystemTheme.value) isSystemInDarkTheme() else darkModeEnabled.value
GigaWeatherTheme(darkTheme = darkTheme, dynamicColor = dynamicColor.value) {
Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding ->
SettingsScreen(
modifier = Modifier.padding(innerPadding),
onBack = { finish() }
)
}
}
}
}
override fun onWindowFocusChanged(hasFocus: Boolean) {
super.onWindowFocusChanged(hasFocus)
if (hasFocus) {
hideSystemBars()
}
}
private fun hideSystemBars() {
val windowInsetsController =
WindowCompat.getInsetsController(window, window.decorView)
windowInsetsController.systemBarsBehavior =
WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
windowInsetsController.hide(WindowInsetsCompat.Type.systemBars())
}
}
@Composable
fun SettingsScreen(modifier: Modifier = Modifier, onBack: () -> Unit) {
val context = LocalContext.current
val sharedPreferences = remember {
context.getSharedPreferences("geo_weather_prefs", Context.MODE_PRIVATE)
}
var darkModeEnabled by remember {
mutableStateOf(sharedPreferences.getBoolean("dark_mode_enabled", false))
}
var useSystemTheme by remember {
mutableStateOf(sharedPreferences.getBoolean("use_system_theme", true))
}
var dynamicColor by remember {
mutableStateOf(sharedPreferences.getBoolean("dynamic_color", true))
}
val tempUnitState by sharedPreferences.collectStringAsState("temp_unit", "celsius")
var tempUnit by remember { mutableStateOf(tempUnitState) }
LaunchedEffect(tempUnitState) { tempUnit = tempUnitState }
val windUnitState by sharedPreferences.collectStringAsState("wind_unit", "kmh")
var windUnit by remember { mutableStateOf(windUnitState) }
LaunchedEffect(windUnitState) { windUnit = windUnitState }
val weatherProviderState by sharedPreferences.collectStringAsState("weather_provider", "open_meteo")
var weatherProvider by remember { mutableStateOf(weatherProviderState) }
LaunchedEffect(weatherProviderState) { weatherProvider = weatherProviderState }
val weatherApiKeyState by sharedPreferences.collectStringAsState("weather_api_key", "")
var weatherApiKey by remember { mutableStateOf(weatherApiKeyState) }
LaunchedEffect(weatherApiKeyState) { weatherApiKey = weatherApiKeyState }
val qweatherApiKeyState by sharedPreferences.collectStringAsState("qweather_api_key", "")
var qweatherApiKey by remember { mutableStateOf(qweatherApiKeyState) }
LaunchedEffect(qweatherApiKeyState) { qweatherApiKey = qweatherApiKeyState }
var tempThreshold by remember {
mutableStateOf(sharedPreferences.getInt("notif_temp_threshold", 5))
}
var windThreshold by remember {
mutableStateOf(sharedPreferences.getInt("notif_wind_threshold", 15))
}
Column(
modifier = modifier
.fillMaxSize()
.verticalScroll(rememberScrollState())
.padding(16.dp),
verticalArrangement = Arrangement.spacedBy(16.dp)
) {
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.spacedBy(8.dp)
) {
FilledTonalButton(onClick = onBack) {
Text(stringResource(R.string.back_btn))
}
}
Text(
text = stringResource(R.string.theme_settings_title),
style = MaterialTheme.typography.headlineSmall
)
Card(
modifier = Modifier.fillMaxWidth(),
colors = CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.surfaceVariant.copy(alpha = 0.5f))
) {
Column(
modifier = Modifier.padding(16.dp),
verticalArrangement = Arrangement.spacedBy(12.dp)
) {
SettingsToggle(
title = stringResource(R.string.dynamic_color_title),
subtitle = stringResource(R.string.dynamic_color_subtitle),
checked = dynamicColor,
onCheckedChange = {
dynamicColor = it
sharedPreferences.edit().putBoolean("dynamic_color", it).apply()
}
)
HorizontalDivider(modifier = Modifier.padding(vertical = 4.dp))
SettingsToggle(
title = stringResource(R.string.follow_system_theme),
checked = useSystemTheme,
onCheckedChange = {
useSystemTheme = it
sharedPreferences.edit().putBoolean("use_system_theme", it).apply()
}
)
SettingsToggle(
title = stringResource(R.string.force_dark_mode),
subtitle = stringResource(R.string.override_system_setting),
checked = darkModeEnabled,
enabled = !useSystemTheme,
onCheckedChange = {
darkModeEnabled = it
sharedPreferences.edit().putBoolean("dark_mode_enabled", it).apply()
}
)
}
}
Text(
text = stringResource(R.string.unit_settings_title),
style = MaterialTheme.typography.headlineSmall
)
Card(
modifier = Modifier.fillMaxWidth(),
colors = CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.surfaceVariant.copy(alpha = 0.5f))
) {
Column(
modifier = Modifier.padding(16.dp),
verticalArrangement = Arrangement.spacedBy(12.dp)
) {
Column {
Text(stringResource(R.string.temperature_unit), style = MaterialTheme.typography.bodyLarge)
Row(verticalAlignment = Alignment.CenterVertically) {
RadioButton(selected = tempUnit == "celsius", onClick = {
tempUnit = "celsius"
sharedPreferences.edit().putString("temp_unit", "celsius").apply()
})
Text(stringResource(R.string.unit_celsius))
Spacer(Modifier.width(16.dp))
RadioButton(selected = tempUnit == "fahrenheit", onClick = {
tempUnit = "fahrenheit"
sharedPreferences.edit().putString("temp_unit", "fahrenheit").apply()
})
Text(stringResource(R.string.unit_fahrenheit))
}
}
HorizontalDivider(modifier = Modifier.padding(vertical = 4.dp))
Column {
Text(stringResource(R.string.wind_speed_unit), style = MaterialTheme.typography.bodyLarge)
Row(verticalAlignment = Alignment.CenterVertically) {
RadioButton(selected = windUnit == "kmh", onClick = {
windUnit = "kmh"
sharedPreferences.edit().putString("wind_unit", "kmh").apply()
})
Text(stringResource(R.string.unit_kmh))
Spacer(Modifier.width(16.dp))
RadioButton(selected = windUnit == "mph", onClick = {
windUnit = "mph"
sharedPreferences.edit().putString("wind_unit", "mph").apply()
})
Text(stringResource(R.string.unit_mph))
}
}
}
}
Text(
text = stringResource(R.string.notification_settings_title),
style = MaterialTheme.typography.headlineSmall
)
Card(
modifier = Modifier.fillMaxWidth(),
colors = CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.surfaceVariant.copy(alpha = 0.5f))
) {
Column(
modifier = Modifier.padding(16.dp),
verticalArrangement = Arrangement.spacedBy(12.dp)
) {
Text(stringResource(R.string.temp_threshold_label, tempThreshold))
Slider(
value = tempThreshold.toFloat(),
onValueChange = { tempThreshold = it.toInt() },
onValueChangeFinished = { sharedPreferences.edit().putInt("notif_temp_threshold", tempThreshold).apply() },
valueRange = 1f..15f,
steps = 14
)
HorizontalDivider(modifier = Modifier.padding(vertical = 4.dp))
Text(stringResource(R.string.wind_threshold_label, windThreshold))
Slider(
value = windThreshold.toFloat(),
onValueChange = { windThreshold = it.toInt() },
onValueChangeFinished = { sharedPreferences.edit().putInt("notif_wind_threshold", windThreshold).apply() },
valueRange = 5f..50f,
steps = 9
)
}
}
Text(
text = stringResource(R.string.weather_provider_title),
style = MaterialTheme.typography.headlineSmall
)
Card(
modifier = Modifier.fillMaxWidth(),
colors = CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.surfaceVariant.copy(alpha = 0.5f))
) {
Column(
modifier = Modifier.padding(16.dp),
verticalArrangement = Arrangement.spacedBy(12.dp)
) {
Row(verticalAlignment = Alignment.CenterVertically) {
RadioButton(selected = weatherProvider == "open_meteo", onClick = {
weatherProvider = "open_meteo"
sharedPreferences.edit().putString("weather_provider", "open_meteo").apply()
})
Text(stringResource(R.string.provider_open_meteo))
}
Row(verticalAlignment = Alignment.CenterVertically) {
RadioButton(selected = weatherProvider == "weatherapi", onClick = {
weatherProvider = "weatherapi"
sharedPreferences.edit().putString("weather_provider", "weatherapi").apply()
})
Text(stringResource(R.string.provider_weatherapi))
}
if (weatherProvider == "weatherapi") {
OutlinedTextField(
value = weatherApiKey,
onValueChange = {
weatherApiKey = it
sharedPreferences.edit().putString("weather_api_key", it).apply()
},
label = { Text(stringResource(R.string.weather_api_key_label)) },
modifier = Modifier.fillMaxWidth(),
singleLine = true
)
}
HorizontalDivider(modifier = Modifier.padding(vertical = 4.dp))
OutlinedTextField(
value = qweatherApiKey,
onValueChange = {
qweatherApiKey = it
sharedPreferences.edit().putString("qweather_api_key", it).apply()
},
label = { Text(stringResource(R.string.qweather_api_key_label)) },
modifier = Modifier.fillMaxWidth(),
singleLine = true
)
}
}
Spacer(modifier = Modifier.height(32.dp))
}
}
@Composable
fun SettingsToggle(
title: String,
subtitle: String? = null,
checked: Boolean,
enabled: Boolean = true,
onCheckedChange: (Boolean) -> Unit
) {
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically
) {
Column(modifier = Modifier.weight(1f)) {
Text(title, style = MaterialTheme.typography.bodyLarge)
if (subtitle != null) {
Text(
text = subtitle,
style = MaterialTheme.typography.bodySmall,
color = MaterialTheme.colorScheme.onSurfaceVariant
)
}
}
Switch(
checked = checked,
enabled = enabled,
onCheckedChange = onCheckedChange
)
}
}