So the problem I am facing is that when the viewModel data updates it doesn't seems to update the state of my bytearrays: ByteArray by (mutableStateOf) and mutableListOf()
When I change pages/come back to the page it does update them again. How can get the view to update for things like lists and bytearrays
Is mutableStateOf the wrong way to update bytearrays and lists? I couldn't really find anything useful.
Example of byte array that doesn't work (using this code with a Float by mutableStateOf works!).
How I retrieve the data in the #Composable:
val Data = BluetoothMonitoring.shared.Data /*from a viewModel class, doesn't update when Data / bytearray /list changes, only when switching pages in app.*/
Class:
class BluetoothMonitoring : ViewModel(){
companion object {
val shared = BluetoothMonitoring()
}
var Data : ByteArray by mutableStateOf( ByteArray(11) { 0x00 })
}
Any help is appreciated and thanks in advance!
You seem to come from IOS/Swift where using Shared objects is a common pattern
In Android, you're not supposed to create a viewmodel instance by hand, you are supposed to use ViewModelFactory, or compose viewModel() function. The ViewModel object basically preserves some data for you across activity recompositions, i.e. when activity is paused, resumed etc
The general good way of structuring your app is using UDF (Unidirectional Data Flow) where, data flows upwards towards the view/composable and events flow downwards towards the viewmodel, data layer etc. We use something called as Flow which is a reactive data stream, which updates the listener whenever some value changes
Keeping in mind these two points, I've created a very brief way of how you could restructure your code, so that it almost always works. Please adapt accordingly to your logic
class MyViewModel: ViewModel(){
// Declare a flow in the viewModel
var myData = MutableStateFlow(0)
fun modifyMyData(newData: Int){
myData = newData
}
}
And in your composable view layer
#Composable
fun YourComposable(){
val myViewModel = viewModel()
val myUiState by myViewModel.myData.collectAsState()
// Now use your value, and change it, it will be changed accordingly and updated everywhere
}
I also recommend reading this codelab
How I handle byte arrays over Bluetooth with kotlin and Android.
I'm talking sic (communication) to arduino over bluetooth in the app I'm making. Kotlin likes Byte and Arduino likes UBYTE so I do all of those translations in the app because Kotlin threads are inline code easy and the phone has more power for such things.
Add toByte() to everthing that is outbound. <- (actual solution)
outS[8] = Color.alpha(word.color).toByte()
outS[9] = Color.red(word.color).toByte()
outS[10] = Color.green(word.color).toByte()
outS[11] = Color.blue(word.color).toByte()
outS[12] = 0.toByte()
outS[13] = 232.toByte()
outS[14] = 34.toByte()
outS[15] = 182.toByte()
//outS[16] = newline working without a newLine!
// outS[16] = newline
val os = getMyOutputStream()
if (os != null) {
os.write(outS)
}
For inbound data...I have to change everything to UByte. <- (actual solution)
val w: Word = wordViewModel.getWord(i)
if (w._id != 0) {
w.rechecked = (byteArray[7].toInt() != 0)
w.recolor = Color.argb(
byteArray[8].toUByte().toInt(),
byteArray[9].toUByte().toInt(),
byteArray[10].toUByte().toInt(),
byteArray[11].toUByte().toInt()
)
//finally update the word
wordViewModel.update(w)
}
My Youtube channel is about model trains not coding there some android and electronics in there. And a video of bluetooth arduino android is coming soon like tonight or tomorrow soon. I've been working on the app for just over a month using it to learn Kotlin. The project is actually working but I have to do the bluetooth connection manually the app actually controls individual neopixels for my model train layout.
I have been bashing my head about this and can't seem to figure it out. In another engine, I could make a struct, then make an array of that struct that I could then edit in the inspector. There seems to be no way of doing this that I can find in Godot.
I want to have a Resource that holds the starting Value and Type of multiple faces on a dice. For example, one side could have "2 Damage" while another has "Heal 3." (this is a first-time godot experiment inspired by Slice&Dice). Every tutorial I watch however makes it seem like, if I want to do so, I'd have to make a completely new Resource for each combination of Value and Type (Damage 1 Resource, Damage 2 Resource, etc.)
class_name DiceResource extends Resource
class DiceFaceData:
export var BaseValue = 0
export(Resource) var Type = preload("Resources/DiceFaceTypes/Damage.tres")
func _init():
Type = 2
BaseValue = preload("Resources/DiceFaceTypes/Damage.tres")
export(Array) var Faces = [DiceFaceData.new()]
I cannot get DiceFaceData to show up in the Inspector's array, or be on the list of object types for an array. Extending Object doesn't work. Extending Node means I have to instantiate it, which I don't want to do for an editor-only Resource.
I find it hard to imagine Godot doesn't have anything like this available. Is there anything I can load in the inspector as just data and not have to instantiate it? Another option is create two arrays, one with int and another Resource, but that seems inconvenient to fill out. Or should I just give up with Resources and make everything a Node attached to a Node attached to a Node? Thanks!
Godot version 3.4.3
EDIT: If you're someone coming from Unity or Unreal, what you're looking for is Resource. While compared to ScriptableObjects or DataAssets from those other engines, that's not the complete answer. You would think, because of the way those game engines handle it, you can only create custom SO or DA as assets in the filesystem/content browser, but you can also use Resources as instanced classes. Instead of creating a new Resource in the filesystem, you can use
export(Resource) var n = preload("res://MyResourceScript.gd").new()
In the inspector, you can choose from the list New MyResourceScript and create it. You won't be referencing an externally made Reference file, you'll be creating a custom one right there. And look at the below answer as well on good tips for using Resources in cool ways.
First of all, I want to say that I sympathize. Custom resources and the inspector do not work well. There is a solution on the work… However that does not mean that the only thing we can do is keep Waiting For Godot.
Observations on your code
About your code, I want to point out that DiceFaceData is not a resource type. You could write it like this:
class DiceFaceData extends Resource:
export var BaseValue = 0
export(Resource) var Type = preload("Resources/DiceFaceTypes/Damage.tres")
func _init():
Type = 2
BaseValue = preload("Resources/DiceFaceTypes/Damage.tres")
And… That solves nothing.
And, also, by the way, I remind you can put it on its own file:
class_name DiceFaceData
extends Resource:
export var BaseValue = 0
export(Resource) var Type = preload("Resources/DiceFaceTypes/Damage.tres")
func _init():
Type = 2
BaseValue = preload("Resources/DiceFaceTypes/Damage.tres")
And… That is not the solution either.
Something else I want to point out is that GDScript has types. See Static typing in GDScript. Use them. To illustrate…
This is a Variant with an ìnt value
var BaseValue = 0
This is an int, typed explicitly:
var BaseValue:int = 0
And this is an int, typed implicitly with type inference:
var BaseValue := 0
And if you were using types Godot would tell you that this is an error:
BaseValue = preload("Resources/DiceFaceTypes/Damage.tres")
Because BaseValue is an int, and you setting a resource to it.
The Array of Resources problem
First of all, this is a Variant that happens to have an Array value, and it is exported as an Array:
export(Array) var Faces = []
Let us type it as an Array:
export(Array) var Faces := []
And sadly we cannot specify the type of the elements of the arrays in Godot 3.x (we need Godot 4.0 for that feature). However we can specify how we export it.
So, this is an Array exported as an Array of Resource:
export(Array, Resource) var Faces := []
See Exporting arrays.
Before you could not get your custom resource type to show up. And now you have the opposite problem: all the resource types show up. And this includes your custom resource type, if it in its own file.
You would guess that we need to specify the resource type we want:
export(Array, DiceFaceData) var Faces = []
And that would be correct if it were a build-in resource type. But it is a custom one. We are expecting this to be fixed in a future version. Meanwhile we will have to leave it with export(Array, Resource).
Mitigating the problem with an addon
To alleviate the pain of having all the possible resource types, consider using the addon "Improved resource picker" by MakovWait. You can find it on itch, or on github.
A proper solution
Anyway, we can do better. But you are going to need to make your script a tool script (you do that by putting tool on the top of the script, and it means that the code from the script can and will run on the editor).
We are going to define a setter with setget, and in there we are going to make sure the elements are of the correct type:
export(Array, Resource) var Faces = [] setget set_faces
func set_faces(new_value:Array) -> void:
Faces = []
for element in new_value:
element = element as DiceFaceData
if element == null:
element = DiceFaceData.new()
Faces.append(element)
Now, in the inspector panel when you increase the size of the array, Godot will insert a new null element to the array, which makes the setter we defined run, which will find that null and convert it to a new instance of your custom resource type, so you don't have to pick the resource type in the inspector panel at all.
A "hacky" solution
As you know, this does not work:
export(Array, DiceFaceData) var Faces = []
However, we can replace an export with _get_property_list. What happens is that Godot asks the object what properties it has to show up in the inspector panel. Godot does this by calling get_property_list And it will statically report the ones it found while parsing (the ones with export). However, Godot also defines a function _get_property_list where we can add more at run time.
See also Advanced exports.
Which begs the question, could we possibly make it work with _get_property_list? Kind of. The The code like this:
var Faces := []
func _get_property_list() -> Array:
return [
{
name = "Faces",
type = TYPE_ARRAY,
hint = 24,
hint_string = "17/17:DiceFaceData"
}
]
It will show up on the inspector as an array where the elements can only be of your custom resource type.
The issue is that it causes some error spam. Which you might or might not be OK with. It is your project, so it is up to you.
I know it looks like voodoo magic in part because we are using some undocumented stuff. If you want an explanation of that 24 and that 17/17: see How to add Array with hint and hint_string?.
About the sub-resources
Every tutorial I watch however makes it seem like, if I want to do so, I'd have to make a completely new Resource for each combination of Value and Type (Damage 1 Resource, Damage 2 Resource, etc.)
I'm not sure what you are getting to with "a completely new Resource", but yes. A resource is an instance of a resource type. And each of those combination would be a resource.
Perhaps "Damage", "Heal" and so on are resources too. Let us see… I'm guessing that is what the Type is for:
export(Resource) var Type = preload("Resources/DiceFaceTypes/Damage.tres")
Godot would be showing all the resource types it is aware of, which is a pain. I'm going to suggest a different approach than those above for this: Make an String enumeration.
export(String, "Damage", "Heal") var Type:String
That will show up as a drop down list on the inspector panel, with the options you specified.
Why String and not int? Ah, because you can then do this if you so desire:
var type_resource := load("Resources/DiceFaceTypes/" + Type + ".tres")
I'm assuming that those have the code that actually does damage or heal or whatever.
Alright, but when you add a new type of dice face, you would have to come here and update it… Or do you? With the power of tool scripts we are going to update that list to reflect the files that actually exist!
First of all, we are not going to use export, so it will be just:
var Type:String
And now we can export it from _get_property_list. There we can query the files. But before we do that, so we are clear what we have to do, the following code is equivalent to the export we had before:
func _get_property_list() -> Array:
return [
{
name = "Type",
type = TYPE_STRING,
hint = PROPERTY_HINT_ENUM,
hint_string = "Damage,Heal"
}
]
No undocumented stuff here.
Our task is to build that hint_string with the names of the files. And that looks like this:
const path := "res://"
func _get_property_list() -> Array:
var hint_string := ""
var directory := Directory.new()
if OK != directory.open(path) or OK != directory.list_dir_begin(true):
push_error("Unable to read path: " + path)
return []
var file_name := directory.get_next()
while file_name != "":
if not directory.current_is_dir() and file_name.get_extension() == "tres":
if hint_string != "":
hint_string += ","
hint_string += file_name
file_name = directory.get_next()
directory.list_dir_end()
return [
{
name = "Type",
type = TYPE_STRING,
hint = PROPERTY_HINT_ENUM,
hint_string = hint_string
}
]
Ah, yes, set the path constant to the path of the folder where the resources types you have are.
Addendum post edit
I want to elaborate on this example:
export(Resource) var n = preload("res://MyResourceScript.gd").new()
Here we are exporting a variable n as a Resource, which will appear in the Inspector panel. The variable is currently a Variant, we could type it Resource:
export(Resource) var n:Resource = preload("res://MyResourceScript.gd").new()
And then we don't need to tell Godot to export it as a Resource, because it is a Resource:
export var n:Resource = preload("res://MyResourceScript.gd").new()
Something else we can do is preload into a const. To be clear, preloads are resolved at parse time. Like this:
const MyResourceScript := preload("res://MyResourceScript.gd")
export var n:Resource = MyResourceScript.new()
This way, if you need to use the same script in multiple places, you don't need to repeat the path.
However, you might not need the path at all. If in the script res://MyResourceScript.gd we add a class_name (at the top of the script):
class_name MyResourceScript
Then we don't need to use preload at all. That name will be available everywhere, and you can just use it:
export var n:Resource = MyResourceScript.new()
Where is that resource stored?
Potentially nowhere. Above we are telling Godot to create a new one when our it initializes our object (e.g. which could be a Node, or another Resource - because, yes, Resources can have Resources) and those would only exist in RAM.
However, if you modify the Resource from the Inspector panel, Godot needs to store those changes somewhere. Now, if you are editing a Node, by default they go to the scene file. If you are editing another Resource, then it goes to wherever that Resource is stored. To be clear, scenes are resources too (PackedScene). And, yes, that means a file can have multiple Resources (A main resurce and sub-resources). You could also tell Godot to store the Resource in its own file from the Inspector panel. The advantage of giving a file to a Resource is in reusing it in multiple places (multiple scenes, for example).
So, a Resource could be stored in a file, or not stored at all. And a resource file could have a Resource alone, or it could also have sub-resources as well.
I'll take a moment to remind you that scenes can have instances of other scenes inside. So, there is no line between scenes and the so called "prefabs" in Godot.
… Did you know?
You can save the resources you created in runtime, using ResourceSaver. Which could be a way to save player progress, for example. You can also load them using load or ResourceLoader (in fact, load is a shorthand for ResourceLoader.load).
In fact, if you can use load or preload on something, it is a Resource. Wait a minute, we did this above:
const MyResourceScript := preload("res://MyResourceScript.gd")
Yep. The Script is a Resource. And yes, you can create that kind of resources in runtime too. Create a GDScript object (GDScript.new()), set its source_code, and reload it. Then you can attach it to an Object (e.g. a Node) with set_script. You can now start thinking of meta-programming, or modding support.
Hi I am a newbie in CodenameOne am now creating a eCommerce app using CodenameOne resource editor ,I have used multilist for displaying products . I have checked the checkbox feature wherein I got the checkbox for all my items .My question here is by code in statemachine how do I get the name of product checked by the user and how to get whether the checkbox is checked or not .I tried implementing findMultiList().getSelected() but it returns always true if I check r uncheck.
Please help me also it would be great if you could tell me how to integrate google drive in my project because I need to pull data from excel sheet and populate it in the list.
You need to get the model and traverse the elements within it:
ListModel<Map<String, Object>> model = (ListModel<Map<String, Object>>)findMultiList(c).getModel();
ArrayList<Map<String, Object>> items = new ArrayList<>();
for(int iter = 0 ; iter < model.getSize() ; iter++) {
Map<String, Object> current = model.getItemAt(iter);
String checked = (String)current.get("emblem");
if(checked != null && "true".equals(checked)) {
items.add(current);
}
}
I haven't tried this code but it should work. Notice that the name "emblem" is the default name used for the MultiButton/MultiList but you can change it to be anything.
You can place a break point on the for loop and inspect the map elements as you traverse them to see how this works.
Codename One doesn't have dedicated support for google drive api yet...
However, it does support Firebase (noSQL, so no table type data)
THis means you'll have to work with variable pairs.
There are resources for table databases, though :
https://www.codenameone.com/javadoc/com/codename1/db/Database.html
check out these libraries
https://github.com/shannah/cn1-data-access-lib
(Accessing data from web, sqlite support)
https://github.com/jegesh/cn1-object-cacher
(cache from web db)
These resources should help; good luck with your development :)
I found a work around to a problem I had, and I want to know if it is valid or not. It is a similar problem to: Grails Gorm : Object references an unsaved transient instance
Lets assume I have two domain Objects (names changed to protect the guilty).
public class Shelf {
String name
Set<Book> books = [] as Set
static hasMany = [books: Book]
}
and
public class Book {
String title
Shelf shelf
}
So this means that 1 Shelf contains 0 to many Books, and one Book can be on only one Shelf.
This Shelf is very large. And at some point, it contains 80,000 Books. All stored nicely in the DB. Of course, adding new Books is getting slower and slower.
This is done by:
Book book1 = new Book("Awesome Title")
existingShelf.addToBooks(book1)
existingShelf.save(flush: true) // super slow
This is slow. Mainly (I assume) because GORM has to confirm the other 80,000 records.
So I did this to try to work around the slow point.
Book book2 = new Book("Awesome Title 2")
book2.save(flush: true)
This gives me an "Object references an unsaved transient instance", which I guess makes sense - the "shelf" value is empty.
So I did something a little weird:
Book book3 = new Book("Awesome Title 3")
book3.shelf = new Shelf()
book3.shelf.id = <known/valid id here>
book2.save(flush: true)
This works. It saves. There are no referential errors. Further code that depends on this... works.
I just made a call that last minutes and reduced it down to seconds.
But that seems too easy. I'm sure I worked around Grails magic some how. And probably broke something in the process.
Advice? Explanations?
Yes, using addTo* methods can be slow. If you look at the generated SQL you'll understand why. Doing the following:
new Book(title: "GORM Performance", shelf: grailsShelf).save()
will be faster and there is technically nothing wrong with it. Just be aware of that your instance of grailsShelf.books will not contain the new book until you've refreshed the collection from the database. This is part of what the addTo* method does for you.
Side note:
Set<Book> books = [] as Set
is unnecessary.
I've been asked to set up a process which monitors the active directory, specifically certain accounts, to check that they are not locked so that should this happen, the support team can get an early warning.
I've found some code to get me started which basically sets up requests and adds them to a notification queue. This event is then assigned to a change event and has an ObjectChangedEventArgs object passed to it.
Currently, it iterates through the attributes and writes them to a text file, as so:
private static void NotifierObjectChanged(object sender,
ObjectChangedEventArgs e)
{
if (e.ResultEntry.Attributes.AttributeNames == null)
{
return;
}
// write the data for the user to a text file...
using (var file = new StreamWriter(#"C:\Temp\UserDataLog.txt", true))
{
file.WriteLine("{0} {1}", DateTime.UtcNow.ToShortDateString(), DateTime.UtcNow.ToShortTimeString());
foreach (string attrib in e.ResultEntry.Attributes.AttributeNames)
{
foreach (object item in e.ResultEntry.Attributes[attrib].GetValues(typeof(string)))
{
file.WriteLine("{0}: {1}", attrib, item);
}
}
}
}
What I'd like is to check the object and if a specific field, such as name, is a specific value, then check to see if the IsAccountLocked attribute is True, otherwise skip the record and wait until the next notification comes in. I'm struggling how to access specific attributes of the ResultEntry without having to iterate through them all.
I hope this makes sense - please ask if I can provide any additional information.
Thanks
Martin
This could get gnarly depending upon your exact business requirements. If you want to talk in more detail ping me offline and I'm happy to help over email/phone/IM.
So the first thing I'd note is that depending upon what the query looks like before this, this could be quite expensive or error prone (ie missing results). This worries me somewhat as most sample code out there gets this wrong. :) How are you getting things that have changed? While this sounds simple, this is actually a somewhat tricky question in directory land, given the semantics supported by AD and the fact that it is a multi-master system where writes happen all over the place (and replicate in after the fact).
Other variables would be things like how often you're going to run this, how large the data set could be in AD, and so on.
AD has some APIs built to help you here (the big one that comes to mind is called DirSync) but this can be somewhat complicated if you haven't used it before. This is where the "ping me offline" part comes in.
To your exact question, I'm assuming your result is actually a SearchResultEntry (if not I can revise, tell me what you have in hand). If that is the case then you'll find an Attributes field hanging off of that guy, and from there there is AttributeNames and Values. I think you'll see how it works from there if you have Values in hand, for example:
foreach (var attr in sre.Attributes.Values)
{
var da = (DirectoryAttribute)attr;
Console.WriteLine(da.Name);
foreach (var val in da.GetValues(typeof(byte[])))
{
// Handle a byte[] val ...
}
}
As I said, if you have something other than a SearchResultEntry in hand, let us know and I can revise the code sample.