PagerScaffold: add swipe down gesture to expand notification shade

This commit is contained in:
MM20 2022-05-21 17:29:26 +02:00
parent 4703cc7085
commit 237361badf
No known key found for this signature in database
GPG Key ID: 0B61A8F2DEAFA389
2 changed files with 87 additions and 0 deletions

View File

@ -1,6 +1,7 @@
package de.mm20.launcher2.ui.launcher package de.mm20.launcher2.ui.launcher
import android.app.Activity import android.app.Activity
import android.util.Log
import android.view.WindowManager import android.view.WindowManager
import androidx.activity.compose.BackHandler import androidx.activity.compose.BackHandler
import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.AnimatedVisibility
@ -10,6 +11,8 @@ import androidx.compose.animation.slideOut
import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.gestures.LocalOverScrollConfiguration import androidx.compose.foundation.gestures.LocalOverScrollConfiguration
import androidx.compose.foundation.gestures.Orientation 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.layout.*
import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll import androidx.compose.foundation.verticalScroll
@ -24,11 +27,17 @@ import androidx.compose.runtime.*
import androidx.compose.runtime.livedata.observeAsState import androidx.compose.runtime.livedata.observeAsState
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.Offset
import androidx.compose.ui.graphics.Color 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.LocalContext
import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.IntOffset import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.Velocity
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel import androidx.lifecycle.viewmodel.compose.viewModel
import com.google.accompanist.pager.ExperimentalPagerApi 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.SearchColumn
import de.mm20.launcher2.ui.launcher.search.SearchVM import de.mm20.launcher2.ui.launcher.search.SearchVM
import de.mm20.launcher2.ui.launcher.widgets.WidgetColumn import de.mm20.launcher2.ui.launcher.widgets.WidgetColumn
import de.mm20.launcher2.ui.utils.rememberNotificationShadeController
import kotlin.math.roundToInt import kotlin.math.roundToInt
@OptIn( @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( Box(
modifier = modifier modifier = modifier
) { ) {
@ -193,6 +239,7 @@ fun PagerScaffold(
modifier = Modifier modifier = Modifier
.requiredWidth(width) .requiredWidth(width)
.fillMaxHeight() .fillMaxHeight()
.nestedScroll(nestedScrollConnection)
.verticalScroll(widgetsScrollState) .verticalScroll(widgetsScrollState)
.padding(start = 8.dp, end = 8.dp, top = 8.dp, bottom = 64.dp) .padding(start = 8.dp, end = 8.dp, top = 8.dp, bottom = 64.dp)
.padding(top = editModePadding), .padding(top = editModePadding),

View File

@ -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)
}
}