Add tooltips to widgets (#1229)
* add tooltips * update toolbar tooltip * prettify ifelse statements
This commit is contained in:
parent
11ae8386fd
commit
8d7084e23f
@ -1,7 +1,6 @@
|
||||
package de.mm20.launcher2.ui.component
|
||||
|
||||
import androidx.compose.animation.animateContentSize
|
||||
import androidx.compose.foundation.combinedClickable
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.ColumnScope
|
||||
import androidx.compose.foundation.layout.Row
|
||||
@ -16,16 +15,11 @@ import androidx.compose.material3.DropdownMenu
|
||||
import androidx.compose.material3.DropdownMenuItem
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.PlainTooltip
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TooltipBox
|
||||
import androidx.compose.material3.TooltipDefaults
|
||||
import androidx.compose.material3.rememberTooltipState
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
@ -35,7 +29,6 @@ import androidx.compose.ui.unit.dp
|
||||
import de.mm20.launcher2.ui.R
|
||||
import de.mm20.launcher2.ui.ktx.toDp
|
||||
import de.mm20.launcher2.ui.locals.LocalWindowPosition
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlin.math.min
|
||||
|
||||
@Composable
|
||||
@ -57,7 +50,6 @@ fun Toolbar(
|
||||
|
||||
@Composable
|
||||
fun Icons(actions: List<ToolbarAction>, slots: Int) {
|
||||
val scope = rememberCoroutineScope()
|
||||
for (i in 0 until min(slots, actions.size)) {
|
||||
if (i == slots - 1 && slots != actions.size) {
|
||||
var showMenu by remember { mutableStateOf(false) }
|
||||
@ -82,28 +74,11 @@ fun Icons(actions: List<ToolbarAction>, slots: Int) {
|
||||
}
|
||||
} else {
|
||||
val action = actions[i]
|
||||
val tooltipState = rememberTooltipState()
|
||||
TooltipBox(
|
||||
positionProvider = TooltipDefaults.rememberTooltipPositionProvider(),
|
||||
tooltip = {
|
||||
PlainTooltip {
|
||||
Text(action.label)
|
||||
}
|
||||
},
|
||||
state = tooltipState
|
||||
) {
|
||||
Tooltip(action.label) {
|
||||
when (action) {
|
||||
is DefaultToolbarAction -> {
|
||||
IconButton(
|
||||
onClick = action.action,
|
||||
modifier = Modifier.combinedClickable(
|
||||
onClick = {},
|
||||
onLongClick = {
|
||||
scope.launch {
|
||||
tooltipState.show()
|
||||
}
|
||||
}
|
||||
)
|
||||
) {
|
||||
Icon(action.icon, contentDescription = action.label)
|
||||
}
|
||||
@ -116,14 +91,6 @@ fun Icons(actions: List<ToolbarAction>, slots: Int) {
|
||||
onClick = {
|
||||
showMenu = true
|
||||
},
|
||||
modifier = Modifier.combinedClickable(
|
||||
onClick = {},
|
||||
onLongClick = {
|
||||
scope.launch {
|
||||
tooltipState.show()
|
||||
}
|
||||
}
|
||||
)
|
||||
) {
|
||||
Icon(action.icon, contentDescription = action.label)
|
||||
}
|
||||
|
||||
@ -0,0 +1,28 @@
|
||||
package de.mm20.launcher2.ui.component
|
||||
|
||||
import androidx.compose.material3.PlainTooltip
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TooltipBox
|
||||
import androidx.compose.material3.TooltipDefaults
|
||||
import androidx.compose.material3.rememberTooltipState
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
|
||||
@Composable
|
||||
fun Tooltip (
|
||||
tooltipText: String,
|
||||
modifier: Modifier = Modifier,
|
||||
content: @Composable () -> Unit
|
||||
) {
|
||||
val tooltipState = rememberTooltipState()
|
||||
|
||||
TooltipBox(
|
||||
state = tooltipState,
|
||||
positionProvider = TooltipDefaults.rememberTooltipPositionProvider(),
|
||||
tooltip = { PlainTooltip { Text(tooltipText) } },
|
||||
modifier = modifier
|
||||
) {
|
||||
content()
|
||||
}
|
||||
|
||||
}
|
||||
@ -49,23 +49,17 @@ import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.IconButtonDefaults
|
||||
import androidx.compose.material3.LinearProgressIndicator
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.PlainTooltip
|
||||
import androidx.compose.material3.Slider
|
||||
import androidx.compose.material3.SliderDefaults
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TooltipBox
|
||||
import androidx.compose.material3.TooltipDefaults
|
||||
import androidx.compose.material3.rememberTooltipState
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.geometry.Rect
|
||||
import androidx.compose.ui.graphics.StrokeCap
|
||||
import androidx.compose.ui.graphics.asImageBitmap
|
||||
import androidx.compose.ui.layout.ContentScale
|
||||
@ -88,13 +82,13 @@ import de.mm20.launcher2.music.PlaybackState
|
||||
import de.mm20.launcher2.music.SupportedActions
|
||||
import de.mm20.launcher2.ui.R
|
||||
import de.mm20.launcher2.ui.component.MissingPermissionBanner
|
||||
import de.mm20.launcher2.ui.component.Tooltip
|
||||
import de.mm20.launcher2.ui.ktx.conditional
|
||||
import de.mm20.launcher2.ui.launcher.transitions.EnterHomeTransitionParams
|
||||
import de.mm20.launcher2.ui.launcher.transitions.HandleEnterHomeTransition
|
||||
import de.mm20.launcher2.ui.locals.LocalCardStyle
|
||||
import de.mm20.launcher2.ui.locals.LocalWindowSize
|
||||
import de.mm20.launcher2.widgets.MusicWidget
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlin.math.min
|
||||
|
||||
@Composable
|
||||
@ -334,44 +328,58 @@ fun MusicWidget(widget: MusicWidget) {
|
||||
|
||||
) {
|
||||
if (supportedActions.skipToPrevious) {
|
||||
IconButton(
|
||||
onClick = {
|
||||
viewModel.skipPrevious()
|
||||
}) {
|
||||
Icon(
|
||||
imageVector = Icons.Rounded.SkipPrevious,
|
||||
stringResource(R.string.music_widget_previous_track)
|
||||
)
|
||||
Tooltip(
|
||||
tooltipText = stringResource(R.string.music_widget_previous_track)
|
||||
) {
|
||||
IconButton(
|
||||
onClick = {
|
||||
viewModel.skipPrevious()
|
||||
}) {
|
||||
Icon(
|
||||
imageVector = Icons.Rounded.SkipPrevious,
|
||||
stringResource(R.string.music_widget_previous_track)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
val playPauseIcon =
|
||||
AnimatedImageVector.animatedVectorResource(R.drawable.anim_ic_play_pause)
|
||||
FilledTonalIconButton(
|
||||
colors = IconButtonDefaults.filledTonalIconButtonColors(
|
||||
containerColor = MaterialTheme.colorScheme.secondaryContainer.copy(alpha = LocalCardStyle.current.opacity),
|
||||
),
|
||||
onClick = { viewModel.togglePause() },
|
||||
) {
|
||||
Icon(
|
||||
painter = rememberAnimatedVectorPainter(
|
||||
playPauseIcon,
|
||||
atEnd = playbackState == PlaybackState.Playing
|
||||
),
|
||||
contentDescription = if (playbackState == PlaybackState.Playing) {
|
||||
stringResource(R.string.music_widget_pause)
|
||||
} else {
|
||||
stringResource(R.string.music_widget_play)
|
||||
}
|
||||
Tooltip(
|
||||
tooltipText = stringResource(
|
||||
if (playbackState == PlaybackState.Playing) R.string.music_widget_pause
|
||||
else R.string.music_widget_play
|
||||
)
|
||||
) {
|
||||
FilledTonalIconButton(
|
||||
colors = IconButtonDefaults.filledTonalIconButtonColors(
|
||||
containerColor = MaterialTheme.colorScheme.secondaryContainer.copy(alpha = LocalCardStyle.current.opacity),
|
||||
),
|
||||
onClick = { viewModel.togglePause() },
|
||||
) {
|
||||
Icon(
|
||||
painter = rememberAnimatedVectorPainter(
|
||||
playPauseIcon,
|
||||
atEnd = playbackState == PlaybackState.Playing
|
||||
),
|
||||
contentDescription = stringResource(
|
||||
if (playbackState == PlaybackState.Playing) R.string.music_widget_pause
|
||||
else R.string.music_widget_play
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
if (supportedActions.skipToNext) {
|
||||
IconButton(onClick = {
|
||||
viewModel.skipNext()
|
||||
}) {
|
||||
Icon(
|
||||
imageVector = Icons.Rounded.SkipNext,
|
||||
stringResource(R.string.music_widget_next_track)
|
||||
)
|
||||
Tooltip(
|
||||
tooltipText = stringResource(R.string.music_widget_next_track)
|
||||
) {
|
||||
IconButton(onClick = {
|
||||
viewModel.skipNext()
|
||||
}) {
|
||||
Icon(
|
||||
imageVector = Icons.Rounded.SkipNext,
|
||||
stringResource(R.string.music_widget_next_track)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
CustomActions(
|
||||
@ -394,29 +402,12 @@ fun CustomActions(
|
||||
val usedSlots = 1 + (if (actions.skipToPrevious) 1 else 0) + (if (actions.skipToNext) 1 else 0)
|
||||
val slots = 5 - usedSlots
|
||||
|
||||
val scope = rememberCoroutineScope()
|
||||
|
||||
for (i in 0 until min(actions.customActions.size, slots - 1)) {
|
||||
val action = actions.customActions[i]
|
||||
val tooltipState = rememberTooltipState()
|
||||
TooltipBox(
|
||||
positionProvider = TooltipDefaults.rememberTooltipPositionProvider(),
|
||||
state = tooltipState,
|
||||
tooltip = {
|
||||
PlainTooltip {
|
||||
Text(action.name.toString())
|
||||
}
|
||||
},
|
||||
Tooltip(
|
||||
tooltipText = action.name.toString()
|
||||
) {
|
||||
IconButton(
|
||||
modifier = Modifier.combinedClickable(
|
||||
onClick = {},
|
||||
onLongClick = {
|
||||
scope.launch {
|
||||
tooltipState.show()
|
||||
}
|
||||
}
|
||||
),
|
||||
onClick = {
|
||||
onActionSelected(action)
|
||||
}
|
||||
@ -428,8 +419,12 @@ fun CustomActions(
|
||||
if (slots < actions.customActions.size) {
|
||||
var showOverflowMenu by remember { mutableStateOf(false) }
|
||||
Box {
|
||||
IconButton(onClick = { showOverflowMenu = true }) {
|
||||
Icon(imageVector = Icons.Rounded.MoreVert, contentDescription = null)
|
||||
Tooltip(
|
||||
tooltipText = stringResource(R.string.action_more_actions)
|
||||
) {
|
||||
IconButton(onClick = { showOverflowMenu = true }) {
|
||||
Icon(imageVector = Icons.Rounded.MoreVert, contentDescription = null)
|
||||
}
|
||||
}
|
||||
DropdownMenu(
|
||||
expanded = showOverflowMenu,
|
||||
@ -456,26 +451,11 @@ fun CustomActions(
|
||||
}
|
||||
}
|
||||
} else if (slots == actions.customActions.size) {
|
||||
val tooltipState = rememberTooltipState()
|
||||
val action = actions.customActions.last()
|
||||
TooltipBox(
|
||||
state = tooltipState,
|
||||
positionProvider = TooltipDefaults.rememberTooltipPositionProvider(),
|
||||
tooltip = {
|
||||
PlainTooltip {
|
||||
Text(action.name.toString())
|
||||
}
|
||||
}
|
||||
Tooltip (
|
||||
tooltipText = action.name.toString()
|
||||
) {
|
||||
IconButton(
|
||||
modifier = Modifier.combinedClickable(
|
||||
onClick = {},
|
||||
onLongClick = {
|
||||
scope.launch {
|
||||
tooltipState.show()
|
||||
}
|
||||
}
|
||||
),
|
||||
onClick = {
|
||||
onActionSelected(action)
|
||||
}
|
||||
|
||||
@ -43,22 +43,17 @@ import androidx.compose.material3.DropdownMenuItem
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.PlainTooltip
|
||||
import androidx.compose.material3.SnackbarDuration
|
||||
import androidx.compose.material3.SnackbarResult
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextButton
|
||||
import androidx.compose.material3.TooltipBox
|
||||
import androidx.compose.material3.TooltipDefaults
|
||||
import androidx.compose.material3.rememberTooltipState
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
@ -74,6 +69,7 @@ import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import de.mm20.launcher2.ui.R
|
||||
import de.mm20.launcher2.ui.component.Banner
|
||||
import de.mm20.launcher2.ui.component.BottomSheetDialog
|
||||
import de.mm20.launcher2.ui.component.Tooltip
|
||||
import de.mm20.launcher2.ui.component.markdown.MarkdownEditor
|
||||
import de.mm20.launcher2.ui.component.markdown.MarkdownText
|
||||
import de.mm20.launcher2.ui.locals.LocalSnackbarHostState
|
||||
@ -94,8 +90,6 @@ fun NotesWidget(
|
||||
val snackbarHostState = LocalSnackbarHostState.current
|
||||
val lifecycleOwner = LocalLifecycleOwner.current
|
||||
|
||||
val scope = rememberCoroutineScope()
|
||||
|
||||
var showConflictResolveSheet by remember { mutableStateOf(false) }
|
||||
var readWriteErrorSheetText by remember { mutableStateOf<String?>(null) }
|
||||
|
||||
@ -181,20 +175,12 @@ fun NotesWidget(
|
||||
Row(
|
||||
modifier = Modifier.padding(8.dp),
|
||||
) {
|
||||
val tooltipState = rememberTooltipState()
|
||||
TooltipBox(
|
||||
state = tooltipState,
|
||||
positionProvider = TooltipDefaults.rememberTooltipPositionProvider(),
|
||||
tooltip = {
|
||||
PlainTooltip {
|
||||
Text(
|
||||
stringResource(
|
||||
if (widget.config.linkedFile == null) R.string.note_widget_link_file
|
||||
else R.string.note_widget_action_unlink_file
|
||||
)
|
||||
)
|
||||
}
|
||||
}) {
|
||||
Tooltip(
|
||||
tooltipText = stringResource(
|
||||
if (widget.config.linkedFile == null) R.string.note_widget_link_file
|
||||
else R.string.note_widget_action_unlink_file
|
||||
),
|
||||
) {
|
||||
IconButton(
|
||||
onClick = {
|
||||
if (widget.config.linkedFile == null) {
|
||||
@ -205,14 +191,6 @@ fun NotesWidget(
|
||||
viewModel.unlinkFile(context)
|
||||
}
|
||||
},
|
||||
modifier = Modifier.combinedClickable(
|
||||
onClick = {},
|
||||
onLongClick = {
|
||||
scope.launch {
|
||||
tooltipState.show()
|
||||
}
|
||||
}
|
||||
)
|
||||
) {
|
||||
Icon(
|
||||
if (widget.config.linkedFile == null) Icons.Rounded.Link
|
||||
@ -225,26 +203,13 @@ fun NotesWidget(
|
||||
}
|
||||
}
|
||||
if (isLastWidget == false) {
|
||||
TooltipBox(
|
||||
state = tooltipState,
|
||||
positionProvider = TooltipDefaults.rememberTooltipPositionProvider(),
|
||||
tooltip = {
|
||||
PlainTooltip {
|
||||
Text(stringResource(R.string.notes_widget_action_dismiss))
|
||||
}
|
||||
}) {
|
||||
Tooltip(
|
||||
tooltipText = stringResource(R.string.notes_widget_action_dismiss)
|
||||
) {
|
||||
IconButton(
|
||||
onClick = {
|
||||
viewModel.dismissNote()
|
||||
},
|
||||
modifier = Modifier.combinedClickable(
|
||||
onClick = {},
|
||||
onLongClick = {
|
||||
scope.launch {
|
||||
tooltipState.show()
|
||||
}
|
||||
}
|
||||
)
|
||||
) {
|
||||
Icon(Icons.Rounded.Delete, null)
|
||||
}
|
||||
@ -297,8 +262,12 @@ fun NotesWidget(
|
||||
}
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
Box {
|
||||
IconButton(onClick = { showMenu = true }) {
|
||||
Icon(Icons.Rounded.MoreVert, stringResource(R.string.action_more_actions))
|
||||
Tooltip(
|
||||
tooltipText = stringResource(R.string.action_more_actions)
|
||||
) {
|
||||
IconButton(onClick = { showMenu = true }) {
|
||||
Icon(Icons.Rounded.MoreVert, stringResource(R.string.action_more_actions))
|
||||
}
|
||||
}
|
||||
DropdownMenu(expanded = showMenu, onDismissRequest = { showMenu = false }) {
|
||||
DropdownMenuItem(
|
||||
|
||||
@ -67,6 +67,7 @@ import de.mm20.launcher2.ui.R
|
||||
import de.mm20.launcher2.ui.common.WeatherLocationSearchDialog
|
||||
import de.mm20.launcher2.ui.component.Banner
|
||||
import de.mm20.launcher2.ui.component.MissingPermissionBanner
|
||||
import de.mm20.launcher2.ui.component.Tooltip
|
||||
import de.mm20.launcher2.ui.component.weather.AnimatedWeatherIcon
|
||||
import de.mm20.launcher2.ui.component.weather.WeatherIcon
|
||||
import de.mm20.launcher2.ui.ktx.blendIntoViewScale
|
||||
@ -231,32 +232,36 @@ fun CurrentWeather(forecast: Forecast, imperialUnits: Boolean) {
|
||||
style = MaterialTheme.typography.titleMedium
|
||||
)
|
||||
}
|
||||
Surface(
|
||||
shape = MaterialTheme.shapes.extraSmall.copy(
|
||||
topStart = CornerSize(0),
|
||||
topEnd = CornerSize(0),
|
||||
bottomEnd = CornerSize(0)
|
||||
),
|
||||
color = MaterialTheme.colorScheme.secondaryContainer.copy(alpha = LocalCardStyle.current.opacity),
|
||||
Tooltip(
|
||||
tooltipText = stringResource(R.string.preference_weather_provider)
|
||||
) {
|
||||
Text(
|
||||
text = "${forecast.provider} (${
|
||||
formatTime(
|
||||
LocalContext.current,
|
||||
forecast.updateTime
|
||||
)
|
||||
})",
|
||||
style = MaterialTheme.typography.bodySmall.copy(fontSize = 8.sp),
|
||||
modifier = Modifier
|
||||
.clickable(onClick = {
|
||||
val intent = Intent(Intent.ACTION_VIEW).apply {
|
||||
data = Uri.parse(forecast.providerUrl)
|
||||
?: return@clickable
|
||||
}
|
||||
context.tryStartActivity(intent)
|
||||
})
|
||||
.padding(start = 8.dp, top = 4.dp, bottom = 4.dp, end = 12.dp)
|
||||
)
|
||||
Surface(
|
||||
shape = MaterialTheme.shapes.extraSmall.copy(
|
||||
topStart = CornerSize(0),
|
||||
topEnd = CornerSize(0),
|
||||
bottomEnd = CornerSize(0)
|
||||
),
|
||||
color = MaterialTheme.colorScheme.secondaryContainer.copy(alpha = LocalCardStyle.current.opacity),
|
||||
) {
|
||||
Text(
|
||||
text = "${forecast.provider} (${
|
||||
formatTime(
|
||||
LocalContext.current,
|
||||
forecast.updateTime
|
||||
)
|
||||
})",
|
||||
style = MaterialTheme.typography.bodySmall.copy(fontSize = 8.sp),
|
||||
modifier = Modifier
|
||||
.clickable(onClick = {
|
||||
val intent = Intent(Intent.ACTION_VIEW).apply {
|
||||
data = Uri.parse(forecast.providerUrl)
|
||||
?: return@clickable
|
||||
}
|
||||
context.tryStartActivity(intent)
|
||||
})
|
||||
.padding(start = 8.dp, top = 4.dp, bottom = 4.dp, end = 12.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
Row(
|
||||
@ -293,71 +298,84 @@ fun CurrentWeather(forecast: Forecast, imperialUnits: Boolean) {
|
||||
horizontalArrangement = Arrangement.SpaceBetween
|
||||
) {
|
||||
if (forecast.humidity != null) {
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
Tooltip(
|
||||
tooltipText = stringResource(R.string.weather_forecast_humidity)
|
||||
) {
|
||||
Icon(
|
||||
imageVector = Icons.Rounded.HumidityPercentage,
|
||||
modifier = Modifier.size(20.dp),
|
||||
tint = MaterialTheme.colorScheme.secondary,
|
||||
contentDescription = null
|
||||
)
|
||||
Spacer(modifier = Modifier.padding(3.dp))
|
||||
Text(
|
||||
text = "${forecast.humidity!!.roundToInt()} %",
|
||||
style = MaterialTheme.typography.bodySmall,
|
||||
)
|
||||
}
|
||||
}
|
||||
if (forecast.windDirection != null || forecast.windSpeed != null) {
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
if (forecast.windDirection != null) {
|
||||
// windDirection is "fromDirection"; Wind (arrow) blows into opposite direction
|
||||
val angle by animateFloatAsState(forecast.windDirection!!.toFloat() + 180f)
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Icon(
|
||||
imageVector = Icons.Rounded.North,
|
||||
modifier = Modifier
|
||||
.rotate(angle)
|
||||
.size(20.dp),
|
||||
contentDescription = null,
|
||||
tint = MaterialTheme.colorScheme.secondary,
|
||||
)
|
||||
} else {
|
||||
Icon(
|
||||
imageVector = Icons.Rounded.Air,
|
||||
contentDescription = null,
|
||||
imageVector = Icons.Rounded.HumidityPercentage,
|
||||
modifier = Modifier.size(20.dp),
|
||||
tint = MaterialTheme.colorScheme.secondary,
|
||||
contentDescription = null
|
||||
)
|
||||
Spacer(modifier = Modifier.padding(3.dp))
|
||||
Text(
|
||||
text = "${forecast.humidity!!.roundToInt()} %",
|
||||
style = MaterialTheme.typography.bodySmall,
|
||||
)
|
||||
}
|
||||
Spacer(modifier = Modifier.padding(3.dp))
|
||||
Text(
|
||||
text = if (forecast.windSpeed != null) {
|
||||
formatWindSpeed(imperialUnits, forecast)
|
||||
}
|
||||
|
||||
}
|
||||
if (forecast.windDirection != null || forecast.windSpeed != null) {
|
||||
Tooltip(
|
||||
tooltipText = stringResource(R.string.weather_forecast_wind)
|
||||
) {
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
if (forecast.windDirection != null) {
|
||||
// windDirection is "fromDirection"; Wind (arrow) blows into opposite direction
|
||||
val angle by animateFloatAsState(forecast.windDirection!!.toFloat() + 180f)
|
||||
Icon(
|
||||
imageVector = Icons.Rounded.North,
|
||||
modifier = Modifier
|
||||
.rotate(angle)
|
||||
.size(20.dp),
|
||||
contentDescription = null,
|
||||
tint = MaterialTheme.colorScheme.secondary,
|
||||
)
|
||||
} else {
|
||||
windDirectionAsWord(forecast.windDirection!!)
|
||||
},
|
||||
style = MaterialTheme.typography.bodySmall,
|
||||
)
|
||||
Icon(
|
||||
imageVector = Icons.Rounded.Air,
|
||||
contentDescription = null,
|
||||
modifier = Modifier.size(20.dp),
|
||||
tint = MaterialTheme.colorScheme.secondary,
|
||||
)
|
||||
}
|
||||
Spacer(modifier = Modifier.padding(3.dp))
|
||||
Text(
|
||||
text = if (forecast.windSpeed != null) {
|
||||
formatWindSpeed(imperialUnits, forecast)
|
||||
} else {
|
||||
windDirectionAsWord(forecast.windDirection!!)
|
||||
},
|
||||
style = MaterialTheme.typography.bodySmall,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (forecast.precipitation != null) {
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
Tooltip(
|
||||
tooltipText = stringResource(id = R.string.weather_forecast_precipitation)
|
||||
) {
|
||||
Icon(
|
||||
imageVector = Icons.Rounded.Rain,
|
||||
modifier = Modifier.size(20.dp),
|
||||
contentDescription = null,
|
||||
tint = MaterialTheme.colorScheme.secondary,
|
||||
)
|
||||
Spacer(modifier = Modifier.padding(3.dp))
|
||||
Text(
|
||||
text = formatPrecipitation(imperialUnits, forecast),
|
||||
style = MaterialTheme.typography.bodySmall,
|
||||
)
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Icon(
|
||||
imageVector = Icons.Rounded.Rain,
|
||||
modifier = Modifier.size(20.dp),
|
||||
contentDescription = null,
|
||||
tint = MaterialTheme.colorScheme.secondary,
|
||||
)
|
||||
Spacer(modifier = Modifier.padding(3.dp))
|
||||
Text(
|
||||
text = formatPrecipitation(imperialUnits, forecast),
|
||||
style = MaterialTheme.typography.bodySmall,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -16,17 +16,12 @@ import androidx.compose.material.icons.rounded.SettingsSuggest
|
||||
import androidx.compose.material3.ButtonDefaults
|
||||
import androidx.compose.material3.HorizontalDivider
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.PlainTooltip
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextButton
|
||||
import androidx.compose.material3.TooltipBox
|
||||
import androidx.compose.material3.TooltipDefaults
|
||||
import androidx.compose.material3.rememberTooltipState
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
@ -36,6 +31,7 @@ import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import de.mm20.launcher2.ui.R
|
||||
import de.mm20.launcher2.ui.component.BottomSheetDialog
|
||||
import de.mm20.launcher2.ui.component.Tooltip
|
||||
import de.mm20.launcher2.ui.component.colorpicker.HctColorPicker
|
||||
import de.mm20.launcher2.ui.component.colorpicker.rememberHctColorPickerState
|
||||
import de.mm20.launcher2.ui.component.preferences.SwitchPreference
|
||||
@ -51,17 +47,8 @@ fun CorePaletteColorPreference(
|
||||
) {
|
||||
var showDialog by remember { mutableStateOf(false) }
|
||||
|
||||
val scope = rememberCoroutineScope()
|
||||
val tooltipState = rememberTooltipState()
|
||||
|
||||
TooltipBox(
|
||||
state = tooltipState,
|
||||
positionProvider = TooltipDefaults.rememberTooltipPositionProvider(),
|
||||
tooltip = {
|
||||
PlainTooltip {
|
||||
Text(title)
|
||||
}
|
||||
},
|
||||
Tooltip(
|
||||
tooltipText = title
|
||||
) {
|
||||
ColorSwatch(
|
||||
color = Color(value ?: defaultValue),
|
||||
|
||||
@ -4,7 +4,6 @@ import androidx.compose.animation.AnimatedContent
|
||||
import androidx.compose.foundation.Canvas
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.combinedClickable
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
@ -25,21 +24,16 @@ import androidx.compose.material3.ButtonDefaults
|
||||
import androidx.compose.material3.HorizontalDivider
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.PlainTooltip
|
||||
import androidx.compose.material3.SegmentedButton
|
||||
import androidx.compose.material3.SegmentedButtonDefaults
|
||||
import androidx.compose.material3.SingleChoiceSegmentedButtonRow
|
||||
import androidx.compose.material3.Slider
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextButton
|
||||
import androidx.compose.material3.TooltipBox
|
||||
import androidx.compose.material3.TooltipDefaults
|
||||
import androidx.compose.material3.rememberTooltipState
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
@ -61,11 +55,11 @@ import de.mm20.launcher2.themes.atTone
|
||||
import de.mm20.launcher2.themes.get
|
||||
import de.mm20.launcher2.ui.R
|
||||
import de.mm20.launcher2.ui.component.BottomSheetDialog
|
||||
import de.mm20.launcher2.ui.component.Tooltip
|
||||
import de.mm20.launcher2.ui.component.colorpicker.HctColorPicker
|
||||
import de.mm20.launcher2.ui.component.colorpicker.rememberHctColorPickerState
|
||||
import de.mm20.launcher2.ui.ktx.hct
|
||||
import hct.Hct
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlin.math.roundToInt
|
||||
import de.mm20.launcher2.themes.Color as ThemeColor
|
||||
|
||||
@ -80,25 +74,15 @@ fun ThemeColorPreference(
|
||||
) {
|
||||
var showDialog by remember { mutableStateOf(false) }
|
||||
|
||||
val scope = rememberCoroutineScope()
|
||||
val tooltipState = rememberTooltipState()
|
||||
|
||||
TooltipBox(
|
||||
state = tooltipState,
|
||||
positionProvider = TooltipDefaults.rememberTooltipPositionProvider(),
|
||||
tooltip = { PlainTooltip { Text(title) } }
|
||||
Tooltip(
|
||||
tooltipText = title
|
||||
) {
|
||||
ColorSwatch(
|
||||
color = Color((value ?: defaultValue).get(corePalette)),
|
||||
modifier = modifier
|
||||
.size(48.dp)
|
||||
.combinedClickable(
|
||||
.clickable(
|
||||
onClick = { showDialog = true },
|
||||
onLongClick = {
|
||||
scope.launch {
|
||||
tooltipState.show()
|
||||
}
|
||||
}
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
@ -1005,4 +1005,7 @@
|
||||
<item quantity="other">%1$s lists selected</item>
|
||||
</plurals>
|
||||
<string name="reset_icon">Reset icon</string>
|
||||
<string name="weather_forecast_humidity">Humidity</string>
|
||||
<string name="weather_forecast_wind">Wind</string>
|
||||
<string name="weather_forecast_precipitation">Precipitation</string>
|
||||
</resources>
|
||||
Loading…
x
Reference in New Issue
Block a user