Android Kotlin: How can I delete the data from Firebase - android

I am a new about Android Kotlin. I try to delete the data from Cloud Firebase when I click the button on my app. I did some necessary code on my adapter but How can ı call the database collection on my Activity? ı shared the my adapter and my Activity code below.
class NoteAdapter(val titleText: ArrayList<String>, val rowImage: ArrayList<String>, val noteText: ArrayList<String>, val listener: onClick) : RecyclerView.Adapter<NoteAdapter.NoteHolder>() {
interface onClick {
fun onItemClickListener(v: View, pos: Int, data: Any)
}
class NoteHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val itemImage : ImageView = itemView.findViewById(R.id.recyclerImage)
val itemDelete: ImageView = itemView.findViewById(R.id.delete)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): NoteHolder {
val v = LayoutInflater.from(parent.context).inflate(R.layout.recycler_row, parent, false)
return NoteHolder(v)
}
override fun onBindViewHolder(holder: NoteHolder, position: Int) {
holder.itemView.recyclerTitleText.text = titleText[position]
Picasso.get().load(rowImage[position]).resize(150,150).into(holder.itemImage)
holder.itemView.setOnClickListener {
val intent = Intent(holder.itemView.context, PastNotesActivity:: class.java)
intent.putExtra("oldTitle", titleText[position])
intent.putExtra("oldNote", noteText[position])
intent.putExtra("oldImage", rowImage[position])
holder.itemView.context.startActivity(intent)
}
holder.itemDelete.setOnClickListener { v: View ->
titleText.removeAt(position)
noteText.removeAt(position)
rowImage.removeAt(position)
notifyItemRemoved(position)
listener.onItemClickListener(v, position, holder.itemView)
}
}
override fun getItemCount(): Int {
return titleText.size
}
override fun getItemId(position: Int):Long {
return position.toLong()
}
override fun getItemViewType(position: Int):Int {
return position
}
}
And This is my Activity code, I create the itemDelete fun in this Activity but How can I define my adapter code in this fun? and I tried to write "{id.data}" in my document but did not work what should I write ?
class ListViewActivity : AppCompatActivity() {
var selectedPicture: Uri? = null
private lateinit var auth: FirebaseAuth
private lateinit var db : FirebaseFirestore
var titleTextFromFB : ArrayList<String> = ArrayList()
var noteTextFromFB : ArrayList<String> = ArrayList()
var imageFromFB : ArrayList<String> = ArrayList()
var adapter: NoteAdapter? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_list_view)
auth = FirebaseAuth.getInstance()
db = FirebaseFirestore.getInstance()
getDataFromFirestore()
// recyclerview
var layoutManager = LinearLayoutManager(this)
recyclerView.layoutManager = layoutManager
// adapter = NoteAdapter(titleTextFromFB, imageFromFB, noteTextFromFB)
//recyclerView.adapter = adapter
adapter = NoteAdapter(titleTextFromFB, imageFromFB, noteTextFromFB, object: NoteAdapter.onClick{
override fun onItemClickListener(v: View, pos: Int, data: Any) {
when(v.id){
R.id.delete -> itemDelete(data)
}
}
})
recyclerView.adapter = adapter
}
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
val menuInflater = menuInflater
menuInflater.inflate(R.menu.add_note, menu)
return super.onCreateOptionsMenu(menu)
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
if (item.itemId == R.id.add_note_click) {
// Take Notes Activity
val intent = Intent(applicationContext, TakeNotesActivity::class.java)
intent.putExtra("info","new")
startActivity(intent)
} else if (item.itemId == R.id.log_out) {
val alert = AlertDialog.Builder(this)
alert.setTitle("Log Out")
alert.setMessage("Are you sure to logout from the app ?")
alert.setPositiveButton("Yes") {dialog, which ->
auth.signOut()
val intent = Intent(applicationContext, MainActivity::class.java)
startActivity(intent)
finish()
}
alert.setNegativeButton("No") {dialog, which ->
}
alert.show()
}
return super.onOptionsItemSelected(item)
}
// get data from firestore
fun getDataFromFirestore() {
db.collection("Notes").orderBy("date", Query.Direction.DESCENDING).addSnapshotListener{ snapshot, exception ->
if (exception != null) {
// If there is a error ,
Toast.makeText(applicationContext, exception.localizedMessage.toString(), Toast.LENGTH_LONG).show()
} else {
if (snapshot != null) {
if (!snapshot.isEmpty) {
titleTextFromFB.clear()
noteTextFromFB.clear()
imageFromFB.clear()
val documents = snapshot.documents
for (document in documents) {
val userEmail = document.get("userEmail") as String
val noteTitle = document.get("noteTitle") as String
val yourNote = document.get("yourNote") as String
val downloadUrl = document.get("downloadUrl") as String
val timestamp = document.get("date") as Timestamp
val date = timestamp.toDate()
titleTextFromFB.add(noteTitle)
imageFromFB.add(downloadUrl)
noteTextFromFB.add(yourNote)
adapter!!.notifyDataSetChanged()
}
}
}
}
}
}
fun itemDelete(data: Any) {
db.collection("Notes").document().delete().addOnSuccessListener {
}
.addOnFailureListener { exception ->
Toast.makeText(applicationContext, exception.localizedMessage.toString(), Toast.LENGTH_LONG).show()
}
}
}

