mirror of
https://github.com/Myzel394/NumberHub.git
synced 2025-06-19 08:45:27 +02:00
Use Pager in PagedIsland
This commit is contained in:
parent
93404c1fac
commit
a58cb01f58
@ -18,76 +18,97 @@
|
|||||||
|
|
||||||
package com.sadellie.unitto.core.ui.common
|
package com.sadellie.unitto.core.ui.common
|
||||||
|
|
||||||
import androidx.annotation.IntRange
|
import androidx.compose.animation.animateContentSize
|
||||||
import androidx.compose.animation.AnimatedContent
|
|
||||||
import androidx.compose.foundation.Canvas
|
import androidx.compose.foundation.Canvas
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
import androidx.compose.foundation.clickable
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.ColumnScope
|
|
||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.size
|
import androidx.compose.foundation.layout.size
|
||||||
|
import androidx.compose.foundation.pager.HorizontalPager
|
||||||
|
import androidx.compose.foundation.pager.PagerState
|
||||||
|
import androidx.compose.foundation.pager.rememberPagerState
|
||||||
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.material3.contentColorFor
|
import androidx.compose.material3.contentColorFor
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
import androidx.compose.runtime.mutableIntStateOf
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.runtime.remember
|
|
||||||
import androidx.compose.runtime.setValue
|
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.draw.clip
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [HorizontalPager] with a background and a page indicator.
|
||||||
|
*
|
||||||
|
* @param modifier [Modifier] that will be applied to the surround [Column].
|
||||||
|
* @param pagerState [PagerState] that will passed [HorizontalPager].
|
||||||
|
* @param backgroundColor [Color] for background.
|
||||||
|
* @param pageIndicatorAlignment [Alignment.Horizontal] for page indicator.
|
||||||
|
* @param onClick Called on all clicks, even if the page didn't change.
|
||||||
|
* @param pageContent Page content. Use passed `currentPage` value.
|
||||||
|
*/
|
||||||
@Composable
|
@Composable
|
||||||
fun PagedIsland(
|
fun PagedIsland(
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
@IntRange(from = 1) pagesCount: Int,
|
pagerState: PagerState,
|
||||||
onPageChange: (currentPage: Int) -> Unit = {},
|
|
||||||
backgroundColor: Color = MaterialTheme.colorScheme.secondaryContainer,
|
backgroundColor: Color = MaterialTheme.colorScheme.secondaryContainer,
|
||||||
pageContent: @Composable ColumnScope.(currentPage: Int) -> Unit,
|
pageIndicatorAlignment: Alignment.Horizontal = Alignment.End,
|
||||||
|
onClick: () -> Unit = {},
|
||||||
|
pageContent: @Composable (currentPage: Int) -> Unit,
|
||||||
) {
|
) {
|
||||||
var currentPage: Int by remember { mutableIntStateOf(0) }
|
|
||||||
val contentColor = MaterialTheme.colorScheme.contentColorFor(backgroundColor)
|
val contentColor = MaterialTheme.colorScheme.contentColorFor(backgroundColor)
|
||||||
val disabledContentColor = contentColor.copy(alpha = 0.5f)
|
val disabledContentColor = contentColor.copy(alpha = 0.5f)
|
||||||
|
val corScope = rememberCoroutineScope()
|
||||||
|
|
||||||
AnimatedContent(
|
|
||||||
modifier = modifier
|
|
||||||
.squashable(
|
|
||||||
onClick = {
|
|
||||||
if (currentPage == pagesCount - 1) currentPage = 0 else currentPage++
|
|
||||||
onPageChange(currentPage)
|
|
||||||
},
|
|
||||||
cornerRadiusRange = 8.dp..32.dp,
|
|
||||||
interactionSource = remember { MutableInteractionSource() }
|
|
||||||
)
|
|
||||||
.background(backgroundColor),
|
|
||||||
targetState = currentPage
|
|
||||||
) { state ->
|
|
||||||
ProvideColor(color = contentColor) {
|
ProvideColor(color = contentColor) {
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier.padding(16.dp)
|
modifier = modifier
|
||||||
|
.clip(RoundedCornerShape(32.dp))
|
||||||
|
.clickable {
|
||||||
|
onClick()
|
||||||
|
if (pagerState.currentPage == (pagerState.pageCount - 1)) return@clickable
|
||||||
|
|
||||||
|
corScope.launch {
|
||||||
|
pagerState.animateScrollToPage(pagerState.currentPage + 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.background(backgroundColor)
|
||||||
|
.padding(16.dp)
|
||||||
) {
|
) {
|
||||||
Row(
|
Row(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.padding(8.dp),
|
.fillMaxWidth()
|
||||||
horizontalArrangement = Arrangement.spacedBy(8.dp)
|
.padding(vertical = 8.dp),
|
||||||
|
horizontalArrangement = Arrangement.spacedBy(8.dp, pageIndicatorAlignment),
|
||||||
) {
|
) {
|
||||||
repeat(pagesCount) {
|
repeat(pagerState.pageCount) {
|
||||||
ADot(color = if (it == state) contentColor else disabledContentColor)
|
PageDot(if (it == pagerState.currentPage) contentColor else disabledContentColor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pageContent(state)
|
|
||||||
|
HorizontalPager(
|
||||||
|
modifier = Modifier
|
||||||
|
.animateContentSize()
|
||||||
|
.fillMaxWidth(),
|
||||||
|
verticalAlignment = Alignment.Top,
|
||||||
|
state = pagerState
|
||||||
|
) { page ->
|
||||||
|
pageContent(page)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun ADot(
|
private fun PageDot(
|
||||||
color: Color,
|
color: Color,
|
||||||
) {
|
) {
|
||||||
Canvas(modifier = Modifier.size(4.dp)) {
|
Canvas(modifier = Modifier.size(4.dp)) {
|
||||||
@ -98,11 +119,16 @@ private fun ADot(
|
|||||||
@Preview
|
@Preview
|
||||||
@Composable
|
@Composable
|
||||||
private fun PreviewPagedIsland() {
|
private fun PreviewPagedIsland() {
|
||||||
PagedIsland(pagesCount = 5) { currentPage ->
|
PagedIsland(
|
||||||
|
modifier = Modifier.size(400.dp, 250.dp),
|
||||||
|
pagerState = rememberPagerState { 5 }
|
||||||
|
) { currentPage ->
|
||||||
|
Column {
|
||||||
Text("Current page: $currentPage")
|
Text("Current page: $currentPage")
|
||||||
|
|
||||||
if (currentPage == 3) {
|
if (currentPage == 3) {
|
||||||
Text("Middle in: $currentPage")
|
Text("Middle in: $currentPage")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,11 +20,14 @@ package com.sadellie.unitto.feature.datecalculator.components
|
|||||||
|
|
||||||
import androidx.annotation.StringRes
|
import androidx.annotation.StringRes
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.pager.rememberPagerState
|
||||||
import androidx.compose.foundation.text.selection.SelectionContainer
|
import androidx.compose.foundation.text.selection.SelectionContainer
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.platform.LocalFocusManager
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
import com.sadellie.unitto.core.base.R
|
import com.sadellie.unitto.core.base.R
|
||||||
@ -38,13 +41,20 @@ internal fun DateTimeResultBlock(
|
|||||||
diff: ZonedDateTimeDifference.Default,
|
diff: ZonedDateTimeDifference.Default,
|
||||||
format: (BigDecimal) -> String
|
format: (BigDecimal) -> String
|
||||||
) {
|
) {
|
||||||
|
val focusManager = LocalFocusManager.current
|
||||||
|
|
||||||
PagedIsland(
|
PagedIsland(
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
pagesCount = 6,
|
pagerState = rememberPagerState { 6 },
|
||||||
|
onClick = { focusManager.clearFocus() },
|
||||||
backgroundColor = MaterialTheme.colorScheme.tertiaryContainer
|
backgroundColor = MaterialTheme.colorScheme.tertiaryContainer
|
||||||
) { currentPage ->
|
) { currentPage ->
|
||||||
when(currentPage) {
|
when(currentPage) {
|
||||||
0 -> {
|
0 -> {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
) {
|
||||||
Text(
|
Text(
|
||||||
text = stringResource(R.string.date_calculator_difference),
|
text = stringResource(R.string.date_calculator_difference),
|
||||||
style = MaterialTheme.typography.labelMedium
|
style = MaterialTheme.typography.labelMedium
|
||||||
@ -78,8 +88,10 @@ internal fun DateTimeResultBlock(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
1 -> {
|
1 -> {
|
||||||
|
Column {
|
||||||
Text(
|
Text(
|
||||||
text = stringResource(R.string.date_calculator_years),
|
text = stringResource(R.string.date_calculator_years),
|
||||||
style = MaterialTheme.typography.labelMedium
|
style = MaterialTheme.typography.labelMedium
|
||||||
@ -88,8 +100,10 @@ internal fun DateTimeResultBlock(
|
|||||||
DateText(diff.sumYears, format)
|
DateText(diff.sumYears, format)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
2 -> {
|
2 -> {
|
||||||
|
Column {
|
||||||
Text(
|
Text(
|
||||||
text = stringResource(R.string.date_calculator_months),
|
text = stringResource(R.string.date_calculator_months),
|
||||||
style = MaterialTheme.typography.labelMedium
|
style = MaterialTheme.typography.labelMedium
|
||||||
@ -98,8 +112,10 @@ internal fun DateTimeResultBlock(
|
|||||||
DateText(diff.sumMonths, format)
|
DateText(diff.sumMonths, format)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
3 -> {
|
3 -> {
|
||||||
|
Column {
|
||||||
Text(
|
Text(
|
||||||
text = stringResource(R.string.date_calculator_days),
|
text = stringResource(R.string.date_calculator_days),
|
||||||
style = MaterialTheme.typography.labelMedium
|
style = MaterialTheme.typography.labelMedium
|
||||||
@ -108,8 +124,10 @@ internal fun DateTimeResultBlock(
|
|||||||
DateText(diff.sumDays, format)
|
DateText(diff.sumDays, format)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
4 -> {
|
4 -> {
|
||||||
|
Column {
|
||||||
Text(
|
Text(
|
||||||
text = stringResource(R.string.date_calculator_hours),
|
text = stringResource(R.string.date_calculator_hours),
|
||||||
style = MaterialTheme.typography.labelMedium
|
style = MaterialTheme.typography.labelMedium
|
||||||
@ -118,8 +136,10 @@ internal fun DateTimeResultBlock(
|
|||||||
DateText(diff.sumHours, format)
|
DateText(diff.sumHours, format)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
5 -> {
|
5 -> {
|
||||||
|
Column {
|
||||||
Text(
|
Text(
|
||||||
text = stringResource(R.string.date_calculator_minutes),
|
text = stringResource(R.string.date_calculator_minutes),
|
||||||
style = MaterialTheme.typography.labelMedium
|
style = MaterialTheme.typography.labelMedium
|
||||||
@ -130,6 +150,7 @@ internal fun DateTimeResultBlock(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
|
@ -21,10 +21,13 @@ package com.sadellie.unitto.feature.datecalculator.difference
|
|||||||
import androidx.compose.animation.AnimatedContent
|
import androidx.compose.animation.AnimatedContent
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.FlowRow
|
import androidx.compose.foundation.layout.FlowRow
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.rememberScrollState
|
||||||
|
import androidx.compose.foundation.verticalScroll
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
@ -47,6 +50,7 @@ import com.sadellie.unitto.feature.datecalculator.components.DateTimeDialogs
|
|||||||
import com.sadellie.unitto.feature.datecalculator.components.DateTimeResultBlock
|
import com.sadellie.unitto.feature.datecalculator.components.DateTimeResultBlock
|
||||||
import com.sadellie.unitto.feature.datecalculator.components.DateTimeSelectorBlock
|
import com.sadellie.unitto.feature.datecalculator.components.DateTimeSelectorBlock
|
||||||
import com.sadellie.unitto.feature.datecalculator.components.DialogState
|
import com.sadellie.unitto.feature.datecalculator.components.DialogState
|
||||||
|
import java.math.BigDecimal
|
||||||
import java.time.ZonedDateTime
|
import java.time.ZonedDateTime
|
||||||
import java.time.temporal.ChronoUnit
|
import java.time.temporal.ChronoUnit
|
||||||
|
|
||||||
@ -72,10 +76,16 @@ private fun DateDifferenceView(
|
|||||||
) {
|
) {
|
||||||
var dialogState by remember { mutableStateOf(DialogState.NONE) }
|
var dialogState by remember { mutableStateOf(DialogState.NONE) }
|
||||||
|
|
||||||
FlowRow(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
.padding(16.dp),
|
.verticalScroll(rememberScrollState()),
|
||||||
|
verticalArrangement = Arrangement.spacedBy(8.dp)
|
||||||
|
) {
|
||||||
|
FlowRow(
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(top = 16.dp, start = 16.dp, end = 16.dp)
|
||||||
|
.fillMaxWidth(),
|
||||||
maxItemsInEachRow = 2,
|
maxItemsInEachRow = 2,
|
||||||
verticalArrangement = Arrangement.spacedBy(8.dp),
|
verticalArrangement = Arrangement.spacedBy(8.dp),
|
||||||
horizontalArrangement = Arrangement.spacedBy(8.dp)
|
horizontalArrangement = Arrangement.spacedBy(8.dp)
|
||||||
@ -107,15 +117,18 @@ private fun DateDifferenceView(
|
|||||||
onDateClick = { dialogState = DialogState.TO_DATE },
|
onDateClick = { dialogState = DialogState.TO_DATE },
|
||||||
containerColor = MaterialTheme.colorScheme.secondaryContainer
|
containerColor = MaterialTheme.colorScheme.secondaryContainer
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
|
||||||
AnimatedContent(
|
AnimatedContent(
|
||||||
targetState = uiState.result,
|
targetState = uiState.result,
|
||||||
modifier = Modifier.weight(2f)
|
modifier = Modifier.fillMaxWidth()
|
||||||
) { result ->
|
) { result ->
|
||||||
when (result) {
|
when (result) {
|
||||||
is ZonedDateTimeDifference.Default -> {
|
is ZonedDateTimeDifference.Default -> {
|
||||||
DateTimeResultBlock(
|
DateTimeResultBlock(
|
||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier
|
||||||
|
.padding(horizontal = 16.dp)
|
||||||
|
.fillMaxWidth(),
|
||||||
diff = result,
|
diff = result,
|
||||||
format = {
|
format = {
|
||||||
it.format(uiState.precision, uiState.outputFormat)
|
it.format(uiState.precision, uiState.outputFormat)
|
||||||
@ -157,7 +170,18 @@ fun DateDifferenceViewPreview() {
|
|||||||
uiState = DifferenceUIState.Ready(
|
uiState = DifferenceUIState.Ready(
|
||||||
start = ZonedDateTimeUtils.nowWithMinutes(),
|
start = ZonedDateTimeUtils.nowWithMinutes(),
|
||||||
end = ZonedDateTimeUtils.nowWithMinutes().truncatedTo(ChronoUnit.MINUTES),
|
end = ZonedDateTimeUtils.nowWithMinutes().truncatedTo(ChronoUnit.MINUTES),
|
||||||
result = ZonedDateTimeDifference.Zero,
|
result = ZonedDateTimeDifference.Default(
|
||||||
|
years = 1,
|
||||||
|
months = 2,
|
||||||
|
days = 3,
|
||||||
|
hours = 4,
|
||||||
|
minutes = 5,
|
||||||
|
sumYears = BigDecimal("0.083"),
|
||||||
|
sumMonths = BigDecimal("1.000"),
|
||||||
|
sumDays = BigDecimal("30.000"),
|
||||||
|
sumHours = BigDecimal("720.000"),
|
||||||
|
sumMinutes = BigDecimal("43200.000"),
|
||||||
|
),
|
||||||
precision = 3,
|
precision = 3,
|
||||||
outputFormat = OutputFormat.PLAIN,
|
outputFormat = OutputFormat.PLAIN,
|
||||||
formatterSymbols = FormatterSymbols.Spaces
|
formatterSymbols = FormatterSymbols.Spaces
|
||||||
|
@ -25,6 +25,7 @@ import androidx.compose.foundation.layout.fillMaxWidth
|
|||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.wrapContentWidth
|
import androidx.compose.foundation.layout.wrapContentWidth
|
||||||
import androidx.compose.foundation.lazy.LazyColumn
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
|
import androidx.compose.foundation.pager.rememberPagerState
|
||||||
import androidx.compose.foundation.rememberScrollState
|
import androidx.compose.foundation.rememberScrollState
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.filled.Architecture
|
import androidx.compose.material.icons.filled.Architecture
|
||||||
@ -122,7 +123,7 @@ fun FormattingScreen(
|
|||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.padding(16.dp),
|
.padding(16.dp),
|
||||||
pagesCount = 2,
|
pagerState = rememberPagerState { 2 },
|
||||||
) { currentPage ->
|
) { currentPage ->
|
||||||
val preview = when (currentPage) {
|
val preview = when (currentPage) {
|
||||||
0 -> "123456.${"789123456".repeat(ceil(uiState.precision.toDouble() / 9.0).toInt())}"
|
0 -> "123456.${"789123456".repeat(ceil(uiState.precision.toDouble() / 9.0).toInt())}"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user