UI only partially updates when state is changed - kotlin

Working on a "file explorer" system where the user can browse through directories and select pictures to add to a collection.
The directory system is a map. The current directory (a key in the map) is stored in a UiState object, and the screen shows the list of images belonging to that directory (that key's values). To change the directory, the state is updated, changing currentDirectory to the key of the new directory. In theory, this change causes the list to recompose, now displaying the images in the new directory.
When the directory is changed, the display recomposes into a list of the images in the new directory. The names of the images are all correct.
THE PROBLEM: If there were x images in the previous directory, the first x images of the new directory have the names they are supposed to have, but when you click on them they give you the image of their counterpart in the previous directory, and the checkbox indicating their selection status will have the same value as that of their counterpart.
EXAMPLE: Directory 1 has a picture of a cat. Directory 2 has a picture of an apple and a picture of an orange. When you change directories from Directory 1 to Directory 2, the apple picture will read "apple", but when you click on it it will show a picture of a cat. If the cat picture's checkbox is checked, the apple picture's will be as well. The orange picture will work properly.
Why does the name update, but the checkbox and button do not? The NamedImage is half updating and half being reused?
//gets the current directory and finds its list of images
#Composable
fun ExplorerScreen(viewModel: ExplorerViewModel) {
var directory = viewModel.uiState.collectAsState().value.currentDirectory
ExplorerNamedImageList(MapOfDirectoriesToListsOfImages[directory])
}
//displays namedImages in that list
#Composable
fun ExplorerNamedImageList(namedImages: MutableList<namedImage>) {
Column() {
for (namedImage in namedImages) {
ExplorerNamedImage(namedImage)
}
}
}
//displays and manages clicks on each namedImage
#Composable
fun ExplorerNamedImage(namedImage: NamedImage) {
var checked by remember { mutableStateOf(isImageSelected(namedImage)) }
Button(
onClick = {
showImage(namedImage.bitmap)
//^THIS SHOWS THE WRONG IMAGE
}) {
Text(namedImage.name)
//^THIS SHOWS THE CORRECT NAME
Checkbox(checked = checked ...) {...}
//^THIS HAS THE VALUE OF THE WRONG IMAGE
}
}
//code that changes the current directory (a function of ExplorerViewModel)
fun changeDirectory(newDirectory: String) {
_uiState.update { currentState ->
currentState.copy(currentDirectory = newDirectory)
}
}

Related

howTo get Image Resource of a ImageButton in kotlin

i want change the ImageResource of a ImageButton that i have find by id.
Motivation
a ImageButton(bottom) works as a reminder/backup of the last click of a ImageButton(top) .
setup:
some ImageButton (at the top of the app).
a ImageButton (at the bottom of the app).
example without errors, but don't find ImageResource of idR1
findViewById<ImageButton>(idR1).setOnClickListener {
findViewById<ImageButton>(idR5_oppCiv).setImageResource(R.drawable.athen_cavalry_swordsman);
not working examples
findViewById<ImageButton>(idR1).setOnClickListener {
findViewById<ImageButton>(idR5_oppCiv).setImageResource(it.resources.getDrawable());
findViewById<ImageButton>(idR1).setOnClickListener {
findViewById<ImageButton>(idR5_oppCiv).setImageResource(it.getImageResource());
try to get and set Drawable
following causes the app to crash when i click on an ImageButton.
Here i use a defType "res" to get the resource (the image hopefully).
val resR1: Int = resources.getIdentifier("r1col$i", "res", this.packageName)
findViewById<ImageButton>(idR1).setOnClickListener {
findViewById<ImageButton>(idR5_oppCiv).setImageDrawable(getDrawable(resR1))
How could i get this image resource of it ? And use it for the other ImageButton?
You should be setting the image like using setImageDrawable like this.
val image = findViewById<ImageButton>(R.id.your_view_id)
image.setOnClickListener {
findViewById<ImageButton>(idR5_oppCiv).setImageDrawable(image.drawable)
}

How to change the fonts of all items on recyclerview runtime

I wanted to change font family of items on a recycler view every time I click a button.
So I coded like below.
rbAritaBuri = view.findViewById(R.id.rb_aritaBuri)
rbCafe24 = view.findViewById(R.id.rb_cafe24SurroundAir)
rbAritaBuri.setOnClickListener {
rv_work_preview.tv_work_content.typeface = Typeface.createFromAsset(requireActivity().assets, "fonts/arita_buri.otf")
}
rbCafe24.setOnClickListener {
rv_work_preview.tv_work_content.typeface = Typeface.createFromAsset(requireActivity().assets, "fonts/cafe24_surround_air.ttf")
}
But it changes only the font family of the first item of the recycler view.
Is there a way to change fonts of them all together runtime? And please tell me why the code I wrote doesn't work right.
Thank you.
If I were in your position, I would:
Put your font changing calls inside of onBindViewHolder(). If you have to, you could put a bool in there like buttonClicked and link its value to your buttons.
Come up with a good way to force a call to onBindViewHolder(). Sometimes notifyDataSetChanged() is enough. But in some cases, you might have to remove the adapter by setting it to null and then reset the adapter to its original value.
Place that logic from step 2 inside of your buttons' onClick()s.
Edit:
What I mean is, create a var inside the class with the most exterior scope, so outside of oncreate().
var textChoice=""
Now use your buttons to change that var.
rbAritaBuri.setOnClickListener {
textChoice="fonts/arita_buri.otf"
}
Now inside your onBindViewHolder(), make the font switch.
when (fontChoice){
"fonts/arita_buri.otf"->{ rv_work_preview.tv_work_content.typeface = Typeface.createFromAsset(requireActivity().assets, "fonts/arita_buri.otf")}
//and so on and so forth for all of your fonts
Now when you want to show the change, call notifyDatasetChanged(). I think maybe the best place to do that would be inside of your buttons. So maybe you'd actually have:
rbAritaBuri.setOnClickListener {
textChoice="fonts/arita_buri.otf"
<The name of your recyclerview adapter>.notifyDatasetChanged()
}
Here is how I solved it, thanks to D. Kupra:
class SampleWorkAdapter(private val context: Context) :
RecyclerView.Adapter<SampleWorkAdapter.ViewHolder>() {
var selectedFont = EditTextActivity.HAMBAK_SNOW
First, I assigned the default font Hambak_snow to selectedFont, type String.
inner class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
...
fun changeFont(font: String) {
CustomFontHelper.setCustomFont(content, font, itemView.context)
} ...
}
Then I wrote a function to be called on onBindViewHolder to change font-family of textview, using custom typeface. https://stackoverflow.com/a/16648457/15096801 This post helped a lot.
override fun onBindViewHolder(viewHolder: ViewHolder, position: Int) {
...
viewHolder.changeFont(selectedFont)
...
}
Now, replaceFont will be called when the variable selectedFont get changed and adapter.notifyDatasetChanged() is called on an activity, like this:
rbMapoFlowerIsland.setOnClickListener {
sampleWorkAdapter.selectedFont = EditTextActivity.MAPO_FLOWER
sampleWorkAdapter.notifyDataSetChanged()
}

Couldn't compare a string with another one that is read from properties file

I'm automating a test of location selection. The options will be in the dropdown menu. There are three options(locations) in the dropdown menu. Depending on the location selected the data on the page will be changed accordingly. I'm trying to store the location in the properties and retrieve from it. The location in the properties file looks like:
location=UK
The code to retrieve the location property:
Properties prop = new Properties();
prop.load(f);
setLocation(prop.getProperty("location"));
When I try to print the location property, the correct value is getting displayed.
System.out.println(prop.getProperty("location")); //The value UK is displayed
The setLocation() method code is:
wait.until(ExpectedConditions.visibilityOf(selectLocation));
selectLocation.click(); //now the dropdown will be displayed
Actions action = new Actions(driver);
if(location == "UK") {
wait.until(ExpectedConditions.visibilityOf(ukLocation));
action.moveToElement(ukLocation).click().build().perform();
}
else if(location == "US") {
wait.until(ExpectedConditions.visibilityOf(usLocation));
action.moveToElement(usLocation).click().build().perform();
}else {
System.out.println("didn't get the location");
}
When I run the code
"didn't get the location"
is getting displayed.
I've implemented the properties for the URL and it worked. Here I can get the location property and display it on the console but the problem is occurring at the string comparison. The setLocation() method works if I pass string as the location like:
setLocation("UK");
Try using the .equals rather ==.
if(location.equals("UK")) {

Open specific folder in folder tree (IBM Content Navigator)

I'm developing a IBM Content Navigator plugin, which allows me to open a selected folder from the search feature in the browse feature. The plugin action contains the following code:
// Variable contentItem is provided by Content Navigator when executing the plugin action.
let layout = ecm.model.desktop.layoutDijit;
let browsePaneMenuItem = layout.launchBarContainer.getMenuItemByID("browsePane");
layout.launchBarContainer._menuItemClick(browsePaneMenuItem, false);
layout.mainPane = layout.launchBarContainer._panels["browsePane"];
layout.mainPane.folderTree._tree._selectItem(contentItem);
This code switches the feature and opens the content of the selected folder (contentItem) as the result set in the center panel. However, the folder tree does not open the item at the specific location. To do that, I've tried the following code:
let repo = layout.mainPane.repository;
let parentItemDocId = contentItem.attributes.Parent;
let parentItemTemplate = parentItemDocId.split(',')[0] || null;
repo.retrieveItem(parentItemDocId, function(item) {
contentItem.parent = item;
layout.mainPane.folderTree._tree._selectItem(item);
console.debug('parents parent: ' + item.parent);
}, parentItemTemplate, "current", null, contentItem.objectStoreId, "", null);
The item.parent property in console.debug is undefined, when I call retrieveItem on the repository object.
The contentItem.parent property points to the search, in which the item is being shown. However, contentItem.attributes.Parent is the docid of the actual parent folder. I suspect, Content Navigator can't open the folder, because the contentItem's parent is not the same item in search feature as in the browse feature.
How can I open the specific folder in the folder tree?
To open a specific folder on a Folder Tree all you need to do is create an array of ids with the path of the folders from the root folder to the folder you want to open (you can see the Dossier example in the redbooks to see how to loop subfolders on the server side).
Then run the below js code, when path is an array of objects with id: (starting with the root folder and ending with the selected folder)
var myPaths = [];
myPaths.push(path);
this.folderTree._tree.set('paths', myPaths);

Get all EMF tree roots from open editors

I am currently making a view which searches for all EObjects matching a certain criteria. This view would search in all opened EMF editors. Is there any programmatic way to retrieve the EMF roots from the editors?
[Edit] I meant the editors like the automatically generated tree view editor from the emf plugin. Given that one editor is open, I would like to get the root EObject from this model tree.
I managed to do it. I added a PartListener2 to my active page and searched for active editors. Then I just added this method.
private void addRoot(IEditorReference editorRef) {
IEditorPart editorPart = editorRef.getEditor(false);
if (editorPart instanceof IEditingDomainProvider) {
IEditingDomainProvider editingDomainProvider = (IEditingDomainProvider) editorPart;
EList<Resource> resourceList = editingDomainProvider.getEditingDomain().getResourceSet().getResources();
for (Resource resource : resourceList) {
for (EObject content : resource.getContents()) {
rootMap.put(content, editorRef);
}
}
}
}