show progressbar in recyclerview's onBindViewHolder - android

I want to show progressBar from activity (in SubitemAdapter.kt) when elements in recyclerView are being loaded (about 150 to populate) but now this progressBar not shows at all. Here is my code:
CurrencyListFragment.kt
class CurrencyListFragment : Fragment(), MainContract.View {
companion object {
private val TAG = CurrencyListFragment::class.qualifiedName
}
private val restModel: RestModel = RestModel()
private val handler: Handler = Handler(Looper.getMainLooper())
private lateinit var mainPresenter: MainPresenter
private lateinit var itemAdapter: ItemAdapter
private lateinit var _layoutManager: LinearLayoutManager
private lateinit var onChangeFragment: OnChangeFragment
private lateinit var currentDate: String
private var isLoading: Boolean = false
private var apiResponseList: MutableList<ApiResponse> = arrayListOf()
private var listSize: Int = 0
override fun onAttach(context: Context) {
super.onAttach(context)
try {
if (activity is OnChangeFragment) onChangeFragment = activity as OnChangeFragment
} catch (error: ClassCastException) {
error.message?.let { Log.e(TAG, it) }
}
}
// #formatter:off
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.currency_list_fragment, container, false)
}
// #formatter:on
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
_layoutManager = LinearLayoutManager(activity)
mainPresenter = MainPresenter(this, restModel, SharedPreferencesModel(activity as Activity))
currentDate = mainPresenter.convertCurrentDate()
if (mainPresenter.checkIfSuchDateExistsinSp(currentDate)) {
Log.i(TAG, "Date $currentDate already exists in SharedPreferences")
mainPresenter.processDateWithoutMakingACall(currentDate)
} else {
mainPresenter.makeACall(currentDate)
Log.i(TAG, "Date $currentDate does not exist in SharedPreferences. Retrofit call made")
}
mainPresenter.saveNumberOfMinusDaysIntoSp(0)
addScrollerListener()
}
override fun showProgressBarOnLoadingCurrencies() {
progress_bar.visibility = View.VISIBLE
}
override fun hideProgressBarOnFinishedLoadingCurrencies() {
progress_bar.visibility = View.GONE
}
override fun setRecyclerViewStateToLoading() {
if (apiResponseList.size > 0) {
apiResponseList.add(ApiResponse("", "", listOf(Currency("", 0f)), true))
itemAdapter.notifyItemInserted(apiResponseList.size - 1)
}
}
override fun removeRecyclerViewStetOfLoading() {
if (apiResponseList.size > 1) {
apiResponseList.removeAt(apiResponseList.size - 1)
listSize = apiResponseList.size
itemAdapter.notifyItemRemoved(listSize)
}
isLoading = false
}
override fun getApiResponseList(): List<ApiResponse> {
return apiResponseList
}
override fun showLogAboutExistingDateInSp(date: String) {
Log.i(TAG, "Date $date already exists in SharedPreferences (new element)")
}
override fun showLogAboutNotExistingDateInSp(date: String) {
Log.i(TAG, "Date $date does not exist in SharedPreferences. Retrofit call made (new element)")
}
override fun assignResponseToRecyclerview(apiResponse: ApiResponse?) {
rv_item.apply {
layoutManager = _layoutManager
apiResponseList.add(apiResponse!!)
itemAdapter = activity?.let { ItemAdapter(apiResponseList, it) }!!
adapter = itemAdapter
}
}
private fun addScrollerListener() {
rv_item.addOnScrollListener(object : RecyclerView.OnScrollListener() {
override fun onScrollStateChanged(rvItem: RecyclerView, newState: Int) {
super.onScrollStateChanged(rvItem, newState)
mainPresenter.processRvitemOnScroll(isLoading, rvItem, newState)
}
})
}
private fun loadMore() {
setRecyclerViewStateToLoading()
var numberOfDays = mainPresenter.getNumberOfMinusDays()
numberOfDays++
mainPresenter.saveNumberOfMinusDaysIntoSp(numberOfDays)
val dateMinusXDays = mainPresenter.currentDateMinusXDaysToStr(numberOfDays)
val nextLimit = listSize + 1
for (i in listSize until nextLimit) {
if (mainPresenter.checkIfSuchDateExistsinSp(dateMinusXDays)) {
Log.i(TAG, "Date $dateMinusXDays already exists in SharedPreferences (new element)")
handler.postDelayed({
mainPresenter.processDateWithoutMakingACall(dateMinusXDays)
}, 2000)
} else {
Log.i(TAG, "Date $dateMinusXDays does not exist in SharedPreferences. Retrofit call made (new element)")
mainPresenter.makeACall(dateMinusXDays)
}
}
itemAdapter.notifyDataSetChanged()
}
override fun notifyChangedItemAdapter() {
itemAdapter.notifyDataSetChanged()
}
override fun onDestroy() {
super.onDestroy()
restModel.cancelJob()
}
}
ItemAdapter.kt
class ItemAdapter(private var items: MutableList<ApiResponse>, private val activity: Activity) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
companion object {
private const val VIEW_TYPE_DATA = 0
private const val VIEW_TYPE_PROGRESS = 1
}
override fun onCreateViewHolder(parent: ViewGroup, p1: Int): RecyclerView.ViewHolder {
return when (p1) {
VIEW_TYPE_DATA -> {
val view = LayoutInflater.from(parent.context).inflate(R.layout.item, parent, false)
DataViewHolder(view, activity)
}
VIEW_TYPE_PROGRESS -> {
val view = LayoutInflater.from(parent.context).inflate(R.layout.progress_bar_layout, parent, false)
ProgressViewHolder(view)
}
else -> throw IllegalArgumentException("Different View type")
}
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
if (holder is DataViewHolder)
holder.bind(items[position])
}
override fun getItemCount() = items.size
override fun getItemViewType(position: Int): Int {
val viewtype = items[position]
return when (viewtype.isLoading) {//if data is load, returns PROGRESSBAR viewtype.
true -> VIEW_TYPE_PROGRESS
false -> VIEW_TYPE_DATA
}
}
class DataViewHolder(view: View, activity: Activity) : RecyclerView.ViewHolder(view) {
private var isRvSubitemVisible = false
private val tvDate = view.tv_date
private val rvSubitem = view.rv_subitem
private val activity = activity
fun bind(apiResponse: ApiResponse) {
tvDate.text = String.format(itemView.context.getString(R.string.day_x), apiResponse.date)
tvDate.setOnClickListener {
if (isRvSubitemVisible) {
rvSubitem.visibility = View.GONE
isRvSubitemVisible = false
} else {
rvSubitem.visibility = View.VISIBLE
isRvSubitemVisible = true
}
}
rvSubitem.apply {
layoutManager = LinearLayoutManager(itemView.context)
adapter = SubitemAdapter(apiResponse.rates, apiResponse.date, activity)
}
}
}
inner class ProgressViewHolder(view: View) : RecyclerView.ViewHolder(view)
}
SubitemAdapter.kt
class SubitemAdapter(private val subitems: List<Currency>, private val day: String, private val activity: Activity) : RecyclerView.Adapter<SubitemAdapter.SubitemViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, p1: Int): SubitemViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.subitem, parent, false)
return SubitemViewHolder(view, day, activity)
}
override fun onBindViewHolder(holder: SubitemViewHolder, position: Int) {
if(position < subitems.size - 1) {
activity.progress_bar.visibility = View.VISIBLE
}
else
activity.progress_bar.visibility = View.GONE
holder.bind(subitems[position], position)
}
override fun getItemCount() = subitems.size
class SubitemViewHolder(view: View, day: String, activity: Activity) : RecyclerView.ViewHolder(view) {
private val subitemRootView = view.subitem_root
private val tvCurrencyName = view.tv_currency_name
private val tvCurrencyValue = view.tv_currency_value
private val day = day
private val activity = activity
fun bind(currency: Currency, position: Int) {
subitemRootView.setOnClickListener { v ->
activity as OnChangeFragment
activity.changeFragment(SpecificCurrencyFragment(), ChangeFragmentData(hashMapOf(currency.currencyName to currency.currencyValue.toString()), day))
}
tvCurrencyName.text = currency.currencyName
tvCurrencyValue.text = currency.currencyValue.toString()
}
}
}
Here is I think everything to help me. But if you need something else more just aks.
Any help will bve really appreciated. Thank you in advance!

