I am developing a weather application and I want to save measurementUnits in SettingsScreen user can choose Imperial Fahrenheit or Metric Celsius after choosing one of this user click save button it has to save it unfortunately it is not working what I want to know where I am making mistake
below my SettingsScreen.kt where I have tried implemented measurement units logic
@Composable
fun SettingsScreen(navController: NavController,
settingsViewModel: SettingsViewModel = hiltViewModel()) {
var unitToggleState by remember { mutableStateOf(false) }
val measurementUnits = listOf("Imperial (F)", "Metric (C)")
val choiceFromDb = settingsViewModel.unitList.collectAsState().value
val defaultChoice = if (choiceFromDb.isNullOrEmpty()) measurementUnits[0] else choiceFromDb[0].unit
var choiceState by remember {
mutableStateOf(defaultChoice)
}
Scaffold(topBar = {
WeatherAppBar(
title = "Settings",
icon = Icons.Default.ArrowBack,
false,
navController = navController){
navController.popBackStack()
}
}) {
Surface(modifier = Modifier
.fillMaxWidth()
.fillMaxHeight()) {
Column(verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally) {
Text(
text = "Change Units of Measurement",
modifier = Modifier.padding(bottom = 15.dp)
)
IconToggleButton(checked = !unitToggleState ,
onCheckedChange = {
unitToggleState = !it
choiceState = if (unitToggleState) {
"Imperial (F)"
} else {
"Metric (C)"
}
Log.d("TAG", "MainContent: $unitToggleState")
}, modifier = Modifier
.fillMaxWidth(0.5f)
.clip(shape = RectangleShape)
.padding(5.dp)
.background(Color.Magenta.copy(alpha = 0.4f))) {
Text(text = if (unitToggleState) "Fahrenheit ºF" else "Celsius ºC" )
}
Button(onClick = {
settingsViewModel.deleteAllUnits()
settingsViewModel.insertUnit(Unit(unit = choiceState
))
},
modifier = Modifier
.padding(3.dp)
.align(CenterHorizontally),
shape = RoundedCornerShape(34.dp),
colors = ButtonDefaults.buttonColors(
backgroundColor = Color(0xFFEFBE42)
)) {
Text(text = "Save",
modifier = Modifier.padding(4.dp),
color = Color.White,
fontSize = 17.sp)
}
}
}
}
}
and below SettinsViewModel.kt
@HiltViewModel
class SettingsViewModel @Inject constructor(
private val repository: WeatherDbRepository
): ViewModel() {
private val _unitList = MutableStateFlow<List<Unit>>(emptyList())
val unitList = _unitList.asStateFlow()
init {
viewModelScope.launch(Dispatchers.IO) {
repository.getUnits().distinctUntilChanged()
.collect { listOfUnits ->
if (listOfUnits.isNullOrEmpty()) {
repository.insertUnit(Unit("unit"))
}else {
_unitList.value = listOfUnits
}
}
}
}
fun insertUnit(unit: Unit) = viewModelScope.launch { repository.insertUnit(unit) }
fun updateUnit(unit: Unit) = viewModelScope.launch { repository.updateUnit(unit) }
fun deleteUnit(unit: Unit) = viewModelScope.launch { repository.deleteUnit(unit) }
fun deleteAllUnits() = viewModelScope.launch { repository.deleteAllUnits() }
}
and below MainScreen.kt
@Composable
fun MainScreen(
navController: NavController,
mainViewModel: MainViewModel = hiltViewModel(),
settingsViewModel: SettingsViewModel = hiltViewModel(),
city: String
) {
val curCity: String = if (city.isBlank()) "Stockholm" else city
val unitFromDb = settingsViewModel.unitList.collectAsState().value
var unit by remember {
mutableStateOf("imperial")
}
var isImperial by remember {
mutableStateOf(false)
}
if (!unitFromDb.isNullOrEmpty()) {
unit = unitFromDb[0].unit.split(" ")[0].lowercase()
isImperial = unit == "imperial"
val weatherData = produceState<DataOrException<Weather, Boolean, Exception>>(
initialValue = DataOrException(loading = true)
) {
value = mainViewModel.getWeatherData(
city = curCity,
units = unit
)
}.value
if (weatherData.loading == true) {
CircularProgressIndicator()
} else if (weatherData.data != null) {
MainScaffold(
weather = weatherData.data!!, navController,
isImperial = isImperial
)
}
}
}
@SuppressLint("UnusedMaterialScaffoldPaddingParameter")
@Composable
fun MainScaffold(
weather: Weather, navController: NavController, isImperial: Boolean
) {
Scaffold(topBar = {
WeatherAppBar(
title = weather.city.name + " ,${weather.city.country}",
navController = navController,
onAddActionClicked = {
navController.navigate(WeatherScreens.SearchScreen.name)
},
elevation = 5.dp
) {
Log.d("TAG", "MainScaffold: Button Clicked")
}
}) {
MainContent(data = weather, isImperial = isImperial)
}
}
@Composable
fun MainContent(data: Weather, isImperial: Boolean) {
val weatherItem = data.list[0]
val imageUrl = "https://openweathermap.org/img/wn/${weatherItem.weather[0].icon}.png"
Column(
Modifier
.padding(4.dp)
.fillMaxWidth(),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(
text = formatDate(weatherItem.dt), // Wed Nov 30
style = MaterialTheme.typography.caption,
color = MaterialTheme.colors.onSecondary,
fontWeight = FontWeight.SemiBold,
modifier = Modifier.padding(6.dp)
)
Surface(
modifier = Modifier
.padding(4.dp)
.size(200.dp),
shape = CircleShape,
color = Color(0xFFFFC400)
) {
Column(
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
WeatherStateImage(imageUrl = imageUrl)
Text(
text = formatDecimals(weatherItem.temp.day) + "º",
style = MaterialTheme.typography.h4,
fontWeight = FontWeight.ExtraBold
)
Text(
text = weatherItem.weather[0].main,
fontStyle = FontStyle.Italic
)
}
}
HumidityWindPressureRow(weather = data.list[0], isImperial = isImperial)
Divider()
SunsetSunRiseRow(weather = data.list[0])
Text(
"This Week",
style = MaterialTheme.typography.subtitle1,
fontWeight = FontWeight.Bold
)
Surface(
modifier = Modifier
.fillMaxWidth()
.fillMaxHeight(),
color = Color(0xFFEEF1EF),
shape = RoundedCornerShape(size = 14.dp)
) {
LazyColumn(
modifier = Modifier.padding(2.dp),
contentPadding = PaddingValues(1.dp)
) {
items(items = data.list) { item: WeatherItem ->
WeatherDetailRow(weather = item)
}
}
}
}
}
I want to know where exactly I am making mistake any help will be appreciated.