diff --git a/i18n/src/main/res/values-de/strings.xml b/i18n/src/main/res/values-de/strings.xml index 165ec4f4..fa142a7f 100644 --- a/i18n/src/main/res/values-de/strings.xml +++ b/i18n/src/main/res/values-de/strings.xml @@ -415,4 +415,5 @@ Wind: Eingefärbte Symbole Symbole an das Farbschema der App anpassen + Keine Wetterdaten verfügbar. \ No newline at end of file diff --git a/i18n/src/main/res/values/strings.xml b/i18n/src/main/res/values/strings.xml index 77f7e27e..f5d370ff 100644 --- a/i18n/src/main/res/values/strings.xml +++ b/i18n/src/main/res/values/strings.xml @@ -445,6 +445,8 @@ Hide details Humidity: Wind: + No weather data available. + Precipitation: License This app is free software. diff --git a/ui/src/main/java/de/mm20/launcher2/ui/widget/MusicWidget.kt b/ui/src/main/java/de/mm20/launcher2/ui/widget/MusicWidget.kt index ad49b8da..3e18cb4c 100644 --- a/ui/src/main/java/de/mm20/launcher2/ui/widget/MusicWidget.kt +++ b/ui/src/main/java/de/mm20/launcher2/ui/widget/MusicWidget.kt @@ -7,14 +7,14 @@ import androidx.compose.foundation.Image import androidx.compose.foundation.background import androidx.compose.foundation.combinedClickable import androidx.compose.foundation.layout.* -import androidx.compose.material3.Icon -import androidx.compose.material3.IconButton -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Text import androidx.compose.material.icons.Icons import androidx.compose.material.icons.rounded.MusicNote import androidx.compose.material.icons.rounded.SkipNext import androidx.compose.material.icons.rounded.SkipPrevious +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.livedata.observeAsState @@ -29,7 +29,6 @@ import de.mm20.launcher2.music.MusicViewModel import de.mm20.launcher2.music.PlaybackState import de.mm20.launcher2.ui.R import de.mm20.launcher2.ui.ktx.conditional -import de.mm20.launcher2.ui.locals.LocalColorScheme import org.koin.androidx.compose.getViewModel @OptIn( @@ -52,111 +51,106 @@ fun MusicWidget() { Row( modifier = Modifier.height(IntrinsicSize.Min) ) { - if (title != null) { + Column( + modifier = Modifier + .padding(top = 16.dp) + .fillMaxHeight() + .weight(2f), + verticalArrangement = Arrangement.SpaceBetween + ) { Column( - modifier = Modifier - .padding(top = 16.dp) - .fillMaxHeight() - .weight(2f), - verticalArrangement = Arrangement.SpaceBetween + modifier = Modifier.padding(horizontal = 16.dp) ) { - Column( - modifier = Modifier.padding(horizontal = 16.dp) - ) { - Text( - text = title ?: "---", - style = MaterialTheme.typography.titleMedium, - maxLines = 1, - overflow = TextOverflow.Ellipsis - ) - Text( - text = artist ?: "---", - modifier = Modifier.padding(vertical = 2.dp), - style = MaterialTheme.typography.bodySmall, - maxLines = 1, - overflow = TextOverflow.Ellipsis - ) - Text( - text = album ?: "---", - style = MaterialTheme.typography.bodySmall, - maxLines = 1, - overflow = TextOverflow.Ellipsis - ) - } - Row( - modifier = Modifier - .fillMaxWidth() - .padding(bottom = 4.dp, end = 4.dp), - horizontalArrangement = Arrangement.SpaceBetween - ) { - IconButton( - onClick = { - viewModel.previous() - }) { - Icon( - imageVector = Icons.Rounded.SkipPrevious, - null - ) - } - val playPauseIcon = animatedVectorResource(R.drawable.anim_ic_play_pause) - IconButton(onClick = { viewModel.togglePause() }) { - Icon( - painter = playPauseIcon.painterFor(atEnd = playbackState == PlaybackState.Playing), - contentDescription = "" - ) - } - IconButton(onClick = { - viewModel.next() + Text( + text = title ?: "---", + style = MaterialTheme.typography.titleMedium, + maxLines = 1, + overflow = TextOverflow.Ellipsis + ) + Text( + text = artist ?: "---", + modifier = Modifier.padding(vertical = 2.dp), + style = MaterialTheme.typography.bodySmall, + maxLines = 1, + overflow = TextOverflow.Ellipsis + ) + Text( + text = album ?: "---", + style = MaterialTheme.typography.bodySmall, + maxLines = 1, + overflow = TextOverflow.Ellipsis + ) + } + Row( + modifier = Modifier + .fillMaxWidth() + .padding(bottom = 4.dp, end = 4.dp), + horizontalArrangement = Arrangement.SpaceBetween + ) { + IconButton( + onClick = { + viewModel.previous() }) { - Icon( - imageVector = Icons.Rounded.SkipNext, - null - ) - } - } - } - Box( - modifier = Modifier - .size(144.dp) - .combinedClickable( - onClick = { - viewModel - .getLaunchIntent(context) - .send() - }, - onLongClick = { - viewModel.openPlayerChooser(context) - } - ) - .conditional( - albumArt == null, - Modifier.background( - MaterialTheme.colorScheme.primaryContainer, - ) - ), - contentAlignment = Alignment.Center - ) { - if (albumArt != null) { - albumArt?.let { - Image( - bitmap = it.asImageBitmap(), - modifier = Modifier - .fillMaxSize(), - contentDescription = null - ) - } - } else { Icon( - imageVector = Icons.Rounded.MusicNote, - contentDescription = null, - tint = MaterialTheme.colorScheme.onPrimaryContainer, - modifier = Modifier.size(56.dp) + imageVector = Icons.Rounded.SkipPrevious, + null + ) + } + val playPauseIcon = animatedVectorResource(R.drawable.anim_ic_play_pause) + IconButton(onClick = { viewModel.togglePause() }) { + Icon( + painter = playPauseIcon.painterFor(atEnd = playbackState == PlaybackState.Playing), + contentDescription = "" + ) + } + IconButton(onClick = { + viewModel.next() + }) { + Icon( + imageVector = Icons.Rounded.SkipNext, + null ) } } - } else { - // TODO } - + Box( + modifier = Modifier + .size(144.dp) + .combinedClickable( + onClick = { + viewModel + .getLaunchIntent(context) + .send() + }, + onLongClick = { + viewModel.openPlayerChooser(context) + } + ) + .conditional( + albumArt == null, + Modifier.background( + MaterialTheme.colorScheme.primaryContainer, + ) + ), + contentAlignment = Alignment.Center + ) { + if (albumArt != null) { + albumArt?.let { + Image( + bitmap = it.asImageBitmap(), + modifier = Modifier + .fillMaxSize(), + contentDescription = null + ) + } + } else { + Icon( + imageVector = Icons.Rounded.MusicNote, + contentDescription = null, + tint = MaterialTheme.colorScheme.onPrimaryContainer, + modifier = Modifier.size(56.dp) + ) + } + } } } \ No newline at end of file diff --git a/ui/src/main/java/de/mm20/launcher2/ui/widget/WeatherWidget.kt b/ui/src/main/java/de/mm20/launcher2/ui/widget/WeatherWidget.kt index ef2bcfc2..d69ccee9 100644 --- a/ui/src/main/java/de/mm20/launcher2/ui/widget/WeatherWidget.kt +++ b/ui/src/main/java/de/mm20/launcher2/ui/widget/WeatherWidget.kt @@ -13,6 +13,7 @@ import androidx.compose.material.DropdownMenu import androidx.compose.material.DropdownMenuItem import androidx.compose.material.icons.Icons import androidx.compose.material.icons.rounded.ArrowDropDown +import androidx.compose.material.icons.rounded.LightMode import androidx.compose.material3.* import androidx.compose.runtime.* import androidx.compose.runtime.livedata.observeAsState @@ -49,18 +50,22 @@ fun WeatherWidget() { var selectedForecastIndex by remember { mutableStateOf(0) } var detailsExpanded by remember { mutableStateOf(false) } - if (weatherData.isEmpty()) return - if (weatherData.size <= selectedDayIndex) { + if (weatherData.isNotEmpty() && weatherData.size <= selectedDayIndex) { selectedDayIndex = 0 return } - if (weatherData[selectedDayIndex].hourlyForecasts.size <= selectedForecastIndex) { + if (weatherData.isNotEmpty() && weatherData[selectedDayIndex].hourlyForecasts.size <= selectedForecastIndex) { selectedForecastIndex = 0 return } + if (weatherData.isEmpty()) { + NoData() + return + } + val selectedForecast = weatherData[selectedDayIndex].hourlyForecasts[selectedForecastIndex] val imperialUnits = LauncherPreferences.instance.imperialUnits @@ -441,3 +446,25 @@ private fun weatherIconById(id: Int): WeatherIcon { else -> WeatherIcon.None } } + +@Composable +fun NoData() { + Row( + modifier = Modifier + .fillMaxWidth() + .wrapContentHeight(), + verticalAlignment = Alignment.CenterVertically + ) { + Icon(imageVector = Icons.Rounded.LightMode, + contentDescription = "", + modifier = Modifier + .padding(24.dp) + .size(32.dp), + tint = MaterialTheme.colorScheme.secondary + ) + Text( + text = stringResource(id = R.string.weather_no_data), + style = MaterialTheme.typography.bodySmall + ) + } +} \ No newline at end of file