diff --git a/base/src/main/java/com/android/launcher3/GestureNavContract.kt b/base/src/main/java/com/android/launcher3/GestureNavContract.kt index 5a0317fb..7a4f48a8 100644 --- a/base/src/main/java/com/android/launcher3/GestureNavContract.kt +++ b/base/src/main/java/com/android/launcher3/GestureNavContract.kt @@ -36,7 +36,7 @@ class GestureNavContract( * Sends the position information to the receiver */ @TargetApi(Build.VERSION_CODES.R) - fun sendEndPosition(position: RectF?, surfaceControl: SurfaceControl?) { + fun sendEndPosition(position: RectF? = null, surfaceControl: SurfaceControl? = null) { val result = Bundle() result.putParcelable(EXTRA_ICON_POSITION, position) result.putParcelable(EXTRA_ICON_SURFACE, surfaceControl) diff --git a/ui/src/main/java/de/mm20/launcher2/ui/launcher/LauncherActivity.kt b/ui/src/main/java/de/mm20/launcher2/ui/launcher/LauncherActivity.kt index 74190e35..8b4a0f61 100644 --- a/ui/src/main/java/de/mm20/launcher2/ui/launcher/LauncherActivity.kt +++ b/ui/src/main/java/de/mm20/launcher2/ui/launcher/LauncherActivity.kt @@ -2,6 +2,7 @@ package de.mm20.launcher2.ui.launcher import android.content.Intent import android.content.res.Configuration +import android.content.res.Resources import android.os.Bundle import androidx.activity.compose.setContent import androidx.activity.viewModels @@ -16,6 +17,7 @@ import androidx.compose.runtime.getValue import androidx.compose.runtime.livedata.observeAsState import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.geometry.Size import androidx.compose.ui.graphics.Color import androidx.core.view.WindowCompat import androidx.core.view.WindowInsetsControllerCompat @@ -35,6 +37,7 @@ import de.mm20.launcher2.ui.launcher.modals.EditFavoritesView import de.mm20.launcher2.ui.launcher.modals.HiddenItemsSheet import de.mm20.launcher2.ui.launcher.transitions.HomeTransitionManager import de.mm20.launcher2.ui.launcher.transitions.LocalHomeTransitionManager +import de.mm20.launcher2.ui.locals.LocalWindowSize import de.mm20.launcher2.ui.theme.LauncherTheme import org.koin.android.ext.android.inject @@ -48,13 +51,18 @@ class LauncherActivity : BaseActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) + val windowSize = Resources.getSystem().displayMetrics.let { + Size(it.widthPixels.toFloat(), it.heightPixels.toFloat()) + } + WindowCompat.setDecorFitsSystemWindows(window, false) viewModel.setDarkMode(resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK == Configuration.UI_MODE_NIGHT_YES) setContent { CompositionLocalProvider( - LocalHomeTransitionManager provides homeTransitionManager + LocalHomeTransitionManager provides homeTransitionManager, + LocalWindowSize provides windowSize ) { LauncherTheme { ProvideSettings { diff --git a/ui/src/main/java/de/mm20/launcher2/ui/launcher/search/common/grid/GridItem.kt b/ui/src/main/java/de/mm20/launcher2/ui/launcher/search/common/grid/GridItem.kt index 0581a383..c2dfd552 100644 --- a/ui/src/main/java/de/mm20/launcher2/ui/launcher/search/common/grid/GridItem.kt +++ b/ui/src/main/java/de/mm20/launcher2/ui/launcher/search/common/grid/GridItem.kt @@ -1,10 +1,10 @@ -package de.mm20.launcher2.ui.launcher.search.common +package de.mm20.launcher2.ui.launcher.search.common.grid +import android.content.ComponentName import androidx.activity.compose.BackHandler import androidx.compose.animation.ExperimentalAnimationApi import androidx.compose.animation.core.animateFloatAsState import androidx.compose.animation.core.tween -import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.layout.* import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text @@ -29,19 +29,19 @@ import de.mm20.launcher2.ui.ktx.toDp import de.mm20.launcher2.ui.ktx.toPixels import de.mm20.launcher2.ui.launcher.search.apps.AppItemGridPopup import de.mm20.launcher2.ui.launcher.search.calendar.CalendarItemGridPopup -import de.mm20.launcher2.ui.launcher.search.common.grid.GridItemVM import de.mm20.launcher2.ui.launcher.search.contacts.ContactItemGridPopup import de.mm20.launcher2.ui.launcher.search.files.FileItemGridPopup import de.mm20.launcher2.ui.launcher.search.shortcut.ShortcutItemGridPopup import de.mm20.launcher2.ui.launcher.search.website.WebsiteItemGridPopup import de.mm20.launcher2.ui.launcher.search.wikipedia.WikipediaItemGridPopup +import de.mm20.launcher2.ui.launcher.transitions.HandleHomeTransition +import de.mm20.launcher2.ui.launcher.transitions.HomeTransitionParams import de.mm20.launcher2.ui.locals.LocalGridIconSize import de.mm20.launcher2.ui.locals.LocalWindowPosition +import de.mm20.launcher2.ui.locals.LocalWindowSize import kotlinx.coroutines.delay -import kotlin.math.pow -@OptIn(ExperimentalFoundationApi::class) @Composable fun GridItem(modifier: Modifier = Modifier, item: Searchable, showLabels: Boolean = true) { val viewModel = remember(item.key) { GridItemVM(item) } @@ -58,6 +58,22 @@ fun GridItem(modifier: Modifier = Modifier, item: Searchable, showLabels: Boolea val launchOnPress = item is File || item is Application || item is AppShortcut || item is Website || item is Wikipedia + val windowSize = LocalWindowSize.current + + if (item is Application) { + HandleHomeTransition { + val cn = ComponentName(item.`package`, item.activity) + if ( + it.componentName == cn && + bounds.right > 0f && bounds.left < windowSize.width && + bounds.bottom > 0f && bounds.top < windowSize.height + ) { + return@HandleHomeTransition HomeTransitionParams(bounds) + } + return@HandleHomeTransition null + } + } + ShapedLauncherIcon( modifier = Modifier .onGloballyPositioned { diff --git a/ui/src/main/java/de/mm20/launcher2/ui/launcher/search/common/grid/SearchResultGrid.kt b/ui/src/main/java/de/mm20/launcher2/ui/launcher/search/common/grid/SearchResultGrid.kt index 258b410e..c81fb1f4 100644 --- a/ui/src/main/java/de/mm20/launcher2/ui/launcher/search/common/grid/SearchResultGrid.kt +++ b/ui/src/main/java/de/mm20/launcher2/ui/launcher/search/common/grid/SearchResultGrid.kt @@ -6,7 +6,6 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import de.mm20.launcher2.search.data.Searchable -import de.mm20.launcher2.ui.launcher.search.common.GridItem import de.mm20.launcher2.ui.layout.BottomReversed import de.mm20.launcher2.ui.locals.LocalGridColumns import kotlin.math.ceil diff --git a/ui/src/main/java/de/mm20/launcher2/ui/launcher/transitions/HomeTransitionHandler.kt b/ui/src/main/java/de/mm20/launcher2/ui/launcher/transitions/HomeTransitionHandler.kt new file mode 100644 index 00000000..881251ac --- /dev/null +++ b/ui/src/main/java/de/mm20/launcher2/ui/launcher/transitions/HomeTransitionHandler.kt @@ -0,0 +1,22 @@ +package de.mm20.launcher2.ui.launcher.transitions + +import android.content.ComponentName +import androidx.compose.runtime.Composable +import androidx.compose.runtime.DisposableEffect +import com.android.launcher3.GestureNavContract + +fun interface HomeTransitionHandler { + fun handle(gestureNavContract: GestureNavContract): HomeTransitionParams? +} + +@Composable +fun HandleHomeTransition(handler: HomeTransitionHandler) { + val transitionManager = LocalHomeTransitionManager.current + DisposableEffect(null) { + transitionManager?.registerHandler(handler) + + onDispose { + transitionManager?.unregisterHandler(handler) + } + } +} \ No newline at end of file diff --git a/ui/src/main/java/de/mm20/launcher2/ui/launcher/transitions/HomeTransitionManager.kt b/ui/src/main/java/de/mm20/launcher2/ui/launcher/transitions/HomeTransitionManager.kt new file mode 100644 index 00000000..f78488c2 --- /dev/null +++ b/ui/src/main/java/de/mm20/launcher2/ui/launcher/transitions/HomeTransitionManager.kt @@ -0,0 +1,36 @@ +package de.mm20.launcher2.ui.launcher.transitions + +import androidx.compose.runtime.Composable +import androidx.compose.runtime.compositionLocalOf +import androidx.compose.ui.geometry.Rect +import androidx.compose.ui.graphics.toAndroidRectF +import com.android.launcher3.GestureNavContract + +class HomeTransitionManager { + + private val handlers = mutableSetOf() + + fun resolve(gestureNavContract: GestureNavContract) { + for (handler in handlers) { + val result = handler.handle(gestureNavContract) + if (result != null) { + gestureNavContract.sendEndPosition(result.targetBounds.toAndroidRectF()) + break + } + } + } + + private fun dispatch(params: HomeTransitionParams) { + + } + + fun registerHandler(handler: HomeTransitionHandler) { + handlers.add(handler) + } + + fun unregisterHandler(handler: HomeTransitionHandler) { + handlers.remove(handler) + } +} + +val LocalHomeTransitionManager = compositionLocalOf { null } \ No newline at end of file diff --git a/ui/src/main/java/de/mm20/launcher2/ui/launcher/transitions/HomeTransitionOffer.kt b/ui/src/main/java/de/mm20/launcher2/ui/launcher/transitions/HomeTransitionOffer.kt new file mode 100644 index 00000000..d77bd948 --- /dev/null +++ b/ui/src/main/java/de/mm20/launcher2/ui/launcher/transitions/HomeTransitionOffer.kt @@ -0,0 +1,8 @@ +package de.mm20.launcher2.ui.launcher.transitions + +import androidx.compose.runtime.Composable +import androidx.compose.ui.geometry.Rect + +fun interface HomeTransitionOffer { + fun accept(targetBounds: Rect, icon: @Composable () -> Unit) +} \ No newline at end of file diff --git a/ui/src/main/java/de/mm20/launcher2/ui/launcher/transitions/HomeTransitionParams.kt b/ui/src/main/java/de/mm20/launcher2/ui/launcher/transitions/HomeTransitionParams.kt new file mode 100644 index 00000000..62b10b0b --- /dev/null +++ b/ui/src/main/java/de/mm20/launcher2/ui/launcher/transitions/HomeTransitionParams.kt @@ -0,0 +1,9 @@ +package de.mm20.launcher2.ui.launcher.transitions + +import androidx.compose.runtime.Composable +import androidx.compose.ui.geometry.Rect + +data class HomeTransitionParams( + val targetBounds: Rect, + val icon: (@Composable () -> Unit)? = null +) \ No newline at end of file