mirror of
https://github.com/Myzel394/NumberHub.git
synced 2025-06-19 00:35:26 +02:00
Use dots to indicate pages
This commit is contained in:
parent
4305354931
commit
4e77eaf01c
@ -0,0 +1,108 @@
|
||||
/*
|
||||
* Unitto is a unit converter for Android
|
||||
* Copyright (c) 2023 Elshan Agaev
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sadellie.unitto.core.ui.common
|
||||
|
||||
import androidx.annotation.IntRange
|
||||
import androidx.compose.animation.AnimatedContent
|
||||
import androidx.compose.foundation.Canvas
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.ColumnScope
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.contentColorFor
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableIntStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
||||
@Composable
|
||||
fun PagedIsland(
|
||||
modifier: Modifier = Modifier,
|
||||
@IntRange(from = 1) pagesCount: Int,
|
||||
onPageChange: (currentPage: Int) -> Unit = {},
|
||||
backgroundColor: Color = MaterialTheme.colorScheme.secondaryContainer,
|
||||
pageContent: @Composable ColumnScope.(currentPage: Int) -> Unit,
|
||||
) {
|
||||
var currentPage: Int by remember { mutableIntStateOf(0) }
|
||||
val contentColor = MaterialTheme.colorScheme.contentColorFor(backgroundColor)
|
||||
val disabledContentColor = contentColor.copy(alpha = 0.5f)
|
||||
|
||||
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) {
|
||||
Column(
|
||||
modifier = Modifier.padding(16.dp)
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.padding(8.dp),
|
||||
horizontalArrangement = Arrangement.spacedBy(8.dp)
|
||||
) {
|
||||
repeat(pagesCount) {
|
||||
ADot(color = if (it == state) contentColor else disabledContentColor)
|
||||
}
|
||||
}
|
||||
pageContent(state)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ADot(
|
||||
color: Color,
|
||||
) {
|
||||
Canvas(modifier = Modifier.size(4.dp)) {
|
||||
drawCircle(color)
|
||||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
private fun PreviewPagedIsland() {
|
||||
PagedIsland(pagesCount = 5) { currentPage ->
|
||||
Text("Current page: $currentPage")
|
||||
|
||||
if (currentPage == 3) {
|
||||
Text("Middle in: $currentPage")
|
||||
}
|
||||
}
|
||||
}
|
@ -18,11 +18,8 @@
|
||||
|
||||
package com.sadellie.unitto.feature.settings.formatting
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.horizontalScroll
|
||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
@ -55,15 +52,18 @@ import com.sadellie.unitto.core.base.OutputFormat
|
||||
import com.sadellie.unitto.core.base.R
|
||||
import com.sadellie.unitto.core.base.Separator
|
||||
import com.sadellie.unitto.core.ui.common.NavigateUpButton
|
||||
import com.sadellie.unitto.core.ui.common.PagedIsland
|
||||
import com.sadellie.unitto.core.ui.common.SegmentedButton
|
||||
import com.sadellie.unitto.core.ui.common.SegmentedButtonsRow
|
||||
import com.sadellie.unitto.core.ui.common.UnittoEmptyScreen
|
||||
import com.sadellie.unitto.core.ui.common.UnittoListItem
|
||||
import com.sadellie.unitto.core.ui.common.UnittoScreenWithLargeTopBar
|
||||
import com.sadellie.unitto.core.ui.common.UnittoSlider
|
||||
import com.sadellie.unitto.core.ui.common.squashable
|
||||
import com.sadellie.unitto.core.ui.common.textfield.FormatterSymbols
|
||||
import com.sadellie.unitto.core.ui.common.textfield.formatExpression
|
||||
import com.sadellie.unitto.core.ui.theme.NumberTypographyUnitto
|
||||
import com.sadellie.unitto.data.common.format
|
||||
import kotlin.math.ceil
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
@Composable
|
||||
@ -80,7 +80,6 @@ fun FormattingRoute(
|
||||
onPrecisionChange = viewModel::updatePrecision,
|
||||
onSeparatorChange = viewModel::updateSeparator,
|
||||
onOutputFormatChange = viewModel::updateOutputFormat,
|
||||
togglePreview = viewModel::togglePreview
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -93,7 +92,6 @@ fun FormattingScreen(
|
||||
onPrecisionChange: (Int) -> Unit,
|
||||
onSeparatorChange: (Int) -> Unit,
|
||||
onOutputFormatChange: (Int) -> Unit,
|
||||
togglePreview: () -> Unit,
|
||||
precisions: ClosedFloatingPointRange<Float> = 0f..16f, // 16th is a MAX_PRECISION (1000)
|
||||
) {
|
||||
val resources = LocalContext.current.resources
|
||||
@ -120,25 +118,24 @@ fun FormattingScreen(
|
||||
.padding(paddingValues)
|
||||
) {
|
||||
item("preview") {
|
||||
Column(
|
||||
Modifier
|
||||
.padding(16.dp)
|
||||
.squashable(
|
||||
onClick = togglePreview,
|
||||
cornerRadiusRange = 8.dp..32.dp,
|
||||
interactionSource = remember { MutableInteractionSource() }
|
||||
)
|
||||
.background(MaterialTheme.colorScheme.secondaryContainer)
|
||||
PagedIsland(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(16.dp)
|
||||
) {
|
||||
.padding(16.dp),
|
||||
pagesCount = 2,
|
||||
) { currentPage ->
|
||||
val preview = when (currentPage) {
|
||||
0 -> "123456.${"789123456".repeat(ceil(uiState.precision.toDouble() / 9.0).toInt())}"
|
||||
1 -> "0.${"1".padStart(uiState.precision, '0')}"
|
||||
else -> ""
|
||||
}
|
||||
.toBigDecimalOrNull()
|
||||
?.format(uiState.precision, uiState.outputFormat)
|
||||
?.formatExpression(uiState.formatterSymbols)
|
||||
?: ""
|
||||
|
||||
Text(
|
||||
text = stringResource(R.string.settings_formatting_preview),
|
||||
style = MaterialTheme.typography.labelMedium,
|
||||
color = MaterialTheme.colorScheme.onSecondaryContainer
|
||||
)
|
||||
Text(
|
||||
text = uiState.preview,
|
||||
text = preview,
|
||||
style = NumberTypographyUnitto.displayMedium,
|
||||
maxLines = 1,
|
||||
modifier = Modifier
|
||||
@ -153,7 +150,10 @@ fun FormattingScreen(
|
||||
item("precision_label") {
|
||||
UnittoListItem(
|
||||
leadingContent = {
|
||||
Icon(Icons.Default.Architecture, stringResource(R.string.settings_precision))
|
||||
Icon(
|
||||
Icons.Default.Architecture,
|
||||
stringResource(R.string.settings_precision)
|
||||
)
|
||||
},
|
||||
headlineContent = {
|
||||
Row(
|
||||
@ -265,15 +265,14 @@ private fun PreviewFormattingScreen() {
|
||||
|
||||
FormattingScreen(
|
||||
uiState = FormattingUIState(
|
||||
preview = "123456.789",
|
||||
precision = 16,
|
||||
separator = Separator.SPACE,
|
||||
outputFormat = OutputFormat.PLAIN
|
||||
outputFormat = OutputFormat.PLAIN,
|
||||
formatterSymbols = FormatterSymbols.Spaces
|
||||
),
|
||||
onPrecisionChange = { currentPrecision = it },
|
||||
onSeparatorChange = { currentSeparator = it },
|
||||
onOutputFormatChange = { currentOutputFormat = it },
|
||||
navigateUpAction = {},
|
||||
togglePreview = {}
|
||||
)
|
||||
}
|
||||
|
@ -21,9 +21,8 @@ package com.sadellie.unitto.feature.settings.formatting
|
||||
import com.sadellie.unitto.core.ui.common.textfield.FormatterSymbols
|
||||
|
||||
data class FormattingUIState(
|
||||
val preview: String = "",
|
||||
val precision: Int = 0,
|
||||
val separator: Int? = null,
|
||||
val outputFormat: Int? = null,
|
||||
val formatterSymbols: FormatterSymbols = FormatterSymbols.Spaces
|
||||
val precision: Int,
|
||||
val separator: Int,
|
||||
val outputFormat: Int,
|
||||
val formatterSymbols: FormatterSymbols,
|
||||
)
|
||||
|
@ -22,64 +22,29 @@ import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.sadellie.unitto.core.base.MAX_PRECISION
|
||||
import com.sadellie.unitto.core.ui.common.textfield.AllFormatterSymbols
|
||||
import com.sadellie.unitto.core.ui.common.textfield.FormatterSymbols
|
||||
import com.sadellie.unitto.core.ui.common.textfield.formatExpression
|
||||
import com.sadellie.unitto.data.common.format
|
||||
import com.sadellie.unitto.data.common.stateIn
|
||||
import com.sadellie.unitto.data.model.repository.UserPreferencesRepository
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.update
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.launch
|
||||
import java.math.BigDecimal
|
||||
import javax.inject.Inject
|
||||
import kotlin.math.ceil
|
||||
|
||||
@HiltViewModel
|
||||
class FormattingViewModel @Inject constructor(
|
||||
private val userPreferencesRepository: UserPreferencesRepository
|
||||
) : ViewModel() {
|
||||
private val _prefs = userPreferencesRepository.formattingPrefs
|
||||
private val _fractional = MutableStateFlow(false)
|
||||
|
||||
val uiState = combine(_prefs, _fractional) { mainPrefs, fractional ->
|
||||
val formatterSymbols = AllFormatterSymbols.getById(mainPrefs.separator)
|
||||
|
||||
return@combine FormattingUIState(
|
||||
preview = updatePreview(
|
||||
fractional = fractional,
|
||||
precision = mainPrefs.digitsPrecision,
|
||||
outputFormat = mainPrefs.outputFormat,
|
||||
formatterSymbols = formatterSymbols
|
||||
),
|
||||
val uiState = _prefs.map { mainPrefs ->
|
||||
FormattingUIState(
|
||||
precision = mainPrefs.digitsPrecision,
|
||||
separator = mainPrefs.separator,
|
||||
outputFormat = mainPrefs.outputFormat,
|
||||
formatterSymbols = formatterSymbols
|
||||
formatterSymbols = AllFormatterSymbols.getById(mainPrefs.separator)
|
||||
)
|
||||
}
|
||||
.stateIn(viewModelScope, null)
|
||||
|
||||
fun togglePreview() = _fractional.update { !it }
|
||||
|
||||
private fun updatePreview(
|
||||
fractional: Boolean,
|
||||
precision: Int,
|
||||
outputFormat: Int,
|
||||
formatterSymbols: FormatterSymbols
|
||||
): String {
|
||||
val bigD = when {
|
||||
fractional -> "0.${"1".padStart(precision, '0')}"
|
||||
precision > 0 -> "123456.${"789123456".repeat(ceil(precision.toDouble() / 9.0).toInt())}"
|
||||
else -> "123456"
|
||||
}
|
||||
|
||||
return BigDecimal(bigD)
|
||||
.format(precision, outputFormat)
|
||||
.formatExpression(formatterSymbols)
|
||||
}
|
||||
|
||||
/**
|
||||
* @see UserPreferencesRepository.updateDigitsPrecision
|
||||
*/
|
||||
|
Loading…
x
Reference in New Issue
Block a user