Add home button gesture trigger

This commit is contained in:
MM20 2023-06-23 18:12:05 +02:00
parent 918f340dd2
commit 62c1a4293f
No known key found for this signature in database
GPG Key ID: 0B61A8F2DEAFA389
12 changed files with 85 additions and 16 deletions

View File

@ -23,6 +23,7 @@ import de.mm20.launcher2.preferences.Settings
import de.mm20.launcher2.searchactions.actions.SearchAction
import de.mm20.launcher2.ui.component.SearchBarLevel
import de.mm20.launcher2.ui.launcher.LauncherScaffoldVM
import de.mm20.launcher2.ui.launcher.gestures.LauncherGestureHandler
import de.mm20.launcher2.ui.launcher.helper.WallpaperBlur
import de.mm20.launcher2.ui.launcher.search.SearchColumn
import de.mm20.launcher2.ui.launcher.search.SearchVM
@ -215,4 +216,5 @@ fun AssistantScaffold(
} else null
)
}
LauncherGestureHandler()
}

View File

@ -6,4 +6,5 @@ enum class Gesture {
SwipeDown,
SwipeLeft,
SwipeRight,
HomeButton,
}

View File

@ -41,6 +41,9 @@ class GestureDetector {
gestureListener?.onDragEnd()
}
fun dispatchHomeButtonPress() {
gestureListener?.onHomeButtonPress()
}
interface OnGestureListener {
fun onTap(position: Offset) {}
@ -54,6 +57,8 @@ class GestureDetector {
fun onDrag(offset: Offset): Boolean = false
fun onDragEnd() {}
fun onHomeButtonPress() {}
}
}

View File