You are already passing a List<Currency> which are the items to be loaded inside your recyclerview. You should not be checking this inside onBindViewHolder since you already have those items when you passed them as an argument to the recyclerview adapter
Instead, when you are passing the List<Currency> to your adapter, you must update the progressbar at that time from activity itself. You can edit your question and add code for your Activity if this didn't help you, I'll try to answer you :)

Related

How can I select all checkBoxes at once in kotlin?

I've got a recyclerView with checkBoxes and I want to select all of them at once by pressing a button
I've try this so far...
This is the Adapter -
class AdapterNfs (context: MainActivity, private val listener: OnItemClickListener) :
RecyclerView.Adapter<AdapterNfs.NfViewHolder>() {
private val context: Context
private var list = emptyList<ReceiverPayment>()
private var status: Boolean = false
init {
this.context = context
}
fun setAllChecked(isChecked: Boolean){
status = isChecked
Log.d("***log", status.toString())
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): NfViewHolder {
val binding = ItemNotasFiscaisBinding.inflate(LayoutInflater.from(parent.context), parent, false)
return NfViewHolder(binding)
}
override fun onBindViewHolder(holder: NfViewHolder, position: Int){
holder.binding.apply {
textNFnumber.text = list[position].id
textNFvalue.text = list[position].totalValue
nfStatus.text = list[position].paid.toString()
}
holder.binding.checkBoxNf.isChecked = status
}
override fun getItemCount() = list.size
inner class NfViewHolder(var binding: ItemNotasFiscaisBinding) : RecyclerView.ViewHolder(binding.root), View.OnClickListener{
init{
binding.checkBoxNf.setOnClickListener(this)
}
override fun onClick(view: View?) {
val checkbox = view as CheckBox
val position : Int = adapterPosition
val data = list
if (position != RecyclerView.NO_POSITION) {
listener.onItemClick(position, checkbox.isChecked, data)
}
}
}
fun setData(newList: List<ReceiverPayment>) {
val nfDiffUtil = DiffUtilGeneric(list, newList)
val nfResult = DiffUtil.calculateDiff(nfDiffUtil)
this.list = newList
nfResult.dispatchUpdatesTo(this)
}
interface OnItemClickListener {
fun onItemClick(
position: Int,
checked: Boolean,
data: List<ReceiverPayment>
)
}
}
and this is the Main -
class MainActivity() : AppCompatActivity(), AdapterNfs.OnItemClickListener {
private val myAdapter = AdapterNfs(this, this)
private lateinit var binding : ActivityMainBinding
private lateinit var mainViewModel: MainViewModel
private lateinit var recyclerView: RecyclerView
private var valueTotal = 00.00
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
mainViewModel = MainViewModel()
setupRecyclerView()
getAllNfs()
setContentView(binding.root)
binding.selectAllCheckBoxes.setOnClickListener {
setAllCheckBoxes(true)
}
}
override fun onItemClick(position: Int, checked: Boolean, data: List<ReceiverPayment>) {
val totalValueSelected = binding.totalValue
val nfSelected = data[position].totalValue.toString().toDouble()
if (checked) {
valueTotal += nfSelected
totalValueSelected.text = valueTotal.toString()
} else {
valueTotal -= nfSelected
totalValueSelected.text = valueTotal.toString()
}
}
private fun setupRecyclerView(){
recyclerView = binding.recyclerViewNfs
binding.recyclerViewNfs.layoutManager = LinearLayoutManager(this)
binding.recyclerViewNfs.itemAnimator = DefaultItemAnimator()
binding.recyclerViewNfs.addItemDecoration(
DividerItemDecoration(
this,
LinearLayoutManager.VERTICAL
)
)
binding.recyclerViewNfs.adapter = myAdapter
}
private fun getAllNfs(){
mainViewModel.allNfs.observe(this#MainActivity){response ->
response.let {
myAdapter.setData(it[0].receiverPayments as List<ReceiverPayment>)
}
}
}
private fun setAllCheckBoxes(isChecked: Boolean){
myAdapter.setAllChecked(isChecked)
}
}
In your adapter , call notifyDataSetChanged() after change the status
fun setAllChecked(isChecked: Boolean){
status = isChecked
Log.d("***log", status.toString())
notifyDataSetChanged()
}

