Optimise Kotlin code for button clicked state - kotlin

I want to change the button background when the button clicked, the function is work by using this code
bank1.setOnClickListener {
bank1.setBackgroundResource(R.drawable.selected_btn_border_blue_bg);
bank2.setBackgroundResource(R.drawable.default_option_border_bg);
bank3.setBackgroundResource(R.drawable.default_option_border_bg);
bank4.setBackgroundResource(R.drawable.default_option_border_bg);
}
bank2.setOnClickListener {
bank2.setBackgroundResource(R.drawable.selected_btn_border_blue_bg);
bank1.setBackgroundResource(R.drawable.default_option_border_bg);
bank3.setBackgroundResource(R.drawable.default_option_border_bg);
bank4.setBackgroundResource(R.drawable.default_option_border_bg);
}
bank3.setOnClickListener {
bank3.setBackgroundResource(R.drawable.selected_btn_border_blue_bg);
bank2.setBackgroundResource(R.drawable.default_option_border_bg);
bank1.setBackgroundResource(R.drawable.default_option_border_bg);
bank4.setBackgroundResource(R.drawable.default_option_border_bg);
}
bank4.setOnClickListener {
bank4.setBackgroundResource(R.drawable.selected_btn_border_blue_bg);
bank2.setBackgroundResource(R.drawable.default_option_border_bg);
bank3.setBackgroundResource(R.drawable.default_option_border_bg);
bank1.setBackgroundResource(R.drawable.default_option_border_bg);
}
But it kinda hardcoded, and make it to so many lines, any way to make the code shorter?

I would keep a variable that keeps track of the selected one like
private var selectedBank: View? = null
And then do
arrayOf(bank1, bank2, bank3, bank4).forEach {
it.setOnClickListener {
selectedBank?.setBackgroundResource(R.drawable.default_option_border_bg)
selectedBank = it
it.setBackgroundResource(R.drawable.selected_btn_border_blue_bg)
}
}
you only need to deselected the previous selected one

Related

How to trigger PC Keyboard inputs in Kotlin Desktop Compose

I am going to develop a POS system using Kotlin Jetpack Compose and I wanna know how to trigger keyboard input events inside my project.
In Compose Desktop You can listen for key events using onKeyEvent Window parameter:
Window(
onCloseRequest = ::exitApplication,
visible = visible,
onKeyEvent = {
if (it.isCtrlPressed && it.key == Key.A) {
println("Ctrl + A is pressed")
true
} else {
// let other handlers receive this event
false
}
}
) {
App()
}
An other options, which will also work for Compose in Android, is using Modifier.onKeyEvent. As documentation says:
will allow it to intercept hardware key events when it (or one of its children) is focused.
So you need to make an item or one of its children focusable and focused. Check out more about focus in compose in this article
To do this you need a FocusRequester, in my example I'm asking focus when view renders using LaunchedEffect.
For the future note, that if user taps on a text field, or an other focusable element will gain focus, your view will loose it. If this focused view is inside your view with onKeyEvent handler, it still gonna work.
An empty box cannot become focused, so you need to add some size with a modifier. It still will be invisible:
val requester = remember { FocusRequester() }
Box(
Modifier
.onKeyEvent {
if (it.isCtrlPressed && it.key == Key.A) {
println("Ctrl + A is pressed")
true
} else {
// let other handlers receive this event
false
}
}
.focusRequester(requester)
.focusable()
.size(10.dp)
)
LaunchedEffect(Unit) {
requester.requestFocus()
}
Alternatively just add content to Box so it will stretch and .size modifier won't be needed anymore
Following the second option of the Philip answer is possible to get a strange behavior when you set the focus and, for some reason, click inside application window. Doing this, is possible "lost" the focus and the key events are not propper handled.
In order to avoid this the suggestion is manually handle this problem by adding a click/tap modifier, which just specifies that when detect a click/tap the requester requests the focus again. See below:
val requester = FocusRequester()
Box(
Modifier
//pointer input handles [onPress] to force focus to the [requester]
.pointerInput(key1 = true) {
detectTapGestures(onPress = {
requester.requestFocus()
})
}
.onKeyEvent {
if (it.isCtrlPressed && it.key == Key.A) {
println("Ctrl + A is pressed")
true
} else {
// let other handlers receive this event
false
}
}
.focusRequester(requester)
.focusable()
.fillMaxSize()
.background(Color.Cyan)
)
LaunchedEffect(Unit) {
requester.requestFocus()
}

What are the possible ways of validating whether all element displayed or not

When I hover the mouse on button, then many options are displayed. Now I want to validate that all the options are displayed or not at single time.
static content = {
timeRangeContainer { $("div.filter-list")[0] }
timeRangeFilterOptions { timeRangeContainer.find ("div.filter-drop li")}
}
def hovermouse(){
interact{
moveToElement(timeRangeFilterButton)
}
def optionDisplayed(){
timeRangeFilterOptions[0].isDisplayed()
}
}
In the above example, I can check only one element whether it displayed or not , But I want to check all the options are displayed or not at single line of code such as (timeRangeFilterOptions.isDisplayed()). Is it possible ?
One way to do it would be:
boolean optionsDisplayed(){
timeRangeFilterOptions*.displayed.every()
}

