Add overlay controls

This commit is contained in:
Oleksandr Balan
2022-06-30 01:15:24 +02:00
parent 8495cbf168
commit 973c54f39c
3 changed files with 108 additions and 81 deletions

View File

@@ -8,12 +8,15 @@ import androidx.activity.compose.setContent
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.Text
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
@@ -22,6 +25,7 @@ import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import eu.wewox.pagecurl.components.SettingsPopup
import eu.wewox.pagecurl.components.overlayControls
import eu.wewox.pagecurl.config.PageCurlConfig
import eu.wewox.pagecurl.page.PageCurl
import eu.wewox.pagecurl.page.rememberPageCurlState
@@ -33,13 +37,31 @@ class MainActivity : ComponentActivity() {
super.onCreate(savedInstanceState)
setContent {
PageCurlTheme {
Column {
Box {
val scope = rememberCoroutineScope()
val state = rememberPageCurlState(max = 6)
var showPopup by remember { mutableStateOf(false) }
PageCurl(
state = state,
config = PageCurlConfig(),
modifier = Modifier.overlayControls(
next = {
scope.launch {
val next = (state.current + 1).coerceAtMost(state.max - 1)
state.snapTo(next)
}
},
prev = {
scope.launch {
val prev = (state.current - 1).coerceAtLeast(0)
state.snapTo(prev)
}
},
center = {
showPopup = true
}
)
) { index ->
Box(
modifier = Modifier
@@ -71,22 +93,28 @@ class MainActivity : ComponentActivity() {
.background(Color.Black, RoundedCornerShape(topStartPercent = 100))
.padding(16.dp)
)
SettingsPopup(
onSnapToFirst = {
scope.launch {
state.snapTo(0)
}
},
onSnapToLast = {
scope.launch {
state.snapTo(state.max - 1)
}
},
modifier = Modifier.align(Alignment.Center)
)
}
}
if (showPopup) {
SettingsPopup(
onSnapToFirst = {
scope.launch {
state.snapTo(0)
showPopup = false
}
},
onSnapToLast = {
scope.launch {
state.snapTo(state.max - 1)
showPopup = false
}
},
onDismiss = {
showPopup = false
}
)
}
}
}
}

View File

@@ -0,0 +1,37 @@
package eu.wewox.pagecurl.components
import androidx.compose.foundation.gestures.awaitFirstDown
import androidx.compose.foundation.gestures.forEachGesture
import androidx.compose.foundation.gestures.waitForUpOrCancellation
import androidx.compose.ui.Modifier
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.unit.center
import androidx.compose.ui.unit.toOffset
internal fun Modifier.overlayControls(
next: () -> Unit,
prev: () -> Unit,
center: () -> Unit,
): Modifier = pointerInput(Unit) {
forEachGesture {
awaitPointerEventScope {
val down = awaitFirstDown().also { it.consume() }
val up = waitForUpOrCancellation() ?: return@awaitPointerEventScope
up.consume()
if ((down.position - up.position).getDistance() > viewConfiguration.touchSlop) {
return@awaitPointerEventScope
}
if ((up.position - size.center.toOffset()).getDistance() < 100f) {
center()
return@awaitPointerEventScope
}
if (up.position.x < size.width / 2) {
prev()
} else {
next()
}
}
}
}

View File

@@ -1,26 +1,16 @@
package eu.wewox.pagecurl.components
import androidx.compose.foundation.clickable
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.Card
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
import androidx.compose.material.TextButton
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.composed
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.Popup
@@ -28,66 +18,38 @@ import androidx.compose.ui.window.Popup
internal fun SettingsPopup(
onSnapToFirst: () -> Unit,
onSnapToLast: () -> Unit,
modifier: Modifier = Modifier
onDismiss: () -> Unit,
) {
var showPopup by remember { mutableStateOf(false) }
Box(
modifier = modifier
.size(100.dp)
.clickableWithoutRipple {
showPopup = true
}
)
if (showPopup) {
Box(Modifier.fillMaxSize()) {
Popup(
alignment = Alignment.Center,
onDismissRequest = { showPopup = false }
Popup(
alignment = Alignment.Center,
onDismissRequest = onDismiss,
) {
Card(
shape = RoundedCornerShape(24.dp),
backgroundColor = MaterialTheme.colors.primary,
elevation = 16.dp,
) {
Column(
verticalArrangement = Arrangement.spacedBy(8.dp),
modifier = Modifier.padding(8.dp)
) {
Card(
shape = RoundedCornerShape(24.dp),
backgroundColor = MaterialTheme.colors.primary,
elevation = 16.dp
TextButton(
onClick = onSnapToFirst
) {
Column(
verticalArrangement = Arrangement.spacedBy(8.dp),
modifier = Modifier.padding(8.dp)
) {
TextButton(
onClick = {
onSnapToFirst()
showPopup = false
}
) {
Text(
text = "Go to first",
color = MaterialTheme.colors.onPrimary
)
}
TextButton(
onClick = {
onSnapToLast()
showPopup = false
}
) {
Text(
text = "Go to last",
color = MaterialTheme.colors.onPrimary
)
}
}
Text(
text = "Go to first",
color = MaterialTheme.colors.onPrimary
)
}
TextButton(
onClick = onSnapToLast
) {
Text(
text = "Go to last",
color = MaterialTheme.colors.onPrimary
)
}
}
}
}
}
private fun Modifier.clickableWithoutRipple(onClick: () -> Unit) = composed {
clickable(
interactionSource = remember { MutableInteractionSource() },
indication = null,
onClick = onClick
)
}