Getting error when use this line:
val surfaceColor: Color by animateColorAsState(
if (isExpanded) MaterialTheme.colors.primary else MaterialTheme.colors.surface,
)
It showing the following warning:
Property delegate must have a 'getValue(Nothing?, KProperty*>)' method. None of the following functions are suitable.
State.getValue(Any?, KProperty<>) where T = Color for inline operator fun State.getValue(thisObj: Any?, property: KProperty<>): T defined in androidx.compose.runtime
Make sure you are using correct import statements.
Compare and try replacing your import statements with correct one from below.
import androidx.compose.animation.animateColorAsState
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Column
import androidx.compose.material.MaterialTheme
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
#Composable
fun YourFunction() {
var isExpanded by remember { mutableStateOf(false) }
val surfaceColor: Color by animateColorAsState(
if (isExpanded) MaterialTheme.colors.primary else MaterialTheme.colors.surface
)
Column(
modifier = Modifier.clickable { isExpanded = !isExpanded }
) {
}
}
Related
I am currently using vaadin v23.
I want to navigate to (change view / page) to "Dashboard"
Default - login page view code looks like this:
package com.fd.jvmbackend.views.adminPanel.login
import com.fd.jvmbackend.extensions.isNull
import com.fd.jvmbackend.views.AdminPanelRoute
import com.fd.jvmbackend.views.BaseView
import com.fd.jvmbackend.views.Extras
import com.vaadin.flow.component.AttachEvent
import com.vaadin.flow.component.DetachEvent
import com.vaadin.flow.component.Text
import com.vaadin.flow.component.Unit
import com.vaadin.flow.component.button.Button
import com.vaadin.flow.component.html.Label
import com.vaadin.flow.component.notification.Notification
import com.vaadin.flow.router.*
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch
import org.apache.commons.lang3.RandomStringUtils
import java.util.concurrent.TimeUnit
#Route(value = AdminPanelRoute.LOGIN)
#PageTitle("Login | FD CMS")
class LoginView() : BaseView() {
private val TAG = "LoginView"
private var viewModel: LoginViewModel? = null
override fun onAttach(attachEvent: AttachEvent?) {
super.onAttach(attachEvent)
viewModel = LoginViewModel()
val label = Label("Welcome.")
val loginField = getLoginTextField("Login", "ex: mike", true, true)
val passwordField = getPasswordField("Password", "ex. myLongPassword", true, true, true)
val button = Button("Log in with credentials")
button.setWidth(15F, Unit.PERCENTAGE)
button.addClickListener { event ->
viewModel?.onLoginClicked(loginField.value, passwordField.value)
}
add(label)
add(loginField)
add(passwordField)
add(button)
collectorsJob = lifecycleScope.launch {
launch {
viewModel?.getPageTitle()?.collect { value ->
println("$TAG -> getPageTitle -> ${value}")
ui.get().access {
ui.get().page.setTitle(value)
}
}
}
launch {
viewModel?.getErrorText()?.collect { value ->
if(value.isNull()){
return#collect
}
ui.get().access {
notification?.close()
notification = Notification.show(value,TimeUnit.SECONDS.toMillis(5).toInt(),Notification.Position.BOTTOM_CENTER)
}
}
}
launch {
viewModel?.getIsLoading()?.collect { value ->
ui.get().access {
if (value) {
progressDialog = getIndeterminateProgressDialog("Loading", "please wait")
progressDialog?.open()
} else {
progressDialog?.close()
progressDialog = null
}
}
ui.get().access {
loginField.isEnabled = !value
}
ui.get().access {
passwordField.isEnabled = !value
}
ui.get().access {
button.isEnabled = !value
}
}
}
launch {
viewModel?.getNavigationRouterLink()?.collect { value ->
if(value.isNull()){
return#collect
}
ui.get().access {
ui.get().navigate(
DashboardView::class.java,
RouteParameters(Extras.USER_ID, RandomStringUtils.randomAlphabetic(10))
)
}
}
}
}
}
override fun onDetach(detachEvent: DetachEvent?) {
viewModel?.onCleared()
viewModel = null
super.onDetach(detachEvent)
}
}
AdminPanelRoute.LOGIN = "login",
AdminPanelRoute.DASHBOARD = "dashboard"
Code which handles navigating to another page/view looks like this:
ui.get().navigate(DashboardView::class.java, RouteParameters(Extras.USER_ID, RandomStringUtils.randomAlphabetic(10)))
After execution this is what I get:
Caused by: com.vaadin.flow.router.NotFoundException: No route found
for the given navigation target
'com.fd.jvmbackend.views.adminPanel.login.DashboardView' and
parameters '{extra_user_id=ElKbspkysb}'
DashboardView.kt contents:
package com.fd.jvmbackend.views.adminPanel.login
import com.fd.jvmbackend.util.ResourceHandler
import com.fd.jvmbackend.views.AdminPanelRoute
import com.vaadin.flow.component.AttachEvent
import com.vaadin.flow.component.DetachEvent
import com.vaadin.flow.component.applayout.AppLayout
import com.vaadin.flow.component.applayout.DrawerToggle
import com.vaadin.flow.component.html.Image
import com.vaadin.flow.component.html.Label
import com.vaadin.flow.router.PageTitle
import com.vaadin.flow.router.Route
#Route(value = AdminPanelRoute.DASHBOARD)
#PageTitle("Dashboard | FD CMS")
class DashboardView:AppLayout() {
private val TAG = "DashboardView"
val label = Label("Secret message -> ")
override fun onAttach(attachEvent: AttachEvent?) {
super.onAttach(attachEvent)
}
override fun onDetach(detachEvent: DetachEvent?) {
super.onDetach(detachEvent)
}
}
Please tell me where is the mistake. What am I doing wrong ? The view -> DashboardView is registered with #Route annotation.
Looks like DashboardView::class.java is interpreted as the literal Java String "com.fd.jvmbackend.views.adminPanel.login.DashboardView", not the class object, and the wrong overload of ui.navigate is called. Try passing the Route String (AdminPanelRoute.DASHBOARD) instead.
EDIT: I note you're also passing route parameters with the second parameter of navigate. DashboardView doesn't accept route parameters, so you should remove those.
The navigation is paramater sensitiv. That means if you navigate to the dashboard Route with Parameters it will not be found. Remove the argument from your UI.navigate expression or declare your #Route with a value like "dashboard/:id". See the URL Template Docu.
I have made a simple Jetpack compose app coupled with a server. When I try to communicate with the server from the app, the app crashes without any error messages.
The app code:
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.material.Text
import androidx.compose.runtime.*
import java.io.BufferedReader
import java.io.InputStreamReader
import java.io.PrintWriter
import java.net.Socket
fun getServerMessage(onServerMessage: (msg: String)-> Unit) {
val client = Socket("127.0.0.1", 9999)
val output = PrintWriter(client.getOutputStream(), true)
val input = BufferedReader(InputStreamReader(client.inputStream))
output.println("msg")
onServerMessage(input.readLine())
}
#Composable
fun GreetingFromServer(name: String) {
var text by remember { mutableStateOf("waiting for message") }
thread { getServerMessage { msg -> text = msg } }
Text(text)
}
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
GreetingFromServer("Android")
}
}
}
The server code:
import java.io.BufferedReader
import java.io.InputStreamReader
import java.io.PrintWriter
import java.net.ServerSocket
fun main(args: Array<String>) {
val server = ServerSocket(9999)
println("printing")
while (true) {
val client = server.accept()
println("a client connected")
val output = PrintWriter(client.getOutputStream(), true)
val input = BufferedReader(InputStreamReader(client.inputStream))
output.println("${input.readLine()} back!")
}
}
Why does the app crash when initiating the client object and when running the thread? And how should I go about fixing that?
(The app still crashes when removing the "thread {}" wrapping.)
Ignoring the backend code, since the question was on Jetpack compose Android aspects, a simplified version of a network call would look something like this.
API call
suspend fun getServerMessage(): String {
delay(5000)
return "Success"
}
ViewModel
class GreetingFromServerViewModel : ViewModel() {
var text by mutableStateOf("waiting for message")
init {
getMessage()
}
private fun getMessage() {
viewModelScope.launch(Dispatchers.IO) {
text = getServerMessage()
}
}
}
View Composable
#Composable
fun GreetingFromServer(
viewmodel: GreetingFromServerViewModel = viewModel(),
) {
Text(viewmodel.text)
}
Actual product apps would have a lot more things like using Repositories to manage data fetching, Retrofit if using REST APIs, etc.
Refer: ViewModel, Coroutines
I can't import constrainAs in Jetpack Compose.
Text("Text", Modifier.constrainAs(text) {
top.linkTo(button.bottom, margin = 16.dp)
})
I added constraintlayout dependency:
implementation "androidx.constraintlayout:constraintlayout-compose:1.0.0-alpha08"
But it still says Unresolved reference: constrainAs
constrainAs belongs to ConstraintLayoutScope
it means that in can be used for any view inside ConstraintLayout, but only on a first level child.
ConstraintLayout {
val ref = createRef()
Box(
// OK
modifier = Modifier.constrainAs(ref) {
}
) {
Box(
// Not OK
modifier = Modifier.constrainAs(ref) {
}
)
}
}
Are you adding the following import?
androidx.constraintlayout.compose.ConstraintLayout
You don't need to import constraintsAs separately.
Better to use another version :
implementation "androidx.constraintlayout:constraintlayout-compose:1.0.0-beta02"
I am trying to understand some typescript but mostly works with Dart.
I see the following example code relevant to what I am doing
import {Component} from 'angular2/core';
import {Validators, MaxLengthValidator, Control, ControlGroup} from 'angular2/common';
import {isPresent} from 'angular2/src/facade/lang';
import {bootstrap} from 'angular2/platform/browser';
export class CustomValidators {
static minLengthWithDescription(minLength: number, desc: string): Function {
return (control: modelModule.Control): {[key: string]: any} => {
if (isPresent(Validators.required(control))) return null;
var v: string = control.value;
return v.length < minLength ?
{"minlength": {"requiredLength": minLength, "actualLength": v.length, "desc": desc}} :
null;
};
}
}
I can follow most of the code but what is the following really doing
return (control: modelModule.Control): {[key: string]: any} =>
Could someone who understands both language convert this small class to Dart?
Thanks
It's mostly about moving types from right to left.
I guess the confusing part is {[key: string]: any} which I think is also just the return type of the returned function. I guess it translates to Map<String,dynamic> but there is currently no way to add a return type annotation for a closure in Dart anyway. A workaround would be to create a typedef
typedef Map<String,dynamic> SomeFunc(modelModule.Control control);
class CustomValidators {
static SomeFunc minLengthWithDescription(int minLength, String desc) {
return (modelModule.Control control) {
if (isPresent(Validators.required(control))) return null;
String v = control.value;
return v.length < minLength ?
{"minlength": {"requiredLength": minLength, "actualLength": v.length, "desc": desc}} :
null;
};
}
}
I can't derive what modelModule. is from the code you provided, but I guess it is some namespace or nested scope to refer to the class Control.
Is behavior like this a bug in javafx2 binding?
It seems logical that standalone application itself is always self-informed about own state (xPosition, yPosition, height, width, and so on).
I'm reading book "Pro JavaFX 2 A Definitive Guide to Rich Clients with Java Technology" and some of code examples simply doesn't work. Note: The code I used here is mine. (Is this book relevant?)
package simplejavafxbindingquestion;
import javafx.application.Application;
import javafx.beans.property.SimpleStringProperty;
import javafx.event.EventHandler;
import javafx.geometry.VPos;
import javafx.scene.Scene;
import javafx.scene.SceneBuilder;
import javafx.scene.control.Button;
import javafx.scene.control.ButtonBuilder;
import javafx.scene.control.Label;
import javafx.scene.control.LabelBuilder;
import javafx.scene.layout.HBox;
import javafx.scene.layout.HBoxBuilder;
import javafx.scene.layout.Pane;
import javafx.scene.layout.PaneBuilder;
import javafx.scene.layout.VBox;
import javafx.scene.layout.VBoxBuilder;
import javafx.scene.text.Font;
import javafx.scene.text.Text;
import javafx.scene.text.TextBuilder;
import javafx.stage.Stage;
public class SimpleJavaFXBindingQuestion extends Application {
#Override
public void start(final Stage stage) {
Text textBoundStageHeight;
Text textRequestedStageHeight;
final Label labelRequestedStageHeight;
VBox vBox;
HBox hBox;
Button btnRequest;
Pane sceneRoot = PaneBuilder.create()
.children(
vBox = VBoxBuilder.create()
.spacing(10)
.children(
textBoundStageHeight = TextBuilder.create()
.textOrigin(VPos.TOP)
.font(Font.font("Ariel", 20))
.build(),
hBox = HBoxBuilder.create()
.children(
textRequestedStageHeight = TextBuilder.create()
.textOrigin(VPos.TOP)
.font(Font.font("Ariel", 20))
.text("requested stage height: ")
.build(),
labelRequestedStageHeight = LabelBuilder.create()
.font(Font.font("Ariel", 20))
.text("Unknown")
.build()
)
.build(),
btnRequest = ButtonBuilder.create()
.text("Request height!")
.font(Font.font("Ariel", 15))
.onAction(new EventHandler<javafx.event.ActionEvent>() {
#Override
public void handle(javafx.event.ActionEvent event) {
labelRequestedStageHeight.setText("" + stage.getHeight());
}
})
.build()
)
.build()
)
.build();
textBoundStageHeight.textProperty()
.bind(new SimpleStringProperty("bound stage height: ")
.concat(stage.getHeight()));
Scene scene = SceneBuilder.create()
.root(sceneRoot)
.build();
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
By saying "this behavior" I assume you are mentioning "stage.getHeight()" in
textBoundStageHeight.textProperty()
.bind(new SimpleStringProperty("bound stage height: ")
.concat(stage.getHeight()));
That behavior is not a bug, as documented in concat javadoc:
... Also if the other Object is an implementation of ObservableValue,
changes in the other Object are reflected automatically in the
resulting StringExpression.
So since stage.getHeight() is not an ObservableValue, the changes of height value will not observed. On other hand stage.heightProperty() implements ObservableValue:
textBoundStageHeight.textProperty()
.bind(new SimpleStringProperty("bound stage height: ")
.concat(stage.heightProperty()));