codeslubber
02/28/2020, 7:25 PMTextField
before, but with a TextFieldInput
that was in a state var, e.g. state { TextFieldInput("") }
) But I already have a state so I wanted to put the TextFieldInput into that instance, so, something like state { TimerState() }
where TimerState has the TextFieldInput in it, but not having much success with that.
The other possibility (part of why I am posting) is way back during early MVC days there was another pattern called PAC. One of the main distinctions is PAC had hierarchies of components, and each component might have its own Abstraction (model) and controller. Should I do that? Make the text input a component? and if so, how do I bubble the edit result up to the enclosing component?Leland Richardson [G]
02/28/2020, 8:00 PMBut I already have a state so I wanted to put the TextFieldInput into that instance, so, something likeWhat was unsuccessful about this?where TimerState has the TextFieldInput in it, but not having much success with that.state { TimerState() }
value
/ onValueChange
parameters be passed through to the lower level component@Composable fun FancyTextField(value: String, onValueChange: (String) -> Unit) {
TextField(value, onValueChange)
}
codeslubber
02/28/2020, 8:06 PMMutableState<TextFieldInput>
. Not sure why .If I have a composable function, it all works, but then when I click submit, how should I get the value back into the outer view? I saw examples that have you pass the var you want it assigned to into the submethod?Leland Richardson [G]
02/28/2020, 8:09 PMcodeslubber
02/28/2020, 8:15 PMclass TimerState(hours:TimeDigit = TimeDigit(0), minutes:TimeDigit = TimeDigit(0), seconds:TimeDigit = TimeDigit(0)) {
var currentStatus:String = {
"$hours:$minutes:$seconds"
}()
var amountOfSkinInput = TextFieldValue("")
var amountOfSkin:Int = 50
}
and this does not work. I think because the input field is not a `MutableState<TextFieldValue>`right? but I can’t nest state {}
so?@Composable
fun numberInput(startAt:Int, range: IntRange, units: String){
val state = state { TextFieldValue(text = "") }
TextField(
value = state.value,
//modifier = Border(Dp.Hairline, Color.Gray),
onValueChange = {
state.value = it
},
keyboardType = KeyboardType.Number,
textStyle = TextStyle(fontSize = 64.sp)
)
Button(onClick = {
if (!range.contains(state.value.text.toInt())){
Log.d("VALIDATOR", "Out of range!")
} else {
}
}){
Text("Submit")
}
}
but then on submit, I would have to assign this value back to the field in the outer view state.Leland Richardson [G]
02/28/2020, 8:30 PMnumberInput
what we call a “controlled” composable@Composable
fun numberInput(
value: Int,
onValueChange: (Int) -> Unit,
startAt:Int,
range: IntRange,
units: String
) {
TextField(
value = value.toString(),
onValueChange= {
// TODO: validation here
onValueChange(it.toInt())
}
)
}
state
will only invalidate the composition when the value itself is setcodeslubber
02/28/2020, 8:35 PMLeland Richardson [G]
02/28/2020, 8:36 PMstate { TimerState() }
and you mutate a property on the TimerState
instance itself, there is no way compose will recognize that and recompose@Model
@Model
class TimerState(hours:TimeDigit = TimeDigit(0), minutes:TimeDigit = TimeDigit(0), seconds:TimeDigit = TimeDigit(0)) {
var currentStatus:String = {
"$hours:$minutes:$seconds"
}()
var amountOfSkinInput = TextFieldValue("")
var amountOfSkin:Int = 50
}
codeslubber
02/28/2020, 8:36 PMLeland Richardson [G]
02/28/2020, 8:37 PMcodeslubber
02/28/2020, 8:37 PMLeland Richardson [G]
02/28/2020, 8:38 PMdata class TimerState(...)
and then have var timerState by state { TimerState(…) }
Then when you want to have an invalidation, you can do timerState = timerState.copy(…)
mutableStateOf
codeslubber
02/28/2020, 8:39 PMLeland Richardson [G]
02/28/2020, 8:39 PMclass TimerState(hours:TimeDigit = TimeDigit(0), minutes:TimeDigit = TimeDigit(0), seconds:TimeDigit = TimeDigit(0)) {
val currentStatus:String = {
"$hours:$minutes:$seconds"
}()
var amountOfSkinInput by mutableStateOf("...")
var amountOfSkin:Int = 50
}
amountOfSkinInput
and since it is backed by a MutableState
instance, it will be observed by composecodeslubber
02/28/2020, 8:39 PMLeland Richardson [G]
02/28/2020, 8:40 PMvar
when using compose unless it is a State
property delegate, or a property on a @Model instancecodeslubber
02/28/2020, 8:41 PMLeland Richardson [G]
02/28/2020, 8:41 PMstate
and immutable value types only@Model
also has its uses, and others might disagree with meTextFieldValue
overload and not the String
overload of TextField
?codeslubber
02/28/2020, 8:44 PMLeland Richardson [G]
02/28/2020, 8:44 PMcodeslubber
02/28/2020, 8:45 PMEditorModel
in there and then found TextFieldValue
was the replacementLeland Richardson [G]
02/28/2020, 8:47 PMcodeslubber
02/28/2020, 8:53 PMLeland Richardson [G]
02/28/2020, 8:58 PMcodeslubber
02/28/2020, 9:33 PMLeland Richardson [G]
02/28/2020, 9:37 PMhistory
one has some interesting use cases i thinkcodeslubber
02/28/2020, 9:51 PMLeland Richardson [G]
02/28/2020, 10:20 PMcodeslubber
02/28/2020, 10:37 PMLeland Richardson [G]
02/28/2020, 10:41 PMcodeslubber
02/28/2020, 10:45 PMLeland Richardson [G]
02/28/2020, 11:26 PMcodeslubber
02/28/2020, 11:27 PMLeland Richardson [G]
02/28/2020, 11:28 PMcodeslubber
02/28/2020, 11:30 PMLeland Richardson [G]
02/28/2020, 11:31 PMcodeslubber
02/28/2020, 11:31 PMLeland Richardson [G]
02/28/2020, 11:31 PMcodeslubber
02/28/2020, 11:31 PMLeland Richardson [G]
02/28/2020, 11:31 PMcodeslubber
02/28/2020, 11:31 PMLeland Richardson [G]
02/28/2020, 11:32 PMcodeslubber
02/28/2020, 11:32 PMLeland Richardson [G]
02/28/2020, 11:32 PMcodeslubber
02/28/2020, 11:33 PMRef
either, it’s solution to import it from java.sql is of course wrong…Leland Richardson [G]
02/28/2020, 11:35 PMclass Ref<T>(var value: T)
private
to the front of it)reduce
@Composable fun <T> reduce(value: T, reducer: (T, T) -> T): T = {
var result = value
var first = false
val ref = remember { first = true; Ref(value) }
if (!first) {
result = reducer(ref.value, value)
}
onCommit { ref.value = result }
return result
}
codeslubber
02/28/2020, 11:38 PMref.value = reducer(ref.value, value)
Leland Richardson [G]
02/28/2020, 11:40 PMcodeslubber
02/29/2020, 12:01 AMLeland Richardson [G]
02/29/2020, 12:08 AMcodeslubber
02/29/2020, 12:10 AM// in the case of the first run, does this return null.... or do we just pass the value that came in???
@Composable
fun prev(value: T): T? {
@Composable val Ambient<T>.current: T
Leland Richardson [G]
02/29/2020, 12:13 AMcodeslubber
02/29/2020, 12:14 AMLeland Richardson [G]
02/29/2020, 12:18 AMcodeslubber
02/29/2020, 1:11 AMLeland Richardson [G]
02/29/2020, 1:15 AMcodeslubber
02/29/2020, 1:25 AMLeland Richardson [G]
02/29/2020, 1:26 AMcodeslubber
02/29/2020, 2:22 AMe: java.lang.IllegalStateException: Backend Internal error: Exception during code generation
Element is unknownThe root cause java.util.NoSuchElementException was thrown at: androidx.compose.plugins.kotlin.compiler.lower.ComposableCallTransformer.irComposableExpr(ComposableCallTransformer.kt:1362)
at org.jetbrains.kotlin.codegen.CompilationErrorHandler.lambda$static$0(CompilationErrorHandler.java:35)
at org.jetbrains.kotlin.backend.jvm.JvmBackendFacade.doGenerateFilesInternal$backend_jvm(JvmBackendFacade.kt:93)
at org.jetbrains.kotlin.backend.jvm.JvmBackendFacade.doGenerateFilesInternal$backend_jvm$default(JvmBackendFacade.kt:64)
at org.jetbrains.kotlin.backend.jvm.JvmBackendFacade.doGenerateFilesInternal$backend_jvm(JvmBackendFacade.kt:52)
at org.jetbrains.kotlin.backend.jvm.JvmIrCodegenFactory.generateModule(JvmIrCodegenFactory.kt:36)
at org.jetbrains.kotlin.codegen.KotlinCodegenFacade.doGenerateFiles(KotlinCodegenFacade.java:47)
at org.jetbrains.kotlin.codegen.KotlinCodegenFacade.compileCorrectFiles(KotlinCodegenFacade.java:39)
at org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler.generate(KotlinToJVMBytecodeCompiler.kt:638)
at org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler.compileModules$cli(KotlinToJVMBytecodeCompiler.kt:198)
at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.kt:172)
at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.kt:56)
at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.kt:85)
at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.kt:43)
at org.jetbrains.kotlin.cli.common.CLITool.exec(CLITool.kt:104)
at org.jetbrains.kotlin.incremental.IncrementalJvmCompilerRunner.runCompiler(IncrementalJvmCompilerRunner.kt:349)
at org.jetbrains.kotlin.incremental.IncrementalJvmCompilerRunner.runCompiler(IncrementalJvmCompilerRunner.kt:105)
at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compileIncrementally(IncrementalCompilerRunner.kt:237)
at org.jetbrains.kotlin.incremental.IncrementalCompilerRunner.compile(IncrementalCompilerRunner.kt:88)
at org.jetbrains.kotlin.daemon.CompileServiceImplBase.execIncrementalCompiler(CompileServiceImpl.kt:606)
at org.jetbrains.kotlin.daemon.CompileServiceImplBase.access$execIncrementalCompiler(CompileServiceImpl.kt:99)
at org.jetbrains.kotlin.daemon.CompileServiceImpl.compile(CompileServiceImpl.kt:1645)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:357)
at sun.rmi.transport.Transport$1.run(Transport.java:200)
at sun.rmi.transport.Transport$1.run(Transport.java:197)
at java.security.AccessController.doPrivileged(Native Method)
at sun.rmi.transport.Transport.serviceCall(Transport.java:196)
at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:573)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:834)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.lambda$run$0(TCPTransport.java:688)
at java.security.AccessController.doPrivileged(Native Method)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:687)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
Caused by: java.util.NoSuchElementException: Collection contains no element matching the predicate.
at androidx.compose.plugins.kotlin.compiler.lower.ComposableCallTransformer.irComposableExpr(ComposableCallTransformer.kt:1362)
at androidx.compose.plugins.kotlin.compiler.lower.ComposableCallTransformer.visitBlock(ComposableCallTransformer.kt:252)
at org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid.visitBlock(IrElementTransformerVoid.kt:128)
at org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid.visitBlock(IrElementTransformerVoid.kt:24)
at org.jetbrains.kotlin.ir.expressions.impl.IrBlockImpl.accept(IrBlockImpl.kt:52)
Leland Richardson [G]
02/29/2020, 3:01 AMjava.util.NoSuchElementException was thrown at: androidx.compose.plugins.kotlin.compiler.lower.ComposableCallTransformer.irComposableExpr(ComposableCallTransformer.kt:1362)This exception happens when the compose runtime module can’t be found on the classpath, or the newer compiler has an older version of compose runtime on the classpath (like dev03). I’m not sure if this is the reason for your issue or not, but can you paste your build.gradle file?
codeslubber
02/29/2020, 3:26 AMdev05
of course…apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
android {
compileSdkVersion 29
defaultConfig {
applicationId "com.ontometrics.dminder.suntimer"
minSdkVersion 21
targetSdkVersion 29
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), '<http://proguard-rules.pro|proguard-rules.pro>'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
}
buildFeatures {
compose true
}
}
dependencies {
implementation fileTree(dir: "libs", include: ["*.jar"])
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation 'androidx.core:core-ktx:1.2.0'
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'androidx.ui:ui-framework:0.1.0-dev05'
implementation 'androidx.ui:ui-layout:0.1.0-dev05'
implementation 'androidx.ui:ui-material:0.1.0-dev05'
implementation 'androidx.ui:ui-tooling:0.1.0-dev05'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
}
Leland Richardson [G]
02/29/2020, 3:54 AM