@ -12,6 +12,7 @@ fun GestureHandler(
onDoubleTap: (Offset) -> Unit = {},
onDrag: (Offset) -> Boolean = { false },
onDragEnd: () -> Unit = {},
onHomeButtonPress: () -> Unit = {},
) {
DisposableEffect(detector) {
detector.gestureListener = object : GestureDetector.OnGestureListener {
@ -34,6 +35,10 @@ fun GestureHandler(
override fun onDragEnd() {
onDragEnd()
}
override fun onHomeButtonPress() {
onHomeButtonPress()
}
}
onDispose {
detector.gestureListener = null

View File

@ -1,6 +1,7 @@
package de.mm20.launcher2.ui.launcher
import android.content.Intent
import android.util.Log
import com.android.launcher3.GestureNavContract
@ -10,14 +11,20 @@ class LauncherActivity: SharedLauncherActivity(LauncherActivityMode.Launcher) {
val navContract = intent?.let { GestureNavContract.fromIntent(it) }
if (navContract != null) {
enterHomeTransitionManager.resolve(navContract, window)
} else {
onBackPressed()
} else if (System.currentTimeMillis() - pausedAt < 50) {
// If the onPause was called less than 50ms ago, we assume that the app was already
// in the foreground when the user pressed the home button. In this case, we dispatch
// the home button press event to the gesture detector.
gestureDetector.dispatchHomeButtonPress()
}
}
private var pausedAt: Long = 0
override fun onPause() {
super.onPause()
enterHomeTransitionManager.clear()
pausedAt = System.currentTimeMillis()
}
override fun onBackPressed() {

View File

@ -94,7 +94,7 @@ class LauncherScaffoldVM : ViewModel(), KoinComponent {
}
fun closeSearch() {
if (isSearchOpen.value == false) return
if (!isSearchOpen.value) return
isSearchOpen.value = false
setSearchbarFocus(false)
}
@ -130,6 +130,8 @@ class LauncherScaffoldVM : ViewModel(), KoinComponent {
settings?.swipeDown?.takeIf { layout != Layout.PullDown } ?: GestureAction.None
val longPressAction = settings?.longPress ?: GestureAction.None
val doubleTapAction = settings?.doubleTap ?: GestureAction.None
val homeButtonAction = settings?.homeButton ?: GestureAction.None
val swipeLeftAppKey =
if (swipeLeftAction == GestureAction.LaunchApp) settings.swipeLeftApp else null
val swipeRightAppKey =
@ -140,12 +142,15 @@ class LauncherScaffoldVM : ViewModel(), KoinComponent {
if (longPressAction == GestureAction.LaunchApp) settings.longPressApp else null
val doubleTapAppKey =
if (doubleTapAction == GestureAction.LaunchApp) settings.doubleTapApp else null
val homeButtonAppKey =
if (homeButtonAction == GestureAction.LaunchApp) settings.homeButtonApp else null
val apps = listOfNotNull(
swipeLeftAppKey,
swipeRightAppKey,
swipeDownAppKey,
longPressAppKey,
doubleTapAppKey
doubleTapAppKey,
homeButtonAppKey,
).let { searchableRepository.getByKeys(it) }
GestureState(
@ -154,11 +159,13 @@ class LauncherScaffoldVM : ViewModel(), KoinComponent {
swipeDownAction = swipeDownAction,
longPressAction = longPressAction,
doubleTapAction = doubleTapAction,
homeButtonAction = homeButtonAction,
swipeLeftApp = apps.firstOrNull { it.key == swipeLeftAppKey },
swipeRightApp = apps.firstOrNull { it.key == swipeRightAppKey },
swipeDownApp = apps.firstOrNull { it.key == swipeDownAppKey },
longPressApp = apps.firstOrNull { it.key == longPressAppKey },
doubleTapApp = apps.firstOrNull { it.key == doubleTapAppKey }
doubleTapApp = apps.firstOrNull { it.key == doubleTapAppKey },
homeButtonApp = apps.firstOrNull { it.key == homeButtonAppKey },
)
}.stateIn(viewModelScope, SharingStarted.Eagerly, GestureState())
@ -167,9 +174,10 @@ class LauncherScaffoldVM : ViewModel(), KoinComponent {
val action = when (gesture) {
Gesture.DoubleTap -> gestureState.value.doubleTapAction
Gesture.LongPress -> gestureState.value.longPressAction
Gesture.SwipeDown -> gestureState.value.swipeDownAction.takeIf { baseLayout.value != Settings.LayoutSettings.Layout.PullDown }
Gesture.SwipeLeft -> gestureState.value.swipeLeftAction.takeIf { baseLayout.value != Settings.LayoutSettings.Layout.Pager }
Gesture.SwipeRight -> gestureState.value.swipeRightAction.takeIf { baseLayout.value != Settings.LayoutSettings.Layout.PagerReversed }
Gesture.SwipeDown -> gestureState.value.swipeDownAction.takeIf { baseLayout.value != Layout.PullDown }
Gesture.SwipeLeft -> gestureState.value.swipeLeftAction.takeIf { baseLayout.value != Layout.Pager }
Gesture.SwipeRight -> gestureState.value.swipeRightAction.takeIf { baseLayout.value != Layout.PagerReversed }
Gesture.HomeButton -> gestureState.value.homeButtonAction
}
val requiresAccessibilityService =
action == GestureAction.OpenRecents
@ -233,6 +241,7 @@ class LauncherScaffoldVM : ViewModel(), KoinComponent {
Gesture.SwipeDown -> gestureState.value.swipeDownApp
Gesture.LongPress -> gestureState.value.longPressApp
Gesture.DoubleTap -> gestureState.value.doubleTapApp
Gesture.HomeButton -> gestureState.value.homeButtonApp
}?.launch(context, options.toBundle())
true
}
@ -252,11 +261,13 @@ data class GestureState(
val swipeDownAction: GestureAction = GestureAction.None,
val longPressAction: GestureAction = GestureAction.None,
val doubleTapAction: GestureAction = GestureAction.None,
val homeButtonAction: GestureAction = GestureAction.None,
val swipeLeftApp: SavableSearchable? = null,
val swipeRightApp: SavableSearchable? = null,
val swipeDownApp: SavableSearchable? = null,
val longPressApp: SavableSearchable? = null,
val doubleTapApp: SavableSearchable? = null,
val homeButtonApp: SavableSearchable? = null,
)
data class FailedGesture(val gesture: Gesture, val action: GestureAction)

View File

@ -69,12 +69,12 @@ import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import com.google.accompanist.systemuicontroller.rememberSystemUiController
import de.mm20.launcher2.preferences.Settings.SearchBarSettings.SearchBarColors
import de.mm20.launcher2.preferences.Settings.SearchBarSettings.SearchBarStyle
import de.mm20.launcher2.searchactions.actions.SearchAction
import de.mm20.launcher2.ui.R
import de.mm20.launcher2.ui.component.SearchBarLevel
import de.mm20.launcher2.ui.gestures.LocalGestureDetector
import de.mm20.launcher2.ui.ktx.animateTo
import de.mm20.launcher2.ui.launcher.gestures.LauncherGestureHandler
import de.mm20.launcher2.ui.launcher.helper.WallpaperBlur
import de.mm20.launcher2.ui.launcher.search.SearchColumn
import de.mm20.launcher2.ui.launcher.search.SearchVM
@ -227,15 +227,18 @@ fun PagerScaffold(
val searchBarOffset = remember { mutableStateOf(0f) }
val scope = rememberCoroutineScope()
BackHandler {
val `handleBackOrHomeEvent` = {
when {
isSearchOpen -> {
viewModel.closeSearch()
searchVM.search("")
true
}
isWidgetEditMode -> {
viewModel.setWidgetEditMode(false)
true
}
widgetsScrollState.value != 0 -> {
@ -245,10 +248,16 @@ fun PagerScaffold(
scope.launch {
searchBarOffset.animateTo(0f)
}
true
}
else -> false
}
}
BackHandler {
`handleBackOrHomeEvent`()
}
val keyboardController = LocalSoftwareKeyboardController.current
val gestureManager = LocalGestureDetector.current
@ -542,6 +551,9 @@ fun PagerScaffold(
} else null
)
}
LauncherGestureHandler(
onHomeButtonPress = handleBackOrHomeEvent,
)
}
private enum class Page {

View File

@ -72,6 +72,7 @@ import de.mm20.launcher2.ui.R
import de.mm20.launcher2.ui.component.SearchBarLevel
import de.mm20.launcher2.ui.gestures.LocalGestureDetector
import de.mm20.launcher2.ui.ktx.animateTo
import de.mm20.launcher2.ui.launcher.gestures.LauncherGestureHandler
import de.mm20.launcher2.ui.launcher.helper.WallpaperBlur
import de.mm20.launcher2.ui.launcher.search.SearchColumn
import de.mm20.launcher2.ui.launcher.search.SearchVM
@ -247,15 +248,17 @@ fun PullDownScaffold(
if (!isWidgetEditMode) searchBarOffset.value = 0f
}
BackHandler {
val handleBackOrHomeEvent = {
when {
isSearchOpen -> {
viewModel.closeSearch()
searchVM.search("")
true
}
isWidgetEditMode -> {
viewModel.setWidgetEditMode(false)
true
}
widgetsScrollState.value != 0 -> {
@ -265,10 +268,16 @@ fun PullDownScaffold(
scope.launch {
searchBarOffset.animateTo(0f)
}
true
}
else -> false
}
}
BackHandler {
handleBackOrHomeEvent()
}
val keyboardController = LocalSoftwareKeyboardController.current
val gestureManager = LocalGestureDetector.current
@ -571,4 +580,7 @@ fun PullDownScaffold(
)
}
LauncherGestureHandler(
onHomeButtonPress = handleBackOrHomeEvent,
)
}

View File

@ -44,10 +44,9 @@ import de.mm20.launcher2.ui.component.NavBarEffects
import de.mm20.launcher2.ui.gestures.GestureDetector
import de.mm20.launcher2.ui.gestures.LocalGestureDetector
import de.mm20.launcher2.ui.ktx.animateTo
import de.mm20.launcher2.ui.launcher.gestures.LauncherGestureHandler
import de.mm20.launcher2.ui.launcher.search.SearchVM
import de.mm20.launcher2.ui.launcher.sheets.LauncherBottomSheets
import de.mm20.launcher2.ui.launcher.sheets.LauncherBottomSheetManager
import de.mm20.launcher2.ui.launcher.sheets.LauncherBottomSheets
import de.mm20.launcher2.ui.launcher.sheets.LocalBottomSheetManager
import de.mm20.launcher2.ui.launcher.transitions.EnterHomeTransition
import de.mm20.launcher2.ui.launcher.transitions.EnterHomeTransitionManager
@ -70,6 +69,8 @@ abstract class SharedLauncherActivity(
internal val enterHomeTransitionManager = EnterHomeTransitionManager()
internal val gestureDetector = GestureDetector()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@ -84,7 +85,6 @@ abstract class SharedLauncherActivity(
viewModel.setSystemInDarkMode(resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK == Configuration.UI_MODE_NIGHT_YES)
val bottomSheetManager = LauncherBottomSheetManager(this)
val gestureDetector = GestureDetector()
setContent {
val snackbarHostState = remember { SnackbarHostState() }
@ -258,7 +258,6 @@ abstract class SharedLauncherActivity(
}
LauncherBottomSheets()
}
LauncherGestureHandler()
}
}
}

View File

@ -34,8 +34,15 @@ import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlin.math.absoluteValue
/**
* Handles gestures on the launcher according to the user's settings.
* @param onHomeButtonPress Called when the home button is pressed. Allows the caller to intercept the event.
* If the function returns true, the event is considered handled and the default action is not performed.
*/
@Composable
fun LauncherGestureHandler() {
fun LauncherGestureHandler(
onHomeButtonPress: () -> Boolean = { false }
) {
val context = LocalContext.current
val wallpaperManager = remember { WallpaperManager.getInstance(context) }
val gestureDetector = LocalGestureDetector.current
@ -69,6 +76,12 @@ fun LauncherGestureHandler() {
onLongPress = {
viewModel.handleGesture(context, Gesture.LongPress)
},
onHomeButtonPress = {
if (onHomeButtonPress()) {
return@GestureHandler
}
viewModel.handleGesture(context, Gesture.HomeButton)
},
onDrag = {
when {
gestureState.swipeRightApp != null && it.x > swipeStartThreshold && (

View File

@ -43,6 +43,7 @@ fun FailedGestureSheet(
Gesture.SwipeDown -> R.string.preference_gesture_swipe_down
Gesture.SwipeLeft -> R.string.preference_gesture_swipe_left
Gesture.SwipeRight -> R.string.preference_gesture_swipe_right
Gesture.HomeButton -> R.string.preference_gesture_home_button
})
BottomSheetDialog(

View File

@ -31,6 +31,7 @@ class FailedGestureSheetVM : ViewModel(), KoinComponent {
Gesture.SwipeRight -> swipeRight = GestureAction.None
Gesture.DoubleTap -> doubleTap = GestureAction.None
Gesture.LongPress -> longPress = GestureAction.None
Gesture.HomeButton -> homeButton = GestureAction.None
}
}.build()
).build()