From 237361badf9ff7b46d931c9c93122369e1943e85 Mon Sep 17 00:00:00 2001 From: MM20 <15646950+MM2-0@users.noreply.github.com> Date: Sat, 21 May 2022 17:29:26 +0200 Subject: [PATCH] PagerScaffold: add swipe down gesture to expand notification shade --- .../launcher2/ui/launcher/PagerScaffold.kt | 47 +++++++++++++++++++ .../ui/utils/NotificationShadeController.kt | 40 ++++++++++++++++ 2 files changed, 87 insertions(+) create mode 100644 ui/src/main/java/de/mm20/launcher2/ui/utils/NotificationShadeController.kt diff --git a/ui/src/main/java/de/mm20/launcher2/ui/launcher/PagerScaffold.kt b/ui/src/main/java/de/mm20/launcher2/ui/launcher/PagerScaffold.kt index 3a4f2bd6..f2f2dd1f 100644 --- a/ui/src/main/java/de/mm20/launcher2/ui/launcher/PagerScaffold.kt +++ b/ui/src/main/java/de/mm20/launcher2/ui/launcher/PagerScaffold.kt @@ -1,6 +1,7 @@ package de.mm20.launcher2.ui.launcher import android.app.Activity +import android.util.Log import android.view.WindowManager import androidx.activity.compose.BackHandler import androidx.compose.animation.AnimatedVisibility @@ -10,6 +11,8 @@ import androidx.compose.animation.slideOut import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.gestures.LocalOverScrollConfiguration import androidx.compose.foundation.gestures.Orientation +import androidx.compose.foundation.gestures.detectDragGestures +import androidx.compose.foundation.gestures.detectVerticalDragGestures import androidx.compose.foundation.layout.* import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll @@ -24,11 +27,17 @@ import androidx.compose.runtime.* import androidx.compose.runtime.livedata.observeAsState import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.geometry.Offset import androidx.compose.ui.graphics.Color +import androidx.compose.ui.input.nestedscroll.NestedScrollConnection +import androidx.compose.ui.input.nestedscroll.NestedScrollSource +import androidx.compose.ui.input.nestedscroll.nestedScroll +import androidx.compose.ui.input.pointer.pointerInput import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.IntOffset +import androidx.compose.ui.unit.Velocity import androidx.compose.ui.unit.dp import androidx.lifecycle.viewmodel.compose.viewModel import com.google.accompanist.pager.ExperimentalPagerApi @@ -42,6 +51,7 @@ import de.mm20.launcher2.ui.launcher.search.SearchBarLevel import de.mm20.launcher2.ui.launcher.search.SearchColumn import de.mm20.launcher2.ui.launcher.search.SearchVM import de.mm20.launcher2.ui.launcher.widgets.WidgetColumn +import de.mm20.launcher2.ui.utils.rememberNotificationShadeController import kotlin.math.roundToInt @OptIn( @@ -133,6 +143,42 @@ fun PagerScaffold( } } + val notificationDragThreshold = with(LocalDensity.current) {200.dp.toPx()} + val notificationShadeController = rememberNotificationShadeController() + + val nestedScrollConnection = remember { + object: NestedScrollConnection { + private var pullDownTotalY: Float? = 0f + override fun onPreScroll(available: Offset, source: NestedScrollSource): Offset { + if (widgetsScrollState.value == 0 && source == NestedScrollSource.Drag) { + val diff = widgetsScrollState.value - available.y + var totalY = pullDownTotalY + if (totalY != null) { + totalY += diff + if (totalY < -notificationDragThreshold) { + notificationShadeController.expandNotifications() + pullDownTotalY = null + } else { + pullDownTotalY = totalY + } + return Offset(0f, -diff) + } else { + return available + } + } + return super.onPreScroll(available, source) + } + + override suspend fun onPreFling(available: Velocity): Velocity { + if (pullDownTotalY == null) { + pullDownTotalY = 0f + return available + } + return super.onPreFling(available) + } + } + } + Box( modifier = modifier ) { @@ -193,6 +239,7 @@ fun PagerScaffold( modifier = Modifier .requiredWidth(width) .fillMaxHeight() + .nestedScroll(nestedScrollConnection) .verticalScroll(widgetsScrollState) .padding(start = 8.dp, end = 8.dp, top = 8.dp, bottom = 64.dp) .padding(top = editModePadding), diff --git a/ui/src/main/java/de/mm20/launcher2/ui/utils/NotificationShadeController.kt b/ui/src/main/java/de/mm20/launcher2/ui/utils/NotificationShadeController.kt new file mode 100644 index 00000000..4bb53f36 --- /dev/null +++ b/ui/src/main/java/de/mm20/launcher2/ui/utils/NotificationShadeController.kt @@ -0,0 +1,40 @@ +package de.mm20.launcher2.ui.utils + +import android.annotation.SuppressLint +import android.content.Context +import android.util.Log +import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember +import androidx.compose.ui.platform.LocalContext +import java.lang.reflect.InvocationTargetException + +class NotificationShadeController( + private val context: Context +) { + @SuppressLint("WrongConstant") + fun expandNotifications() { + Log.e("MM20", "pull down") + try { + val statusBarService = context.getSystemService("statusbar") + Class.forName("android.app.StatusBarManager") + .getMethod("expandNotificationsPanel") + .invoke(statusBarService) + } catch (e: IllegalAccessException) { + Log.e("MM20", Log.getStackTraceString(e)) + } catch (e: InvocationTargetException) { + Log.e("MM20", Log.getStackTraceString(e)) + } catch (e: NoSuchMethodException) { + Log.e("MM20", Log.getStackTraceString(e)) + } catch (e: ClassNotFoundException) { + Log.e("MM20", Log.getStackTraceString(e)) + } + } +} + +@Composable +fun rememberNotificationShadeController(): NotificationShadeController { + val context = LocalContext.current + return remember(context) { + NotificationShadeController(context) + } +} \ No newline at end of file