RecyclerView SelectionTracker unable to keep track after navigating back to fragment

In my scenario, I have two fragments. In my first Fragment I have a RecyclerView with SelectionTracker. After selecting an item in my first fragment I can navigate to the second fragment. But from my second fragment if I navigate back to the first fragment using back button all my previous selection is lost. How can I prevent this?
I am using Jetpack Navigation Component to handle Fragment navigation.
Here is my fragment
class SelectVideoForCourseFragment : Fragment(R.layout.fragment_select_video_for_course) {
.....
..
private val adapter by lazy { MediaListAdapter() }
private lateinit var selectionTracker: SelectionTracker<String>
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
initializeListeners()
initializeRecyclerView(savedInstanceState)
fetchMedias()
}
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
selectionTracker.onSaveInstanceState(outState)
}
private fun fetchMedias() {
val mediaRepo = MediaRepo()
mediaRepo.getVideos(contentResolver).observe(viewLifecycleOwner) {
adapter.submitItems(it)
}
}
private fun initializeRecyclerView(savedInstanceState: Bundle?) {
binding.mediaList.layoutManager = GridLayoutManager(requireContext(), 3)
binding.mediaList.addItemDecoration(GridSpacingItemDecoration(3, 5.dp, false))
binding.mediaList.adapter = adapter
selectionTracker = SelectionTracker.Builder(
"tracker-select-video-for-course",
binding.mediaList,
MediaItemKeyProvider(adapter),
MediaItemDetailsLookup(binding.mediaList),
StorageStrategy.createStringStorage()
).withSelectionPredicate(
SelectionPredicates.createSelectSingleAnything()
).build()
if (savedInstanceState != null) {
selectionTracker.onRestoreInstanceState(savedInstanceState)
}
adapter.tracker = selectionTracker
}
......
...
}
My RecyclerView Adapter:
class MediaListAdapter: RecyclerView.Adapter<RecyclerView.ViewHolder>() {
val differ = AsyncListDiffer(this, DIFF_CALLBACK_MEDIA)
var tracker: SelectionTracker<String>? = null
fun submitItems(updatedItems: List<Any>) {
differ.submitList(updatedItems)
}
fun getSelections(): List<MediaEntity> {
....
..
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return if (viewType == 1) {
val binding = ListItemImageBinding.inflate(
LayoutInflater.from(parent.context),
parent,
false
)
ViewHolderImage(binding)
} else {
val binding = ListItemVideoBinding.inflate(
LayoutInflater.from(parent.context),
parent,
false
)
ViewHolderVideo(binding)
}
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
if (holder is ViewHolderImage) {
tracker?.let {
val item = differ.currentList[position] as ImageEntity
holder.bind(item , it.isSelected(item.uri.toString()))
}
} else {
holder as ViewHolderVideo
val item = differ.currentList[position] as VideoEntity
tracker?.let {
holder.bind(item, it.isSelected(item.uri.toString()))
}
}
}
override fun getItemCount(): Int = differ.currentList.size
override fun getItemViewType(position: Int): Int {
return if (differ.currentList[position] is ImageEntity) {
1
} else {
2
}
}
inner class ViewHolderImage(
private val binding: ListItemImageBinding): RecyclerView.ViewHolder(binding.root
) {
fun bind(item: ImageEntity, isSelected: Boolean) {
.....
...
}
fun getItemDetails(): ItemDetailsLookup.ItemDetails<String> =
object : ItemDetailsLookup.ItemDetails<String>() {
override fun getPosition(): Int = absoluteAdapterPosition
override fun getSelectionKey(): String {
val item = differ.currentList[absoluteAdapterPosition] as ImageEntity
return item.uri.toString()
}
override fun inSelectionHotspot(e: MotionEvent): Boolean = true
}
}
inner class ViewHolderVideo(
private val binding: ListItemVideoBinding,
): RecyclerView.ViewHolder(binding.root) {
fun bind(item: VideoEntity, isSelected: Boolean) {
.....
...
}
fun getItemDetails(): ItemDetailsLookup.ItemDetails<String> =
object : ItemDetailsLookup.ItemDetails<String>() {
override fun getPosition(): Int = absoluteAdapterPosition
override fun getSelectionKey(): String {
val item = differ.currentList[absoluteAdapterPosition] as VideoEntity
return item.uri.toString()
}
override fun inSelectionHotspot(e: MotionEvent): Boolean = true
}
}
companion object {
val DIFF_CALLBACK_MEDIA = object: DiffUtil.ItemCallback<Any>() {
.....
...
}
}
}

