Replace onGloballyPositioned with onRectChanged but then don't do it because it doesn't work

This commit is contained in:
MM20 2024-11-22 17:26:02 +01:00
parent fc5c0c84dc
commit 8f0e967143
No known key found for this signature in database
GPG Key ID: 0B61A8F2DEAFA389
17 changed files with 109 additions and 96 deletions

View File

@ -118,7 +118,7 @@ fun TagChip(
horizontalArrangement = Arrangement.Center, horizontalArrangement = Arrangement.Center,
) { ) {
val foregroundLayer = (icon as? StaticLauncherIcon)?.foregroundLayer val foregroundLayer = (icon as? StaticLauncherIcon)?.foregroundLayer
AnimatedVisibility(foregroundLayer != null && (!compact || foregroundLayer is TextLayer)) { AnimatedVisibility(!compact || foregroundLayer is TextLayer) {
if (foregroundLayer is TextLayer) { if (foregroundLayer is TextLayer) {
Text( Text(
text = foregroundLayer.text, text = foregroundLayer.text,
@ -135,7 +135,7 @@ fun TagChip(
) )
} }
} }
AnimatedVisibility(foregroundLayer != null && (!compact || foregroundLayer is VectorLayer)) { AnimatedVisibility(!compact || foregroundLayer is VectorLayer) {
Text( Text(
tag.tag, tag.tag,
style = MaterialTheme.typography.labelLarge, style = MaterialTheme.typography.labelLarge,

View File

@ -29,6 +29,7 @@ import androidx.compose.ui.geometry.Size
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.TransformOrigin import androidx.compose.ui.graphics.TransformOrigin
import androidx.compose.ui.graphics.graphicsLayer import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.unit.IntOffset
import androidx.core.view.WindowCompat import androidx.core.view.WindowCompat
import androidx.core.view.WindowInsetsControllerCompat import androidx.core.view.WindowInsetsControllerCompat
import androidx.lifecycle.Lifecycle import androidx.lifecycle.Lifecycle
@ -254,7 +255,7 @@ abstract class SharedLauncherActivity(
scaleY = 1f + s * (1 - p) scaleY = 1f + s * (1 - p)
}) { }) {
it.icon?.invoke( it.icon?.invoke(
Offset( IntOffset(
dX, dX,
dY dY
) )

View File

@ -53,12 +53,12 @@ import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.clip
import androidx.compose.ui.geometry.Rect
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.pluralStringResource import androidx.compose.ui.res.pluralStringResource
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.IntRect
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.lerp import androidx.compose.ui.unit.lerp
import androidx.compose.ui.unit.roundToIntRect import androidx.compose.ui.unit.roundToIntRect
@ -485,7 +485,7 @@ fun AppItemGridPopup(
app: Application, app: Application,
show: MutableTransitionState<Boolean>, show: MutableTransitionState<Boolean>,
animationProgress: Float, animationProgress: Float,
origin: Rect, origin: IntRect,
onDismiss: () -> Unit onDismiss: () -> Unit
) { ) {
AnimatedVisibility( AnimatedVisibility(
@ -493,11 +493,11 @@ fun AppItemGridPopup(
enter = expandIn( enter = expandIn(
animationSpec = tween(300), animationSpec = tween(300),
expandFrom = Alignment.TopEnd, expandFrom = Alignment.TopEnd,
) { origin.roundToIntRect().size }, ) { origin.size },
exit = shrinkOut( exit = shrinkOut(
animationSpec = tween(300), animationSpec = tween(300),
shrinkTowards = Alignment.TopEnd, shrinkTowards = Alignment.TopEnd,
) { origin.roundToIntRect().size }, ) { origin.size },
) { ) {
AppItem( AppItem(
modifier = Modifier modifier = Modifier

View File

@ -39,13 +39,13 @@ import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Rect
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.toArgb import androidx.compose.ui.graphics.toArgb
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextDecoration import androidx.compose.ui.text.style.TextDecoration
import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.IntRect
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.roundToIntRect import androidx.compose.ui.unit.roundToIntRect
import de.mm20.launcher2.search.CalendarEvent import de.mm20.launcher2.search.CalendarEvent
@ -340,7 +340,7 @@ fun CalendarItemGridPopup(
calendar: CalendarEvent, calendar: CalendarEvent,
show: MutableTransitionState<Boolean>, show: MutableTransitionState<Boolean>,
animationProgress: Float, animationProgress: Float,
origin: Rect, origin: IntRect,
onDismiss: () -> Unit onDismiss: () -> Unit
) { ) {
AnimatedVisibility( AnimatedVisibility(
@ -348,11 +348,11 @@ fun CalendarItemGridPopup(
enter = expandIn( enter = expandIn(
animationSpec = tween(300), animationSpec = tween(300),
expandFrom = Alignment.Center, expandFrom = Alignment.Center,
) { origin.roundToIntRect().size }, ) { origin.size },
exit = shrinkOut( exit = shrinkOut(
animationSpec = tween(300), animationSpec = tween(300),
shrinkTowards = Alignment.Center, shrinkTowards = Alignment.Center,
) { origin.roundToIntRect().size }, ) { origin.size },
) { ) {
CalendarItem( CalendarItem(
modifier = Modifier modifier = Modifier

View File

@ -4,7 +4,7 @@ import android.content.Context
import android.util.Log import android.util.Log
import android.widget.Toast import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.compose.ui.geometry.Rect import androidx.compose.ui.unit.IntRect
import androidx.core.app.ActivityOptionsCompat import androidx.core.app.ActivityOptionsCompat
import de.mm20.launcher2.applications.AppRepository import de.mm20.launcher2.applications.AppRepository
import de.mm20.launcher2.appshortcuts.AppShortcutRepository import de.mm20.launcher2.appshortcuts.AppShortcutRepository
@ -33,7 +33,6 @@ import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.emptyFlow import kotlinx.coroutines.flow.emptyFlow
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.map
@ -96,7 +95,7 @@ class SearchableItemVM : ListItemViewModel(), KoinComponent {
} }
val children = searchable.flatMapLatest { val children = searchable.flatMapLatest {
when(it) { when (it) {
is Application -> appShortcutRepository is Application -> appShortcutRepository
.findMany( .findMany(
componentName = it.componentName, componentName = it.componentName,
@ -104,6 +103,7 @@ class SearchableItemVM : ListItemViewModel(), KoinComponent {
manifest = true, manifest = true,
dynamic = true, dynamic = true,
) )
is AppShortcut -> { is AppShortcut -> {
val packageName = it.componentName?.packageName ?: return@flatMapLatest flowOf( val packageName = it.componentName?.packageName ?: return@flatMapLatest flowOf(
emptyList() emptyList()
@ -115,22 +115,23 @@ class SearchableItemVM : ListItemViewModel(), KoinComponent {
) )
.map { listOfNotNull(it) } .map { listOfNotNull(it) }
} }
else -> flowOf( else -> flowOf(
emptyList() emptyList()
) )
} }
} }
fun launch(context: Context, bounds: Rect? = null): Boolean { fun launch(context: Context, bounds: IntRect? = null): Boolean {
val searchable = searchable.value ?: return false val searchable = searchable.value ?: return false
val view = (context as? AppCompatActivity)?.window?.decorView val view = (context as? AppCompatActivity)?.window?.decorView
val options = if (bounds != null && view != null) { val options = if (bounds != null && view != null) {
ActivityOptionsCompat.makeScaleUpAnimation( ActivityOptionsCompat.makeScaleUpAnimation(
view, view,
bounds.left.toInt(), bounds.left,
bounds.top.toInt(), bounds.top,
bounds.width.toInt(), bounds.width,
bounds.height.toInt() bounds.height,
) )
} else { } else {
ActivityOptionsCompat.makeBasic() ActivityOptionsCompat.makeBasic()
@ -166,7 +167,7 @@ class SearchableItemVM : ListItemViewModel(), KoinComponent {
} }
fun launchChild(context: Context, child: SavableSearchable) { fun launchChild(context: Context, child: SavableSearchable) {
if(child.launch(context, null)) { if (child.launch(context, null)) {
favoritesService.reportLaunch(child) favoritesService.reportLaunch(child)
} }
} }

View File

@ -1,5 +1,6 @@
package de.mm20.launcher2.ui.launcher.search.common.grid package de.mm20.launcher2.ui.launcher.search.common.grid
import android.util.Log
import androidx.activity.compose.BackHandler import androidx.activity.compose.BackHandler
import androidx.compose.animation.core.Animatable import androidx.compose.animation.core.Animatable
import androidx.compose.animation.core.MutableTransitionState import androidx.compose.animation.core.MutableTransitionState
@ -32,7 +33,6 @@ import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Rect
import androidx.compose.ui.hapticfeedback.HapticFeedbackType import androidx.compose.ui.hapticfeedback.HapticFeedbackType
import androidx.compose.ui.input.pointer.pointerInput import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.layout.boundsInWindow import androidx.compose.ui.layout.boundsInWindow
@ -45,7 +45,9 @@ import androidx.compose.ui.semantics.contentDescription
import androidx.compose.ui.semantics.semantics import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.IntRect
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.roundToIntRect
import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.compose.collectAsStateWithLifecycle
import de.mm20.launcher2.search.AppShortcut import de.mm20.launcher2.search.AppShortcut
import de.mm20.launcher2.search.Application import de.mm20.launcher2.search.Application
@ -97,7 +99,7 @@ fun GridItem(
val context = LocalContext.current val context = LocalContext.current
var showPopup by remember(item.key) { mutableStateOf(false) } var showPopup by remember(item.key) { mutableStateOf(false) }
var bounds by remember { mutableStateOf(Rect.Zero) } var bounds by remember { mutableStateOf(IntRect.Zero) }
val launchOnPress = !item.preferDetailsOverLaunch val launchOnPress = !item.preferDetailsOverLaunch
val hapticFeedback = LocalHapticFeedback.current val hapticFeedback = LocalHapticFeedback.current
@ -168,7 +170,7 @@ fun GridItem(
modifier = Modifier modifier = Modifier
.padding(4.dp) .padding(4.dp)
.onGloballyPositioned { .onGloballyPositioned {
bounds = it.boundsInWindow() bounds = it.boundsInWindow().roundToIntRect()
} then } then
if (highlight) Modifier.background( if (highlight) Modifier.background(
MaterialTheme.colorScheme.surface, MaterialTheme.colorScheme.surface,
@ -201,7 +203,7 @@ fun GridItem(
} }
@Composable @Composable
fun ItemPopup(origin: Rect, searchable: Searchable, onDismissRequest: () -> Unit) { fun ItemPopup(origin: IntRect, searchable: Searchable, onDismissRequest: () -> Unit) {
val show = remember { val show = remember {
MutableTransitionState(false).apply { MutableTransitionState(false).apply {
targetState = true targetState = true
@ -265,9 +267,9 @@ fun ItemPopup(origin: Rect, searchable: Searchable, onDismissRequest: () -> Unit
modifier = Modifier modifier = Modifier
.placeOverlay( .placeOverlay(
origin.translate( origin.translate(
-8.dp.toPixels(), -8.dp.toPixels().toInt(),
-WindowInsets.systemBars.union(WindowInsets.ime) -WindowInsets.systemBars.union(WindowInsets.ime)
.getTop(LocalDensity.current).toFloat() .getTop(LocalDensity.current)
), ),
animationProgress.value animationProgress.value
) )
@ -376,7 +378,7 @@ fun ItemPopup(origin: Rect, searchable: Searchable, onDismissRequest: () -> Unit
} }
private fun Modifier.placeOverlay( private fun Modifier.placeOverlay(
origin: Rect, origin: IntRect,
animationProgress: Float, animationProgress: Float,
): Modifier { ): Modifier {
return layout { measurable, constraints -> return layout { measurable, constraints ->
@ -386,16 +388,16 @@ private fun Modifier.placeOverlay(
( (
lerp( lerp(
origin.center.x, origin.center.x,
constraints.maxWidth / 2f, constraints.maxWidth / 2,
((placeable.width.toFloat() - origin.width) / (constraints.maxWidth.toFloat() - origin.width)) ((placeable.width.toFloat() - origin.width) / (constraints.maxWidth.toFloat() - origin.width))
) - placeable.width / 2f).toInt(), ) - placeable.width / 2),
lerp( lerp(
origin.top, origin.top,
(origin.center.y - placeable.height / 2f).coerceIn( (origin.center.y - placeable.height / 2).coerceIn(
0f, 0,
constraints.maxHeight.toFloat() - placeable.height.toFloat(), constraints.maxHeight - placeable.height,
), ),
animationProgress.pow(2f) animationProgress.pow(2)
).toInt() ).toInt()
) )
} }

View File

@ -5,7 +5,6 @@ import androidx.compose.foundation.background
import androidx.compose.foundation.combinedClickable import androidx.compose.foundation.combinedClickable
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.LocalContentColor import androidx.compose.material3.LocalContentColor
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
@ -16,11 +15,12 @@ import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Rect
import androidx.compose.ui.layout.boundsInWindow import androidx.compose.ui.layout.boundsInWindow
import androidx.compose.ui.layout.onGloballyPositioned import androidx.compose.ui.layout.onGloballyPositioned
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.unit.IntRect
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.roundToIntRect
import de.mm20.launcher2.search.AppShortcut import de.mm20.launcher2.search.AppShortcut
import de.mm20.launcher2.search.Article import de.mm20.launcher2.search.Article
import de.mm20.launcher2.search.CalendarEvent import de.mm20.launcher2.search.CalendarEvent
@ -68,12 +68,12 @@ fun ListItem(
) )
) )
var bounds by remember { mutableStateOf(Rect.Zero) } var bounds by remember { mutableStateOf(IntRect.Zero) }
Box( Box(
modifier = modifier modifier = modifier
.background(background) .background(background)
.onGloballyPositioned { .onGloballyPositioned {
bounds = it.boundsInWindow() bounds = it.boundsInWindow().roundToIntRect()
}, },
) { ) {
CompositionLocalProvider( CompositionLocalProvider(

View File

@ -28,7 +28,6 @@ import androidx.compose.material.icons.automirrored.rounded.Message
import androidx.compose.material.icons.automirrored.rounded.NavigateNext import androidx.compose.material.icons.automirrored.rounded.NavigateNext
import androidx.compose.material.icons.automirrored.rounded.OpenInNew import androidx.compose.material.icons.automirrored.rounded.OpenInNew
import androidx.compose.material.icons.rounded.Directions import androidx.compose.material.icons.rounded.Directions
import androidx.compose.material.icons.rounded.Edit
import androidx.compose.material.icons.rounded.Email import androidx.compose.material.icons.rounded.Email
import androidx.compose.material.icons.rounded.OpenInNew import androidx.compose.material.icons.rounded.OpenInNew
import androidx.compose.material.icons.rounded.Phone import androidx.compose.material.icons.rounded.Phone
@ -51,7 +50,6 @@ import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.clip
import androidx.compose.ui.geometry.Rect
import androidx.compose.ui.graphics.TransformOrigin import androidx.compose.ui.graphics.TransformOrigin
import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.hapticfeedback.HapticFeedbackType import androidx.compose.ui.hapticfeedback.HapticFeedbackType
@ -62,6 +60,7 @@ import androidx.compose.ui.res.pluralStringResource
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.AnnotatedString import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.IntRect
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.roundToIntRect import androidx.compose.ui.unit.roundToIntRect
import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.compose.collectAsStateWithLifecycle
@ -605,7 +604,7 @@ fun ContactItemGridPopup(
contact: Contact, contact: Contact,
show: MutableTransitionState<Boolean>, show: MutableTransitionState<Boolean>,
animationProgress: Float, animationProgress: Float,
origin: Rect, origin: IntRect,
onDismiss: () -> Unit onDismiss: () -> Unit
) { ) {
AnimatedVisibility( AnimatedVisibility(
@ -613,11 +612,11 @@ fun ContactItemGridPopup(
enter = expandIn( enter = expandIn(
animationSpec = tween(300), animationSpec = tween(300),
expandFrom = Alignment.TopStart, expandFrom = Alignment.TopStart,
) { origin.roundToIntRect().size }, ) { origin.size },
exit = shrinkOut( exit = shrinkOut(
animationSpec = tween(300), animationSpec = tween(300),
shrinkTowards = Alignment.TopStart, shrinkTowards = Alignment.TopStart,
) { origin.roundToIntRect().size }, ) { origin.size },
) { ) {
ContactItem( ContactItem(
modifier = Modifier modifier = Modifier

View File

@ -43,6 +43,7 @@ import androidx.compose.ui.graphics.TransformOrigin
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.IntRect
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.roundToIntRect import androidx.compose.ui.unit.roundToIntRect
import androidx.lifecycle.compose.LocalLifecycleOwner import androidx.lifecycle.compose.LocalLifecycleOwner
@ -324,7 +325,7 @@ fun FileItemGridPopup(
file: File, file: File,
show: MutableTransitionState<Boolean>, show: MutableTransitionState<Boolean>,
animationProgress: Float, animationProgress: Float,
origin: Rect, origin: IntRect,
onDismiss: () -> Unit onDismiss: () -> Unit
) { ) {
AnimatedVisibility( AnimatedVisibility(
@ -332,11 +333,11 @@ fun FileItemGridPopup(
enter = expandIn( enter = expandIn(
animationSpec = tween(300), animationSpec = tween(300),
expandFrom = Alignment.TopEnd, expandFrom = Alignment.TopEnd,
) { origin.roundToIntRect().size }, ) { origin.size },
exit = shrinkOut( exit = shrinkOut(
animationSpec = tween(300), animationSpec = tween(300),
shrinkTowards = Alignment.TopEnd, shrinkTowards = Alignment.TopEnd,
) { origin.roundToIntRect().size }, ) { origin.size },
) { ) {
FileItem( FileItem(
modifier = Modifier modifier = Modifier

View File

@ -49,7 +49,6 @@ import androidx.compose.material.icons.rounded.DirectionsBoat
import androidx.compose.material.icons.rounded.DirectionsBus import androidx.compose.material.icons.rounded.DirectionsBus
import androidx.compose.material.icons.rounded.DirectionsRailway import androidx.compose.material.icons.rounded.DirectionsRailway
import androidx.compose.material.icons.rounded.DirectionsTransit import androidx.compose.material.icons.rounded.DirectionsTransit
import androidx.compose.material.icons.rounded.Edit
import androidx.compose.material.icons.rounded.Language import androidx.compose.material.icons.rounded.Language
import androidx.compose.material.icons.rounded.Navigation import androidx.compose.material.icons.rounded.Navigation
import androidx.compose.material.icons.rounded.Phone import androidx.compose.material.icons.rounded.Phone
@ -59,15 +58,11 @@ import androidx.compose.material.icons.rounded.Subway
import androidx.compose.material.icons.rounded.Train import androidx.compose.material.icons.rounded.Train
import androidx.compose.material.icons.rounded.Tram import androidx.compose.material.icons.rounded.Tram
import androidx.compose.material.icons.rounded.Tune import androidx.compose.material.icons.rounded.Tune
import androidx.compose.material.icons.rounded.Visibility
import androidx.compose.material.icons.rounded.VisibilityOff
import androidx.compose.material3.AssistChip import androidx.compose.material3.AssistChip
import androidx.compose.material3.AssistChipDefaults import androidx.compose.material3.AssistChipDefaults
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedCard import androidx.compose.material3.OutlinedCard
import androidx.compose.material3.SnackbarDuration
import androidx.compose.material3.SnackbarResult
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState import androidx.compose.runtime.collectAsState
@ -79,7 +74,6 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.clip
import androidx.compose.ui.draw.rotate import androidx.compose.ui.draw.rotate
import androidx.compose.ui.geometry.Rect
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.TransformOrigin import androidx.compose.ui.graphics.TransformOrigin
import androidx.compose.ui.graphics.graphicsLayer import androidx.compose.ui.graphics.graphicsLayer
@ -91,16 +85,15 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.IntOffset import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.IntRect
import androidx.compose.ui.unit.IntSize import androidx.compose.ui.unit.IntSize
import androidx.compose.ui.unit.TextUnit import androidx.compose.ui.unit.TextUnit
import androidx.compose.ui.unit.TextUnitType import androidx.compose.ui.unit.TextUnitType
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.max import androidx.compose.ui.unit.max
import androidx.compose.ui.unit.roundToIntRect
import androidx.compose.ui.unit.times import androidx.compose.ui.unit.times
import androidx.lifecycle.compose.LocalLifecycleOwner import androidx.lifecycle.compose.LocalLifecycleOwner
import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.lifecycleScope
import blend.Blend.harmonize import blend.Blend.harmonize
import coil.compose.AsyncImage import coil.compose.AsyncImage
import de.mm20.launcher2.i18n.R import de.mm20.launcher2.i18n.R
@ -130,7 +123,6 @@ import de.mm20.launcher2.ui.locals.LocalGridSettings
import de.mm20.launcher2.ui.locals.LocalSnackbarHostState import de.mm20.launcher2.ui.locals.LocalSnackbarHostState
import de.mm20.launcher2.ui.modifier.scale import de.mm20.launcher2.ui.modifier.scale
import kotlinx.coroutines.flow.emptyFlow import kotlinx.coroutines.flow.emptyFlow
import kotlinx.coroutines.launch
import java.time.Duration import java.time.Duration
import java.time.LocalDateTime import java.time.LocalDateTime
import java.time.ZonedDateTime import java.time.ZonedDateTime
@ -390,7 +382,8 @@ fun LocationItem(
.padding( .padding(
top = 4.dp, top = 4.dp,
bottom = 4.dp, bottom = 4.dp,
start = 12.dp) start = 12.dp
)
.clickable( .clickable(
enabled = attribution.url != null enabled = attribution.url != null
) { ) {
@ -827,7 +820,7 @@ fun LocationItemGridPopup(
location: Location, location: Location,
show: MutableTransitionState<Boolean>, show: MutableTransitionState<Boolean>,
animationProgress: Float, animationProgress: Float,
origin: Rect, origin: IntRect,
onDismiss: () -> Unit onDismiss: () -> Unit
) { ) {
AnimatedVisibility( AnimatedVisibility(
@ -835,11 +828,11 @@ fun LocationItemGridPopup(
enter = expandIn( enter = expandIn(
animationSpec = tween(300), animationSpec = tween(300),
expandFrom = Alignment.TopEnd, expandFrom = Alignment.TopEnd,
) { origin.roundToIntRect().size }, ) { origin.size },
exit = shrinkOut( exit = shrinkOut(
animationSpec = tween(300), animationSpec = tween(300),
shrinkTowards = Alignment.TopEnd, shrinkTowards = Alignment.TopEnd,
) { origin.roundToIntRect().size }, ) { origin.size },
) { ) {
LocationItem( LocationItem(
modifier = Modifier modifier = Modifier

View File

@ -46,14 +46,13 @@ import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.clip
import androidx.compose.ui.geometry.Rect
import androidx.compose.ui.graphics.TransformOrigin
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.semantics.Role import androidx.compose.ui.semantics.Role
import androidx.compose.ui.semantics.role import androidx.compose.ui.semantics.role
import androidx.compose.ui.semantics.semantics import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.IntRect
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.roundToIntRect import androidx.compose.ui.unit.roundToIntRect
import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.compose.collectAsStateWithLifecycle
@ -71,7 +70,6 @@ import de.mm20.launcher2.ui.launcher.search.listItemViewModel
import de.mm20.launcher2.ui.launcher.sheets.LocalBottomSheetManager import de.mm20.launcher2.ui.launcher.sheets.LocalBottomSheetManager
import de.mm20.launcher2.ui.locals.LocalFavoritesEnabled import de.mm20.launcher2.ui.locals.LocalFavoritesEnabled
import de.mm20.launcher2.ui.locals.LocalGridSettings import de.mm20.launcher2.ui.locals.LocalGridSettings
import de.mm20.launcher2.ui.modifier.scale
import kotlin.math.pow import kotlin.math.pow
@Composable @Composable
@ -201,10 +199,13 @@ fun AppShortcutItem(
) )
} }
if(shortcut.isUnavailable) { if (shortcut.isUnavailable) {
MissingPermissionBanner( MissingPermissionBanner(
modifier = Modifier.padding(start = 16.dp, end = 16.dp, top = 16.dp), modifier = Modifier.padding(start = 16.dp, end = 16.dp, top = 16.dp),
text = stringResource(R.string.shortcut_unavailable_description, stringResource(R.string.app_name)), text = stringResource(
R.string.shortcut_unavailable_description,
stringResource(R.string.app_name)
),
onClick = { onClick = {
viewModel.requestShortcutPermission(context as AppCompatActivity) viewModel.requestShortcutPermission(context as AppCompatActivity)
} }
@ -491,7 +492,7 @@ fun ShortcutItemGridPopup(
shortcut: AppShortcut, shortcut: AppShortcut,
show: MutableTransitionState<Boolean>, show: MutableTransitionState<Boolean>,
animationProgress: Float, animationProgress: Float,
origin: Rect, origin: IntRect,
onDismiss: () -> Unit onDismiss: () -> Unit
) { ) {
AnimatedVisibility( AnimatedVisibility(
@ -499,11 +500,11 @@ fun ShortcutItemGridPopup(
enter = expandIn( enter = expandIn(
animationSpec = tween(300), animationSpec = tween(300),
expandFrom = Alignment.TopEnd, expandFrom = Alignment.TopEnd,
) { origin.roundToIntRect().size }, ) { origin.size },
exit = shrinkOut( exit = shrinkOut(
animationSpec = tween(300), animationSpec = tween(300),
shrinkTowards = Alignment.TopEnd, shrinkTowards = Alignment.TopEnd,
) { origin.roundToIntRect().size }, ) { origin.size },
) { ) {
AppShortcutItem( AppShortcutItem(
modifier = Modifier modifier = Modifier

View File

@ -29,11 +29,11 @@ import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.clip
import androidx.compose.ui.geometry.Rect
import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.IntRect
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.roundToIntRect import androidx.compose.ui.unit.roundToIntRect
import coil.compose.AsyncImage import coil.compose.AsyncImage
@ -169,11 +169,13 @@ fun WebsiteItem(
modifier = Modifier.fillMaxWidth() modifier = Modifier.fillMaxWidth()
) { ) {
Column( Column(
modifier = Modifier.weight(1f).padding( modifier = Modifier
start = 16.dp, .weight(1f)
end = 16.dp, .padding(
top = 16.dp, start = 16.dp,
) end = 16.dp,
top = 16.dp,
)
) { ) {
Text( Text(
text = website.labelOverride ?: website.label, text = website.labelOverride ?: website.label,
@ -280,7 +282,7 @@ fun WebsiteItemGridPopup(
website: Website, website: Website,
show: MutableTransitionState<Boolean>, show: MutableTransitionState<Boolean>,
animationProgress: Float, animationProgress: Float,
origin: Rect, origin: IntRect,
onDismiss: () -> Unit onDismiss: () -> Unit
) { ) {
AnimatedVisibility( AnimatedVisibility(
@ -288,11 +290,11 @@ fun WebsiteItemGridPopup(
enter = expandIn( enter = expandIn(
animationSpec = tween(300), animationSpec = tween(300),
expandFrom = Alignment.Center, expandFrom = Alignment.Center,
) { origin.roundToIntRect().size }, ) { origin.size },
exit = shrinkOut( exit = shrinkOut(
animationSpec = tween(300), animationSpec = tween(300),
shrinkTowards = Alignment.Center, shrinkTowards = Alignment.Center,
) { origin.roundToIntRect().size }, ) { origin.size },
) { ) {
WebsiteItem( WebsiteItem(
modifier = Modifier modifier = Modifier

View File

@ -36,6 +36,7 @@ import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.AnnotatedString import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.fromHtml import androidx.compose.ui.text.fromHtml
import androidx.compose.ui.unit.IntRect
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.roundToIntRect import androidx.compose.ui.unit.roundToIntRect
import coil.compose.AsyncImage import coil.compose.AsyncImage
@ -268,7 +269,7 @@ fun ArticleItemGridPopup(
article: Article, article: Article,
show: MutableTransitionState<Boolean>, show: MutableTransitionState<Boolean>,
animationProgress: Float, animationProgress: Float,
origin: Rect, origin: IntRect,
onDismiss: () -> Unit onDismiss: () -> Unit
) { ) {
AnimatedVisibility( AnimatedVisibility(
@ -276,11 +277,11 @@ fun ArticleItemGridPopup(
enter = expandIn( enter = expandIn(
animationSpec = tween(300), animationSpec = tween(300),
expandFrom = Alignment.Center, expandFrom = Alignment.Center,
) { origin.roundToIntRect().size }, ) { origin.size },
exit = shrinkOut( exit = shrinkOut(
animationSpec = tween(300), animationSpec = tween(300),
shrinkTowards = Alignment.Center, shrinkTowards = Alignment.Center,
) { origin.roundToIntRect().size }, ) { origin.size },
) { ) {
ArticleItem( ArticleItem(
modifier = Modifier modifier = Modifier

View File

@ -3,9 +3,11 @@ package de.mm20.launcher2.ui.launcher.transitions
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.geometry.Offset import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.geometry.Rect import androidx.compose.ui.geometry.Rect
import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.IntRect
data class EnterHomeTransition( data class EnterHomeTransition(
val startBounds: Rect? = null, val startBounds: IntRect? = null,
val targetBounds: Rect? = null, val targetBounds: IntRect? = null,
val icon: (@Composable (animVector: Offset, progress: () -> Float) -> Unit)? = null val icon: (@Composable (animVector: IntOffset, progress: () -> Float) -> Unit)? = null
) )

View File

@ -2,10 +2,12 @@ package de.mm20.launcher2.ui.launcher.transitions
import android.view.Window import android.view.Window
import androidx.compose.runtime.compositionLocalOf import androidx.compose.runtime.compositionLocalOf
import androidx.compose.ui.geometry.Offset import androidx.compose.ui.graphics.toAndroidRect
import androidx.compose.ui.geometry.Rect
import androidx.compose.ui.geometry.Size
import androidx.compose.ui.graphics.toAndroidRectF import androidx.compose.ui.graphics.toAndroidRectF
import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.IntRect
import androidx.compose.ui.unit.IntSize
import androidx.core.graphics.toRectF
import com.android.launcher3.GestureNavContract import com.android.launcher3.GestureNavContract
import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableSharedFlow
@ -19,14 +21,19 @@ class EnterHomeTransitionManager {
for (handler in handlers) { for (handler in handlers) {
val result = handler.handle(gestureNavContract) val result = handler.handle(gestureNavContract)
if (result != null) { if (result != null) {
val startRect = Rect(Offset(0f, 0f), Size(window.decorView.width.toFloat(), window.decorView.height.toFloat())) val startRect = IntRect(
IntOffset.Zero,
IntSize(window.decorView.width, window.decorView.height)
)
val targetBounds = result.targetBounds val targetBounds = result.targetBounds
gestureNavContract.sendEndPosition(targetBounds.toAndroidRectF()) gestureNavContract.sendEndPosition(targetBounds.toAndroidRect().toRectF())
currentTransition.tryEmit(EnterHomeTransition( currentTransition.tryEmit(
startBounds = startRect, EnterHomeTransition(
icon = result.icon, startBounds = startRect,
targetBounds = targetBounds, icon = result.icon,
)) targetBounds = targetBounds,
)
)
return return
} }
} }

View File

@ -3,10 +3,11 @@ package de.mm20.launcher2.ui.launcher.transitions
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.Stable import androidx.compose.runtime.Stable
import androidx.compose.ui.geometry.Offset import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.geometry.Rect import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.IntRect
@Stable @Stable
data class EnterHomeTransitionParams( data class EnterHomeTransitionParams(
val targetBounds: Rect, val targetBounds: IntRect,
val icon: (@Composable (animVector: Offset, progress: () -> Float) -> Unit)? = null val icon: (@Composable (animVector: IntOffset, progress: () -> Float) -> Unit)? = null
) )

View File

@ -76,7 +76,9 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.semantics.contentDescription import androidx.compose.ui.semantics.contentDescription
import androidx.compose.ui.semantics.semantics import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.IntRect
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.roundToIntRect
import androidx.core.content.res.ResourcesCompat import androidx.core.content.res.ResourcesCompat
import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.viewmodel.compose.viewModel import androidx.lifecycle.viewmodel.compose.viewModel
@ -278,13 +280,13 @@ fun MusicWidget(widget: MusicWidget) {
) { ) {
if (art != null) { if (art != null) {
val windowSize = LocalWindowSize.current val windowSize = LocalWindowSize.current
var bounds by remember { mutableStateOf(Rect.Zero) } var bounds by remember { mutableStateOf(IntRect.Zero) }
Image( Image(
bitmap = art.asImageBitmap(), bitmap = art.asImageBitmap(),
modifier = Modifier modifier = Modifier
.fillMaxSize() .fillMaxSize()
.onGloballyPositioned { .onGloballyPositioned {
bounds = it.boundsInWindow() bounds = it.boundsInWindow().roundToIntRect()
}, },
contentDescription = null, contentDescription = null,
contentScale = ContentScale.Crop contentScale = ContentScale.Crop