This code won't work:
db.collection("Notes").document().delete().addOnSuccessListener {
The db.collection("Notes").document() call creates a reference to a new document, which you then delete. So nothing happens.
What you need to do is determine the ID of the document that the user clicked on, and pass that into the document(...) call. That gives you a DocumentReference to the correct document, so that the delete() call will then delete that document.
The key to determining the ID of the document the user clicked on is in this code:
adapter = NoteAdapter(titleTextFromFB, imageFromFB, noteTextFromFB, object: NoteAdapter.onClick{
override fun onItemClickListener(v: View, pos: Int, data: Any) {
when(v.id){
R.id.delete -> itemDelete(data)
}
}
})
You will need to determine the ID from one of these parameters: v, post, or data. I typically do this by keeping a list of document IDs or DocumentSnapshot objects in my adapter or activity, and then looking the clicked item up by its position/index.
So in your getDataFromFirestore function, add the snapshots to a list that you've defined as a field in your activity class:
// in your activity, declare a list;
var mDocuments: List<DocumentSnapshot>? = null
// Then in getDataFromFirestore store that list
...
mDocuments = snapshot.documents;
val documents = snapshot.documents
for (document in documents) {
...
}
...
// And use it when calling itemDelete:
adapter = NoteAdapter(titleTextFromFB, imageFromFB, noteTextFromFB, object: NoteAdapter.onClick{
override fun onItemClickListener(v: View, pos: Int, data: Any) {
when(v.id){
R.id.delete -> itemDelete(mDocuments[pos])
}
}
})
// To then finally delete the document by its ID
fun itemDelete(doc: DocumentSnapshot) {
db.collection("Notes").document(doc.Id).delete()
}

Related

Change color of un/selected Items in RecyclerView

My problem is that I want to select an item in a RecyclerView and it should change the color and if I click on another the first selected item should change to the default color (and the last clicked should have the selected color).
I have already a color change of the selected one and if I click on the selected one again it changes to default color. Now I am only missing that if I click on an unselected item and if I have already a selected item they "switch" the color
This is my SubItem class:
class SubItem(val channel: Channel) : Item<GroupieViewHolder>() {
#SuppressLint("ResourceAsColor")
override fun bind(viewHolder: GroupieViewHolder, position: Int) {
val profileImageUrl = channel.channel_logo
viewHolder.itemView.sub_item_name.text = channel.channel_name
viewHolder.itemView.sub_item_layout.setBackgroundResource(R.color.white)
viewHolder.itemView.sub_item_name.setTextColor(R.color.colorSecondaryText)
val targetImageView = viewHolder.itemView.sub_item_profile
try {
Picasso.get().load(profileImageUrl)
.placeholder(R.drawable.ic_baseline_account_circle_24)
.into(targetImageView)
}catch (e:Exception){
Log.d("SubItem","${e.message}")
}
viewHolder.itemView.sub_item_layout.setOnClickListener {
if (selected_position == position){
selected_position = null
viewHolder.itemView.sub_item_layout.setBackgroundResource(R.color.white)
viewHolder.itemView.sub_item_name.setTextColor(R.color.colorSecondaryText)
}
else{
selected_position = position
viewHolder.itemView.sub_item_layout.setBackgroundResource(R.color.colorSecondaryText)
viewHolder.itemView.sub_item_name.setTextColor(R.color.black)
}
}
}
override fun getLayout(): Int {
return R.layout.subscription_item
}
}
If it is helping here is my function where I add the items to the RecyclerView
private fun fetchSubs() {
val uid = auth.uid
val user = database.getReference("/users/$uid/subscriptions")
val adapter = GroupAdapter<GroupieViewHolder>()
user.addListenerForSingleValueEvent(object : ValueEventListener{
#SuppressLint("NotifyDataSetChanged")
override fun onDataChange(p0: DataSnapshot) {
p0.children.forEach{
val sub = it.getValue(Subscription::class.java) ?: return
if (sub.subscribed == true) {
val ref = database.getReference("/channels/${sub.channel_uid}")
ref.addListenerForSingleValueEvent(object : ValueEventListener {
override fun onDataChange(p0: DataSnapshot) {
val channel = p0.getValue(Channel::class.java) ?: return
adapter.add(SubItem(channel))
}
override fun onCancelled(error: DatabaseError) {
}
})
}
}
adapter.setOnItemClickListener{ item, view ->
val subItem = item as SubItem
val channelName = subItem.channel.channel_name
val channelUid = subItem.channel.uid
Toast.makeText(requireContext(),"$channelName : $channelUid", Toast.LENGTH_SHORT).show()
fetchSubs()
}
sub_recyclerview.adapter = adapter
}
override fun onCancelled(error: DatabaseError) {
}
})
}
sorry that I am not using Models and Adapter
For everyone who uses groupie like me this could help you in future.
This is my solution for my Problem.
SubItem class
class SubItem(val channel: Channel) : Item<GroupieViewHolder>() {
#SuppressLint("ResourceAsColor")
override fun bind(viewHolder: GroupieViewHolder, position: Int) {
val profileImageUrl = channel.channel_logo
viewHolder.itemView.sub_item_name.text = channel.channel_name
val targetImageView = viewHolder.itemView.sub_item_profile
try {
Picasso.get().load(profileImageUrl)
.placeholder(R.drawable.ic_baseline_account_circle_24)
.into(targetImageView)
}catch (e:Exception){
Log.d("SubItem","${e.message}")
// Toast.makeText(,e.message,Toast.LENGTH_SHORT).show()
}
checkFilter(viewHolder,position)
}
#SuppressLint("ResourceAsColor")
private fun checkFilter(v: GroupieViewHolder, p: Int) {
when (SubscriptionsFragment.list[p]) {
true -> {
v.itemView.sub_item_layout.setBackgroundResource(R.color.colorDivider)
v.itemView.sub_item_name.setTextColor(R.color.black)
}
false -> {
v.itemView.sub_item_layout.setBackgroundResource(R.color.white)
v.itemView.sub_item_name.setTextColor(R.color.colorSecondaryText)
}
}
}
override fun getLayout(): Int {
return R.layout.subscription_item
}
}
My function with setOnItemClickListener
private fun fetchSubs() {
val uid = auth.uid
val user = database.getReference("/users/$uid/subscriptions")
val adapter = GroupAdapter<GroupieViewHolder>()
user.addListenerForSingleValueEvent(object : ValueEventListener{
#SuppressLint("NotifyDataSetChanged")
override fun onDataChange(p0: DataSnapshot) {
list = mutableListOf()
p0.children.forEach{
val sub = it.getValue(Subscription::class.java) ?: return
if (sub.subscribed == true) {
val ref = database.getReference("/channels/${sub.channel_uid}")
ref.addListenerForSingleValueEvent(object : ValueEventListener {
override fun onDataChange(p0: DataSnapshot) {
val channel = p0.getValue(Channel::class.java) ?: return
list.add(false) // created in companion object: var list = mutableListOf<Boolean>()
oldList.add(false) // created in companion object: var oldlist = mutableListOf<Boolean>()
adapter.add(SubItem(channel))
}
override fun onCancelled(error: DatabaseError) {
}
})
}
}
adapter.setOnItemClickListener{ item, view ->
val subItem = item as SubItem
val pos = adapter.getAdapterPosition(subItem)
// Here happens the magic
list[pos] = !list[pos] // change selected item from false to true or from true to false
val l = list[pos] // saving Boolean
list = mutableListOf()
oldList.forEach{ // using oldList to loop so many times I need
list.add(false) // setting all to false
}
if (l){ // if Boolean is true
list[pos] = !list[pos] // change selected item from false to true
}
val channelUid = subItem.channel.uid
fetchVideos(channelUid)
adapter.notifyDataSetChanged() // refresh all items in SubItem
}
try {
sub_recyclerview.adapter = adapter
} catch(e:Exception){
Log.d("fetchSubs","${e.message}")
}
}
override fun onCancelled(error: DatabaseError) {
}
})
}

RecyclerVIew onCreateViewHolder and onBindViewHolder is not called

I'm having two fragments
1.UploadFragment - to upload data to firestore
2.FetchFragemnt - fetch data from firestore and display it in recyclerView
these two fragments are used in a NavigationDrawer.
My problem is in fetchFragment initially recyclerView displays datas that are fetched from firestore.
but when I navigate to UploadFragment and return back to FetchFragment RecyclerView is not loaded.
Also, onCreateViewHolder and onBindViewHolder are not called when I navigate to UploadFragment and return back to FetchFragment.
Please someone help.
FetchFragment code :
class FetchFragment : Fragment(R.layout.fragment_fetch) {
private lateinit var binding : FragmentFetchBinding
private lateinit var adapter: PersonsAdapter
private lateinit var personsList: MutableList<PersonsDb>
private val personCollectionRef = Firebase.firestore.collection("persons")
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding = FragmentFetchBinding.bind(view)
personsList = mutableListOf()
adapter = PersonsAdapter(personsList){item ->
Intent(requireContext(),UpdateActivity::class.java).also{
it.putExtra("EXTRA_DETAILS",item.id)
startActivity(it)
}
}
binding.rvPersons.adapter = adapter
binding.rvPersons.layoutManager = LinearLayoutManager(requireContext())
fetchPPerson()
binding.svFilter.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
override fun onQueryTextSubmit(p0: String?): Boolean {
//Performs search when user hit the search button on the keyboard
// adapter.getFilter().filter(p0);
return false
}
override fun onQueryTextChange(p0: String?): Boolean {
//Start filtering the list as user start entering the characters
adapter.getFilter().filter(p0);
return false
}
})
}
private fun fetchPPerson() = CoroutineScope(Dispatchers.IO).launch{
try{
val querySnapshot = personCollectionRef.get().await()
personsList.clear()
for(document in querySnapshot.documents){
val person = document.toObject<Person>()
personsList.add(
PersonsDb(document.id,
person?.name.toString(),
person?.age.toString().toInt(),
Date(person?.dob.toString())
))
}
withContext(Dispatchers.Main){
adapter.notifyDataSetChanged()
}
}catch (e:Exception){
withContext(Dispatchers.Main){
Toast.makeText(requireContext(),e.message, Toast.LENGTH_LONG).show()
Log.d("Fetch Error", e.message)
}
}
}
}
My Recycler Adapter :
class PersonsAdapter (
var persons : List<PersonsDb>,
private val listener: (PersonsDb) -> Unit
):RecyclerView.Adapter<PersonsAdapter.PersonsViewHolder>(),Filterable{
var personsList = persons
inner class PersonsViewHolder(val binding : ItemPersonBinding):
RecyclerView.ViewHolder(binding.root)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PersonsViewHolder {
val binding = ItemPersonBinding.inflate(LayoutInflater.from(parent.context),parent,false)
return PersonsViewHolder(binding)
}
override fun getItemCount(): Int {
return persons.size
}
override fun getFilter(): Filter {
return filter
}
override fun onBindViewHolder(holder: PersonsViewHolder, position: Int) {
val item = persons[position]
with(holder){
with(persons[position]){
binding.tvName.text = this.name
binding.tvAge.text = this.age.toString()
// binding.tvDob.text = this.dob.toString()
binding.tvDob.text = updateDateInView(this.dob)
}
}
holder.itemView.setOnClickListener { listener(item) }
}
private fun updateDateInView(cal : Date) : String{
val myFormat = "dd/MM/yyyy" // mention the format you need
val sdf = SimpleDateFormat(myFormat, Locale.US)
// binding.dpDob.setText(sdf.format(cal.getTime()))
return sdf.format(cal.getTime())
}
private val filter: Filter = object : Filter() {
override fun performFiltering(constraint: CharSequence): FilterResults {
var filteredList: MutableList<PersonsDb> = arrayListOf()
if (constraint.isEmpty()) {
filteredList.addAll(personsList)
} else {
val filterPattern = constraint.toString().toLowerCase().trim { it <= ' ' }
for (item in 0..persons.size -1) {
if (persons[item].name.toLowerCase().contains(filterPattern)
|| persons[item].age.toString().contains(filterPattern)) {
filteredList.add(persons[item])
}
}
}
val results = FilterResults()
results.count = filteredList.size
results.values = filteredList
// Log.d("Filter Values", results.values.toString())
return results
}
override fun publishResults(charSequence: CharSequence, filterResults: FilterResults) {
persons = if(filterResults == null || filterResults.values == null){
personsList
}
else
filterResults.values as List<PersonsDb>
notifyDataSetChanged()
}
}
}
Can you check Item count( log item count ) . That way you will know if data exists
for recyclerview when returning to FetchFragment . I suspect empty data could be reason.

