parent
7f512f70fd
commit
035199d74c
@ -45,8 +45,6 @@ actual fun LeMOdelBottomSheet(
|
|||||||
ModalBottomSheet(
|
ModalBottomSheet(
|
||||||
onDismissRequest = onDismissRequest,
|
onDismissRequest = onDismissRequest,
|
||||||
sheetState = bottomSheetState,
|
sheetState = bottomSheetState,
|
||||||
windowInsets = WindowInsets.systemBars
|
|
||||||
.only(WindowInsetsSides.Top),
|
|
||||||
content = {
|
content = {
|
||||||
content(contentPadding)
|
content(contentPadding)
|
||||||
},
|
},
|
||||||
|
@ -145,7 +145,7 @@ fun UrlFlatTextField(
|
|||||||
placeholder = placeholder,
|
placeholder = placeholder,
|
||||||
value = value,
|
value = value,
|
||||||
keyboardOptions = keyboardOptions.copy(
|
keyboardOptions = keyboardOptions.copy(
|
||||||
autoCorrect = false,
|
autoCorrectEnabled = false,
|
||||||
keyboardType = KeyboardType.Uri,
|
keyboardType = KeyboardType.Uri,
|
||||||
),
|
),
|
||||||
keyboardActions = keyboardActions,
|
keyboardActions = keyboardActions,
|
||||||
@ -188,7 +188,7 @@ fun EmailFlatTextField(
|
|||||||
placeholder = placeholder,
|
placeholder = placeholder,
|
||||||
value = value,
|
value = value,
|
||||||
keyboardOptions = keyboardOptions.copy(
|
keyboardOptions = keyboardOptions.copy(
|
||||||
autoCorrect = false,
|
autoCorrectEnabled = false,
|
||||||
keyboardType = KeyboardType.Email,
|
keyboardType = KeyboardType.Email,
|
||||||
),
|
),
|
||||||
keyboardActions = keyboardActions,
|
keyboardActions = keyboardActions,
|
||||||
@ -231,7 +231,7 @@ fun PasswordFlatTextField(
|
|||||||
placeholder = placeholder,
|
placeholder = placeholder,
|
||||||
value = value,
|
value = value,
|
||||||
keyboardOptions = keyboardOptions.copy(
|
keyboardOptions = keyboardOptions.copy(
|
||||||
autoCorrect = false,
|
autoCorrectEnabled = false,
|
||||||
keyboardType = KeyboardType.Password,
|
keyboardType = KeyboardType.Password,
|
||||||
),
|
),
|
||||||
keyboardActions = keyboardActions,
|
keyboardActions = keyboardActions,
|
||||||
|
@ -3,14 +3,13 @@ package com.artemchep.keyguard.ui.text
|
|||||||
import androidx.compose.foundation.layout.BoxWithConstraints
|
import androidx.compose.foundation.layout.BoxWithConstraints
|
||||||
import androidx.compose.foundation.layout.BoxWithConstraintsScope
|
import androidx.compose.foundation.layout.BoxWithConstraintsScope
|
||||||
import androidx.compose.foundation.text.InlineTextContent
|
import androidx.compose.foundation.text.InlineTextContent
|
||||||
import androidx.compose.foundation.text.InternalFoundationTextApi
|
|
||||||
import androidx.compose.foundation.text.TextDelegate
|
|
||||||
import androidx.compose.material3.LocalContentColor
|
import androidx.compose.material3.LocalContentColor
|
||||||
import androidx.compose.material3.LocalTextStyle
|
import androidx.compose.material3.LocalTextStyle
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.CompositionLocalProvider
|
import androidx.compose.runtime.CompositionLocalProvider
|
||||||
import androidx.compose.runtime.Immutable
|
import androidx.compose.runtime.Immutable
|
||||||
|
import androidx.compose.runtime.Stable
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
@ -29,6 +28,7 @@ import androidx.compose.ui.text.TextStyle
|
|||||||
import androidx.compose.ui.text.font.FontFamily
|
import androidx.compose.ui.text.font.FontFamily
|
||||||
import androidx.compose.ui.text.font.FontStyle
|
import androidx.compose.ui.text.font.FontStyle
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
|
import androidx.compose.ui.text.rememberTextMeasurer
|
||||||
import androidx.compose.ui.text.style.TextAlign
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
import androidx.compose.ui.text.style.TextDecoration
|
import androidx.compose.ui.text.style.TextDecoration
|
||||||
import androidx.compose.ui.text.style.TextOverflow
|
import androidx.compose.ui.text.style.TextOverflow
|
||||||
@ -40,14 +40,16 @@ import androidx.compose.ui.unit.IntOffset
|
|||||||
import androidx.compose.ui.unit.IntSize
|
import androidx.compose.ui.unit.IntSize
|
||||||
import androidx.compose.ui.unit.LayoutDirection
|
import androidx.compose.ui.unit.LayoutDirection
|
||||||
import androidx.compose.ui.unit.TextUnit
|
import androidx.compose.ui.unit.TextUnit
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.unit.isSpecified
|
import androidx.compose.ui.unit.isSpecified
|
||||||
import com.artemchep.keyguard.ui.text.SuggestedFontSizesStatus.Companion.rememberSuggestedFontSizesStatus
|
import com.artemchep.keyguard.ui.text.SuggestedFontSizesStatus.Companion.validSuggestedFontSizes
|
||||||
import kotlin.math.min
|
import kotlin.math.min
|
||||||
|
import kotlin.math.roundToInt
|
||||||
import kotlin.reflect.KProperty
|
import kotlin.reflect.KProperty
|
||||||
|
|
||||||
// Code is based on the
|
// Code is based on the
|
||||||
// https://gist.github.com/inidamleader/b594d35362ebcf3cedf81055df519300
|
// https://gist.github.com/inidamleader/b594d35362ebcf3cedf81055df519300
|
||||||
// and is under "no licence for this code, you can use it without problem" :)
|
// and is under "MIT License"
|
||||||
//
|
//
|
||||||
// Thanks!
|
// Thanks!
|
||||||
|
|
||||||
@ -67,7 +69,7 @@ import kotlin.reflect.KProperty
|
|||||||
* this will be [LocalContentColor].
|
* this will be [LocalContentColor].
|
||||||
* @param suggestedFontSizes The suggested font sizes to choose from (Should be sorted from smallest to largest, not empty and contains only sp text unit).
|
* @param suggestedFontSizes The suggested font sizes to choose from (Should be sorted from smallest to largest, not empty and contains only sp text unit).
|
||||||
* @param suggestedFontSizesStatus Whether or not suggestedFontSizes is valid: not empty - contains oly sp text unit - sorted.
|
* @param suggestedFontSizesStatus Whether or not suggestedFontSizes is valid: not empty - contains oly sp text unit - sorted.
|
||||||
* You can check validity by invoking [List<TextUnit>.suggestedFontSizesStatus]
|
* You can check validity by invoking [List<TextUnit>.suggestedFontSizesStatus].
|
||||||
* @param stepGranularityTextSize The step size for adjusting the text size. this parameter is ignored if [suggestedFontSizes] is specified and [suggestedFontSizesStatus] is [SuggestedFontSizesStatus.VALID].
|
* @param stepGranularityTextSize The step size for adjusting the text size. this parameter is ignored if [suggestedFontSizes] is specified and [suggestedFontSizesStatus] is [SuggestedFontSizesStatus.VALID].
|
||||||
* @param minTextSize The minimum text size allowed. this parameter is ignored if [suggestedFontSizes] is specified or [suggestedFontSizesStatus] is [SuggestedFontSizesStatus.VALID].
|
* @param minTextSize The minimum text size allowed. this parameter is ignored if [suggestedFontSizes] is specified or [suggestedFontSizesStatus] is [SuggestedFontSizesStatus.VALID].
|
||||||
* @param maxTextSize The maximum text size allowed.
|
* @param maxTextSize The maximum text size allowed.
|
||||||
@ -95,7 +97,7 @@ import kotlin.reflect.KProperty
|
|||||||
* text, baselines and other details. The callback can be used to add additional decoration or
|
* text, baselines and other details. The callback can be used to add additional decoration or
|
||||||
* functionality to the text. For example, to draw selection around the text.
|
* functionality to the text. For example, to draw selection around the text.
|
||||||
* @param style style configuration for the text such as color, font, line height etc.
|
* @param style style configuration for the text such as color, font, line height etc.
|
||||||
* @param lineSpacingRatio The ratio of line spacing to text size.
|
* @param lineSpaceRatio The ratio of line spacing to text size.
|
||||||
*
|
*
|
||||||
* @author Reda El Madini - For support, contact gladiatorkilo@gmail.com
|
* @author Reda El Madini - For support, contact gladiatorkilo@gmail.com
|
||||||
*/
|
*/
|
||||||
@ -104,8 +106,8 @@ fun AutoSizeText(
|
|||||||
text: String,
|
text: String,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
color: Color = Color.Unspecified,
|
color: Color = Color.Unspecified,
|
||||||
suggestedFontSizes: ImmutableWrapper<List<TextUnit>> = emptyList<TextUnit>().toImmutableWrapper(),
|
suggestedFontSizes: List<TextUnit> = emptyList(),
|
||||||
suggestedFontSizesStatus: SuggestedFontSizesStatus = suggestedFontSizes.rememberSuggestedFontSizesStatus,
|
suggestedFontSizesStatus: SuggestedFontSizesStatus = SuggestedFontSizesStatus.UNKNOWN,
|
||||||
stepGranularityTextSize: TextUnit = TextUnit.Unspecified,
|
stepGranularityTextSize: TextUnit = TextUnit.Unspecified,
|
||||||
minTextSize: TextUnit = TextUnit.Unspecified,
|
minTextSize: TextUnit = TextUnit.Unspecified,
|
||||||
maxTextSize: TextUnit = TextUnit.Unspecified,
|
maxTextSize: TextUnit = TextUnit.Unspecified,
|
||||||
@ -121,7 +123,7 @@ fun AutoSizeText(
|
|||||||
minLines: Int = 1,
|
minLines: Int = 1,
|
||||||
onTextLayout: (TextLayoutResult) -> Unit = {},
|
onTextLayout: (TextLayoutResult) -> Unit = {},
|
||||||
style: TextStyle = LocalTextStyle.current,
|
style: TextStyle = LocalTextStyle.current,
|
||||||
lineSpacingRatio: Float = style.lineHeight.value / style.fontSize.value,
|
lineSpaceRatio: Float = style.lineHeight.value / style.fontSize.value,
|
||||||
) {
|
) {
|
||||||
AutoSizeText(
|
AutoSizeText(
|
||||||
text = AnnotatedString(text),
|
text = AnnotatedString(text),
|
||||||
@ -144,7 +146,7 @@ fun AutoSizeText(
|
|||||||
minLines = minLines,
|
minLines = minLines,
|
||||||
onTextLayout = onTextLayout,
|
onTextLayout = onTextLayout,
|
||||||
style = style,
|
style = style,
|
||||||
lineSpacingRatio = lineSpacingRatio,
|
lineSpacingRatio = lineSpaceRatio,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -163,8 +165,8 @@ fun AutoSizeText(
|
|||||||
text: AnnotatedString,
|
text: AnnotatedString,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
color: Color = Color.Unspecified,
|
color: Color = Color.Unspecified,
|
||||||
suggestedFontSizes: ImmutableWrapper<List<TextUnit>> = emptyList<TextUnit>().toImmutableWrapper(),
|
suggestedFontSizes: List<TextUnit> = emptyList(),
|
||||||
suggestedFontSizesStatus: SuggestedFontSizesStatus = suggestedFontSizes.rememberSuggestedFontSizesStatus,
|
suggestedFontSizesStatus: SuggestedFontSizesStatus = SuggestedFontSizesStatus.UNKNOWN,
|
||||||
stepGranularityTextSize: TextUnit = TextUnit.Unspecified,
|
stepGranularityTextSize: TextUnit = TextUnit.Unspecified,
|
||||||
minTextSize: TextUnit = TextUnit.Unspecified,
|
minTextSize: TextUnit = TextUnit.Unspecified,
|
||||||
maxTextSize: TextUnit = TextUnit.Unspecified,
|
maxTextSize: TextUnit = TextUnit.Unspecified,
|
||||||
@ -178,15 +180,14 @@ fun AutoSizeText(
|
|||||||
softWrap: Boolean = true,
|
softWrap: Boolean = true,
|
||||||
maxLines: Int = Int.MAX_VALUE,
|
maxLines: Int = Int.MAX_VALUE,
|
||||||
minLines: Int = 1,
|
minLines: Int = 1,
|
||||||
inlineContent: ImmutableWrapper<Map<String, InlineTextContent>> = mapOf<String, InlineTextContent>().toImmutableWrapper(),
|
inlineContent: Map<String, InlineTextContent> = mapOf(),
|
||||||
onTextLayout: (TextLayoutResult) -> Unit = {},
|
onTextLayout: (TextLayoutResult) -> Unit = {},
|
||||||
style: TextStyle = LocalTextStyle.current,
|
style: TextStyle = LocalTextStyle.current,
|
||||||
lineSpacingRatio: Float = style.lineHeight.value / style.fontSize.value,
|
lineSpacingRatio: Float = style.lineHeight.value / style.fontSize.value,
|
||||||
) {
|
) {
|
||||||
// Change font scale to 1F
|
// Change font scale to 1F
|
||||||
CompositionLocalProvider(
|
val newDensity = Density(density = LocalDensity.current.density, fontScale = 1F)
|
||||||
LocalDensity provides Density(density = LocalDensity.current.density, fontScale = 1F)
|
CompositionLocalProvider(LocalDensity provides newDensity) {
|
||||||
) {
|
|
||||||
BoxWithConstraints(
|
BoxWithConstraints(
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
contentAlignment = alignment,
|
contentAlignment = alignment,
|
||||||
@ -209,6 +210,7 @@ fun AutoSizeText(
|
|||||||
val layoutDirection = LocalLayoutDirection.current
|
val layoutDirection = LocalLayoutDirection.current
|
||||||
val density = LocalDensity.current
|
val density = LocalDensity.current
|
||||||
val fontFamilyResolver = LocalFontFamilyResolver.current
|
val fontFamilyResolver = LocalFontFamilyResolver.current
|
||||||
|
val textMeasurer = rememberTextMeasurer()
|
||||||
val coercedLineSpacingRatio = lineSpacingRatio.takeIf { it.isFinite() && it >= 1 } ?: 1F
|
val coercedLineSpacingRatio = lineSpacingRatio.takeIf { it.isFinite() && it >= 1 } ?: 1F
|
||||||
val shouldMoveBackward: (TextUnit) -> Boolean = {
|
val shouldMoveBackward: (TextUnit) -> Boolean = {
|
||||||
shouldShrink(
|
shouldShrink(
|
||||||
@ -217,45 +219,52 @@ fun AutoSizeText(
|
|||||||
fontSize = it,
|
fontSize = it,
|
||||||
lineHeight = it * coercedLineSpacingRatio,
|
lineHeight = it * coercedLineSpacingRatio,
|
||||||
),
|
),
|
||||||
minLines = minLines,
|
|
||||||
maxLines = maxLines,
|
maxLines = maxLines,
|
||||||
softWrap = softWrap,
|
|
||||||
layoutDirection = layoutDirection,
|
layoutDirection = layoutDirection,
|
||||||
|
softWrap = softWrap,
|
||||||
density = density,
|
density = density,
|
||||||
fontFamilyResolver = fontFamilyResolver,
|
fontFamilyResolver = fontFamilyResolver,
|
||||||
|
textMeasurer = textMeasurer,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
val electedFontSize = kotlin.run {
|
val electedFontSize = remember(key1 = suggestedFontSizes) {
|
||||||
if (suggestedFontSizesStatus == SuggestedFontSizesStatus.VALID)
|
if (suggestedFontSizesStatus == SuggestedFontSizesStatus.VALID)
|
||||||
suggestedFontSizes.value
|
suggestedFontSizes
|
||||||
else
|
else
|
||||||
remember(key1 = suggestedFontSizes) {
|
suggestedFontSizes.validSuggestedFontSizes
|
||||||
suggestedFontSizes.value
|
}?.let {
|
||||||
.filter { it.isSp }
|
remember(
|
||||||
.takeIf { it.isNotEmpty() }
|
key1 = it,
|
||||||
?.sortedBy { it.value }
|
key2 = shouldMoveBackward,
|
||||||
|
) {
|
||||||
|
it.findElectedValue(shouldMoveBackward = shouldMoveBackward)
|
||||||
}
|
}
|
||||||
}
|
} ?: run {
|
||||||
?.findElectedValue(shouldMoveBackward = shouldMoveBackward)
|
val candidateFontSizesIntProgress = rememberCandidateFontSizesIntProgress(
|
||||||
?: rememberCandidateFontSizesIntProgress(
|
|
||||||
density = density,
|
density = density,
|
||||||
dpSize = DpSize(maxWidth, maxHeight),
|
containerDpSize = DpSize(maxWidth, maxHeight),
|
||||||
maxTextSize = maxTextSize,
|
maxTextSize = maxTextSize,
|
||||||
minTextSize = minTextSize,
|
minTextSize = minTextSize,
|
||||||
stepGranularityTextSize = stepGranularityTextSize,
|
stepGranularityTextSize = stepGranularityTextSize,
|
||||||
).findElectedValue(
|
)
|
||||||
transform = { density.toSp(it) },
|
remember(
|
||||||
|
key1 = candidateFontSizesIntProgress,
|
||||||
|
key2 = shouldMoveBackward,
|
||||||
|
) {
|
||||||
|
candidateFontSizesIntProgress.findElectedValue(
|
||||||
|
transform = { density.intPxToSp(it) },
|
||||||
shouldMoveBackward = shouldMoveBackward,
|
shouldMoveBackward = shouldMoveBackward,
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
Text(
|
Text(
|
||||||
text = text,
|
text = text,
|
||||||
overflow = overflow,
|
overflow = overflow,
|
||||||
softWrap = softWrap,
|
softWrap = softWrap,
|
||||||
maxLines = maxLines,
|
maxLines = maxLines,
|
||||||
minLines = minLines,
|
minLines = minLines,
|
||||||
inlineContent = inlineContent.value,
|
inlineContent = inlineContent,
|
||||||
onTextLayout = onTextLayout,
|
onTextLayout = onTextLayout,
|
||||||
style = combinedTextStyle.copy(
|
style = combinedTextStyle.copy(
|
||||||
fontSize = electedFontSize,
|
fontSize = electedFontSize,
|
||||||
@ -266,32 +275,7 @@ fun AutoSizeText(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@OptIn(InternalFoundationTextApi::class)
|
|
||||||
private fun BoxWithConstraintsScope.shouldShrink(
|
private fun BoxWithConstraintsScope.shouldShrink(
|
||||||
text: AnnotatedString,
|
|
||||||
textStyle: TextStyle,
|
|
||||||
minLines: Int,
|
|
||||||
maxLines: Int,
|
|
||||||
softWrap: Boolean,
|
|
||||||
layoutDirection: LayoutDirection,
|
|
||||||
density: Density,
|
|
||||||
fontFamilyResolver: FontFamily.Resolver,
|
|
||||||
) = TextDelegate(
|
|
||||||
text = text,
|
|
||||||
style = textStyle,
|
|
||||||
maxLines = maxLines,
|
|
||||||
minLines = minLines,
|
|
||||||
softWrap = softWrap,
|
|
||||||
overflow = TextOverflow.Clip,
|
|
||||||
density = density,
|
|
||||||
fontFamilyResolver = fontFamilyResolver,
|
|
||||||
).layout(
|
|
||||||
constraints = constraints,
|
|
||||||
layoutDirection = layoutDirection,
|
|
||||||
).hasVisualOverflow
|
|
||||||
|
|
||||||
|
|
||||||
private fun BoxWithConstraintsScope.shouldShrink2(
|
|
||||||
text: AnnotatedString,
|
text: AnnotatedString,
|
||||||
textStyle: TextStyle,
|
textStyle: TextStyle,
|
||||||
maxLines: Int,
|
maxLines: Int,
|
||||||
@ -312,43 +296,46 @@ private fun BoxWithConstraintsScope.shouldShrink2(
|
|||||||
fontFamilyResolver = fontFamilyResolver,
|
fontFamilyResolver = fontFamilyResolver,
|
||||||
).hasVisualOverflow
|
).hasVisualOverflow
|
||||||
|
|
||||||
|
@Stable
|
||||||
@Composable
|
@Composable
|
||||||
private fun rememberCandidateFontSizesIntProgress(
|
private fun rememberCandidateFontSizesIntProgress(
|
||||||
density: Density,
|
density: Density,
|
||||||
dpSize: DpSize,
|
containerDpSize: DpSize,
|
||||||
minTextSize: TextUnit = TextUnit.Unspecified,
|
minTextSize: TextUnit = TextUnit.Unspecified,
|
||||||
maxTextSize: TextUnit = TextUnit.Unspecified,
|
maxTextSize: TextUnit = TextUnit.Unspecified,
|
||||||
stepGranularityTextSize: TextUnit = TextUnit.Unspecified,
|
stepGranularityTextSize: TextUnit = TextUnit.Unspecified,
|
||||||
): IntProgression {
|
): IntProgression {
|
||||||
val max = remember(key1 = maxTextSize, key2 = dpSize, key3 = density) {
|
val max = remember(key1 = density, key2 = maxTextSize, key3 = containerDpSize) {
|
||||||
val intSize = density.toIntSize(dpSize)
|
val intSize = density.dpSizeRoundToIntSize(containerDpSize)
|
||||||
min(intSize.width, intSize.height).let { max ->
|
min(intSize.width, intSize.height).let { max ->
|
||||||
maxTextSize
|
maxTextSize
|
||||||
.takeIf { it.isSp }
|
.takeIf { it.isSp }
|
||||||
?.let { density.roundToPx(it) }
|
?.let { density.spRoundToPx(it) }
|
||||||
?.coerceIn(range = 0..max)
|
?.coerceIn(range = 0..max)
|
||||||
?: max
|
?: max
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val min = remember(key1 = minTextSize, key2 = max, key3 = density) {
|
val min = remember(key1 = density, key2 = minTextSize, key3 = max) {
|
||||||
minTextSize
|
minTextSize
|
||||||
.takeIf { it.isSp }
|
.takeIf { it.isSp }
|
||||||
?.let { density.roundToPx(it) }
|
?.let { density.spToIntPx(it) }
|
||||||
?.coerceIn(range = 0..max)
|
?.coerceIn(range = 0..max)
|
||||||
?: 0
|
?: 0
|
||||||
}
|
}
|
||||||
|
|
||||||
val step = remember(
|
val step = remember(
|
||||||
stepGranularityTextSize,
|
key1 = listOf(
|
||||||
|
density,
|
||||||
min,
|
min,
|
||||||
max,
|
max,
|
||||||
density,
|
stepGranularityTextSize,
|
||||||
|
)
|
||||||
) {
|
) {
|
||||||
stepGranularityTextSize
|
stepGranularityTextSize
|
||||||
.takeIf { it.isSp }
|
.takeIf { it.isSp }
|
||||||
?.let { density.roundToPx(it) }
|
?.let { density.spToIntPx(it) }
|
||||||
?.coerceIn(minimumValue = 1, maximumValue = max - min)
|
?.coerceIn(1, max - min)
|
||||||
?: 1
|
?: 1
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -358,7 +345,7 @@ private fun rememberCandidateFontSizesIntProgress(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// This function works by using a binary search algorithm
|
// This function works by using a binary search algorithm
|
||||||
fun <E> List<E>.findElectedValue(shouldMoveBackward: (E) -> Boolean) = run {
|
fun <T> List<T>.findElectedValue(shouldMoveBackward: (T) -> Boolean) = run {
|
||||||
indices.findElectedValue(
|
indices.findElectedValue(
|
||||||
transform = { this[it] },
|
transform = { this[it] },
|
||||||
shouldMoveBackward = shouldMoveBackward,
|
shouldMoveBackward = shouldMoveBackward,
|
||||||
@ -366,9 +353,9 @@ fun <E> List<E>.findElectedValue(shouldMoveBackward: (E) -> Boolean) = run {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// This function works by using a binary search algorithm
|
// This function works by using a binary search algorithm
|
||||||
private fun <E> IntProgression.findElectedValue(
|
private fun <T> IntProgression.findElectedValue(
|
||||||
transform: (Int) -> E,
|
transform: (Int) -> T,
|
||||||
shouldMoveBackward: (E) -> Boolean,
|
shouldMoveBackward: (T) -> Boolean,
|
||||||
) = run {
|
) = run {
|
||||||
var low = first / step
|
var low = first / step
|
||||||
var high = last / step
|
var high = last / step
|
||||||
@ -379,7 +366,7 @@ private fun <E> IntProgression.findElectedValue(
|
|||||||
else
|
else
|
||||||
low = mid + 1
|
low = mid + 1
|
||||||
}
|
}
|
||||||
transform((high * step).coerceAtLeast(minimumValue = first * step))
|
transform((high * step).coerceAtLeast(first * step))
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class SuggestedFontSizesStatus {
|
enum class SuggestedFontSizesStatus {
|
||||||
@ -391,11 +378,17 @@ enum class SuggestedFontSizesStatus {
|
|||||||
VALID
|
VALID
|
||||||
else
|
else
|
||||||
INVALID
|
INVALID
|
||||||
val ImmutableWrapper<List<TextUnit>>.rememberSuggestedFontSizesStatus
|
|
||||||
@Composable get() = remember(key1 = this) { value.suggestedFontSizesStatus }
|
val List<TextUnit>.validSuggestedFontSizes
|
||||||
|
get() = takeIf { it.isNotEmpty() } // Optimization: empty check first to immediately return null
|
||||||
|
?.filter { it.isSp }
|
||||||
|
?.takeIf { it.isNotEmpty() }
|
||||||
|
?.sortedBy { it.value }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
|
||||||
@Immutable
|
@Immutable
|
||||||
data class ImmutableWrapper<T>(val value: T)
|
data class ImmutableWrapper<T>(val value: T)
|
||||||
|
|
||||||
@ -403,9 +396,188 @@ fun <T> T.toImmutableWrapper() = ImmutableWrapper(this)
|
|||||||
|
|
||||||
operator fun <T> ImmutableWrapper<T>.getValue(thisRef: Any?, property: KProperty<*>) = value
|
operator fun <T> ImmutableWrapper<T>.getValue(thisRef: Any?, property: KProperty<*>) = value
|
||||||
|
|
||||||
private fun Density.roundToPx(sp: TextUnit): Int = sp.roundToPx()
|
//
|
||||||
|
// Utils
|
||||||
|
//
|
||||||
|
|
||||||
private fun Density.toSp(px: Int): TextUnit = px.toSp()
|
// DP
|
||||||
|
private fun Density.dpToSp(dp: Dp) = if (dp.isSpecified) dp.toSp() else TextUnit.Unspecified
|
||||||
|
|
||||||
private fun Density.toIntSize(dpSize: DpSize): IntSize =
|
private fun Density.dpToFloatPx(dp: Dp) = if (dp.isSpecified) dp.toPx() else Float.NaN
|
||||||
IntSize(dpSize.width.roundToPx(), dpSize.height.roundToPx())
|
|
||||||
|
private fun Density.dpToIntPx(dp: Dp) = if (dp.isSpecified) dp.toPx().toInt() else 0
|
||||||
|
|
||||||
|
private fun Density.dpRoundToPx(dp: Dp) = if (dp.isSpecified) dp.roundToPx() else 0
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun Dp.toSp() = LocalDensity.current.dpToSp(this)
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun Dp.toFloatPx() = LocalDensity.current.dpToFloatPx(this)
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun Dp.toIntPx() = LocalDensity.current.dpToIntPx(this)
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun Dp.roundToPx() = LocalDensity.current.dpRoundToPx(this)
|
||||||
|
|
||||||
|
private fun Dp.toRecDpSize() = if (isSpecified) DpSize(this, this) else DpSize.Unspecified
|
||||||
|
|
||||||
|
private fun Dp.toRecDpOffset() = if (isSpecified) DpOffset(this, this) else DpOffset.Unspecified
|
||||||
|
|
||||||
|
|
||||||
|
// TEXT UNIT
|
||||||
|
private fun Density.spToDp(sp: TextUnit) = if (sp.isSpecified) sp.toDp() else Dp.Unspecified
|
||||||
|
|
||||||
|
private fun Density.spToFloatPx(sp: TextUnit) = if (sp.isSpecified) sp.toPx() else Float.NaN
|
||||||
|
|
||||||
|
private fun Density.spToIntPx(sp: TextUnit) = if (sp.isSpecified) sp.toPx().toInt() else 0
|
||||||
|
|
||||||
|
private fun Density.spRoundToPx(sp: TextUnit) = if (sp.isSpecified) sp.roundToPx() else 0
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun TextUnit.toDp() = LocalDensity.current.spToDp(this)
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun TextUnit.toFloatPx() = LocalDensity.current.spToFloatPx(this)
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun TextUnit.toIntPx() = LocalDensity.current.spToIntPx(this)
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun TextUnit.roundToPx() = LocalDensity.current.spRoundToPx(this)
|
||||||
|
|
||||||
|
|
||||||
|
// FLOAT
|
||||||
|
private fun Density.floatPxToDp(px: Float) = if (px.isFinite()) px.toDp() else Dp.Unspecified
|
||||||
|
|
||||||
|
private fun Density.floatPxToSp(px: Float) = if (px.isFinite()) px.toSp() else TextUnit.Unspecified
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun Float.toDp() = LocalDensity.current.floatPxToDp(this)
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun Float.toSp() = LocalDensity.current.floatPxToSp(this)
|
||||||
|
|
||||||
|
private fun Float.toIntPx() = if (isFinite()) toInt() else 0
|
||||||
|
|
||||||
|
private fun Float.roundToPx() = if (isFinite()) roundToInt() else 0
|
||||||
|
|
||||||
|
private fun Float.toRecSize() = if (isFinite()) Size(this, this) else Size.Unspecified
|
||||||
|
|
||||||
|
private fun Float.toRecOffset() = if (isFinite()) Offset(this, this) else Offset.Unspecified
|
||||||
|
|
||||||
|
// INT
|
||||||
|
private fun Density.intPxToDp(px: Int) = px.toDp()
|
||||||
|
|
||||||
|
private fun Density.intPxToSp(px: Int) = px.toSp()
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun Int.toDp() = LocalDensity.current.intPxToDp(this)
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun Int.toSp() = LocalDensity.current.intPxToSp(this)
|
||||||
|
|
||||||
|
private fun Int.toFloatPx() = toFloat()
|
||||||
|
|
||||||
|
private fun Int.toRecIntSize() = IntSize(this, this)
|
||||||
|
|
||||||
|
private fun Int.toRecIntOffset() = IntOffset(this, this)
|
||||||
|
|
||||||
|
|
||||||
|
// DP SIZE
|
||||||
|
private fun Density.dpSizeToIntSize(dpSize: DpSize) =
|
||||||
|
if (dpSize.isSpecified) IntSize(dpSize.width.toPx().toInt(), dpSize.height.toPx().toInt())
|
||||||
|
else IntSize.Zero
|
||||||
|
|
||||||
|
private fun Density.dpSizeRoundToIntSize(dpSize: DpSize) =
|
||||||
|
if (dpSize.isSpecified) IntSize(dpSize.width.roundToPx(), dpSize.height.roundToPx())
|
||||||
|
else IntSize.Zero
|
||||||
|
|
||||||
|
private fun Density.dpSizeToSize(dpSize: DpSize) =
|
||||||
|
if (dpSize.isSpecified) Size(dpSize.width.toPx(), dpSize.height.toPx())
|
||||||
|
else Size.Unspecified
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun DpSize.toIntSize() = LocalDensity.current.dpSizeToIntSize(this)
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun DpSize.roundToIntSize() = LocalDensity.current.dpSizeRoundToIntSize(this)
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun DpSize.toSize() = LocalDensity.current.dpSizeToSize(this)
|
||||||
|
|
||||||
|
private fun DpSize.isSpaced() = isSpecified && width > 0.dp && height > 0.dp
|
||||||
|
|
||||||
|
|
||||||
|
// SIZE
|
||||||
|
private fun Density.sizeToDpSize(size: Size) =
|
||||||
|
if (size.isSpecified) DpSize(size.width.toDp(), size.height.toDp())
|
||||||
|
else DpSize.Unspecified
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun Size.toDpSize() =
|
||||||
|
if (isSpecified) LocalDensity.current.sizeToDpSize(this)
|
||||||
|
else DpSize.Unspecified
|
||||||
|
|
||||||
|
private fun Size.toIntSize() =
|
||||||
|
if (isSpecified) IntSize(width.toInt(), height.toInt())
|
||||||
|
else IntSize.Zero
|
||||||
|
|
||||||
|
private fun Size.isSpaced() = isSpecified && width > 0F && height > 0F
|
||||||
|
|
||||||
|
|
||||||
|
// INT SIZE
|
||||||
|
private fun Density.intSizeToDpSize(intSize: IntSize) = DpSize(intSize.width.toDp(), intSize.height.toDp())
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun IntSize.toDpSize() = LocalDensity.current.intSizeToDpSize(this)
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun IntSize.toSize() = Size(width.toFloat(), height.toFloat())
|
||||||
|
|
||||||
|
private fun IntSize.isSpaced() = width > 0 && height > 0
|
||||||
|
|
||||||
|
|
||||||
|
// DP OFFSET
|
||||||
|
private fun Density.dpOffsetToIntOffset(dpOffset: DpOffset) =
|
||||||
|
if (dpOffset.isSpecified) IntOffset(dpOffset.x.toPx().toInt(), dpOffset.y.toPx().toInt())
|
||||||
|
else IntOffset.Zero
|
||||||
|
|
||||||
|
private fun Density.dpOffsetRoundToIntOffset(dpOffset: DpOffset) =
|
||||||
|
if (dpOffset.isSpecified) IntOffset(dpOffset.x.roundToPx(), dpOffset.y.roundToPx())
|
||||||
|
else IntOffset.Zero
|
||||||
|
|
||||||
|
private fun Density.dpOffsetToOffset(dpOffset: DpOffset) =
|
||||||
|
if (dpOffset.isSpecified) Offset(dpOffset.x.toPx(), dpOffset.y.toPx())
|
||||||
|
else Offset.Unspecified
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun DpOffset.toIntOffset() = LocalDensity.current.dpOffsetToIntOffset(this)
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun DpOffset.roundToIntOffset() = LocalDensity.current.dpOffsetRoundToIntOffset(this)
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun DpOffset.toOffset() = LocalDensity.current.dpOffsetToOffset(this)
|
||||||
|
|
||||||
|
|
||||||
|
// OFFSET
|
||||||
|
private fun Density.offsetToDpOffset(offset: Offset) =
|
||||||
|
if (offset.isSpecified) DpOffset(offset.x.toDp(), offset.y.toDp())
|
||||||
|
else DpOffset.Unspecified
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun Offset.toDpOffset() = LocalDensity.current.offsetToDpOffset(this)
|
||||||
|
|
||||||
|
private fun Offset.toIntOffset() =
|
||||||
|
if (isSpecified) IntOffset(x.toInt(), y.toInt())
|
||||||
|
else IntOffset.Zero
|
||||||
|
|
||||||
|
// INT OFFSET
|
||||||
|
private fun Density.intOffsetToDpOffset(intOffset: IntOffset) = DpOffset(intOffset.x.toDp(), intOffset.y.toDp())
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun IntOffset.toDpOffset() = LocalDensity.current.intOffsetToDpOffset(this)
|
||||||
|
|
||||||
|
private fun IntOffset.toOffset() = Offset(x.toFloat(), y.toFloat())
|
||||||
|
Loading…
x
Reference in New Issue
Block a user