TornadoFx pass data from mysql to table view - kotlin

I have a class to pass notes from mysql to tableview in kotlin but i cant seem to make it work
Im a little new in kotlin for desktop, only used in android with firebase
This is my class to get the notes
class Notes(id_notes: Int = 0, title: String = "none", description: String = "none"){
private var id_notes: SimpleIntegerProperty = SimpleIntegerProperty(id_notes)
private var title: SimpleStringProperty = SimpleStringProperty(title)
private var description: SimpleStringProperty = SimpleStringProperty(description)
fun getId(): Int {
return id_notes.get()
}
fun setId(id: Int) {
id_notes.set(id)
}
fun getTitle(): String {
return title.get()
}
fun setTitle(Title: String) {
title.set(Title)
}
fun getDescription(): String {
return description.get()
}
fun setDescription(Description: String) {
description.set(Description)
}
then i have the actual code
tableview(data){
prefWidth = 400.0
column("ID", Notes::getId)
column("Title", Notes::getTitle)
rowExpander {
label {
this.text = Notes::getDescription.toString()
}
}
}
private fun getNotes(){
try {
val notes = Notes()
val sql = ("SELECT id_notes, title, description, date FROM notes")
val con: Connection? = Conn.connection()
stmt = con?.createStatement()
rs = stmt?.executeQuery(sql)
while (rs!!.next()) {
notes.setId(rs!!.getInt("id_notes"))
notes.setDescription(rs!!.getString("description"))
notes.setTitle(rs!!.getString("title"))
data.add(notes.toString())
}
} catch (ex: SQLException) {
alert(Alert.AlertType.ERROR, "Error", "Could not perform this action")
}
}

At the end I will try to solve your problem, but please, read this part first, because this is far more import for you than the actual answer. I believe your programing skills (for now) are not the required for the kind of things you are trying to accomplish, especially because you are converting your class to string before adding it to your data (which seem to be a collection of string not a collection of Notes), so I don’t know how you expect the tableview will get your Id, Title and Description.
Also, you have a constructor for Notes, but you are overcomplicating things by not using it and assign values later. In other hand, you getNotes() function is never call in your code, probably is called in some other part you are not showing.
Because of that, I think you should slow down a little bit, try to level up your basic skills (specially working with classes and collections), them read the tornadofx manual, and them try with this kind of stuff.
Now this is my solution. First try this without the database. I did it this way because I don’t know if there is any problem with your database. Them change the getNotes() function to the way is in your code, without converting the notes.toString(), just de data.add(notes). Remember to click the button to load the data.
class Prueba: View("MainView") {
//data should be an FXCollections.observableArrayList<Notes>
//You didn't show your data variable type, but apparently is some collection of string
val data = FXCollections.observableArrayList<Notes>()
override val root = vbox {
tableview(data){
prefWidth = 400.0
column("ID", Notes::getId)
column("Title", Notes::getTitle)
rowExpander() {
label() {
//Note the difference here, Notes::getDescription.toString() won't do what you want
this.text = it.getDescription()
}
}
}
//This button is calling the function getNotes(), so data can be loaded
button("Load Data") {
action {
getNotes()
}
}
}
//Note this function is out side root now
private fun getNotes() {
data.clear()
data.add(Notes(1,"Title 1", "Description 1"))
data.add(Notes(2,"Title 2", "Description 2"))
data.add(Notes(3,"Title 3", "Description 3"))
}
}

Related

Can't call a function from CountDownTimer object. What am I missing?

I'm going through Googles Kotlin Compose tutorials. One of the tasks is to build a game where you unscramble words. After completing it, I tried to improve the game on my own, and just can't figure out how to add a countdown timer to it. I want the program to skip a word when time runs out.
I'm a programming noob, it's not quite clear to me yet how classes and objects work and how they differ from functions.
The code for the timer at the moment:
object Timer: CountDownTimer(60000, 1000) {
override fun onTick(millisUntilFinished: Long) {
TODO("Not yet implemented")
}
override fun onFinish() {
skipWord() // <<----------- **Unresolved reference: skipWord**
}
}
Elsewhere in my code I have:
class GameViewModel : ViewModel() {
//....
fun skipWord() { // <<---------------- Function that skips to the next word
updateGameState(_uiState.value.score)
updateUserGuess("")
}
//.....
private fun pickRandomWordAndShuffle(): String {
// Continue picking up a new random word until you get one that hasn't been used before
if (currentLanguage == "English") {
currentWord = engWords.random()
} else {
currentWord = finWords.random()
}
setPointAmount()
Timer.start() // <<---------------Start a new countdown for a new word.
if (usedWords.contains(currentWord)) {
return pickRandomWordAndShuffle()
} else {
usedWords.add(currentWord)
return shuffleCurrentWord(currentWord)
}
}
}
Also, a separate problem: the .random() always uses the same seed and picks the same words to unscramble.
Change
object Timer: CountDownTimer(60000, 1000) {
...
to
val timer = object: CountDownTimer(60000, 1000) {
...
and put in into your GameViewModel class.
To solve random issue provide some seed to Random object, like:
var myRandom = Random(System.currentTimeMillis())
and then
currentWord = engWords[myRandon.nextInt(engwords.lastIndex)]

Kotlin / value passing to List<>()

I have a question in List<Contact>() I'm asked to pass init and size. I'm not sure if it's obligated to pass it as in my following tutorial ArrayList<String>() was empty, maybe it's because I was using List<>? Also, it doesn't recognize lowercase() and add() is it also related to List<>?
Code Snippet
val contacts = remember { DataProvider.contactList }
var filteredContacts: List<Contact>
val textState = remember { mutableStateOf(TextFieldValue("")) }
LazyColumn(
...
) {
val searchText = textVal.value.text
filteredContacts = if (searchText.isEmpty()){
contacts
}
else{
val resultList = List<Contact>()
for (contact in contacts) {
if (contact.lowercase(Locale.getDefault()).contains(searchText.lowercase(Locale.getDefault()))) {
resultList.add(contact)
}
}
resultList
}
In kotlin, List has no add method. For that you would need to have a MutableList.
Regarding lowercase method, this is available for Strings. You are trying to apply that to a Contact object, which I guess has no lowercase method.

How to retrieve data from Firestore that stored as an Array and set them as EditText values in Kotlin?

I have stored some data as an array in Firestore using the following code. Now, I want to get those values and put them one by one into the EditTexts. How can I do that?
private fun addZipToFirebase() {
val zipList = createListOfZipCodes()
mFireStore.collection(Constants.USERS)
.document(FirestoreClass().getCurrentUserID())
.update("zip_codes", zipList)
.addOnSuccessListener {
Toast.makeText(
this#AssignZIPCodeActivity,
"Zip Codes updates successfully",
Toast.LENGTH_SHORT
).show()
}
.addOnFailureListener { exception ->
Log.e(
javaClass.simpleName,
exception.message,
exception
)
}
}
Edit:
I am trying with the following code to get the data. I want each Zip Code under the field name zip_codes (in the screenshot), in each EditText (etPinCodeOne, etPinCodeTwo, etPinCodeThree and so on). But with following code what I am getting is all the zip codes together in the EditText. Exctely like, [123456, 789456, 132645,798654, 798654, 799865, 764997, 497646, 946529, 946585]. I want each codes in each EditText.
private fun getZipCodesFromFirebase() {
mFireStore.collection(Constants.USERS)
.document(FirestoreClass().getCurrentUserID())
.get()
.addOnSuccessListener { document ->
val list: ArrayList<String> = ArrayList()
list.add(document["zip_codes"].toString())
Toast.makeText(this#AssignZIPCodeActivity,list.toString(),Toast.LENGTH_SHORT).show()
binding.etZipCodeOne.setText(list[0])
}
}
Can someone help me with this please?
To be able to get the zip_codes array, you need to have inside your User class, a property called zip_codes that needs to be declared of type List:
val zip_codes: List<String>
Now, to get it accordingly, please use the following lines of code:
val uid = FirebaseAuth.getInstance().currentUser!!.uid
val rootRef = FirebaseFirestore.getInstance()
val usersRef = rootRef.collection("users")
val uidRef = usersRef.document(uid)
uidRef.get().addOnCompleteListener { task ->
if (task.isSuccessful) {
val document = task.result
if (document.exists()) {
val zip_codes = document.toObject(User::class.java).zip_codes
//Do what you need to do with your list
} else {
Log.d(TAG, "No such document")
}
} else {
Log.d(TAG, "get failed with ", task.exception)
}
}
Since you are getting multiple zip codes, you should consider using a ListView, or even better a RecyclerView, rather than EditTexts.

Kotlin by lazy throws NullPointerException

I am currently trying to learn Kotlin with the help of the book "Kotlin Programming The Big Nerd Ranch Guide" and so far everything worked.
But now I am struggling with the "lazy" initialization which throws a NullPointerException which says
Cannot invoke "kotlin.Lazy.getValue()" because "< local1>" is null
The corresponding lines are:
val hometown by lazy { selectHometown() }
private fun selectHometown(): String = File("data/towns.txt").readText().split("\n").shuffled().first()
In case you want to compile it yourself or need more code for a better understanding I provide the Game.kt and Player.kt down below. If "lazy" is dropped for a "normal" initialization the hometown gets assigned as intended.
Any tips for solving the problem and understanding the cause of it is welcome.
// Game.kt
package com.bignerdranch.nyethack
fun main(args: Array<String>) {
val player = Player("Madrigal")
player.castFireball()
}
private fun printPlayerStatus(player: Player) {
println("(Aura: ${player.auraColor()}) " + "(Blessed: ${if (player.isBlessed) "YES" else "NO"})")
println("${player.name} ${player.formatHealthStatus()}")
}
// Player.kt
package com.bignerdranch.nyethack
import java.io.File
class Player(_name: String, var healthPoints: Int = 100, val isBlessed: Boolean, private val isImmortal: Boolean) {
var name = _name
get() = "${field.capitalize()} of $hometown"
private set(value) {
field = value.trim()
}
constructor(name: String) : this(name, isBlessed = true, isImmortal = false) {
if (name.toLowerCase() == "kar") healthPoints = 40
}
init {
require(healthPoints > 0, { "healthPoints must be greater than zero." })
require(name.isNotBlank(), { "Player must have a name" })
}
val hometown by lazy { selectHometown() }
private fun selectHometown(): String = File("data/towns.txt").readText().split("\n").shuffled().first()
fun castFireball(numFireballs: Int = 2) =
println("A glass of Fireball springs into existence. (x$numFireballs)")
fun auraColor(): String {
val auraVisible = isBlessed && healthPoints > 60 || isImmortal
return if (auraVisible) "GREEN" else "NONE"
}
fun formatHealthStatus() =
when (healthPoints) {
100 -> "is an excellent condition!"
in 90..99 -> "has a few scratches."
in 75..89 -> if (isBlessed) {
"has some minor wounds but is healing quite quickly"
} else {
"has some minor wounds"
}
in 15..74 -> "looks pretty hurt"
else -> "is in awful condition!"
}
}
I forgot the towns.txt so here it is (not that it matters much)
Neversummer
Abelhaven
Phandoril
Tampa
Sanorith
Trell
Zan'tro
Hermi Hermi
Curlthistle Forest
When something like this happens, it's usually due to bad ordering of initialization.
The initialization of the Player class goes this way:
the name property has its backing field initialized with the _name value
the init block is run, and tries to access name
the getter of name tries to read the hometown property, but fails because hometown is still not initialized
...if things had gone right, the hometown property would be initialized now with the lazy delegate
So basically you're trying to access hometown before the lazy delegate is configured.
If you move hometown's declaration above the init block, you should be fine.
You can see the fix in action on the playground

Kotlin - Trying to factorize code with high-order function

I'm quite new to Kotlin and I'd like to see if using high-order functions can help in my case.
My use-case is that I need to call the methods of an IInterface derived class to send events to one or more components. And I'd like to make this generic, and I want to check if a high-order funtion can help. A sample of code will help to understand (well, I hope so!).
private val eventListeners = mutableListOf<IEventInterface>() // List filled somewhere else!
private fun sendConnectionEvent(dummyString: String) {
val deadListeners = mutableListOf<IEventInterface>()
eventListeners.forEach {
try {
it.onConnectionEvent(dummyString)
} catch (e: DeadObjectException) {
Log.d(TAG, "Removing listener - Exception ${e.message}")
deadListeners.add(it)
}
}
deadListeners.forEach { it ->
eventListeners.remove(it)
}
}
private fun sendWonderfulEvent(dummyString: String, dummyInt: Int) {
val deadListeners = mutableListOf<IEventInterface>()
eventListeners.forEach {
try {
it.onWonderfulEvent(dummyString, dummyInt)
} catch (e: DeadObjectException) {
Log.d(TAG, "Removing listener - Exception ${e.message}")
deadListeners.add(it)
}
}
deadListeners.forEach { it ->
eventListeners.remove(it)
}
}
I added 2 similar methods (I will have many more in the real use case) and I think (I hope!) that something could be done but I can't make high-order function works in this case because:
I want to call the same method on several instances, and not 'just' a basic function
To make things even worse, the methods I need to call don't have the same prototype (that would have been too easy!).
Hope this is clear enough.
Thanks for your help!
VR
Here is how it can be done
fun onEvent(body: (IEventInterface) -> Unit) {
val deadListeners = mutableListOf<IEventInterface>()
eventListeners.forEach {
try {
body(it)
} catch (ex: DeadObjectException) {
Log.d(TAG, "Removing listener - Exception ${e.message}")
deadListeners.add(it)
}
}
deadListeners.forEach { it ->
eventListeners.remove(it)
}
}
Supposing an interface like this:
interface IEventInterface {
fun onConnectionEvent(dummyString: String)
fun onWonderfulEvent(dummyString: String, dummyInt: Int)
}
Define an generic type that implements your defined interface ( <T : IEventInterface>)
Define an mutable list of this type to receive your implementation (MutableList<T>.removeIfThrows)
Expect an extension function for you type that will do your specific validation (and custom parameters if you want)
Using an apply and returning the instance you can run your code like a pipeline
Executing the custom validation when you want
private fun <T : IEventInterface> MutableList<T>.removeIfThrows(validation: T.() -> Unit, customLogMessage: String? = null): MutableList<T> {
return apply {
removeIf {
it.runCatching {
validation()
}.onFailure { error ->
print(customLogMessage ?: "Removing listener - Exception ${error.message}")
}.isFailure
}
}
}
Define your specific implementation passing just the function with custom validation as an parameter
private fun <T : IEventInterface> MutableList<T>.sendConnectionEvent(dummyString: String) = removeIfThrows({
onConnectionEvent(dummyString)
})
private fun <T : IEventInterface> MutableList<T>.sendWonderfulEvent(dummyString: String, dummyInt: Int) = removeIfThrows({
onWonderfulEvent(dummyString, dummyInt)
})
Now you can run your code like an pipeline modifying your original object like this
private fun nowYouCanDoSomethingLikeThis() {
eventListeners
.sendConnectionEvent("some dummy string")
.sendWonderfulEvent("some another dummy string", 123)
}