Add home button gesture trigger
This commit is contained in:
parent
918f340dd2
commit
62c1a4293f
@ -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()
|
||||
}
|
||||
@ -6,4 +6,5 @@ enum class Gesture {
|
||||
SwipeDown,
|
||||
SwipeLeft,
|
||||
SwipeRight,
|
||||
HomeButton,
|
||||
}
|
||||
@ -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() {}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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() {
|
||||
|
||||
@ -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)
|
||||
@ -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 {
|
||||
|
||||
@ -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,
|
||||
)
|
||||
}
|
||||
@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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 && (
|
||||
|
||||
@ -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(
|
||||
|
||||
@ -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()
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user