Key expected String[] but value was a java.lang.String

I am getting issues of getting my USER KEY and it returned as null even if there's a username.
Thing is I am just trying to get my username.
I am currently using firebase database
class NewMessageActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_new_message)
supportActionBar?.title="Select User"
/*
val adapter = GroupAdapter<ViewHolder>()
adapter.add(UserItem())
adapter.add(UserItem())
adapter.add(UserItem())
new_message_list.adapter = adapter
*/
fetchusers()
}
companion object {
val USER_KEY = "USER_KEY"
}
private fun fetchusers(){
val ref = FirebaseDatabase.getInstance().getReference("/users")
ref.addListenerForSingleValueEvent(object: ValueEventListener {
override fun onDataChange(p0: DataSnapshot) {
val adapter = GroupAdapter<ViewHolder>()
p0.children.forEach {
Log.d("NewMessage", it.toString())
val user = it.getValue(User::class.java)
if (user != null){
adapter.add(UserItem(user))
}
}
adapter.setOnItemClickListener { item, view ->
val userItem = item as UserItem
val intent = Intent(view.context, ChatLogActivity::class.java)
intent.putExtra(USER_KEY, userItem.user.username)
startActivity(intent)
finish()
}
new_message_list.adapter = adapter
}
override fun onCancelled(p0: DatabaseError) {
}
})
}
}
class UserItem(val user: User): Item<ViewHolder>() {
override fun bind(viewHolder: ViewHolder, position: Int){
//list stuff
viewHolder.itemView.username_textview_new.text = user.username
Picasso.get().load(user.profileImageUrl).into(viewHolder.itemView.imageview_new_msg)
}
override fun getLayout(): Int {
return R.layout.user_row_new_message
}
}
This one really frustrated me for hours. I needed this for my chat log title for each person
Maybe I should skip this?
I am just new to android development
Can anyone help?
error in debug