How to insert items at a certain position in a recyclerView?

I have set up a fragment with a recyclerView in it and I fetch data from firestore successfully. What I want to know is that if it is possible to add items at a certain position in recyclerView. Suppose, I want to add an item (from a different collection in Firestore) after every 5 items in a recyclervView. Is it possible to do it in Android using Kotlin?
Thank you.
Edit:
DashboardFragment.kt
class DashboardFragment : BaseFragment() {
var srchProductsList: ArrayList<Product> = ArrayList()
var adList: ArrayList<Ads> = ArrayList()
var srchTempProductsList: ArrayList<Product> = ArrayList()
var newView: String = "ListView"
private lateinit var binding: FragmentDashboardBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setHasOptionsMenu(true)
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
binding = FragmentDashboardBinding.inflate(inflater, container, false)
binding.fbDashboard.setImageResource(R.drawable.ic_grid_view)
binding.fbDashboard.setOnClickListener {
if (newView=="ListView"){
newView="GridView"
fb_dashboard.setImageResource(R.drawable.ic_list_view)
}else{
newView="ListView"
fb_dashboard.setImageResource(R.drawable.ic_grid_view)
}
onResume()
}
return binding.root
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
val id = item.itemId
when (id) {
R.id.action_settings -> {
startActivity(Intent(activity, SettingsActivity::class.java))
return true
}
R.id.action_cart -> {
startActivity(Intent(activity, CartListActivity::class.java))
return true
}
}
return super.onOptionsItemSelected(item)
}
override fun onResume() {
super.onResume()
srchProductsList.clear()
srchTempProductsList.clear()
getDashboardItemsList()
}
private fun getDashboardItemsList() {
showProgressDialog(resources.getString(R.string.please_wait))
getDashboardItemsList2()
}
fun successDashboardItemsList(dashboardItemsList: ArrayList<Product>) {
val adsLists =getListOfAds()
hideProgressDialog()
if (dashboardItemsList.size > 0) {
Toast.makeText(
context,
"Total " + dashboardItemsList.size + " products loaded",
Toast.LENGTH_LONG
).show()
rv_dashboard_items.visibility = View.VISIBLE
tv_no_dashboard_items_found.visibility = View.GONE
rv_dashboard_items.layoutManager =
StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL)
rv_dashboard_items.setHasFixedSize(true)
val adapter = DashboardItemsListAdapterTest(requireActivity(), dashboardItemsList,adsLists)
rv_dashboard_items.adapter = adapter
//////// I HAVE PROBLEM WITH THE FOLLOWING BLOCK OF CODE WHICH IS WHY I HAVE COMMENTED IT OUT ONLY TO CHECK IF OTHER PART OF THE CODE IS WORKING. I NEED TO FIX THE ERROR FOR THE BELOW BLOCK OF CODE ALSO
/* adapter.setOnClickListener(object :
DashboardItemsListAdapter.OnClickListener {
override fun onClick(position: Int, product: Product) {
val intent = Intent(context, ProductDetailsActivity::class.java)
intent.putExtra(Constants.EXTRA_PRODUCT_ID, product.product_id)
intent.putExtra(Constants.EXTRA_PRODUCT_OWNER_ID, product.user_id)
startActivity(intent)
}
})*/
} else {
rv_dashboard_items.visibility = View.GONE
tv_no_dashboard_items_found.visibility = View.VISIBLE
}
}
fun successDashboardItemsListListView(dashboardItemsList: ArrayList<Product>) {
val adsLists =getListOfAds()
hideProgressDialog()
if (dashboardItemsList.size > 0) {
Toast.makeText(
context,
"Total " + dashboardItemsList.size + " products loaded",
Toast.LENGTH_LONG
).show()
rv_dashboard_items.visibility = View.VISIBLE
tv_no_dashboard_items_found.visibility = View.GONE
rv_dashboard_items.layoutManager =
LinearLayoutManager(context)
rv_dashboard_items.setHasFixedSize(true)
val adapter = DashboardItemsListAdapterTest(requireActivity(), dashboardItemsList,adsLists)
rv_dashboard_items.adapter = adapter
//////// I HAVE PROBLEM WITH THE FOLLOWING BLOCK OF CODE WHICH IS WHY I HAVE COMMENTED IT OUT ONLY TO CHECK IF OTHER PART OF THE CODE IS WORKING. I NEED TO FIX THE ERROR FOR THE BELOW BLOCK OF CODE ALSO
/* adapter.setOnClickListener(object :
DashboardItemsListAdapter.OnClickListener {
override fun onClick(position: Int, product: Product) {
val intent = Intent(context, ProductDetailsActivity::class.java)
intent.putExtra(Constants.EXTRA_PRODUCT_ID, product.product_id)
intent.putExtra(Constants.EXTRA_PRODUCT_OWNER_ID, product.user_id)
startActivity(intent)
}
})*/
} else {
rv_dashboard_items.visibility = View.GONE
tv_no_dashboard_items_found.visibility = View.VISIBLE
}
}
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
inflater.inflate(R.menu.dashboard_menu, menu)
super.onCreateOptionsMenu(menu, inflater)
val item = menu.findItem(R.id.my_search_bar)
val searchView = item?.actionView as SearchView
searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
override fun onQueryTextSubmit(query: String?): Boolean {
srchTempProductsList.clear()
val searchKey = query
if (searchKey != null) {
if (searchKey.isNotEmpty()) {
srchProductsList.forEach {
if (it.description.toLowerCase(Locale.getDefault())
.contains(searchKey)
) {
srchTempProductsList.add(it)
}
}
rv_dashboard_items.adapter!!.notifyDataSetChanged()
} else {
srchTempProductsList.clear()
srchTempProductsList.addAll(srchProductsList)
rv_dashboard_items.adapter!!.notifyDataSetChanged()
}
}
return false
}
override fun onQueryTextChange(newText: String?): Boolean {
srchTempProductsList.clear()
val searchText = newText!!.toLowerCase(Locale.getDefault())
if (searchText.isNotEmpty()) {
srchProductsList.forEach {
if (it.description.toLowerCase(Locale.getDefault()).contains(searchText)) {
srchTempProductsList.add(it)
}
}
rv_dashboard_items.adapter!!.notifyDataSetChanged()
} else {
srchTempProductsList.clear()
srchTempProductsList.addAll(srchProductsList)
rv_dashboard_items.adapter!!.notifyDataSetChanged()
}
return false
}
})
}
private fun getDashboardItemsList2() {
val mFireStore = FirebaseFirestore.getInstance()
mFireStore.collection(Constants.PRODUCTS)
.get()
.addOnSuccessListener { document ->
for (i in document.documents) {
val product = i.toObject(Product::class.java)!!
product.product_id = i.id
srchProductsList.add(product)
}
srchTempProductsList.addAll(srchProductsList)
if (newView == "ListView") {
successDashboardItemsListListView(srchTempProductsList)
} else {
successDashboardItemsList(srchTempProductsList)
}
}
.addOnFailureListener {
}
}
private fun getListOfAds() : ArrayList<Ads>{
val mFireStore = FirebaseFirestore.getInstance()
mFireStore.collection("ads")
.get()
.addOnSuccessListener { document ->
for (i in document.documents) {
val ad = i.toObject(Ads::class.java)!!
ad.ad_id = i.id
adList.add(ad)
}
}
.addOnFailureListener {
}
return adList
}
}
DashboardItemListAdapterTest.kt
open class DashboardItemsListAdapterTest(
private val context: Context,
private var prodlist: ArrayList<Product>,
private var adslist: ArrayList<Ads>) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
companion object {
const val produc= 1
const val ads= 2
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return if (viewType == produc) {
val view = LayoutInflater.from(parent.context)
.inflate(R.layout.item_dashboard_list_view_layout, parent, false)
Collection1Holder(view)
} else {
val view = LayoutInflater.from(parent.context)
.inflate(R.layout.item_dashboard_ad_view_layout, parent, false)
Collection2Holder(view)
}
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
val promodel = prodlist[position]
val adsmodel = adslist[position]
if(getItemViewType(position) == produc) {
holder.itemView.tv_item_name.text = promodel.title
}else{
holder.itemView.tv_item_name.text = adsmodel.title
}
}
override fun getItemCount(): Int {
return prodlist.size + adslist.size
}
override fun getItemViewType(position: Int): Int {
return if(position%5 == 0) ads else produc
}
inner class Collection1Holder(itemView: View) : RecyclerView.ViewHolder(itemView) {
}
inner class Collection2Holder(itemView: View) : RecyclerView.ViewHolder(itemView) {
}
}
Model class
Ads.kt
data class Ads(
val title: String = "",
var ad_id: String = ""
)
You can use two viewholder for two different collections of data.
Change your adapter class like this.
class YourAdapter() : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
companion object {
const val COLLCTION1= 1
const val COLLCTION2= 2
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return if (viewType == COLLCTION1) {
val view = LayoutInflater.from(viewGroup.context)
.inflate(R.layout.collection1, viewGroup, false)
Collection1Holder(view)
} else {
val view = LayoutInflater.from(viewGroup.context)
.inflate(R.layout.collection2, viewGroup, false)
Collection2Holder(view)
}
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
if(getItemViewType(position) == COLLCTION1) {
holder.name.text = collection1.text
}else{
holder.name.text = collection2.text
}
}
override fun getItemCount(): Int {
return collection1.size + collection2.size
}
override fun getItemViewType(position: Int): Int {
return if(position%5 == 0) COLLCTION2 else COLLCTION1
}
inner class Collection1Holder(itemView: View) : RecyclerView.ViewHolder(itemView) {
}
inner class Collection2Holder(itemView: View) : RecyclerView.ViewHolder(itemView) {
}
}

