PagerScaffold: add swipe down gesture to expand notification shade
This commit is contained in:
parent
4703cc7085
commit
237361badf
@ -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),
|
||||||
|
|||||||
@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user