Android Kotlin: Wrong images showing in RecyclerView. How can I fix it?

the pictures I show in my recyclerview list are mixed with each other. Let's say that letter A indicates photo X, and letter B indicates photo Y. On my Recyclerview list, A is showing Y photo, and B shows the photo X.When I open the application again, there is no problem. I've been dealing with this problem for a few days, I've tried many solutions but I did not find a true solution until now. How should I solve it? Thanx
If you want to look my adapter and activity code, ı shared the below
My adapter:
class NoteAdapter(private var titleText: ArrayList<String>, private var imageButton: ArrayList<String>, private var noteText: ArrayList<String>) : RecyclerView.Adapter<NoteAdapter.ViewHolder>() {
inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val itemTitle : TextView = itemView.findViewById(R.id.recyclerTitleText)
val itemImage : ImageView = itemView.findViewById(R.id.recyclerImage)
init {
itemView.setOnClickListener { v: View ->
// Toast.makeText(itemView.context,"You clicked on item # ${position + 1}", Toast.LENGTH_SHORT).show()
val intent = Intent(itemView.context, PastNotesActivity::class.java)
intent.putExtra("oldTitle", titleText[position])
intent.putExtra("oldNote", noteText[position])
intent.putExtra("oldImage", imageButton[position])
itemView.context.startActivity(intent)
}
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val v = LayoutInflater.from(parent.context).inflate(R.layout.recycler_row, parent, false)
return ViewHolder(v)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.itemTitle.text = titleText[position]
Picasso.get().load(imageButton[position]).resize(150,150).into(holder.itemImage)
}
override fun getItemCount(): Int {
return titleText.size
}
}
My Activity
class ListViewActivity : AppCompatActivity() {
private lateinit var auth: FirebaseAuth
private lateinit var db : FirebaseFirestore
var titleTextFromFB : ArrayList<String> = ArrayList()
var noteTextFromFB : ArrayList<String> = ArrayList()
var imageFromFB : ArrayList<String> = ArrayList()
var adapter: NoteAdapter? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_list_view)
auth = FirebaseAuth.getInstance()
db = FirebaseFirestore.getInstance()
getDataFromFirestore()
// recyclerview
var layoutManager = LinearLayoutManager(this)
recyclerView.layoutManager = layoutManager
adapter = NoteAdapter(titleTextFromFB, imageFromFB, noteTextFromFB)
recyclerView.adapter = adapter
}
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
val menuInflater = menuInflater
menuInflater.inflate(R.menu.add_note, menu)
return super.onCreateOptionsMenu(menu)
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
if (item.itemId == R.id.add_note_click) {
// Take Notes Activity
val intent = Intent(applicationContext, TakeNotesActivity::class.java)
intent.putExtra("info","new")
startActivity(intent)
} else if (item.itemId == R.id.log_out) {
val alert = AlertDialog.Builder(this)
alert.setTitle("Log Out")
alert.setMessage("Are you sure to logout from the app ?")
alert.setPositiveButton("Yes") {dialog, which ->
auth.signOut()
val intent = Intent(applicationContext, MainActivity::class.java)
startActivity(intent)
finish()
}
alert.setNegativeButton("No") {dialog, which ->
}
alert.show()
}
return super.onOptionsItemSelected(item)
}
// get data from firestore
fun getDataFromFirestore() {
db.collection("Notes").orderBy("date", Query.Direction.DESCENDING).addSnapshotListener{ snapshot, exception ->
if (exception != null) {
// If there is a error ,
Toast.makeText(applicationContext, exception.localizedMessage.toString(), Toast.LENGTH_LONG).show()
} else {
if (snapshot != null) {
if (!snapshot.isEmpty) {
titleTextFromFB.clear()
noteTextFromFB.clear()
val documents = snapshot.documents
for (document in documents) {
val userEmail = document.get("userEmail") as String
val noteTitle = document.get("noteTitle") as String
val yourNote = document.get("yourNote") as String
val downloadUrl = document.get("downloadUrl") as String
val timestamp = document.get("date") as Timestamp
val date = timestamp.toDate()
titleTextFromFB.add(noteTitle)
imageFromFB.add(downloadUrl)
noteTextFromFB.add(yourNote)
adapter!!.notifyDataSetChanged()
}
}
}
}
}
}
}

