Reputation: 57
I am newbie Kotlin programmer. I used Notes tutorial to create a recycle view with add button.
In this tutorial he used MVVM pattern design. (model,ViewModel,Repository, and Firebse) NavGraph also used.
My Goal of this app is to start my own application, which is to have a list of players name and info on each item list on the recycle view with a buttons to determine if players came on time or late
so, I need to have a fragment for late players list (which has another recycleView) to show items when late button clicked.
What I have so far, I am able to create a players list "note" and can be deleted, edited but I need when late button clicked send the item to late players fragment with username and time when the button clicked
I have tried to create a data class for late players (usename, id, date). I tried to bind data from the main layout to late players layout but I failed ...
please guide me how to fix my issue
Please find source code for the whole app here on this link https://github.com/abdoh77/MTeamApp
This is what i have now and I need to get to pass data from Players list to another fragment with recycle view
Here is the Data model
package com.example.mteam.data.model
import android.os.Parcelable
import com.google.firebase.firestore.ServerTimestamp
import kotlinx.parcelize.Parcelize
import java.util.Date
@Parcelize
data class PlayersNote (
var id: String = "",
val username: String ="",
val mobile: String="",
@ServerTimestamp
val date: Date = Date(),
):Parcelable
This is the utility
package com.example.mteam.util
sealed class UiState <out T>{
//loading, success, failure
object Loading: UiState<Nothing>()
//we will show the progress bar only
data class Success<out T>(val data: T): UiState<T>()
// On Success we will return data (T) Generic "anyType"
data class Failure(val error: String?): UiState<Nothing>()
// String to indicate failure message
}
Here is Repository class
package com.example.mteam.data.repository
import com.example.mteam.data.model.PlayersNote
import com.example.mteam.util.FireStoreTables
import com.example.mteam.util.UiState
import com.google.firebase.firestore.FirebaseFirestore
class PlayersNoteRepositoryImp(
val database: FirebaseFirestore
//Repository depending on Firebase to get the data.
): PlayersNoteRepository {
//we will get data from firebase collection
override fun getNotes(result: (UiState<List<PlayersNote>>) -> Unit){
database.collection(FireStoreTables.NOTE)
.get()
.addOnSuccessListener {
val notes = arrayListOf<PlayersNote>()
for (document in it){
//convert the document into model class
val note = document.toObject(PlayersNote::class.java)
// convert the document to this model class
notes.add(note) // add model class into the playersNote
list
}
result.invoke(
UiState.Success(notes)
)
}
.addOnFailureListener {
result.invoke(
UiState.Failure(
it.localizedMessage
)
)
}
}
override fun addNote(note: PlayersNote, result: (UiState<String>) -> Unit) {
val document = database.collection(FireStoreTables.NOTE).document()
note.id = document.id
document
.set(note)
.addOnSuccessListener {
result.invoke(
UiState.Success("Created successfully")
)
}
.addOnFailureListener {
result.invoke(
UiState.Failure(
it.localizedMessage
)
)
}
}
override fun updateNote(note: PlayersNote, result: (UiState<String>) -> Unit) {
val document = database.collection(FireStoreTables.NOTE).document(note.id)
document
.set(note)
.addOnSuccessListener {
result.invoke(
UiState.Success("Note updated successfully")
)
}
.addOnFailureListener {
result.invoke(
UiState.Failure(
it.localizedMessage
)
)
}
}
override fun deleteNote(note: PlayersNote, result: (UiState<String>) -> Unit) {
val document = database.collection(FireStoreTables.NOTE).document(note.id)
document
.delete()
.addOnSuccessListener {
result.invoke(
UiState.Success("Note Deleted successfully")
)
}
.addOnFailureListener {
result.invoke(
UiState.Failure(
it.localizedMessage
)
)
}
}
}
Here is my Adapter
package com.example.mteam.note
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.example.mteam.data.model.PlayersNote
import com.example.mteam.databinding.ItemsPlayersListBinding
class NoteListingAdapter(
val onItemClicked: (Int, PlayersNote) -> Unit,
val onEditClicked: (Int, PlayersNote) -> Unit,
val onDeleteClicked: (Int, PlayersNote) -> Unit
) : RecyclerView.Adapter<NoteListingAdapter.MyViewHolder>() {
private var list: MutableList<PlayersNote> = arrayListOf()
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
val itemView = ItemsPlayersListBinding.inflate(LayoutInflater.from(parent.context),parent,false)
return MyViewHolder(itemView)
}
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
val item = list[position]
holder.bind(item)
}
fun updateList(list: MutableList<PlayersNote>){
this.list = list
notifyDataSetChanged()
}
fun removeItem(position: Int){
list.removeAt(position)
notifyItemChanged(position)
}
override fun getItemCount(): Int {
return list.size
}
inner class MyViewHolder(val binding: ItemsPlayersListBinding) :
RecyclerView.ViewHolder(binding.root) {
fun bind(item: PlayersNote){
// binding.id.setText(item.id)
binding.mTitle.setText(item.username)
binding.mSubTitle.setText(item.mobile)
binding.edit.setOnClickListener {
onEditClicked.invoke(bindingAdapterPosition,item) }
binding.delete.setOnClickListener {
onDeleteClicked.invoke(bindingAdapterPosition,item) }
binding.itemLayout.setOnClickListener {
onItemClicked.invoke(bindingAdapterPosition,item) }
}
}
}
Here is the Player list activity code
package com.example.mteam.note
import android.nfc.Tag
import android.os.Bundle
import android.provider.Settings.Global.putString
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels
import androidx.navigation.fragment.findNavController
import com.example.mteam.R
import com.example.mteam.data.model.PlayersNote
import com.example.mteam.databinding.FragmentNotePlayersListBinding
import com.example.mteam.util.UiState
import com.example.mteam.util.hide
import com.example.mteam.util.show
import com.example.mteam.util.toast
import com.google.android.material.tabs.TabLayout.TabGravity
import dagger.hilt.android.AndroidEntryPoint
@AndroidEntryPoint
class NotePlayersList : Fragment() {
val TAG: String = "NotePlayersList"
lateinit var binding : FragmentNotePlayersListBinding
val viewModel: PlayersNoteViewModel by viewModels() // instance of
viewModel to get the data to the fragment
var deletePosition: Int = -1
var list: MutableList<PlayersNote> = arrayListOf()
val adapter by lazy {
NoteListingAdapter(
onItemClicked = { pos, item ->
findNavController().navigate(
R.id.action_notePlayersList_to_notePlayersDetails,Bundle().apply {
putString("type","view")
putParcelable("note",item)
})
},
onEditClicked = {pos, item ->
findNavController().navigate(
R.id.action_notePlayersList_to_notePlayersDetails,Bundle().apply
{
putString("type","edit")
putParcelable("note",item)
})
},
onDeleteClicked = { pos, item ->
deletePosition = pos
viewModel.deleteNote(item)
}
)
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
binding = FragmentNotePlayersListBinding.inflate(layoutInflater)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding.recyclerView.adapter = adapter
binding.recyclerView.itemAnimator = null
binding.createButton.setOnClickListener{
findNavController().navigate(
R.id.action_notePlayersList_to_notePlayersDetails,Bundle().apply {
putString("type","create")
})
}
viewModel.getNotes() //we are calling this function from the ViewModel
viewModel.note.observe(viewLifecycleOwner){
//This is how we got data from live data inside fragment
when(it){
is UiState.Loading -> {
binding.progressBar.show()
//Log.e(TAG,"Loading")
}
is UiState.Failure -> {
binding.progressBar.hide()
toast(it.error)
//Log.e(TAG,it.error. toString())
}
is UiState.Success -> {
binding.progressBar.hide()
list = it.data.toMutableList()
adapter.updateList(list)
}
}
}
viewModel.deleteNote.observe(viewLifecycleOwner){
//This is how we got data from live data inside fragment
when(it){
is UiState.Loading -> {
binding.progressBar.show()
//Log.e(TAG,"Loading")
}
is UiState.Failure -> {
binding.progressBar.hide()
toast(it.error)
// Log.e(TAG,it.error. toString())
}
is UiState.Success -> {
binding.progressBar.hide()
toast(it.data)
if (deletePosition != -1) {
list.removeAt(deletePosition)
adapter.updateList(list)
}
}
}
}
}
}
This is the ViewModel
package com.example.mteam.note
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import com.example.mteam.data.model.PlayersNote
import com.example.mteam.data.repository.PlayersNoteRepository
import com.example.mteam.util.UiState
import dagger.hilt.android.lifecycle.HiltViewModel
import javax.inject.Inject
@HiltViewModel
class PlayersNoteViewModel @Inject constructor(
val repository: PlayersNoteRepository //Dependency of Repository
): ViewModel() {
//To pass data from view model to fragment or activity we use
livedata
private val _notes = MutableLiveData<UiState<List<PlayersNote>>>()
val note: LiveData<UiState<List<PlayersNote>>>
get() = _notes
// to add note
private val _addNote = MutableLiveData< UiState<String>>()
val addNote: LiveData<UiState<String>> //we used String because we are going to pass doucments ID
get() = _addNote
// to update note
private val _updateNote = MutableLiveData< UiState<String>>()
val updateNote: LiveData<UiState<String>> //we used String because we are going to pass doucments ID
get() = _updateNote
// to delete note
private val _deleteNote = MutableLiveData< UiState<String>>()
val deleteNote: LiveData<UiState<String>> //we used String because we are going to pass doucments ID
get() = _deleteNote
fun getNotes() {
_notes.value = UiState.Loading
repository.getNotes {
_notes.value = it
}
}
fun addNote(note: PlayersNote){ //will pass the note object
_addNote.value =UiState.Loading // to trger the loading state
repository.addNote(note){ //getting the note from repository
_addNote.value = it
}
}
fun updateNote(note: PlayersNote){ //will pass the note object
_updateNote.value =UiState.Loading // to trger the loading state
repository.updateNote(note){ //getting the note from repository
_updateNote.value = it
}
}
fun deleteNote(note: PlayersNote) {
_deleteNote.value =UiState.Loading // to trger the loading state
repository.deleteNote(note){ //getting the note from repository
_deleteNote.value = it
}
}
}
Thank you
Upvotes: 0
Views: 35