TornadoFX - remove item with ContextMenu right click option - kotlin

So I have a table view that displays an observedArrayList of AccountsAccount(name, login, pass), those are data classes. When I right click a cell there pops an option of delete. What I want to do is delete that Account from the observedArrayList
Only I can not find any way to do this. I am not experienced with JavaFX or TornadoFX and I also can't find the answer with google or in the TornadoFX guides and docs.
This is my code:
class ToolView : View() {
override val root = VBox()
companion object handler {
//val account1 = Account("Google", "martvdham#gmail.com", "kkk")
//val account2 = Account("Google", "martvdham#gmail.com", "Password")
var accounts = FXCollections.observableArrayList<Account>(
)
var gson = GsonBuilder().setPrettyPrinting().create()
val ggson = Gson()
fun writeData(){
FileWriter("accounts.json").use {
ggson.toJson(accounts, it)
}
}
fun readData(){
accounts.clear()
FileReader("accounts.json").use{
var account = gson.fromJson(it, Array<Account>::class.java)
if(account == null){return}
for(i in account){
accounts.add(i)
}
}
}
}
init {
readData()
borderpane {
center {
tableview<Account>{
items = accounts
column("Name", Account::name)
column("Login", Account::login)
column("Password", Account::password)
contextMenu = ContextMenu().apply{
menuitem("Delete"){
selectedItem?.apply{// HERE IS WHERE THE ITEM DELETE CODE SHOULD BE}
}
}
}
}
bottom{
button("Add account").setOnAction{
replaceWith(AddView::class, ViewTransition.SlideIn)
}
}
}
}
}
Thanks!

To clarify #Martacus's answer, in your case you only need to replace // HERE IS WHERE THE ITEM DELETE CODE SHOULD BE with accounts.remove(this) and you're in business.
You could also replace the line
selectedItem?.apply{ accounts.remove(this) }
with
selectedItem?.let{ accounts.remove(it) }
From my experience, let is more common than apply when you are just using a value instead of setting up a receiver.
Note that the process will be different if the accounts list is constructed asynchronously and copied in, which is the default behavior of asyncItems { accounts }.

selectedItem is the item you have selected/rightclicked.
Then you can use arraylist.remove(selectedItem)

Related

onSensorChanged function is called in an other app but not in mine (Kotlin)

i want to implement a step counter in my app, so i search how to make that and i found lot of differents implementations.
I notably found an app on GitHub which works. I have tried to implement this code in my app and in an other "test" app but any of them works and i don't no why.
The problem is caused by the onSensorChanged function of my STEP_COUNTER which is not called.
I have search in all the files of the app and i don't found the problem.
If somebody have a solution...
(I'm french so sorry if it's badly written)
the code i use:
private var sensorManager: SensorManager? = null
// Creating a variable which will give the running status
// and initially given the boolean value as false
private var running = false
// Creating a variable which will counts total steps
// and it has been given the value of 0 float
private var totalSteps = 0f
// Creating a variable which counts previous total
// steps and it has also been given the value of 0 float
private var previousTotalSteps = 0f
//in the onCreate
loadData()
resetSteps()
// Adding a context of SENSOR_SERVICE as Sensor Manager
sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager
override fun onResume() {
super.onResume()
mainHandler.post(pingRunnable)
binding.map.onResume()
running = true
// Returns the number of steps taken by the user since the last reboot while activated
// This sensor requires permission android.permission.ACTIVITY_RECOGNITION.
// So don't forget to add the following permission in AndroidManifest.xml present in manifest folder of the app.
val stepSensor = sensorManager?.getDefaultSensor(Sensor.TYPE_STEP_COUNTER)
if (stepSensor == null) {
// This will give a toast message to the user if there is no sensor in the device
Toast.makeText(this, "No sensor detected on this device", Toast.LENGTH_SHORT).show()
} else {
// Rate suitable for the user interface
sensorManager?.registerListener(this, stepSensor, SensorManager.SENSOR_DELAY_UI)
}
}
override fun onSensorChanged(event: SensorEvent?) {
// Calling the TextView that we made in activity_main.xml
// by the id given to that TextView
var tvStepsTaken = findViewById<TextView>(R.id.step)
if (running) {
totalSteps = event!!.values[0]
// Current steps are calculated by taking the difference of total steps
// and previous steps
val currentSteps = totalSteps.toInt() - previousTotalSteps.toInt()
// It will show the current steps to the user
tvStepsTaken.text = ("$currentSteps")
}
}
private fun resetSteps() {
var resetButton = findViewById<Button>(R.id.reset)
resetButton.setOnClickListener {
// This will give a toast message if the user want to reset the steps
previousTotalSteps = totalSteps
// When the user will click long tap on the screen,
// the steps will be reset to 0
testFragment?.binding?.step?.text = 0.toString()
// This will save the data
saveData()
true
}
}
private fun saveData() {
// Shared Preferences will allow us to save
// and retrieve data in the form of key,value pair.
// In this function we will save data
val sharedPreferences = getSharedPreferences("myPrefs", Context.MODE_PRIVATE)
val editor = sharedPreferences.edit()
editor.putFloat("key1", previousTotalSteps)
editor.apply()
}
private fun loadData() {
// In this function we will retrieve data
val sharedPreferences = getSharedPreferences("myPrefs", Context.MODE_PRIVATE)
val savedNumber = sharedPreferences.getFloat("key1", 0f)
// Log.d is used for debugging purposes
Log.d("MainActivity", "$savedNumber")
previousTotalSteps = savedNumber
}
override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) {
// We do not have to write anything in this function for this app
}

How to open phone gallery clicking a recycler view item (inside custom adapter class)

I'm dev an app that use a recycler view to show items composed by an image and a text. The user can add an item with a custom image, doing this in a normal activity it's easy:
Intent intent = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
launcher.launch(intent);
private final ActivityResultLauncher<Intent> launcher = registerForActivityResult(
new ActivityResultContracts.StartActivityForResult(),
result -> {
if (result.getResultCode() == Activity.RESULT_OK
&& result.getData() != null) {
Uri photoUri = result.getData().getData();
image_to_up = photoUri;
image_uploaded = true;
element_image_add.setImageURI(photoUri);
}
}
);
But if I want let the user edit a recycler view item image, then the same code wont work inside the custom adapter, I get:
Cannot resolve method 'registerForActivityResult' in Adapter
So, how can I do it? How can I let the user open the gallery and select an image inside a custom adapter class?
Define this in your Activity class:
private final ActivityResultLauncher<Intent> launcher = registerForActivityResult(
new ActivityResultContracts.StartActivityForResult(),
result -> {
if (result.getResultCode() == Activity.RESULT_OK
&& result.getData() != null) {
Uri photoUri = result.getData().getData();
image_to_up = photoUri;
image_uploaded = true;
element_image_add.setImageURI(photoUri);
}
}
);
and then create a function in the activity class that call this launcher, then call this function from the adapter class:
public void launch_func() {
Intent intent = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
launcher.launch(intent);
}
Basically you can't call the method inside the adapter so you call it from your activity class, it's not the prettiest but it should works.
You need an activity reference to use the registerForActivityResult method inside the Adapter.
Pass the Activity variable using the constructor of the Adapter and use it like this:
ActivityResultLauncher<Intent> launcher = ((YourActivityClass) activity).registerForActivityResult(
new ActivityResultContracts.StartActivityForResult(),
result -> {
if (result.getResultCode() == Activity.RESULT_OK
&& result.getData() != null) {
//your logic
}
});

Open web page on click at a button in a JetBrains Space chat message using Kotlin SDK