how to filter list data in descending order in kotlin?

From the Android app, I wrote for I want to add, add a button in the toolbar that acts as a toggle. When the toggle is disabled (the default state) all posts should be shown, when it is enabled (after a tap) the list should only show the posts having user_id set to 1 and sorted by descending published_at. Tapping on the button again will return it to its default state.
Note that publishedAt returning date and publishedAt and user_id coming from postList from the server I want to know how can I implement above requirement what kind of steps should I have to follow
below my logic implementation in MainActivity.kt
class MainActivity : AppCompatActivity() {
#Inject
lateinit var restInterface: RestInterface
private fun initializeDagger() = App.appComponent.inject(this)
var context: Context? = null
private var filteredList: List<Post>? = null
private var recyclerView: RecyclerView? = null
private var switch1: Switch? = null
private var restAdapter: RestAdapter? = null
private var postList: List<Post>? = null
private var restList: RestList? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
initializeDagger()
recyclerView = findViewById(R.id.recycler_view)
switch1 = findViewById(R.id.switch1)
fetchPosts()
switch1.setOnclickListener {
postList.forEach { postItem: Post ->
if (postItem.userId == 1)
filteredList.add(postItem)
}
recyclerView.post = filteredList
recyclerView.notifyDatasetChanged()
}
// Collections.sort( filteredList.get(4).publishedAt, Collections.reverseOrder());
}
private fun fetchPosts() {
val progress = ProgressDialog(this)
progress.setMessage("Loading... ")
progress.isIndeterminate = true
progress.show()
restInterface?.getPosts?.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : DisposableSingleObserver<Response<RestList>>() {
override fun onSuccess(response: Response<RestList>) {
restList = response.body()
val layoutManager = LinearLayoutManager(applicationContext)
recyclerView?.layoutManager = layoutManager
// initialize postList with posts
postList = restList?.posts
restAdapter = postList?.let { RestAdapter(it, restList) }
recyclerView?.adapter = restAdapter
}
override fun onError(e: Throwable) {
progress.dismiss()
Toast.makeText(context, "" + e.message, Toast.LENGTH_SHORT).show()
}
})
}
}
below my RestAdapter.kt
class RestAdapter(val post: List<Post>,val restList: RestList?) : RecyclerView.Adapter<RestAdapter.PostHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PostHolder {
val itemView = LayoutInflater.from(parent.context).inflate(R.layout.post_list, null)
return PostHolder(itemView)
}
override fun getItemCount(): Int {
return post.size
}
override fun onBindViewHolder(holder: PostHolder, position: Int) {
val posts = post[position]
Picasso
.get() // give it the context
.load(posts.image) // load the image
.into(holder.postImage)
holder.userId.text = posts.userId.toString()
holder.postTitle.text = posts.title
holder.postTime.text = posts.publishedAt
holder.postDescription.text = posts.description
}
class PostHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val postImage: ImageView = itemView.findViewById(R.id.postImage)
val userId: TextView = itemView.findViewById(R.id.userId)
val postTitle: TextView = itemView.findViewById(R.id.postTitle)
val postTime: TextView = itemView.findViewById(R.id.postTime)
val postDescription: TextView = itemView.findViewById(R.id.postDescription)
}
}
You can use method .sortedByDescending or .sortedBy on list :)
[Edit]
I give you a simple solution for that, maybe not the best but should work
1. Change RestAdapter constructor to (var post: List,val restList: RestList?)
Add method to updateData in apadapter:
fun filterData(isChecked: Boolean) {
if (isChecked) {
val filteredList = arrayListOf<Post>()
filteredList.addAll(restList?posts.filter { it.user_id == 1 }.sortedByDescending { it.published_at })
post = filteredList
} else {
post = restList?.posts
}
notifyDatasetChanged()
}
And in your class use this:
switch1.setOnclickListener {
restAdapter?.filterData(switch1.isChecked()//state of your switch i.e isChecked() which return true or false)
}

Categories

Resources