mirror of
https://github.com/InsanusMokrassar/MicroUtils.git
synced 2024-11-22 08:13:49 +00:00
add number picker, set picker and small text field
This commit is contained in:
parent
cbc868448b
commit
a65bb2f419
@ -2,6 +2,11 @@
|
||||
|
||||
## 0.20.1
|
||||
|
||||
* `SmallTextField`:
|
||||
* Module is initialized
|
||||
* `Pickers`:
|
||||
* Module is initialized
|
||||
|
||||
## 0.20.0
|
||||
|
||||
* `Versions`:
|
||||
|
18
android/pickers/build.gradle
Normal file
18
android/pickers/build.gradle
Normal file
@ -0,0 +1,18 @@
|
||||
plugins {
|
||||
id "org.jetbrains.kotlin.multiplatform"
|
||||
id "org.jetbrains.kotlin.plugin.serialization"
|
||||
id "com.android.library"
|
||||
alias(libs.plugins.jb.compose)
|
||||
}
|
||||
|
||||
apply from: "$mppProjectWithSerializationAndComposePresetPath"
|
||||
|
||||
kotlin {
|
||||
sourceSets {
|
||||
androidMain {
|
||||
dependencies {
|
||||
api project(":micro_utils.android.smalltextfield")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
1
android/pickers/src/androidMain/AndroidManifest.xml
Normal file
1
android/pickers/src/androidMain/AndroidManifest.xml
Normal file
@ -0,0 +1 @@
|
||||
<manifest package="dev.inmo.micro_utils.android.pickers"/>
|
27
android/pickers/src/androidMain/kotlin/Fling.kt
Normal file
27
android/pickers/src/androidMain/kotlin/Fling.kt
Normal file
@ -0,0 +1,27 @@
|
||||
package dev.inmo.micro_utils.android.pickers
|
||||
|
||||
import androidx.compose.animation.core.*
|
||||
|
||||
internal suspend fun Animatable<Float, AnimationVector1D>.fling(
|
||||
initialVelocity: Float,
|
||||
animationSpec: DecayAnimationSpec<Float>,
|
||||
adjustTarget: ((Float) -> Float)?,
|
||||
block: (Animatable<Float, AnimationVector1D>.() -> Unit)? = null,
|
||||
): AnimationResult<Float, AnimationVector1D> {
|
||||
val targetValue = animationSpec.calculateTargetValue(value, initialVelocity)
|
||||
val adjustedTarget = adjustTarget?.invoke(targetValue)
|
||||
|
||||
return if (adjustedTarget != null) {
|
||||
animateTo(
|
||||
targetValue = adjustedTarget,
|
||||
initialVelocity = initialVelocity,
|
||||
block = block
|
||||
)
|
||||
} else {
|
||||
animateDecay(
|
||||
initialVelocity = initialVelocity,
|
||||
animationSpec = animationSpec,
|
||||
block = block,
|
||||
)
|
||||
}
|
||||
}
|
222
android/pickers/src/androidMain/kotlin/NumberPicker.kt
Normal file
222
android/pickers/src/androidMain/kotlin/NumberPicker.kt
Normal file
@ -0,0 +1,222 @@
|
||||
package dev.inmo.micro_utils.android.pickers
|
||||
|
||||
import androidx.compose.animation.core.Animatable
|
||||
import androidx.compose.animation.core.exponentialDecay
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.gestures.*
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.text.KeyboardActions
|
||||
import androidx.compose.foundation.text.KeyboardOptions
|
||||
import androidx.compose.material.ContentAlpha
|
||||
import androidx.compose.material.IconButton
|
||||
import androidx.compose.material.ProvideTextStyle
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.KeyboardArrowDown
|
||||
import androidx.compose.material.icons.filled.KeyboardArrowUp
|
||||
import androidx.compose.material3.*
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.ExperimentalComposeUiApi
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.alpha
|
||||
import androidx.compose.ui.focus.FocusRequester
|
||||
import androidx.compose.ui.focus.focusRequester
|
||||
import androidx.compose.ui.geometry.Offset
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.input.pointer.PointerInputScope
|
||||
import androidx.compose.ui.input.pointer.pointerInput
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.text.ExperimentalTextApi
|
||||
import androidx.compose.ui.text.TextStyle
|
||||
import androidx.compose.ui.text.input.KeyboardType
|
||||
import androidx.compose.ui.unit.IntOffset
|
||||
import androidx.compose.ui.unit.center
|
||||
import androidx.compose.ui.unit.dp
|
||||
import dev.inmo.micro_utils.android.smalltextfield.SmallTextField
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlin.math.abs
|
||||
import kotlin.math.absoluteValue
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
private inline fun PointerInputScope.checkContains(offset: Offset): Boolean {
|
||||
return ((size.center.x - offset.x).absoluteValue < size.width / 2) && ((size.center.y - offset.y).absoluteValue < size.height / 2)
|
||||
}
|
||||
|
||||
// src: https://gist.github.com/vganin/a9a84653a9f48a2d669910fbd48e32d5
|
||||
|
||||
@OptIn(ExperimentalTextApi::class, ExperimentalComposeUiApi::class)
|
||||
@Composable
|
||||
fun NumberPicker(
|
||||
number: Int,
|
||||
modifier: Modifier = Modifier,
|
||||
range: IntRange? = null,
|
||||
textStyle: TextStyle = LocalTextStyle.current,
|
||||
arrowsColor: Color = MaterialTheme.colorScheme.primary,
|
||||
allowUseManualInput: Boolean = true,
|
||||
onStateChanged: (Int) -> Unit = {},
|
||||
) {
|
||||
val coroutineScope = rememberCoroutineScope()
|
||||
val numbersColumnHeight = 36.dp
|
||||
val halvedNumbersColumnHeight = numbersColumnHeight / 2
|
||||
val halvedNumbersColumnHeightPx = with(LocalDensity.current) { halvedNumbersColumnHeight.toPx() }
|
||||
|
||||
fun animatedStateValue(offset: Float): Int = number - (offset / halvedNumbersColumnHeightPx).toInt()
|
||||
|
||||
val animatedOffset = remember { Animatable(0f) }.apply {
|
||||
if (range != null) {
|
||||
val offsetRange = remember(number, range) {
|
||||
val value = number
|
||||
val first = -(range.last - value) * halvedNumbersColumnHeightPx
|
||||
val last = -(range.first - value) * halvedNumbersColumnHeightPx
|
||||
first..last
|
||||
}
|
||||
updateBounds(offsetRange.start, offsetRange.endInclusive)
|
||||
}
|
||||
}
|
||||
val coercedAnimatedOffset = animatedOffset.value % halvedNumbersColumnHeightPx
|
||||
val animatedStateValue = animatedStateValue(animatedOffset.value)
|
||||
val disabledArrowsColor = arrowsColor.copy(alpha = ContentAlpha.disabled)
|
||||
|
||||
val inputFieldShown = if (allowUseManualInput) {
|
||||
remember { mutableStateOf(false) }
|
||||
} else {
|
||||
null
|
||||
}
|
||||
|
||||
Column(
|
||||
modifier = modifier
|
||||
.wrapContentSize()
|
||||
.draggable(
|
||||
orientation = Orientation.Vertical,
|
||||
state = rememberDraggableState { deltaY ->
|
||||
if (inputFieldShown ?.value != true) {
|
||||
coroutineScope.launch {
|
||||
animatedOffset.snapTo(animatedOffset.value + deltaY)
|
||||
}
|
||||
}
|
||||
},
|
||||
onDragStopped = { velocity ->
|
||||
if (inputFieldShown ?.value != true) {
|
||||
coroutineScope.launch {
|
||||
val endValue = animatedOffset.fling(
|
||||
initialVelocity = velocity,
|
||||
animationSpec = exponentialDecay(frictionMultiplier = 20f),
|
||||
adjustTarget = { target ->
|
||||
val coercedTarget = target % halvedNumbersColumnHeightPx
|
||||
val coercedAnchors =
|
||||
listOf(-halvedNumbersColumnHeightPx, 0f, halvedNumbersColumnHeightPx)
|
||||
val coercedPoint = coercedAnchors.minByOrNull { abs(it - coercedTarget) }!!
|
||||
val base =
|
||||
halvedNumbersColumnHeightPx * (target / halvedNumbersColumnHeightPx).toInt()
|
||||
coercedPoint + base
|
||||
}
|
||||
).endState.value
|
||||
|
||||
onStateChanged(animatedStateValue(endValue))
|
||||
animatedOffset.snapTo(0f)
|
||||
}
|
||||
}
|
||||
}
|
||||
),
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
val spacing = 4.dp
|
||||
|
||||
val upEnabled = range == null || range.first < number
|
||||
IconButton(
|
||||
{
|
||||
onStateChanged(number - 1)
|
||||
inputFieldShown ?.value = false
|
||||
},
|
||||
enabled = upEnabled
|
||||
) {
|
||||
Icon(Icons.Default.KeyboardArrowUp, "", tint = if (upEnabled) arrowsColor else disabledArrowsColor)
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.height(spacing))
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.offset { IntOffset(x = 0, y = coercedAnimatedOffset.roundToInt()) },
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
val baseLabelModifier = Modifier.align(Alignment.Center)
|
||||
ProvideTextStyle(textStyle) {
|
||||
Text(
|
||||
text = (animatedStateValue - 1).toString(),
|
||||
modifier = baseLabelModifier
|
||||
.offset(y = -halvedNumbersColumnHeight)
|
||||
.alpha(coercedAnimatedOffset / halvedNumbersColumnHeightPx)
|
||||
)
|
||||
|
||||
if (inputFieldShown ?.value == true) {
|
||||
val currentValue = remember { mutableStateOf(number.toString()) }
|
||||
|
||||
val focusRequester = remember { FocusRequester() }
|
||||
SmallTextField(
|
||||
currentValue.value,
|
||||
{
|
||||
val asDigit = it.toIntOrNull()
|
||||
when {
|
||||
(asDigit == null && it.isEmpty()) -> currentValue.value = (range ?.first ?: 0).toString()
|
||||
(asDigit != null && (range == null || asDigit in range)) -> currentValue.value = it
|
||||
else -> { /* do nothing */ }
|
||||
}
|
||||
},
|
||||
baseLabelModifier.focusRequester(focusRequester).width(IntrinsicSize.Min).pointerInput(number) {
|
||||
detectTapGestures {
|
||||
if (!checkContains(it)) {
|
||||
currentValue.value.toIntOrNull() ?.let(onStateChanged)
|
||||
inputFieldShown.value = false
|
||||
}
|
||||
}
|
||||
},
|
||||
keyboardOptions = KeyboardOptions(
|
||||
keyboardType = KeyboardType.Number
|
||||
),
|
||||
keyboardActions = KeyboardActions {
|
||||
currentValue.value.toIntOrNull() ?.let(onStateChanged)
|
||||
inputFieldShown.value = false
|
||||
},
|
||||
singleLine = true,
|
||||
textStyle = textStyle
|
||||
)
|
||||
LaunchedEffect(Unit) {
|
||||
focusRequester.requestFocus()
|
||||
}
|
||||
} else {
|
||||
Text(
|
||||
text = animatedStateValue.toString(),
|
||||
modifier = baseLabelModifier
|
||||
.alpha(1 - abs(coercedAnimatedOffset) / halvedNumbersColumnHeightPx)
|
||||
.clickable {
|
||||
if (inputFieldShown ?.value == false) {
|
||||
inputFieldShown.value = true
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
Text(
|
||||
text = (animatedStateValue + 1).toString(),
|
||||
modifier = baseLabelModifier
|
||||
.offset(y = halvedNumbersColumnHeight)
|
||||
.alpha(-coercedAnimatedOffset / halvedNumbersColumnHeightPx)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Spacer(modifier = Modifier.height(spacing))
|
||||
|
||||
val downEnabled = range == null || range.last > number
|
||||
IconButton(
|
||||
{
|
||||
onStateChanged(number + 1)
|
||||
inputFieldShown ?.value = false
|
||||
},
|
||||
enabled = downEnabled
|
||||
) {
|
||||
Icon(Icons.Default.KeyboardArrowDown, "", tint = if (downEnabled) arrowsColor else disabledArrowsColor)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
156
android/pickers/src/androidMain/kotlin/SetPicker.kt
Normal file
156
android/pickers/src/androidMain/kotlin/SetPicker.kt
Normal file
@ -0,0 +1,156 @@
|
||||
package dev.inmo.micro_utils.android.pickers
|
||||
|
||||
import androidx.compose.animation.core.Animatable
|
||||
import androidx.compose.animation.core.exponentialDecay
|
||||
import androidx.compose.foundation.gestures.*
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.material.ContentAlpha
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.KeyboardArrowDown
|
||||
import androidx.compose.material.icons.filled.KeyboardArrowUp
|
||||
import androidx.compose.material3.*
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.ExperimentalComposeUiApi
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.alpha
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.text.ExperimentalTextApi
|
||||
import androidx.compose.ui.text.TextStyle
|
||||
import androidx.compose.ui.unit.dp
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlin.math.*
|
||||
|
||||
@OptIn(ExperimentalTextApi::class, ExperimentalComposeUiApi::class)
|
||||
@Composable
|
||||
fun <T> SetPicker(
|
||||
current: T,
|
||||
dataList: List<T>,
|
||||
modifier: Modifier = Modifier,
|
||||
textStyle: TextStyle = LocalTextStyle.current,
|
||||
arrowsColor: Color = MaterialTheme.colorScheme.primary,
|
||||
dataToString: @Composable (T) -> String = { it.toString() },
|
||||
onStateChanged: (T) -> Unit = {},
|
||||
) {
|
||||
val coroutineScope = rememberCoroutineScope()
|
||||
val numbersColumnHeight = 8.dp + with(LocalDensity.current) {
|
||||
textStyle.lineHeight.toDp()
|
||||
}
|
||||
val numbersColumnHeightPx = with(LocalDensity.current) { numbersColumnHeight.toPx() }
|
||||
val halvedNumbersColumnHeight = numbersColumnHeight / 2
|
||||
val halvedNumbersColumnHeightPx = with(LocalDensity.current) { halvedNumbersColumnHeight.toPx() }
|
||||
|
||||
val index = dataList.indexOfFirst { it === current }.takeIf { it > -1 } ?: dataList.indexOf(current)
|
||||
val lastIndex = dataList.size - 1
|
||||
|
||||
fun animatedStateValue(offset: Float): Int = index - (offset / halvedNumbersColumnHeightPx).toInt()
|
||||
|
||||
val animatedOffset = remember { Animatable(0f) }.apply {
|
||||
val offsetRange = remember(index, lastIndex) {
|
||||
val value = index
|
||||
val first = -(lastIndex - value) * halvedNumbersColumnHeightPx
|
||||
val last = value * halvedNumbersColumnHeightPx
|
||||
first..last
|
||||
}
|
||||
updateBounds(offsetRange.start, offsetRange.endInclusive)
|
||||
}
|
||||
val indexAnimatedOffset = if (animatedOffset.value > 0) {
|
||||
(index - floor(animatedOffset.value / halvedNumbersColumnHeightPx).toInt())
|
||||
} else {
|
||||
(index - ceil(animatedOffset.value / halvedNumbersColumnHeightPx).toInt())
|
||||
}
|
||||
val coercedAnimatedOffset = animatedOffset.value % halvedNumbersColumnHeightPx
|
||||
val boxOffset = (indexAnimatedOffset * halvedNumbersColumnHeightPx) - coercedAnimatedOffset
|
||||
val disabledArrowsColor = arrowsColor.copy(alpha = ContentAlpha.disabled)
|
||||
val scrollState = rememberScrollState()
|
||||
|
||||
Column(
|
||||
modifier = modifier
|
||||
.wrapContentSize()
|
||||
.draggable(
|
||||
orientation = Orientation.Vertical,
|
||||
state = rememberDraggableState { deltaY ->
|
||||
coroutineScope.launch {
|
||||
animatedOffset.snapTo(animatedOffset.value + deltaY)
|
||||
}
|
||||
},
|
||||
onDragStopped = { velocity ->
|
||||
coroutineScope.launch {
|
||||
val endValue = animatedOffset.fling(
|
||||
initialVelocity = velocity,
|
||||
animationSpec = exponentialDecay(frictionMultiplier = 20f),
|
||||
adjustTarget = { target ->
|
||||
val coercedTarget = target % halvedNumbersColumnHeightPx
|
||||
val coercedAnchors =
|
||||
listOf(-halvedNumbersColumnHeightPx, 0f, halvedNumbersColumnHeightPx)
|
||||
val coercedPoint = coercedAnchors.minByOrNull { abs(it - coercedTarget) }!!
|
||||
val base =
|
||||
halvedNumbersColumnHeightPx * (target / halvedNumbersColumnHeightPx).toInt()
|
||||
coercedPoint + base
|
||||
}
|
||||
).endState.value
|
||||
|
||||
onStateChanged(dataList.elementAt(animatedStateValue(endValue)))
|
||||
animatedOffset.snapTo(0f)
|
||||
}
|
||||
}
|
||||
),
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
val spacing = 4.dp
|
||||
|
||||
val upEnabled = index > 0
|
||||
IconButton(
|
||||
{
|
||||
onStateChanged(dataList.elementAt(index - 1))
|
||||
},
|
||||
enabled = upEnabled
|
||||
) {
|
||||
Icon(Icons.Default.KeyboardArrowUp, "", tint = if (upEnabled) arrowsColor else disabledArrowsColor)
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.height(spacing))
|
||||
Box(
|
||||
modifier = Modifier,
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
ProvideTextStyle(textStyle) {
|
||||
dataList.forEachIndexed { i, t ->
|
||||
val alpha = when {
|
||||
i == indexAnimatedOffset - 1 -> coercedAnimatedOffset / halvedNumbersColumnHeightPx
|
||||
i == indexAnimatedOffset -> 1 - (abs(coercedAnimatedOffset) / halvedNumbersColumnHeightPx)
|
||||
i == indexAnimatedOffset + 1 -> -coercedAnimatedOffset / halvedNumbersColumnHeightPx
|
||||
else -> return@forEachIndexed
|
||||
}
|
||||
val offset = when {
|
||||
i == indexAnimatedOffset - 1 && coercedAnimatedOffset > 0 -> coercedAnimatedOffset - halvedNumbersColumnHeightPx
|
||||
i == indexAnimatedOffset -> coercedAnimatedOffset
|
||||
i == indexAnimatedOffset + 1 && coercedAnimatedOffset < 0 -> coercedAnimatedOffset + halvedNumbersColumnHeightPx
|
||||
else -> return@forEachIndexed
|
||||
}
|
||||
Text(
|
||||
text = dataToString(t),
|
||||
modifier = Modifier
|
||||
.alpha(alpha)
|
||||
.offset(y = with(LocalDensity.current) { offset.toDp() })
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Spacer(modifier = Modifier.height(spacing))
|
||||
|
||||
val downEnabled = index < lastIndex
|
||||
IconButton(
|
||||
{
|
||||
onStateChanged(dataList.elementAt(index + 1))
|
||||
},
|
||||
enabled = downEnabled
|
||||
) {
|
||||
Icon(Icons.Default.KeyboardArrowDown, "", tint = if (downEnabled) arrowsColor else disabledArrowsColor)
|
||||
}
|
||||
}
|
||||
}
|
18
android/smalltextfield/build.gradle
Normal file
18
android/smalltextfield/build.gradle
Normal file
@ -0,0 +1,18 @@
|
||||
plugins {
|
||||
id "org.jetbrains.kotlin.multiplatform"
|
||||
id "org.jetbrains.kotlin.plugin.serialization"
|
||||
id "com.android.library"
|
||||
alias(libs.plugins.jb.compose)
|
||||
}
|
||||
|
||||
apply from: "$mppProjectWithSerializationAndComposePresetPath"
|
||||
|
||||
kotlin {
|
||||
sourceSets {
|
||||
androidMain {
|
||||
dependencies {
|
||||
api libs.android.compose.material3
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1 @@
|
||||
<manifest package="dev.inmo.micro_utils.android.smalltextfield"/>
|
@ -0,0 +1,66 @@
|
||||
package dev.inmo.micro_utils.android.smalltextfield
|
||||
|
||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.defaultMinSize
|
||||
import androidx.compose.foundation.text.BasicTextField
|
||||
import androidx.compose.foundation.text.KeyboardActions
|
||||
import androidx.compose.foundation.text.KeyboardOptions
|
||||
import androidx.compose.foundation.text.selection.LocalTextSelectionColors
|
||||
import androidx.compose.material3.*
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.Shape
|
||||
import androidx.compose.ui.graphics.SolidColor
|
||||
import androidx.compose.ui.graphics.takeOrElse
|
||||
import androidx.compose.ui.text.TextStyle
|
||||
import androidx.compose.ui.text.input.VisualTransformation
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun SmallTextField(
|
||||
value: String,
|
||||
onValueChange: (String) -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
enabled: Boolean = true,
|
||||
readOnly: Boolean = false,
|
||||
textStyle: TextStyle = LocalTextStyle.current,
|
||||
textColor: Color = textStyle.color.takeOrElse {
|
||||
LocalContentColor.current
|
||||
},
|
||||
visualTransformation: VisualTransformation = VisualTransformation.None,
|
||||
keyboardOptions: KeyboardOptions = KeyboardOptions.Default,
|
||||
keyboardActions: KeyboardActions = KeyboardActions.Default,
|
||||
singleLine: Boolean = false,
|
||||
maxLines: Int = if (singleLine) 1 else Int.MAX_VALUE,
|
||||
minLines: Int = 1,
|
||||
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
|
||||
) {
|
||||
BasicTextField(
|
||||
value = value,
|
||||
modifier = modifier,
|
||||
onValueChange = onValueChange,
|
||||
enabled = enabled,
|
||||
readOnly = readOnly,
|
||||
textStyle = textStyle.copy(
|
||||
color = textColor
|
||||
),
|
||||
visualTransformation = visualTransformation,
|
||||
keyboardOptions = keyboardOptions,
|
||||
keyboardActions = keyboardActions,
|
||||
interactionSource = interactionSource,
|
||||
singleLine = singleLine,
|
||||
maxLines = maxLines,
|
||||
minLines = minLines,
|
||||
cursorBrush = SolidColor(
|
||||
textStyle.color.takeOrElse {
|
||||
LocalContentColor.current
|
||||
}
|
||||
)
|
||||
)
|
||||
}
|
@ -35,6 +35,7 @@ android-appCompat = "1.6.1"
|
||||
android-fragment = "1.6.1"
|
||||
android-espresso = "3.5.1"
|
||||
android-test = "1.1.5"
|
||||
android-compose-material3 = "1.1.1"
|
||||
|
||||
android-props-minSdk = "21"
|
||||
android-props-compileSdk = "33"
|
||||
@ -83,6 +84,7 @@ jb-exposed = { module = "org.jetbrains.exposed:exposed-core", version.ref = "jb-
|
||||
android-coreKtx = { module = "androidx.core:core-ktx", version.ref = "android-coreKtx" }
|
||||
android-recyclerView = { module = "androidx.recyclerview:recyclerview", version.ref = "android-recyclerView" }
|
||||
android-appCompat-resources = { module = "androidx.appcompat:appcompat-resources", version.ref = "android-appCompat" }
|
||||
android-compose-material3 = { module = "androidx.compose.material3:material3", version.ref = "android-compose-material3" }
|
||||
android-fragment = { module = "androidx.fragment:fragment", version.ref = "android-fragment" }
|
||||
android-espresso = { module = "androidx.test.espresso:espresso-core", version.ref = "android-espresso" }
|
||||
android-test-junit = { module = "androidx.test.ext:junit", version.ref = "android-test" }
|
||||
|
@ -32,6 +32,8 @@ String[] includes = [
|
||||
":coroutines",
|
||||
":coroutines:compose",
|
||||
":android:recyclerview",
|
||||
":android:pickers",
|
||||
":android:smalltextfield",
|
||||
":android:alerts:common",
|
||||
":android:alerts:recyclerview",
|
||||
":serialization:base64",
|
||||
|
Loading…
Reference in New Issue
Block a user