Remove corner clip, draw content behind system bars
This commit is contained in:
parent
e565780015
commit
c7c97a3866
@ -14,9 +14,11 @@ 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.draw.blur
|
||||||
import androidx.compose.ui.geometry.Size
|
import androidx.compose.ui.geometry.Size
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.graphics.graphicsLayer
|
import androidx.compose.ui.graphics.graphicsLayer
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.core.view.WindowCompat
|
import androidx.core.view.WindowCompat
|
||||||
import androidx.core.view.WindowInsetsControllerCompat
|
import androidx.core.view.WindowInsetsControllerCompat
|
||||||
import androidx.lifecycle.Lifecycle
|
import androidx.lifecycle.Lifecycle
|
||||||
@ -111,7 +113,6 @@ class LauncherActivity : BaseActivity() {
|
|||||||
PullDownScaffold(
|
PullDownScaffold(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
.systemBarsPadding()
|
|
||||||
.graphicsLayer {
|
.graphicsLayer {
|
||||||
scaleX = 0.5f + enterTransition.value * 0.5f
|
scaleX = 0.5f + enterTransition.value * 0.5f
|
||||||
scaleY = 0.5f + enterTransition.value * 0.5f
|
scaleY = 0.5f + enterTransition.value * 0.5f
|
||||||
@ -125,7 +126,6 @@ class LauncherActivity : BaseActivity() {
|
|||||||
PagerScaffold(
|
PagerScaffold(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
.systemBarsPadding()
|
|
||||||
.graphicsLayer {
|
.graphicsLayer {
|
||||||
scaleX = enterTransition.value
|
scaleX = enterTransition.value
|
||||||
scaleY = enterTransition.value
|
scaleY = enterTransition.value
|
||||||
|
|||||||
@ -22,21 +22,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.draw.clip
|
|
||||||
import androidx.compose.ui.geometry.Offset
|
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.NestedScrollConnection
|
||||||
import androidx.compose.ui.input.nestedscroll.NestedScrollSource
|
import androidx.compose.ui.input.nestedscroll.NestedScrollSource
|
||||||
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
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.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.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.systemuicontroller.rememberSystemUiController
|
import com.google.accompanist.systemuicontroller.rememberSystemUiController
|
||||||
import de.mm20.launcher2.ui.R
|
import de.mm20.launcher2.ui.R
|
||||||
import de.mm20.launcher2.ui.ktx.toPixels
|
import de.mm20.launcher2.ui.ktx.toPixels
|
||||||
@ -61,7 +57,6 @@ fun PagerScaffold(
|
|||||||
) {
|
) {
|
||||||
val viewModel: LauncherScaffoldVM = viewModel()
|
val viewModel: LauncherScaffoldVM = viewModel()
|
||||||
val searchVM: SearchVM = viewModel()
|
val searchVM: SearchVM = viewModel()
|
||||||
val context = LocalContext.current
|
|
||||||
|
|
||||||
val isSearchOpen by viewModel.isSearchOpen.observeAsState(false)
|
val isSearchOpen by viewModel.isSearchOpen.observeAsState(false)
|
||||||
val isWidgetEditMode by viewModel.isWidgetEditMode.observeAsState(false)
|
val isWidgetEditMode by viewModel.isWidgetEditMode.observeAsState(false)
|
||||||
@ -70,6 +65,25 @@ fun PagerScaffold(
|
|||||||
val searchScrollState = rememberScrollState()
|
val searchScrollState = rememberScrollState()
|
||||||
val swipeableState = rememberSwipeableState(if (isSearchOpen) Page.Search else Page.Widgets)
|
val swipeableState = rememberSwipeableState(if (isSearchOpen) Page.Search else Page.Widgets)
|
||||||
|
|
||||||
|
val showStatusBarScrim by remember {
|
||||||
|
derivedStateOf {
|
||||||
|
if (isSearchOpen) {
|
||||||
|
searchScrollState.value < searchScrollState.maxValue
|
||||||
|
} else {
|
||||||
|
widgetsScrollState.value > 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val showNavBarScrim by remember {
|
||||||
|
derivedStateOf {
|
||||||
|
if (isSearchOpen) {
|
||||||
|
searchScrollState.value > 0
|
||||||
|
} else {
|
||||||
|
widgetsScrollState.value > 0 && widgetsScrollState.value < widgetsScrollState.maxValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
val isWidgetsScrollZero by remember {
|
val isWidgetsScrollZero by remember {
|
||||||
derivedStateOf {
|
derivedStateOf {
|
||||||
widgetsScrollState.value == 0
|
widgetsScrollState.value == 0
|
||||||
@ -79,11 +93,15 @@ fun PagerScaffold(
|
|||||||
val systemUiController = rememberSystemUiController()
|
val systemUiController = rememberSystemUiController()
|
||||||
|
|
||||||
val colorSurface = MaterialTheme.colorScheme.surface
|
val colorSurface = MaterialTheme.colorScheme.surface
|
||||||
LaunchedEffect(isWidgetEditMode, darkStatusBarIcons, colorSurface) {
|
LaunchedEffect(isWidgetEditMode, darkStatusBarIcons, colorSurface, showStatusBarScrim) {
|
||||||
if (isWidgetEditMode) {
|
if (isWidgetEditMode) {
|
||||||
systemUiController.setStatusBarColor(
|
systemUiController.setStatusBarColor(
|
||||||
colorSurface
|
colorSurface
|
||||||
)
|
)
|
||||||
|
} else if (showStatusBarScrim) {
|
||||||
|
systemUiController.setStatusBarColor(
|
||||||
|
colorSurface.copy(0.75f),
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
systemUiController.setStatusBarColor(
|
systemUiController.setStatusBarColor(
|
||||||
Color.Transparent,
|
Color.Transparent,
|
||||||
@ -92,12 +110,18 @@ fun PagerScaffold(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LaunchedEffect(darkNavBarIcons) {
|
LaunchedEffect(darkNavBarIcons, showNavBarScrim) {
|
||||||
systemUiController.setNavigationBarColor(
|
if (showNavBarScrim) {
|
||||||
Color.Transparent,
|
systemUiController.setNavigationBarColor(
|
||||||
darkIcons = darkNavBarIcons,
|
colorSurface.copy(0.75f),
|
||||||
navigationBarContrastEnforced = false
|
)
|
||||||
)
|
} else {
|
||||||
|
systemUiController.setNavigationBarColor(
|
||||||
|
Color.Transparent,
|
||||||
|
darkIcons = darkNavBarIcons,
|
||||||
|
navigationBarContrastEnforced = false
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val blurWallpaper by remember {
|
val blurWallpaper by remember {
|
||||||
@ -138,11 +162,11 @@ fun PagerScaffold(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val notificationDragThreshold = with(LocalDensity.current) {200.dp.toPx()}
|
val notificationDragThreshold = with(LocalDensity.current) { 200.dp.toPx() }
|
||||||
val notificationShadeController = rememberNotificationShadeController()
|
val notificationShadeController = rememberNotificationShadeController()
|
||||||
|
|
||||||
val nestedScrollConnection = remember {
|
val nestedScrollConnection = remember {
|
||||||
object: NestedScrollConnection {
|
object : NestedScrollConnection {
|
||||||
private var pullDownTotalY: Float? = 0f
|
private var pullDownTotalY: Float? = 0f
|
||||||
override fun onPreScroll(available: Offset, source: NestedScrollSource): Offset {
|
override fun onPreScroll(available: Offset, source: NestedScrollSource): Offset {
|
||||||
val diff = widgetsScrollState.value - available.y
|
val diff = widgetsScrollState.value - available.y
|
||||||
@ -171,6 +195,8 @@ fun PagerScaffold(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val insets = WindowInsets.systemBars.asPaddingValues()
|
||||||
|
|
||||||
Box(
|
Box(
|
||||||
modifier = modifier
|
modifier = modifier
|
||||||
) {
|
) {
|
||||||
@ -218,12 +244,12 @@ fun PagerScaffold(
|
|||||||
val editModePadding by animateDpAsState(if (isWidgetEditMode) 56.dp else 0.dp)
|
val editModePadding by animateDpAsState(if (isWidgetEditMode) 56.dp else 0.dp)
|
||||||
|
|
||||||
val clockPadding by animateDpAsState(
|
val clockPadding by animateDpAsState(
|
||||||
if (isWidgetsScrollZero) 64.dp else 0.dp
|
if (isWidgetsScrollZero) 64.dp + insets.calculateBottomPadding() else 0.dp
|
||||||
)
|
)
|
||||||
|
|
||||||
val clockHeight by remember {
|
val clockHeight by remember {
|
||||||
derivedStateOf {
|
derivedStateOf {
|
||||||
height - (64.dp - clockPadding)
|
height - (64.dp + insets.calculateTopPadding() + insets.calculateBottomPadding() - clockPadding)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -231,10 +257,10 @@ fun PagerScaffold(
|
|||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.requiredWidth(width)
|
.requiredWidth(width)
|
||||||
.fillMaxHeight()
|
.fillMaxHeight()
|
||||||
.padding(horizontal = 8.dp)
|
|
||||||
.clip(MaterialTheme.shapes.medium)
|
|
||||||
.nestedScroll(nestedScrollConnection)
|
.nestedScroll(nestedScrollConnection)
|
||||||
.verticalScroll(widgetsScrollState)
|
.verticalScroll(widgetsScrollState)
|
||||||
|
.systemBarsPadding()
|
||||||
|
.padding(horizontal = 8.dp)
|
||||||
.padding(top = 8.dp, bottom = 64.dp)
|
.padding(top = 8.dp, bottom = 64.dp)
|
||||||
.padding(top = editModePadding),
|
.padding(top = editModePadding),
|
||||||
clockHeight = { clockHeight },
|
clockHeight = { clockHeight },
|
||||||
@ -254,10 +280,10 @@ fun PagerScaffold(
|
|||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.requiredWidth(width)
|
.requiredWidth(width)
|
||||||
.fillMaxHeight()
|
.fillMaxHeight()
|
||||||
.padding(horizontal = 8.dp)
|
|
||||||
.clip(MaterialTheme.shapes.medium)
|
|
||||||
.verticalScroll(searchScrollState, reverseScrolling = true)
|
.verticalScroll(searchScrollState, reverseScrolling = true)
|
||||||
.imePadding()
|
.imePadding()
|
||||||
|
.systemBarsPadding()
|
||||||
|
.padding(horizontal = 8.dp)
|
||||||
.padding(top = 8.dp, bottom = 64.dp)
|
.padding(top = 8.dp, bottom = 64.dp)
|
||||||
.padding(bottom = webSearchPadding),
|
.padding(bottom = webSearchPadding),
|
||||||
reverse = true,
|
reverse = true,
|
||||||
@ -302,6 +328,7 @@ fun PagerScaffold(
|
|||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.align(Alignment.BottomCenter)
|
.align(Alignment.BottomCenter)
|
||||||
.padding(start = 8.dp, end = 8.dp, bottom = 8.dp)
|
.padding(start = 8.dp, end = 8.dp, bottom = 8.dp)
|
||||||
|
.systemBarsPadding()
|
||||||
.imePadding()
|
.imePadding()
|
||||||
.offset(y = widgetEditModeOffset),
|
.offset(y = widgetEditModeOffset),
|
||||||
level = { searchBarLevel }, focused = focusSearchBar, onFocusChange = {
|
level = { searchBarLevel }, focused = focusSearchBar, onFocusChange = {
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
package de.mm20.launcher2.ui.launcher
|
package de.mm20.launcher2.ui.launcher
|
||||||
|
|
||||||
import android.util.Log
|
|
||||||
import androidx.activity.compose.BackHandler
|
import androidx.activity.compose.BackHandler
|
||||||
import androidx.compose.animation.AnimatedVisibility
|
import androidx.compose.animation.AnimatedVisibility
|
||||||
import androidx.compose.animation.core.animateDpAsState
|
import androidx.compose.animation.core.animateDpAsState
|
||||||
@ -19,7 +18,6 @@ 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.draw.clip
|
|
||||||
import androidx.compose.ui.geometry.Offset
|
import androidx.compose.ui.geometry.Offset
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.graphics.TransformOrigin
|
import androidx.compose.ui.graphics.TransformOrigin
|
||||||
@ -43,6 +41,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.modifier.verticalFadingEdges
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlin.math.roundToInt
|
import kotlin.math.roundToInt
|
||||||
|
|
||||||
@ -55,7 +54,6 @@ fun PullDownScaffold(
|
|||||||
) {
|
) {
|
||||||
val viewModel: LauncherScaffoldVM = viewModel()
|
val viewModel: LauncherScaffoldVM = viewModel()
|
||||||
val searchVM: SearchVM = viewModel()
|
val searchVM: SearchVM = viewModel()
|
||||||
val context = LocalContext.current
|
|
||||||
|
|
||||||
val density = LocalDensity.current
|
val density = LocalDensity.current
|
||||||
|
|
||||||
@ -67,12 +65,41 @@ fun PullDownScaffold(
|
|||||||
|
|
||||||
val systemUiController = rememberSystemUiController()
|
val systemUiController = rememberSystemUiController()
|
||||||
|
|
||||||
|
val isWidgetsScrollZero by remember {
|
||||||
|
derivedStateOf {
|
||||||
|
widgetsScrollState.value == 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val showStatusBarScrim by remember {
|
||||||
|
derivedStateOf {
|
||||||
|
if (isSearchOpen) {
|
||||||
|
searchScrollState.value > 0
|
||||||
|
} else {
|
||||||
|
widgetsScrollState.value > 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val showNavBarScrim by remember {
|
||||||
|
derivedStateOf {
|
||||||
|
if (isSearchOpen) {
|
||||||
|
searchScrollState.value < searchScrollState.maxValue
|
||||||
|
} else {
|
||||||
|
widgetsScrollState.value > 0 && widgetsScrollState.value < widgetsScrollState.maxValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
val colorSurface = MaterialTheme.colorScheme.surface
|
val colorSurface = MaterialTheme.colorScheme.surface
|
||||||
LaunchedEffect(isWidgetEditMode, darkStatusBarIcons, colorSurface) {
|
LaunchedEffect(isWidgetEditMode, darkStatusBarIcons, colorSurface, showStatusBarScrim) {
|
||||||
if (isWidgetEditMode) {
|
if (isWidgetEditMode) {
|
||||||
systemUiController.setStatusBarColor(
|
systemUiController.setStatusBarColor(
|
||||||
colorSurface
|
colorSurface
|
||||||
)
|
)
|
||||||
|
} else if (showStatusBarScrim) {
|
||||||
|
systemUiController.setStatusBarColor(
|
||||||
|
colorSurface.copy(0.75f),
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
systemUiController.setStatusBarColor(
|
systemUiController.setStatusBarColor(
|
||||||
Color.Transparent,
|
Color.Transparent,
|
||||||
@ -81,12 +108,18 @@ fun PullDownScaffold(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LaunchedEffect(darkNavBarIcons) {
|
LaunchedEffect(darkNavBarIcons, showNavBarScrim) {
|
||||||
systemUiController.setNavigationBarColor(
|
if (showNavBarScrim) {
|
||||||
Color.Transparent,
|
systemUiController.setNavigationBarColor(
|
||||||
darkIcons = darkNavBarIcons,
|
colorSurface.copy(0.75f),
|
||||||
navigationBarContrastEnforced = false
|
)
|
||||||
)
|
} else {
|
||||||
|
systemUiController.setNavigationBarColor(
|
||||||
|
Color.Transparent,
|
||||||
|
darkIcons = darkNavBarIcons,
|
||||||
|
navigationBarContrastEnforced = false
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val offsetY = remember { mutableStateOf(0f) }
|
val offsetY = remember { mutableStateOf(0f) }
|
||||||
@ -151,7 +184,7 @@ fun PullDownScaffold(
|
|||||||
consumed
|
consumed
|
||||||
}
|
}
|
||||||
isSearchOpen && (offsetY.value < 0 || source == NestedScrollSource.Drag && newValue > searchScrollState.maxValue) -> {
|
isSearchOpen && (offsetY.value < 0 || source == NestedScrollSource.Drag && newValue > searchScrollState.maxValue) -> {
|
||||||
val consumed = available.y - (value- searchScrollState.maxValue)
|
val consumed = available.y - (value - searchScrollState.maxValue)
|
||||||
offsetY.value = (offsetY.value + (consumed * 0.5f)).coerceIn(-maxOffset, 0f)
|
offsetY.value = (offsetY.value + (consumed * 0.5f)).coerceIn(-maxOffset, 0f)
|
||||||
consumed
|
consumed
|
||||||
}
|
}
|
||||||
@ -182,11 +215,13 @@ fun PullDownScaffold(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val insets = WindowInsets.systemBars.asPaddingValues()
|
||||||
Box(
|
Box(
|
||||||
modifier = modifier
|
modifier = modifier
|
||||||
.padding(horizontal = 8.dp)
|
.verticalFadingEdges(
|
||||||
.clip(MaterialTheme.shapes.medium)
|
top = insets.calculateTopPadding(),
|
||||||
|
amount = 0.85f
|
||||||
|
)
|
||||||
.nestedScroll(nestedScrollConnection)
|
.nestedScroll(nestedScrollConnection)
|
||||||
.offset { IntOffset(0, offsetY.value.toInt()) },
|
.offset { IntOffset(0, offsetY.value.toInt()) },
|
||||||
contentAlignment = Alignment.TopCenter
|
contentAlignment = Alignment.TopCenter
|
||||||
@ -230,12 +265,21 @@ fun PullDownScaffold(
|
|||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.requiredHeight(height)
|
.requiredHeight(height)
|
||||||
.verticalScroll(searchScrollState)
|
.verticalScroll(searchScrollState)
|
||||||
.padding(vertical = 8.dp)
|
.systemBarsPadding()
|
||||||
|
.padding(8.dp)
|
||||||
.padding(top = 56.dp)
|
.padding(top = 56.dp)
|
||||||
.padding(top = webSearchPadding)
|
.padding(top = webSearchPadding)
|
||||||
.imePadding()
|
.imePadding()
|
||||||
)
|
)
|
||||||
val editModePadding by animateDpAsState(if (isWidgetEditMode) 56.dp else 0.dp)
|
val editModePadding by animateDpAsState(if (isWidgetEditMode) 56.dp else 0.dp)
|
||||||
|
val clockPadding by animateDpAsState(
|
||||||
|
if (isWidgetsScrollZero) insets.calculateBottomPadding() else 0.dp
|
||||||
|
)
|
||||||
|
val clockHeight by remember {
|
||||||
|
derivedStateOf {
|
||||||
|
height - (insets.calculateTopPadding() + insets.calculateBottomPadding() - clockPadding)
|
||||||
|
}
|
||||||
|
}
|
||||||
WidgetColumn(
|
WidgetColumn(
|
||||||
modifier =
|
modifier =
|
||||||
Modifier
|
Modifier
|
||||||
@ -248,9 +292,11 @@ fun PullDownScaffold(
|
|||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.requiredHeight(height)
|
.requiredHeight(height)
|
||||||
.verticalScroll(widgetsScrollState)
|
.verticalScroll(widgetsScrollState)
|
||||||
.padding(vertical = 8.dp)
|
.systemBarsPadding()
|
||||||
|
.padding(8.dp)
|
||||||
.padding(top = editModePadding),
|
.padding(top = editModePadding),
|
||||||
clockHeight = { height },
|
clockHeight = { clockHeight },
|
||||||
|
clockBottomPadding = { clockPadding },
|
||||||
editMode = isWidgetEditMode,
|
editMode = isWidgetEditMode,
|
||||||
onEditModeChange = {
|
onEditModeChange = {
|
||||||
viewModel.setWidgetEditMode(it)
|
viewModel.setWidgetEditMode(it)
|
||||||
@ -268,6 +314,8 @@ fun PullDownScaffold(
|
|||||||
exit = slideOut { IntOffset(0, -it.height) }
|
exit = slideOut { IntOffset(0, -it.height) }
|
||||||
) {
|
) {
|
||||||
CenterAlignedTopAppBar(
|
CenterAlignedTopAppBar(
|
||||||
|
modifier = Modifier
|
||||||
|
.systemBarsPadding(),
|
||||||
title = {
|
title = {
|
||||||
Text(stringResource(R.string.menu_edit_widgets))
|
Text(stringResource(R.string.menu_edit_widgets))
|
||||||
},
|
},
|
||||||
@ -285,7 +333,7 @@ fun PullDownScaffold(
|
|||||||
offsetY.value != 0f -> SearchBarLevel.Raised
|
offsetY.value != 0f -> SearchBarLevel.Raised
|
||||||
isSearchOpen && searchScrollState.value == 0 -> SearchBarLevel.Active
|
isSearchOpen && searchScrollState.value == 0 -> SearchBarLevel.Active
|
||||||
isSearchOpen && searchScrollState.value > 0 -> SearchBarLevel.Raised
|
isSearchOpen && searchScrollState.value > 0 -> SearchBarLevel.Raised
|
||||||
widgetsScrollState.value > 0 -> SearchBarLevel.Raised
|
!isWidgetsScrollZero -> SearchBarLevel.Raised
|
||||||
else -> SearchBarLevel.Resting
|
else -> SearchBarLevel.Resting
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -300,7 +348,8 @@ fun PullDownScaffold(
|
|||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.wrapContentHeight()
|
.wrapContentHeight()
|
||||||
.padding(vertical = 8.dp)
|
.systemBarsPadding()
|
||||||
|
.padding(8.dp)
|
||||||
.offset { IntOffset(0, searchBarOffset.value.toInt()) }
|
.offset { IntOffset(0, searchBarOffset.value.toInt()) }
|
||||||
.offset {
|
.offset {
|
||||||
IntOffset(
|
IntOffset(
|
||||||
|
|||||||
@ -0,0 +1,89 @@
|
|||||||
|
package de.mm20.launcher2.ui.modifier
|
||||||
|
|
||||||
|
import androidx.annotation.FloatRange
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.draw.drawWithContent
|
||||||
|
import androidx.compose.ui.geometry.Offset
|
||||||
|
import androidx.compose.ui.geometry.Rect
|
||||||
|
import androidx.compose.ui.graphics.BlendMode
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.graphics.LinearGradientShader
|
||||||
|
import androidx.compose.ui.graphics.Paint
|
||||||
|
import androidx.compose.ui.graphics.drawscope.drawIntoCanvas
|
||||||
|
import androidx.compose.ui.unit.Dp
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import kotlin.math.pow
|
||||||
|
|
||||||
|
fun Modifier.verticalFadingEdges(
|
||||||
|
enabled: Boolean = true,
|
||||||
|
top: Dp = 0.dp,
|
||||||
|
bottom: Dp = 0.dp,
|
||||||
|
/**
|
||||||
|
* How strong the fading effect should be.
|
||||||
|
* If 1, edges will be completely transparent.
|
||||||
|
* If 0, the modifier will have no effect at all.
|
||||||
|
*/
|
||||||
|
@FloatRange(from = 0.0, to = 1.0, fromInclusive = true, toInclusive = true) amount: Float = 1f
|
||||||
|
): Modifier {
|
||||||
|
if(!enabled) return this
|
||||||
|
if (top == 0.dp && bottom == 0.dp) return this
|
||||||
|
|
||||||
|
return this then drawWithContent {
|
||||||
|
|
||||||
|
val topColors = if (top > 0.dp) createColors(
|
||||||
|
1f - amount,
|
||||||
|
top.roundToPx() + 1,
|
||||||
|
) else emptyList()
|
||||||
|
val bottomColors = if (bottom > 0.dp) createColors(
|
||||||
|
1f - amount,
|
||||||
|
bottom.roundToPx() + 1,
|
||||||
|
reverse = true
|
||||||
|
) else emptyList()
|
||||||
|
|
||||||
|
val topSteps = if (top > 0.dp) createColorSteps(
|
||||||
|
size.height,
|
||||||
|
top.toPx() * 1.3f,
|
||||||
|
top.roundToPx() + 1
|
||||||
|
) else emptyList()
|
||||||
|
val bottomSteps = if (bottom > 0.dp) createColorSteps(
|
||||||
|
size.height,
|
||||||
|
bottom.toPx() * 1.3f,
|
||||||
|
bottom.roundToPx() + 1,
|
||||||
|
reverse = true
|
||||||
|
) else emptyList()
|
||||||
|
|
||||||
|
val paint = Paint().apply {
|
||||||
|
blendMode = BlendMode.DstIn
|
||||||
|
shader = LinearGradientShader(
|
||||||
|
Offset.Zero,
|
||||||
|
Offset(0f, size.height),
|
||||||
|
colors = topColors + bottomColors,
|
||||||
|
colorStops = topSteps + bottomSteps
|
||||||
|
)
|
||||||
|
}
|
||||||
|
drawContent()
|
||||||
|
drawIntoCanvas {
|
||||||
|
it.drawRect(
|
||||||
|
Rect(0f, 0f, size.width, size.height),
|
||||||
|
paint
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createColors(alpha: Float, steps: Int, reverse: Boolean = false): List<Color> {
|
||||||
|
val interval = 1f / (steps - 1)
|
||||||
|
return (0 until steps).map {
|
||||||
|
val x = interval * if (reverse) (steps - 1 - it) else it
|
||||||
|
val y = (1 - alpha) * (1f - (x - 1f).pow(2)) + alpha
|
||||||
|
Color.Black.copy(alpha = y)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createColorSteps(height: Float, size: Float, steps: Int, reverse: Boolean = false): List<Float> {
|
||||||
|
val interval = 1f / (steps - 1)
|
||||||
|
return (0 until steps).map {
|
||||||
|
val x = interval * if (reverse) (steps - 1 - it) else it
|
||||||
|
if (reverse) 1 - (x * size / height) else (x * size / height)
|
||||||
|
}
|
||||||
|
}
|
||||||
93
ui/src/main/java/de/mm20/launcher2/ui/modifier/Scrims.kt
Normal file
93
ui/src/main/java/de/mm20/launcher2/ui/modifier/Scrims.kt
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
package de.mm20.launcher2.ui.modifier
|
||||||
|
|
||||||
|
import androidx.annotation.FloatRange
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.draw.drawWithCache
|
||||||
|
import androidx.compose.ui.geometry.Offset
|
||||||
|
import androidx.compose.ui.geometry.Rect
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.graphics.LinearGradientShader
|
||||||
|
import androidx.compose.ui.graphics.Paint
|
||||||
|
import androidx.compose.ui.graphics.drawscope.drawIntoCanvas
|
||||||
|
import androidx.compose.ui.unit.Dp
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import kotlin.math.pow
|
||||||
|
|
||||||
|
fun Modifier.verticalScrims(
|
||||||
|
enabled: Boolean = true,
|
||||||
|
top: Dp = 0.dp,
|
||||||
|
bottom: Dp = 0.dp,
|
||||||
|
/**
|
||||||
|
* How strong the fading effect should be.
|
||||||
|
* If 1, edges will be completely transparent.
|
||||||
|
* If 0, the modifier will have no effect at all.
|
||||||
|
*/
|
||||||
|
@FloatRange(from = 0.0, to = 1.0, fromInclusive = true, toInclusive = true) amount: Float = 1f
|
||||||
|
): Modifier {
|
||||||
|
if (!enabled) return this
|
||||||
|
if (top == 0.dp && bottom == 0.dp) return this
|
||||||
|
|
||||||
|
return this then drawWithCache {
|
||||||
|
onDrawWithContent {
|
||||||
|
val topColors = if (top > 0.dp) createColors(
|
||||||
|
1f - amount,
|
||||||
|
top.roundToPx() + 1,
|
||||||
|
) else emptyList()
|
||||||
|
val bottomColors = if (bottom > 0.dp) createColors(
|
||||||
|
1f - amount,
|
||||||
|
bottom.roundToPx() + 1,
|
||||||
|
reverse = true
|
||||||
|
) else emptyList()
|
||||||
|
|
||||||
|
val topSteps = if (top > 0.dp) createColorSteps(
|
||||||
|
size.height,
|
||||||
|
top.toPx() * 1.3f,
|
||||||
|
top.roundToPx() + 1
|
||||||
|
) else emptyList()
|
||||||
|
val bottomSteps = if (bottom > 0.dp) createColorSteps(
|
||||||
|
size.height,
|
||||||
|
bottom.toPx() * 1.3f,
|
||||||
|
bottom.roundToPx() + 1,
|
||||||
|
reverse = true
|
||||||
|
) else emptyList()
|
||||||
|
|
||||||
|
val paint = Paint().apply {
|
||||||
|
shader = LinearGradientShader(
|
||||||
|
Offset.Zero,
|
||||||
|
Offset(0f, size.height),
|
||||||
|
colors = topColors + bottomColors,
|
||||||
|
colorStops = topSteps + bottomSteps
|
||||||
|
)
|
||||||
|
}
|
||||||
|
drawContent()
|
||||||
|
drawIntoCanvas {
|
||||||
|
it.drawRect(
|
||||||
|
Rect(0f, 0f, size.width, size.height),
|
||||||
|
paint
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createColors(alpha: Float, steps: Int, reverse: Boolean = false): List<Color> {
|
||||||
|
val interval = 1f / (steps - 1)
|
||||||
|
return (0 until steps).map {
|
||||||
|
val x = interval * if (reverse) (steps - 1 - it) else it
|
||||||
|
val y = 1f - ((1 - alpha) * (1f - (x - 1f).pow(2)) + alpha)
|
||||||
|
Color.Black.copy(alpha = y)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createColorSteps(
|
||||||
|
height: Float,
|
||||||
|
size: Float,
|
||||||
|
steps: Int,
|
||||||
|
reverse: Boolean = false
|
||||||
|
): List<Float> {
|
||||||
|
val interval = 1f / (steps - 1)
|
||||||
|
return (0 until steps).map {
|
||||||
|
val x = interval * if (reverse) (steps - 1 - it) else it
|
||||||
|
if (reverse) 1 - (x * size / height) else (x * size / height)
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user