Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BasicTextField2 + TextFieldState fix for this issue #1

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
root = true

[*]
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true


[*.{kt,kts}]
ij_kotlin_allow_trailing_comma = true
ij_kotlin_allow_trailing_comma_on_call_site = true
ij_kotlin_imports_layout = *
5 changes: 2 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
# Compose-Input
Demoing weird issues with Molecule and Compose UI text input

https://user-images.githubusercontent.com/1245751/182052554-393887e4-5e00-4d5e-8a75-d1b88a415f4c.mp4
BasicTextField2 + TextFieldState fixes the previous text field issues

https://github.com/chris-horner/Compose-Input/assets/44558292/0de5bb92-2de4-428d-a23e-44d99bf5a346
29 changes: 14 additions & 15 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@ plugins {

android {
namespace 'com.example.composeinput'
compileSdk 32
compileSdk 34

defaultConfig {
applicationId "com.example.composeinput"
minSdk 24
targetSdk 32
targetSdk 34
versionCode 1
versionName "1.0"

Expand All @@ -26,17 +26,17 @@ android {
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
sourceCompatibility JavaVersion.VERSION_11
targetCompatibility JavaVersion.VERSION_11
}
kotlinOptions {
jvmTarget = '1.8'
jvmTarget = '11'
}
buildFeatures {
compose true
}
composeOptions {
kotlinCompilerExtensionVersion '1.1.1'
kotlinCompilerExtensionVersion '1.5.1'
}
packagingOptions {
resources {
Expand All @@ -46,12 +46,11 @@ android {
}

dependencies {

implementation 'androidx.core:core-ktx:1.7.0'
implementation 'androidx.activity:activity-compose:1.3.1'
implementation "androidx.compose.ui:ui:$compose_ui_version"
implementation "androidx.compose.ui:ui-tooling-preview:$compose_ui_version"
implementation "androidx.compose.material:material:$compose_ui_version"
debugImplementation "androidx.compose.ui:ui-tooling:$compose_ui_version"
debugImplementation "androidx.compose.ui:ui-test-manifest:$compose_ui_version"
}
implementation 'androidx.core:core-ktx:1.10.1'
implementation 'androidx.activity:activity-compose:1.7.2'
implementation 'androidx.compose.ui:ui:1.6.0-alpha02'
implementation 'androidx.compose.ui:ui-tooling-preview:1.6.0-alpha02'
implementation 'androidx.compose.material:material:1.6.0-alpha02'
debugImplementation 'androidx.compose.ui:ui-tooling:1.6.0-alpha02'
debugImplementation 'androidx.compose.ui:ui-test-manifest:1.6.0-alpha02'
}
80 changes: 63 additions & 17 deletions app/src/main/java/com/example/composeinput/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,23 @@ package com.example.composeinput
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.text2.BasicTextField2
import androidx.compose.foundation.text2.input.TextFieldState
import androidx.compose.foundation.text2.input.textAsFlow
import androidx.compose.material.Button
import androidx.compose.material.MaterialTheme
import androidx.compose.material.OutlinedTextField
import androidx.compose.material.Switch
import androidx.compose.material.Text
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
Expand All @@ -22,26 +28,51 @@ 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
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.unit.dp
import app.cash.molecule.RecompositionClock.ContextClock
import app.cash.molecule.RecompositionClock.Immediate
import androidx.compose.ui.unit.sp
import app.cash.molecule.RecompositionMode
import app.cash.molecule.launchMolecule
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.StateFlow

class MainActivity : ComponentActivity() {

@OptIn(ExperimentalFoundationApi::class)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {

var useImmediateClock by remember { mutableStateOf(false) }
val scope = rememberCoroutineScope()
val events = remember { MutableSharedFlow<String>(extraBufferCapacity = 1) }
val state: String = remember(useImmediateClock) {
scope.launchMolecule(if (useImmediateClock) Immediate else ContextClock) {
events.collectAsState(initial = "").value
val events = remember { MutableSharedFlow<Event>(extraBufferCapacity = 1) }
val moleculeStateFlow: StateFlow<UiState> = remember(useImmediateClock) {
scope.launchMolecule(
if (useImmediateClock) RecompositionMode.Immediate else RecompositionMode.ContextClock,
) {
val textFieldState = remember { TextFieldState("") }
var someDerivedText by remember { mutableStateOf("") }
var haveDelay by remember { mutableStateOf(true) }
LaunchedEffect(events) {
events.collect { event ->
when (event) {
Event.FlipDelaySwitch -> haveDelay = !haveDelay
}
}
}
LaunchedEffect(Unit) {
textFieldState.textAsFlow().collect { text ->
if (haveDelay) {
delay((200..600L).random())
}
someDerivedText = text.map { "$it$it" }.joinToString(separator = "")
}
}
UiState(textFieldState, someDerivedText, haveDelay)
}
}.collectAsState().value
}
val uiState: UiState by moleculeStateFlow.collectAsState()

MaterialTheme {
Column(
Expand All @@ -58,16 +89,31 @@ class MainActivity : ComponentActivity() {
onCheckedChange = { useImmediateClock = !useImmediateClock },
)
}
OutlinedTextField(
value = state,
onValueChange = { events.tryEmit(it) },
modifier = Modifier.fillMaxWidth()
)
Text(
"A reliable way to observe issues is to enter text into the input field, and then hold down backspace to rapidly delete characters."
Row(verticalAlignment = Alignment.CenterVertically) {
Text("Is delay on: ${uiState.isDelayOn}")
}
BasicTextField2(
state = uiState.textFieldState,
modifier = Modifier.fillMaxWidth().border(1.dp, Color.Red),
textStyle = TextStyle.Default.copy(fontSize = 24.sp),
)
Text(uiState.someOtherUiState)
Button(onClick = { events.tryEmit(Event.FlipDelaySwitch) }) {
Text("Add/Remove delay from someOtherUiState mapping")
}
}
}
}
}
}
}

sealed interface Event {
data object FlipDelaySwitch : Event
}

@OptIn(ExperimentalFoundationApi::class)
data class UiState(
val textFieldState: TextFieldState,
val someOtherUiState: String,
val isDelayOn: Boolean,
)
15 changes: 5 additions & 10 deletions build.gradle
Original file line number Diff line number Diff line change
@@ -1,11 +1,6 @@
buildscript {
ext {
compose_ui_version = '1.2.0'
}
} // Top-level build file where you can add configuration options common to all sub-projects/modules.
plugins {
id 'com.android.application' version '7.3.0-beta05' apply false
id 'com.android.library' version '7.3.0-beta05' apply false
id 'org.jetbrains.kotlin.android' version '1.6.10' apply false
id 'app.cash.molecule' version '0.3.0' apply false
}
id 'com.android.application' version '8.2.0-alpha14' apply false
id 'com.android.library' version '8.2.0-alpha14' apply false
id 'org.jetbrains.kotlin.android' version '1.9.0' apply false
id 'app.cash.molecule' version '1.1.0' apply false
}
2 changes: 1 addition & 1 deletion gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#Thu Jul 28 11:11:38 AEST 2022
distributionBase=GRADLE_USER_HOME
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.2.1-bin.zip
distributionPath=wrapper/dists
zipStorePath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME