I want to remove a object from the list and so that i can add just required string and pass it . i have a model class like this
data class TagItem(
val tagTittle: String,
val isSelected: Boolean
)
this data class is mapped for the Lazy Column for making the list select and deSelect the items
var tagsItems by remember {
mutableStateOf(
(tagsList).map {
TagItem(
tagTittle = it,
isSelected = false
)
}
)
}
val productEveryTags = tagsItems.filter {
it.isSelected
}
Log.i(TAG,"Only this $productEveryTags ")
viewModel.onEvent(ProductUploadEvent.EnteredProductTags(productEveryTags))
i am filtering the selected items alone but in my log statement
Only this [TagItem(tagTittle=Tagged , isSelected=true), TagItem(tagTittle=Ducati , isSelected=true)]
How can i remove the "isSelected" object and just get the "tagTittle" alone into a single List
You can simply map your instances for the output:
Log.i(TAG,"Only this ${productEveryTags.map { it.tagTittle }}")
Or combine it with the existing filter. Depending on whether you are interested in duplicates, you can also directly map to a set:
val productEveryTags = tagsItems.filter {
it.isSelected
}.mapTo(LinkedHashSet()) {
it.tagTittle
}
Log.i(TAG,"Only this $productEveryTags")
Related
I want to filter nested lists with kotlin without changing the object type.
data class ExamResponse(
val list: List<ExamObj>
)
data class ExamObj(
val objList: List<ExamObj2>
)
data class ExamObj2(
val name: String,
val age: Int
)
For example, I want to get the list 'ExamObj' with age value 27 for the above model.
The method to return the list is as follows.
fun progress(respList: List<ExamObj>): List<ExamObj>{}
this method takes a list of 'ExamObj' and filters the 'objList' in 'ExamObj' and returns the 'ExamObj' list again
val result = respList.map {
it.objList.filter {
it.age == 27
}
}
Using this I achieved the desired result but the type issue appeared.
I think you forgot to wrap filtered ExamObj2 list in a ExamObj class...
val result = respList.map { examObj ->
ExamObj(examObj.objList.filter { it.age == 27 })
}
I am trying to extract from a list all element which are not in the sublist already created. I cannot make it work using .filterNot because it filtering on the overall data class store in the list.
var subList2 = allList.filterNot { subList1.contains(it) }.toMutableList()
but allList and subList are a list of data class defined as :
data class Food(
var name: Name,
var state: State
)
As of now, using this code, the sublist2 can contain food that are in sublist1 because state is different.
I want the filter to be done only on name so the sublist2 only contain food which is not in the sublist1 whatever the state is.
Any idea ?
Try to map the subList1 names:
val subList1Names = subList1.map { it.name }
var subList2 = allList.filterNot { it.name in subList1Names }.toMutableList()
I am quite new to Jetpack compose and have an issue that my list is not recomposing when a property of an object in the list changes. In my composable I get a list of available appointments from my view model and it is collected as a state.
// AppointmentsScreen.kt
#Composable
internal fun AppointmentScreen(
navController: NavHostController
) {
val appointmentsViewModel = hiltViewModel<AppointmentViewModel>()
val availableAppointments= appointmentsViewModel.appointmentList.collectAsState()
AppointmentContent(appointments = availableAppointments, navController = navController)
}
In my view model I get the data from a dummy repository which returns a flow.
// AppointmentViewModel.kt
private val _appointmentList = MutableStateFlow(emptyList<Appointment>())
val appointmentList : StateFlow<List<Appointment>> = _appointmentList.asStateFlow()
init {
getAppointmentsFromRepository()
}
// Get the data from the dummy repository
private fun getAppointmentsFromRepository() {
viewModelScope.launch(Dispatchers.IO) {
dummyRepository.getAllAppointments()
.distinctUntilChanged()
.collect { listOfAppointments ->
if (listOfAppointments.isNullOrEmpty()) {
Log.d(TAG, "Init: Empty Appointment List")
} else {
_appointmentList.value = listOfAppointments
}
}
}
}
// dummy function for demonstration, this is called from a UI button
fun setAllStatesToPaused() {
dummyRepository.setSatesInAllObjects(AppointmentState.Finished)
// Get the new data
getAppointmentsFromRepository()
}
Here is the data class for appointments
// Appointment data class
data class Appointment(
val uuid: String,
var state: AppointmentState = AppointmentState.NotStarted,
val title: String,
val timeStart: LocalTime,
val estimatedDuration: Duration? = null,
val timeEnd: LocalTime? = null
)
My question: If a property of one of the appointment objects (in the view models variable appointmentList) changes then there is no recomposition. I guess it is because the objects are still the same and only the properties have changed. What do I have to do that the if one of the properties changes also a recomposition of the screen is fired?
For example if you have realtime app that display stocks/shares with share prices then you will probably also have a list with stock objects and the share price updates every few seconds. The share price is a property of the stock object so this quite a similiar situation.
So I'm updating my RecylerView with StateFlow<List> like following:
My data class:
data class Student(val name: String, var isSelected: Boolean)
My ViewModel logic:
fun updateStudentsOnSelectionChanged(targetStudent: Student) {
val targetIndex = _students.value.indexOf(targetStudent)
val isSelected = !targetStudent.isSelected
_students.value[targetIndex].isSelected = isSelected //<- doesn't work
}
Problem: The UI is not changed, but the isSelected inside _student is changed, what's going on? (same to LiveData)
I assume _students is a StateFlow<List>. Changing the isSelected property of the Student model doesn't trigger the StateFlow. The workaround would be to make the isSelected property of the Student data class immutable to get it compared when new state is set, create a MutableList out of the current list and copy the existing Student object with the new value for isSelected property:
data class Student(val name: String, val isSelected: Boolean)
val students = _students.value.toMutableList()
students[targetIndex] = students[targetIndex].copy(isSelected = isSelected)
_students.value = students
Ok, thanks to #Tenfour04 and #Sergey, I finally found out that StateFlow/LiveData cannot detect the internal changes, that's because they are both actually comparing the Reference of the .value.
That means, If I want to force the StateFow<List> to update, the only way is to assign a new List to it, therefore I created the following helper extension function:
fun <T> List<T>.mapButReplace(targetItem: T, newItem: T) = map {
if (it == targetItem) {
newItem
} else {
it
}
}
//this function returns a new List with the content I wanted
In Fragment:
val itemCheckAction: (Student) -> Unit = { student ->
val newStudent = student.copy(isSelected = !student.isSelected) //prepare a new Student
viewModel.updateStudentsOnSelectionChanged(student, newStudent) //update the StateFlow
}
In ViewModel:
fun updateStudentsOnSelectionChanged(currentStudent: Student, newStudent: Student) {
val newList = _students.value.mapButReplace(currentStudent, newStudent)
_students.value = newList //assign a new List with different reference
}
I have multiple select option and I can receive their ids what I need is to make array of those ids in order to send them to server.
Why I want to make array of my array?
Because my main array includes other information and I just need to extract (make array) of ids not any other values such as names.
Example
I will select 2 items and I receive
id->1
name->one
id->2
name->two
Then I just need to make array like:
items[
0->1
1->2
]
Code
private fun printSelectedValue() {
serviceAdapter?.getList()?.let {
it.forEach { service ->
Log.e("printSelectedValue", "selected service name:- ${service.service.name}")
// I need array of this (service.id)
Log.e("printSelectedValue", "selected service id:- ${service.id}")
}
}
}
PS: I need to be able to use this array (array of ids) in another function so it's preferred to have private value in my fragment in order to access it in other function
Any idea?
fun getSelectedIds(): Map<Int, Int> {
val items = serviceAdapter?.getList() ?: return
return items.withIndex().associate { (index, item) -> index to item.id }
}
I am just giving you an example, change this code according to your use case
In your data class add an extra field for detecting the item is selected or not
so your data class should look like this
data class Item(val id: Int, val name: String, var isSelected: Boolean)
While selecting deselecting item change the value of isSelected accordingly.
Then before sending the value populate an empty ArrayList from selected ArrayList like this
val selectedList = actualDataSet.filter { it.isSelected }
var ids = ArrayList<Int>()
selectedList.forEach { service ->
ids.add(service.id)
}
//here you will get the ArrayList of selected items' id