I have a simple chat bot that renders "on this day" facts based on Wikipedia.
As you can see, there's a button on my UI. I want that if the user taps on it, a new browser tab opens with given Wikipedia url.
Until now, I only see the possibility to send other messages using buttons and there action (PostMessageAction).
Do you have any tip on how to achieve my feature idea?
Code
private fun makeMessage(container: OnThisDay): ChatMessage {
return message {
...
section {
text("On this day (${container.date}) happened:")
container.happenings.reversed().forEach {
text(
size = MessageTextSize.SMALL,
content = "${it.year}:\n${it.description}",
)
controls {
wikipediaButton(it.wikipediaUrl) <-- BUTTON
}
divider()
}
}
}
}
private fun MessageControlGroupBuilder.wikipediaButton(urlString: String) {
val action = PostMessageAction("a", "b") <-- NO other action possible?
button("Open Wikipedia", action, MessageButtonStyle.SECONDARY)
}
Screenshot
You can use NavigateUrlAction for this. Here's an example:
message {
section {
controls {
button(
text = "Open Wikipedia",
style = MessageButtonStyle.PRIMARY,
action = NavigateUrlAction(
url = "https://wikipedia.org",
withBackUrl = false,
openInNewTab = true
)
)
}
}
}

SwiftUI : How I can set refreshable for my Scrollview without List

import SwiftUI
struct HomeView: View {
#StateObject var vm = NewsViewModel()
let dataService = NewsDataService.instance
init() {
dataService.apiCall(text: "Korea")
}
var body: some View {
NavigationView {
ScrollView(.vertical, showsIndicators: false) {
SearchView()
VStack {
Divider()
if let newsArray = vm.newsArray?.articles {
ForEach(newsArray) { news in
NewsRowView(news: news)
}
}
}
}
.navigationTitle("News")
.navigationBarTitleDisplayMode(.automatic)
}
}
}
struct HomeView_Previews: PreviewProvider {
static var previews: some View {
HomeView()
}
}
Hi, I tried to find refresh for my scrollview.
But, most of the examples were capable with List.
As you can see my code, I makde my list with HStack children View.
Because of that, I can't use the ".refreshable" modifier.
So, I want to know how I can set that in my view.
And If I can, I want to see detailed code as well!
Thanks.
You could use refreshable like this in your NewsRowView. Keep in mind you would need to make sure you are using ObservableObject where necessary so that it will give you the new data once it's updated.
.refreshable {
Task {
let dataService = NewsDataService.instance
dataService.apiCall(text: "Korea")
}
}

How to have Kotlin "Listen" when a function finish executing Successfully