Update status from viewholder on click android kotlin

I have a shopping cart (Recycle View).
When you click on a product, it should change its state(change the background background and the status in the ROOM)
I thought to solve this problem like this:
When you click on the product update the product status in the ROOM and update the list of products and depending on the status change the color, but the problem is that when in the itemadapter I can not call viewlifecycleowner. It doesn't see it(
If I write this logic in a fragment, then I can't call this function from ViewHolder.
Please help
class OrderItemAdapter() : RecyclerView.Adapter<OrderItemAdapter.ViewHolder>() {
private var mListProduct: MutableList<Product?>? = null
private var mViewModel: OrderViewModel? = null
constructor(viewModel: OrderViewModel, listProduct: MutableList<Product?>?) : this() {
mListProduct = listProduct
mViewModel = viewModel
}
override fun getItemCount(): Int {
return if (mListProduct == null) 0 else mListProduct!!.size
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.bind(position)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val inflater = LayoutInflater.from(parent.context)
return ViewHolder(inflater.inflate(R.layout.frg_order_item, parent, false))
}
inner class ViewHolder(val view: View) : RecyclerView.ViewHolder(view) {
private val title: TextView = view.findViewById(R.id.product_name)
private val count: TextView = view.findViewById(R.id.product_count)
private val price: TextView = view.findViewById(R.id.product_price)
private val btnEdit: Button = view.findViewById(R.id.product_edit)
private val btnChange: Button = view.findViewById(R.id.button_change)
private val productImage: ImageView = view.findViewById(R.id.product_image)
private val btnDone: Button = view.findViewById(R.id.done)
#ExperimentalCoroutinesApi
fun bind(pos: Int) {
title.text = mListProduct?.get(pos)?.name
price.text = mListProduct?.get(pos)?.price.toString()
count.text = mListProduct?.get(pos)?.brgew.toString() + " " + mListProduct?.get(pos)?.gewei.toString() + " " + mListProduct?.get(pos)?.quantity.toString() + " " + mListProduct?.get(pos)?.units.toString()
view.setBackgroundColor(changerColorStatus( mListProduct?.get(pos)?.status!!))
//count.text = pos.toString()
productImage.downloadAndSetImage(mListProduct?.get(pos)?.pathImage!!)
btnDone.setOnClickListener {
val product = mListProduct?.get(pos)
if (product != null) {
mViewModel!!.toCollectProduct(product.id!!)
}
}
btnEdit.setOnClickListener {
val product = mListProduct?.get(pos)
if (product != null) {
view.findNavController().navigate(
OrderFragmentDirections.actionOrderFragmentToProductEntryDialogFragment(product)
}
}
btnChange.setOnClickListener {
val product = mListProduct?.get(pos)
view.findNavController().navigate((OrderFragmentDirections.actionOrderFragmentToBarcodeScanningActivity()))
}
}
}
fun submitList(it: List<Product>?) {
mListProduct = it?.toMutableList()
notifyDataSetChanged()
}
fun changerColorStatus(statusProduct: StatusProduct): Int {
return when (statusProduct) {
StatusProduct.COLLECTED -> Color.GREEN
StatusProduct.NOT_COLLECTED -> Color.YELLOW
StatusProduct.EDIT -> Color.CYAN
StatusProduct.REMOVED -> Color.GRAY
StatusProduct.REPLACE -> Color.GRAY
}
}
}
OrderViewModel
#ExperimentalCoroutinesApi
class OrderViewModel #ViewModelInject constructor(private val ordersRepository: OrdersRepository) :
ViewModel() {
//TODO MAKE MUTABLE
fun getBasket(id: Long): LiveData<Resource<List<Product>>> = ordersRepository.getBasket(id)
fun toCollectProduct(id: Long) {
ordersRepository.toCollectProduct(id)
}
fun updateFromLocalDB(id: Long) = ordersRepository.getOrderLocal(id);
}
OrderFragment
#ExperimentalCoroutinesApi
#AndroidEntryPoint
class OrderFragment : Fragment() {
private var orderId = -1L
private val mViewModel: OrderViewModel by viewModels()
private lateinit var mAdapter: OrderItemAdapter
private lateinit var recycler: RecyclerView
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
return inflater.inflate(R.layout.frg_order, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
recycler = view.chat_recycle_view
arguments?.let {
val safeArgs = OrderFragmentArgs.fromBundle(it)
orderId = safeArgs.idOrder
//TODO Log it
setupRecycler()
setupObservers()
}
fab.setOnClickListener {
view.findNavController().navigate(R.id.action_orderFragment_to_barcodeScanningActivity)
}
}
private fun setupRecycler() {
recycler.layoutManager = LinearLayoutManager(context)
val itemDecor = DividerItemDecoration(context, RecyclerView.VERTICAL)
recycler.addItemDecoration(itemDecor)
mAdapter = OrderItemAdapter(mViewModel, null)
recycler.adapter = mAdapter
chat_swipe_refresh.setOnRefreshListener { setupObservers() }
// mViewModel.getBasket(orderId)
}
private fun setupObservers() {
mViewModel.getBasket(orderId).observe(viewLifecycleOwner, Observer {
when (it.status) {
Resource.Status.SUCCESS -> {
//binding.progressBar.visibility = View.GONE
isRefreshing(false)
if (!it.data?.isNullOrEmpty()!!) mAdapter.submitList(it.data)
}
Resource.Status.ERROR -> {
Toast.makeText(requireContext(), it.message, Toast.LENGTH_SHORT).show()
isRefreshing(false)
}
Resource.Status.LOADING -> {
isRefreshing(true)
//progressBar.visibility = View.VISIBLE
}
}
})
}
private fun isRefreshing(refreshing : Boolean){
chat_swipe_refresh.isRefreshing = refreshing
}
fun updateFromLocalDB(id: Long,view: View){
mViewModel!!.updateFromLocalDB(id).observe(viewLifecycleOwner, Observer {
mAdapter.submitList(it)
})
}
}
First of all instead of Passing view model to adapter you should pass function (lambda or listener) to your adapter then your viewHolder like:
class Yourfragment {
val adapter = YourAdapter( { it:Int ->
// here you can use viewModel calls
})
}
class YourAdapter(val clickFunc:(Int) -> Unit){
// ...
}
// (Int)->Unit mean clickFunc is a function which gets integer as argument and return Unit
// then in your viewHolder.
init {
itemView.setOnCLickListener{ clickFunc.invoke(adapterPosition) }
}

Why use Navigation switch between BottomNavigationView images disappear?

As below Gif.
Why images in Works tag of BottomNavigationView's Profile will disappear after switch between BottomNavigationView. But those images will appear after I enter to Home's category item of BottomNavigationView ??
MainActivity.kt
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
navController = nav_host_fragment.findNavController()
bottom_nav_view.setupWithNavController(navController)
}
WorksFragment.kt
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
uid = FirebaseAuth.getInstance().currentUser?.uid
val worksFragmentViewModel= ViewModelProvider(this).get(WorksFragmentViewModel::class.java)
worksFragmentViewModel.getSelfThumbnailPhoto().observe(viewLifecycleOwner, Observer {
works_fragment_recycyler_view.apply {
setHasFixedSize(true)
layoutManager = GridLayoutManager(context, 3)
adapter = ThumbnailWorksAdapter(it).apply {
notifyDataSetChanged()
}
}
})
}
WorksFragmentViewModel.kt
class WorksFragmentViewModel : ViewModel() {
private var worksFragmentReposity = WorksFragmentReposity()
fun getSelfThumbnailPhoto() = worksFragmentReposity.getSelfThumbnailPhoto()
}
WorksFragmentReposity.kt
class WorksFragmentReposity {
private var selfThumbnailLiveData = SelfThumbnailLiveData()
fun getSelfThumbnailPhoto():LiveData<List<UploadedImages>> = selfThumbnailLiveData
}
SelfThumbnailLiveData.kt
class SelfThumbnailLiveData : LiveData<List<UploadedImages>>(), EventListener<QuerySnapshot> {
private val TAG= SelfThumbnailLiveData::class.java.simpleName
private lateinit var listenerRegistration: ListenerRegistration
private var isRegistered :Boolean = false
private val uid = FirebaseAuth.getInstance().currentUser?.uid
private val query = Firebase.firestore.collection("uploadedImages")
.whereEqualTo("uid", uid)
.orderBy("timestamp", Query.Direction.DESCENDING)
override fun onActive() {
super.onActive()
listenerRegistration = query.addSnapshotListener(this)
isRegistered = true
}
override fun onInactive() {
super.onInactive()
if (isRegistered) {
listenerRegistration.remove()
}
}
override fun onEvent(querySnapshot: QuerySnapshot?, firebaseFirestoreException: FirebaseFirestoreException?) {
Log.d(TAG, ": ${firebaseFirestoreException?.message}");
querySnapshot?.let {
val uploadedImagesList = mutableListOf<UploadedImages>()
it.documents.forEach { documentSnapshot ->
val uploadedImages = documentSnapshot.toObject(UploadedImages::class.java)
?: UploadedImages()
uploadedImagesList.add(uploadedImages)
}
Log.d(TAG, "uploadedImagesList: $uploadedImagesList");
value = uploadedImagesList
}
}
}
TabFragmentPagerAdapter.kt
class TabFragmentPagerAdapter(context: Context,fm: FragmentManager) : FragmentPagerAdapter(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) {
private val TAB_TITLES = arrayOf("Works","User Info")
private val fragments:List<Fragment> = listOf(
WorksFragment(),
UserInfoFragment()
)
override fun getItem(position: Int): Fragment {
return fragments[position]
}
override fun getCount(): Int {
return fragments.count()
}
override fun getPageTitle(position: Int): CharSequence? {
return TAB_TITLES[position]
}
}
ThumbnailWorksAdapter.kt
class ThumbnailWorksAdapter(private val uploadImagesList: List<UploadedImages>) : RecyclerView.Adapter<ThumbnailWorksAdapter.ThumbnailWorksHolder>() {
inner class ThumbnailWorksHolder(itemView: View) : RecyclerView.ViewHolder(itemView)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ThumbnailWorksHolder {
val view = LayoutInflater.from(parent.context)
.inflate(R.layout.thumbnail_works_holder_images, parent, false)
return ThumbnailWorksHolder(view)
}
override fun getItemCount(): Int {
return uploadImagesList.size
}
override fun onBindViewHolder(holder: ThumbnailWorksHolder, position: Int) {
val uploadedImages = uploadImagesList[position]
holder.itemView.apply {
Picasso.get()
.load(uploadedImages.downloadImagesUriList[0])
.centerCrop(Gravity.CENTER_HORIZONTAL)
.resize(100,100)
.into(thumbnail_works_images)
}
}
}
ProfileFragment.kt
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
//Bind tabLayout with viewPager
val tabFragmentPagerAdapter = TabFragmentPagerAdapter(requireContext(), parentFragmentManager).apply {
notifyDataSetChanged()
}
profileViewPager.adapter = tabFragmentPagerAdapter
tabLayout.setupWithViewPager(profileViewPager)
}
Someone had helped me solve the problem.
ProfileFragment.kt
val tabFragmentPagerAdapter = TabFragmentPagerAdapter(requireContext(), childFragmentManager).apply {
notifyDataSetChanged()
}

Categories

Resources