JavaFX TextField causes NullPointerException

I am using a Button with an event to control the input of a user, but I am having trouble checking whether or not the TextField is empty.
The TextField and Button are declared before the button event, like
TextField svar = new TextField();
Button submitB = new Button("submit");
This is my code:
submitB.setOnAction((event) -> {
if (svar.getText().equals(null) {
primaryStage.setTitle("No input!");
}
if (svar.getText().subSequence(0, 1).toString().toLowerCase().equals(animals.get(pic).getName().subSequence(0, 1).toString().toLowerCase())) {
primaryStage.setTitle("RÄTT!");
bild.setImage(new Image(animals.get(pic+=1).getImgsrc()));
svar.setText(null);
svar.requestFocus();
}
else
{
primaryStage.setTitle("FEL!");
svar.setText(null);
svar.requestFocus();
}
});
This piece of the code above is what in my mind should handle a situation where the TextField is empty:
if (svar.getText().equals(null) {
primaryStage.setTitle("No input!");
}
However I am still getting a NullPointerException no matter what. I've tried some different solutions which have all failed and I'm hoping someone can point me in the right direction. Thanks!
Instead of calling equals to check for null, you should use "==" like:
if (svar.getText() == null) {
Reason you get NPE (NullPointerException) is, since as you say svar.getText() is null, you are trying to call equals on null and a reason for NPE.
The correct way to do it, is not check for Null, but to check for a empty String:
if (svar.getText().equals("") {
primaryStage.setTitle("No input!");
}
Some prefer:
if ("".equals(svar.getText() {
primaryStage.setTitle("No input!");
}

How do I display invalid form Dijits inside closed TitlePanes?

I have a large Dijit-based form with many Dijits in collapsible TitlePanes.
When the form validates, any invalid items hidden inside closed TitlePanes (obviously) cannot be seen. So it appears as though the form is just dead and won't submit, though, unbeknownst to the user, there's actually an error hidden in a closed TitlePane which is preventing the form processing.
What's the solution here? Is there an easy way to simply open all TitlePanes containing Dijits that are in an error state?
If validation is done by following, it will work:-
function validateForm() {
var myform = dijit.byId("myform");
myform.connectChildren();
var isValid = myform.validate();
var errorFields = dojo.query(".dijitError");
errorFields.forEach(fieldnode){
var titlePane = getParentTitlePane(fieldnode);
//write a method getParentTitlePane to find the pane to which this field belongs
if(titlePane) {
titlePane.set('open',true);
}
}
return isValid;
}
function getParentTitlePane(fieldnode) {
var titlePane;
//dijitTitlePane is the class of TitlePane widget
while(fieldnode && fieldnode.className!="dijitTitlePane") {
fieldnode= fieldnode.parentNode;
}
if(fieldnode) {
mynode = dijit.getEnclosingWidget(fieldnode);
}
return titlePane;
}
Lets say if the following is the HTML and we call the above validateForm on submit of form.
<form id="myform" data-dojo-type="dijit/form/Form" onSubmit="validateForm();">
......
</form>
Here's what I ended up doing (I'm not great with Javascript, so this might sucked, but it works -- suggestions for improvement are appreciated):
function openTitlePanes(form) {
// Iterate through the child widgets of the form
dijit.registry.findWidgets(document.getElementById(form.id)).forEach(function(item) {
// Is this a title pane?
if (item.baseClass == 'dijitTitlePane') {
// Iterate the children of this title pane
dijit.registry.findWidgets(document.getElementById(item.id)).forEach(function(child) {
// Does this child have a validator, and -- if so -- is it valid?
if (!(typeof child.isValid === 'undefined') && !child.isValid()) {
// It's not valid, make sure the title pane is open
item.set('open', true);
}
});
}
});
}

ExtJS 4 GroupingSummary How To Deactivate Expand on Summary Row Click

I have an ExtJS 4 grid with GroupingSummary Feature. ExtJs Default is grid is expanded when user clicks on any cell in grouping row. I want to disable this feature, no expansion should take place except when user clicks on designated 'expand' icon. How do I accomplish this?
There is the 'groupclick' event, is there a way to override its default behaviour and do nothing / remove it?
Thanks in advance
The method for it appears to be inherited from Grouping rather than GroupingSummary, so I suspect you need to override this method to prevent the current behaviour:
onGroupClick: function(view, group, idx, foo, e) {
var me = this,
toggleCls = me.toggleCls,
groupBd = Ext.fly(group.nextSibling, '_grouping');
if (groupBd.hasCls(me.collapsedCls)) {
me.expand(groupBd);
} else {
me.collapse(groupBd);
}
So you will need another file with something similar to the following:
Ext.require('Ext.grid.Grouping');
Ext.define('your.class.here', {
override: 'Ext.grid.Grouping',
onGroupClick: function() {
//do nothing
});
)};
Then you should be able to write a function that mimicks it was doing on groupclick, but instead on your icon click. Hope that helps.