Always show weather and music widgets even if there's no data available

This commit is contained in:
MM20 2021-12-15 20:26:55 +01:00
parent 960c645010
commit fb50c9bd9d
No known key found for this signature in database
GPG Key ID: 0B61A8F2DEAFA389
4 changed files with 130 additions and 106 deletions

View File

@ -415,4 +415,5 @@
<string name="weather_wind">Wind:</string>
<string name="preference_themed_icons">Eingefärbte Symbole</string>
<string name="preference_themed_icons_summary">Symbole an das Farbschema der App anpassen</string>
<string name="weather_no_data">Keine Wetterdaten verfügbar.</string>
</resources>

View File

@ -445,6 +445,8 @@
<string name="weather_widget_hide_details">Hide details</string>
<string name="weather_humidity">Humidity:</string>
<string name="weather_wind">Wind:</string>
<string name="weather_no_data">No weather data available.</string>
<string name="weather_precipitation">Precipitation:</string>
<string name="preference_category_license">License</string>
<string name="preference_about_license">This app is free software.</string>

View File

@ -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)
)
}
}
}
}

View File

@ -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
)
}
}