This is my first time using Kotlin, I have to write a simple command-line application where it takes a list of user input strings. Valid inputs are only "Apple" or "Orange" and calculate the price (which is 60 cents and 25 cents respectively). I'm having some trouble with the 3rd requirement
"Build a service that listens for when orders are complete and sends a notification to the customer regarding its status and estimated delivery time. The Mail service subscribes to events from the Orders service and publishes the appropriate event that the customer (you) is able to read from the terminal"
this is what I have done so far
MainApp.tk
import java.util.Scanner
import kotlin.system.exitProcess;
import app.Checkout;
var shopRunning = true;
var applecount = 0;
fun main(args: Array<String>) {
while (shopRunning) {
println("Welcome to Express Store");
println("1. Checkout");
println("2. exit");
var userOption = 0;
//request the user to eneter an option
//if user eneter a options that is not valid it will keep looping til option that is enterd is accepted;
var userSeletedOption = false;
val inputScanner = Scanner(System.`in`);
while (!userSeletedOption) {
print("Select an Option: ");
userOption = inputScanner.nextInt();
//if input entered by the user is not accepted and invaliud message is printed and is promted to enter an option again.
if (userOption != 1 && userOption != 2) {
println("Invalid input detected!");
} else {
userSeletedOption = true;
}
}
if (userOption == 1) {
val checkout = Checkout();
println("We currently have apples and oranges in Stock.")
var list: MutableList<String> = ArrayList();
println(list.size);
var doneAddingToCart = false;
while(!doneAddingToCart){
print("enter name of item to be enter or exit to finish adding to the cart: ")
var item = inputScanner.next();
if(item.equals("exit")){
doneAddingToCart=true;
}
else{
list.add(item);
}
}
if(checkout.verify(list)){ //checks if list has any item that is not an apple or orange
println("Thank you for your Pruchse");
val cost = checkout.Chasher(list)
println("You bought: "+ list.toString());
print("your total is: "+ cost);//returns the total cost
exitProcess(1);//exits from the application
}
} else if (userOption == 2) {
print("Have a great day.");
exitProcess(1);
}
}
}
CheckOut.tk
class Checkout {
//checks if the user entered any invaild items
public fun verify (cart: MutableList<String>) : Boolean{
for(item in cart){
if(!item.equals("Apple") && !item.equals("Orange")){
return false;
}
}
return true;
}
public fun Chasher (cart: MutableList<String>) : Double{
var total = 0.0;
var orangecount = 0;//step 2 offers
var applecount = 0;//step 2 offers
for(item in cart){//step 1 function
if(item.equals("Apple") || item.equals("apple")){
applecount+=1;
total= total + 0.6;
}
if(item.equals("Orange") || item.equals("orange")){
orangecount +=1;
total=total +0.25;
}
}
if(orangecount ==3){//buy three for the price of 2.step 2
println("You qaulidified for our buy 3 oragnes for the price of 2 offer")
total -=0.25;
}
if(applecount ==1){//buy one aple get 1 free. step 2
println("You buy 1 apple get one free")
cart.add("Apple");
}
return total;
}
}
I don't need to send an email just send a message to the command line. Currently, I'm just printing messages (just to see if what I currently have even works). Yeah, I know there many spelling errors, english and writing was never my strongest subject
I can only provide three hints that might help you:
If you exit your program using System.exit, use 0 if the run did not have any problem. (Excerpt from JavaDoc: "The argument serves as a status code; by convention, a nonzero status code indicates abnormal termination.")
For checking equality, simply use == which corresponds to equals in Java. In your special case however, you can use item.equals("apple", ignoreCase=true) or simply item.equals("apple", true).
I'm not sure what the author of your task exactly expects as a solution.
In can imagine you are expected to use lambdas.
An example: Your could refactor your Checkout class like that:
class Checkout {
/**
* Checks if the given [cart] contains only apples and oranges,
* and calls [onSuccess].
* If also other articles are contained, [onSuccess] is not called.
*/
fun verify(cart: List<String>, onSuccess: (List<String>) -> Unit): Unit {
for (item in cart) {
if (!item.equals("apple", true) && !item.equals("Orange", true)) {
return
}
}
onSuccess(cart)
}
}
And then call
val cart = listOf("Orange", "Apple", "apple", "orange")
Checkout().verify(cart, { cart: List<String> ->
println("Thanks you for your purchase: $cart")
})
or even shorter (curly brackets are outside of parenthesis)
Checkout().verify(cart) { cart: List<String> ->
println("Thanks you for your purchase: $cart")
}
What I did here was to extract what is executed if your validation succeeds:
For that, I used a lambda function that accepts a list of articles/strings (List<String>) and returns something I ignore/don't care about -> Unit.
The advantage of that approach is that callers of your verify method can decide what to do on success at their liking because they can pass a lambda function around like any other variable. Here:
val cart = listOf("Orange", "Apple", "apple", "orange")
val onSuccess = { cart: List<String> ->
println("Thanks you for your purchase: $cart")
}
Checkout().verify(cart, onSuccess)
You could also extend Checkout to allow an observer to register.
I deliberately kept the code very simple. Normally you would allow multiple observers to register, only expose what clients are supposed to see and hide the rest, etc.
class Checkout(
val onSuccess : (List<String>) -> Unit
) {
fun verify(cart: List<String>): Unit {
for (item in cart) {
if (!item.equals("apple", true) && !item.equals("Orange", true)) {
return
}
}
onSuccess(cart)
}
}
val checkout = Checkout({ cart: List<String> ->
println("Thanks you for your purchase: $cart")
})
and then
val cart = listOf("Orange", "Apple", "apple", "orange")
checkout.verify(cart)
Be sure to check out https://play.kotlinlang.org/byExample/04_functional/01_Higher-Order%20Functions to learn more about lambda / higher-order functions.