Always show weather and music widgets even if there's no data available
This commit is contained in:
parent
960c645010
commit
fb50c9bd9d
@ -415,4 +415,5 @@
|
|||||||
<string name="weather_wind">Wind:</string>
|
<string name="weather_wind">Wind:</string>
|
||||||
<string name="preference_themed_icons">Eingefärbte Symbole</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="preference_themed_icons_summary">Symbole an das Farbschema der App anpassen</string>
|
||||||
|
<string name="weather_no_data">Keine Wetterdaten verfügbar.</string>
|
||||||
</resources>
|
</resources>
|
||||||
@ -445,6 +445,8 @@
|
|||||||
<string name="weather_widget_hide_details">Hide details</string>
|
<string name="weather_widget_hide_details">Hide details</string>
|
||||||
<string name="weather_humidity">Humidity:</string>
|
<string name="weather_humidity">Humidity:</string>
|
||||||
<string name="weather_wind">Wind:</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="weather_precipitation">Precipitation:</string>
|
||||||
<string name="preference_category_license">License</string>
|
<string name="preference_category_license">License</string>
|
||||||
<string name="preference_about_license">This app is free software.</string>
|
<string name="preference_about_license">This app is free software.</string>
|
||||||
|
|||||||
@ -7,14 +7,14 @@ import androidx.compose.foundation.Image
|
|||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.combinedClickable
|
import androidx.compose.foundation.combinedClickable
|
||||||
import androidx.compose.foundation.layout.*
|
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.Icons
|
||||||
import androidx.compose.material.icons.rounded.MusicNote
|
import androidx.compose.material.icons.rounded.MusicNote
|
||||||
import androidx.compose.material.icons.rounded.SkipNext
|
import androidx.compose.material.icons.rounded.SkipNext
|
||||||
import androidx.compose.material.icons.rounded.SkipPrevious
|
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.Composable
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.livedata.observeAsState
|
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.music.PlaybackState
|
||||||
import de.mm20.launcher2.ui.R
|
import de.mm20.launcher2.ui.R
|
||||||
import de.mm20.launcher2.ui.ktx.conditional
|
import de.mm20.launcher2.ui.ktx.conditional
|
||||||
import de.mm20.launcher2.ui.locals.LocalColorScheme
|
|
||||||
import org.koin.androidx.compose.getViewModel
|
import org.koin.androidx.compose.getViewModel
|
||||||
|
|
||||||
@OptIn(
|
@OptIn(
|
||||||
@ -52,111 +51,106 @@ fun MusicWidget() {
|
|||||||
Row(
|
Row(
|
||||||
modifier = Modifier.height(IntrinsicSize.Min)
|
modifier = Modifier.height(IntrinsicSize.Min)
|
||||||
) {
|
) {
|
||||||
if (title != null) {
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(top = 16.dp)
|
||||||
|
.fillMaxHeight()
|
||||||
|
.weight(2f),
|
||||||
|
verticalArrangement = Arrangement.SpaceBetween
|
||||||
|
) {
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier.padding(horizontal = 16.dp)
|
||||||
.padding(top = 16.dp)
|
|
||||||
.fillMaxHeight()
|
|
||||||
.weight(2f),
|
|
||||||
verticalArrangement = Arrangement.SpaceBetween
|
|
||||||
) {
|
) {
|
||||||
Column(
|
Text(
|
||||||
modifier = Modifier.padding(horizontal = 16.dp)
|
text = title ?: "---",
|
||||||
) {
|
style = MaterialTheme.typography.titleMedium,
|
||||||
Text(
|
maxLines = 1,
|
||||||
text = title ?: "---",
|
overflow = TextOverflow.Ellipsis
|
||||||
style = MaterialTheme.typography.titleMedium,
|
)
|
||||||
maxLines = 1,
|
Text(
|
||||||
overflow = TextOverflow.Ellipsis
|
text = artist ?: "---",
|
||||||
)
|
modifier = Modifier.padding(vertical = 2.dp),
|
||||||
Text(
|
style = MaterialTheme.typography.bodySmall,
|
||||||
text = artist ?: "---",
|
maxLines = 1,
|
||||||
modifier = Modifier.padding(vertical = 2.dp),
|
overflow = TextOverflow.Ellipsis
|
||||||
style = MaterialTheme.typography.bodySmall,
|
)
|
||||||
maxLines = 1,
|
Text(
|
||||||
overflow = TextOverflow.Ellipsis
|
text = album ?: "---",
|
||||||
)
|
style = MaterialTheme.typography.bodySmall,
|
||||||
Text(
|
maxLines = 1,
|
||||||
text = album ?: "---",
|
overflow = TextOverflow.Ellipsis
|
||||||
style = MaterialTheme.typography.bodySmall,
|
)
|
||||||
maxLines = 1,
|
}
|
||||||
overflow = TextOverflow.Ellipsis
|
Row(
|
||||||
)
|
modifier = Modifier
|
||||||
}
|
.fillMaxWidth()
|
||||||
Row(
|
.padding(bottom = 4.dp, end = 4.dp),
|
||||||
modifier = Modifier
|
horizontalArrangement = Arrangement.SpaceBetween
|
||||||
.fillMaxWidth()
|
) {
|
||||||
.padding(bottom = 4.dp, end = 4.dp),
|
IconButton(
|
||||||
horizontalArrangement = Arrangement.SpaceBetween
|
onClick = {
|
||||||
) {
|
viewModel.previous()
|
||||||
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()
|
|
||||||
}) {
|
}) {
|
||||||
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(
|
Icon(
|
||||||
imageVector = Icons.Rounded.MusicNote,
|
imageVector = Icons.Rounded.SkipPrevious,
|
||||||
contentDescription = null,
|
null
|
||||||
tint = MaterialTheme.colorScheme.onPrimaryContainer,
|
)
|
||||||
modifier = Modifier.size(56.dp)
|
}
|
||||||
|
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)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -13,6 +13,7 @@ import androidx.compose.material.DropdownMenu
|
|||||||
import androidx.compose.material.DropdownMenuItem
|
import androidx.compose.material.DropdownMenuItem
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.rounded.ArrowDropDown
|
import androidx.compose.material.icons.rounded.ArrowDropDown
|
||||||
|
import androidx.compose.material.icons.rounded.LightMode
|
||||||
import androidx.compose.material3.*
|
import androidx.compose.material3.*
|
||||||
import androidx.compose.runtime.*
|
import androidx.compose.runtime.*
|
||||||
import androidx.compose.runtime.livedata.observeAsState
|
import androidx.compose.runtime.livedata.observeAsState
|
||||||
@ -49,18 +50,22 @@ fun WeatherWidget() {
|
|||||||
var selectedForecastIndex by remember { mutableStateOf(0) }
|
var selectedForecastIndex by remember { mutableStateOf(0) }
|
||||||
var detailsExpanded by remember { mutableStateOf(false) }
|
var detailsExpanded by remember { mutableStateOf(false) }
|
||||||
|
|
||||||
if (weatherData.isEmpty()) return
|
|
||||||
|
|
||||||
if (weatherData.size <= selectedDayIndex) {
|
if (weatherData.isNotEmpty() && weatherData.size <= selectedDayIndex) {
|
||||||
selectedDayIndex = 0
|
selectedDayIndex = 0
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (weatherData[selectedDayIndex].hourlyForecasts.size <= selectedForecastIndex) {
|
if (weatherData.isNotEmpty() && weatherData[selectedDayIndex].hourlyForecasts.size <= selectedForecastIndex) {
|
||||||
selectedForecastIndex = 0
|
selectedForecastIndex = 0
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (weatherData.isEmpty()) {
|
||||||
|
NoData()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
val selectedForecast = weatherData[selectedDayIndex].hourlyForecasts[selectedForecastIndex]
|
val selectedForecast = weatherData[selectedDayIndex].hourlyForecasts[selectedForecastIndex]
|
||||||
val imperialUnits = LauncherPreferences.instance.imperialUnits
|
val imperialUnits = LauncherPreferences.instance.imperialUnits
|
||||||
|
|
||||||
@ -441,3 +446,25 @@ private fun weatherIconById(id: Int): WeatherIcon {
|
|||||||
else -> WeatherIcon.None
|
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
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user