I am am trying to put filter in expandable recylerview but not able to achieve:
Please find the code below:
class adapter1(internal var context: Context, internal var mData: MutableList<faqBody?>,val
fragmentInterface: FragmentInterface) : RecyclerView.Adapter<adapter1.myViewHolder>()
,Filterable {
internal var mfilter: NewFilter
var orginallist: MutableList<faqBody?> = ArrayList()
override fun getFilter(): Filter {
return mfilter
}
init {
mfilter = NewFilter(this#adapter1)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): adapter1.myViewHolder {
val view =
LayoutInflater.from(context).inflate(R.layout.recyclerview_adapter12, parent, false)
return myViewHolder(view)
}
override fun onBindViewHolder(holder: adapter1.myViewHolder, position: Int) {
val countryDataItem = mData[position]
val intMaxNoOfChild = 0
holder.country.text = countryDataItem!!.menuText
val noOfChildTextViews = holder.linearLayout_childItems.childCount
val noOfChild = countryDataItem.childItem.size
for (index in 0 until noOfChildTextViews) {
val currentTextView =
holder.linearLayout_childItems.getChildAt(index) as TextView
currentTextView.visibility = View.VISIBLE
}
if (noOfChild < noOfChildTextViews) {
for (index in noOfChild until noOfChildTextViews) {
val currentTextView =
holder.linearLayout_childItems.getChildAt(index) as TextView
currentTextView.visibility = View.GONE
}
}
for (textViewIndex in 0 until noOfChild) {
val currentTextView =
holder.linearLayout_childItems.getChildAt(textViewIndex) as TextView
currentTextView.setText(countryDataItem.childItem[textViewIndex].menuText)
}
}
override fun getItemCount(): Int {
return mData.size
}
inner class myViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView),
View.OnClickListener {
internal var country: TextView
val linearLayout_childItems: LinearLayout
init {
country = itemView.findViewById(R.id.country)
linearLayout_childItems = itemView.findViewById(R.id.ll_child_items)
linearLayout_childItems.visibility = View.GONE
var intMaxNoOfChild = 0
for (index in mData.indices) {
val intMaxSizeTemp = mData[index]!!.childItem.size
if (intMaxSizeTemp > intMaxNoOfChild) intMaxNoOfChild = intMaxSizeTemp
}
for (indexView in 0 until intMaxNoOfChild) {
val textView = TextView(context)
textView.id = indexView
textView.setPadding(5, 20, 0, 20)
// textView.background = ContextCompat.getDrawable(context, R.drawable.background_sub_module_text)
val layoutParams = LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.WRAP_CONTENT
)
textView.setOnClickListener(this)
linearLayout_childItems.addView(textView, layoutParams)
}
country.setOnClickListener(this)
}
override fun onClick(view: View) {
if (view.getId() == R.id.country) {
if (linearLayout_childItems.visibility == View.VISIBLE) {
linearLayout_childItems.visibility = View.GONE
} else {
linearLayout_childItems.visibility = View.VISIBLE
}
} else {
val textViewClicked = view as TextView
Toast.makeText(
context, "" + textViewClicked.text.toString(), Toast.LENGTH_SHORT
).show()
fragmentInterface.onClick(textViewClicked.text.toString())
}
}
}
inner class NewFilter(var mAdapter: adapter1) : Filter() {
override fun performFiltering(charSequence: CharSequence): FilterResults {
orginallist.clear()
orginallist.addAll(mData)
val results = FilterResults()
if (charSequence.length == 0) {
mData.addAll(orginallist)
} else {
val filterPattern = charSequence.toString().toLowerCase().trim { it <= ' ' }
for (i in 0..orginallist.size) {
val newList: ArrayList<childItem> = ArrayList<childItem>()
for (childmenu in orginallist[i]!!.childItem) {
if (childmenu.menuText.toLowerCase().contains(filterPattern)) {
newList.add(childmenu)
}
}
val faqBody = faqBody(menuText = orginallist[i]!!.menuText, childItem = newList)
mData.add(faqBody)
}
}
results.values = mData
results.count = mData.size
return results
}
override fun publishResults(charSequence: CharSequence, filterResults: FilterResults) {
mAdapter.notifyDataSetChanged()
}
}
}
Can anyone help on the above.
mData is the list of faqBody that contains chilitems of the same.
faqbody (
menutext: String
childItem : List<childItem>
)
chilitem(
menutext: String
)
Related
I had to remade ArrayAdapter with filter feature to RecyclerView Adapter because of nested scrolling issues. But after I remade it, RecyclerView is empty, but adapter.itemCount is returning right value. Problem is that after I call adapter.notifyDataSetChanged(), it is not calling onCreateViewHolder or onBindViewHolder function.
class ZoneViewHolder(val root: ViewGroup): RecyclerView.ViewHolder(root) {
fun bind(
zone: FlightZone,
manageZoneCheck: (View)-> Unit,
maybeAutoselectZone: (View) -> Unit){
root.setOnClickListener {
manageZoneCheck(root.find(R.id.check))
}
root.find<View>(R.id.check).also { check->
check.setOnClickListener {
manageZoneCheck(check)
}
//autoselect zone if it was previously picked (after search reset)
maybeAutoselectZone(check)
}
root.findText(R.id.zoneNum).text = zone.name
root.findText(R.id.zoneName).apply {
isSelected = true
text = zone.radarInfo
}
root.findText(R.id.separator).setVisibleNotGone(zone.radarInfo != null)
}
}
class ZoneListAdapter(
private val ctx: Context,
private val inflater: LayoutInflater,
private val zoneView: Int,
private val zoneList: List<FlightZone>,
private var list: MutableList<FlightZone>,
private val pickedZones: List<FlightZone>,
private val onZoneChecked: (FlightZone, Boolean) -> Unit,
private val onAllZonesChecked: (Boolean) -> Unit,
private val onFilterDone: (List<FlightZone>) -> Unit
): RecyclerView.Adapter<ZoneViewHolder>(), Filterable{
override fun getItemCount() = list.size
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ZoneViewHolder {
return ZoneViewHolder(inflater.inflate(zoneView, parent, false) as ViewGroup)
}
override fun onBindViewHolder(vh: ZoneViewHolder, position: Int) {
val zone = list[position]
App.log("ZoneListAdapter: onBindView: ${list.size}")
vh.bind(
zone,
manageZoneCheck = { check->
manageZoneCheck(check, zone)
},
maybeAutoselectZone = {check->
App.log("ZoneListAdapter: alreadyPicked: ${pickedZones.size}")
if (pickedZones.find { it.id == zone.id } != null) check.callOnClick()
}
)
}
/**
* Custom Filter implementation for custom suggestions we provide.
*/
data class ZoneFilterable(val zone: FlightZone, val prefixLength: Int)
internal var tempItems: MutableList<FlightZone> = zoneList.toMutableList()
internal var suggestions: MutableList<ZoneFilterable> = mutableListOf()
internal val sharedCounterLock = Semaphore(1)
private var filter = object : Filter(){
override fun performFiltering(constraint: CharSequence?): FilterResults {
return if (constraint != null) {
sharedCounterLock.acquire()
suggestions.clear()
filterByName(constraint)
suggestions.sortedByDescending { it.prefixLength }
val filterResults = FilterResults()
filterResults.values = suggestions
filterResults.count = suggestions.size
sharedCounterLock.release()
filterResults
} else {
FilterResults()
}
}
private fun filterByName(constraint: CharSequence?){
tempItems.forEach {
val zoneName = it.name.toLowerCase(Locale.getDefault())
val zoneNameNonAccent = zoneName.removeDiacritics()
val query = constraint.toString().toLowerCase(Locale.getDefault())
val queryNonAccent = query.removeDiacritics()
App.log("FlightZonePicker filter zone name non-accent: $zoneNameNonAccent")
if (zoneNameNonAccent.contains(queryNonAccent)) {
val prefix = zoneName.commonPrefixWith(query)
suggestions.add(ZoneFilterable(it, prefix.length))
}
}
}
override fun publishResults(constraint: CharSequence?, results: FilterResults) {
if (results.count > 0) {
list.clear()
val filterList = results.values as? List<Any?>
var resultList = mutableListOf<FlightZone>()
GlobalScope.launch(Dispatchers.Main) {
val resultListAsync = async {
withContext(Dispatchers.Default) {
val list = mutableListOf<FlightZone>()
sharedCounterLock.acquire()
val iter = filterList?.iterator()
iter?.let {
while (iter.hasNext()) {
val item = iter.next()
(item as ZoneFilterable).let { (zoneEntity) -> list.add(zoneEntity) }
}
}
sharedCounterLock.release()
return#withContext list
}
}
resultList = resultListAsync.await().take(10).toMutableList()
App.log("ZoneListAdapter: Results: ${resultList.size}")
list.addAll(resultList)
onFilterDone.invoke(resultList)
}
}
}
}
init {
tempItems = zoneList.toMutableList()
}
override fun getFilter(): Filter {
return filter
}
}
MainClass:
zoneListRecycleView = findViewById(R.id.zoneResults)
zoneListAdapter = ZoneListAdapter(
ctx,
f.layoutInflater,
R.layout.zone_pick_item,
zoneList,
filteredZones,
pickedZones,
onZoneChecked = {
zone, isPicked ->
pickedZones.apply {
if (isPicked){
if (find { it.id == zone.id } == null) add(zone)
} else {
if (find { it.id == zone.id } != null) remove(zone)
}
}
zoneListAdapter.notifyDataSetChanged()
},
onAllZonesChecked = {ischecked->
pickedZones.apply {
clear()
if(ischecked) addAll(zoneList)
}
zoneListAdapter.notifyDataSetChanged()
},
::onFilterResult
)
zoneListRecycleView.adapter = zoneListAdapter
private fun onFilterResult(list: List<FlightZone>){
filteredZones = list.toMutableList()
zoneListAdapter.notifyDataSetChanged()
App.log("ZonelistAdapter: count = ${zoneListAdapter.itemCount}")
}
UPDATE:
I changed Adapter to ListAdapter and I changed publishResults function to
resultList = resultListAsync.await().take(10).toMutableList()
onFilterDone.invoke(resultList)
And inside my parent class I call:
private fun onFilterResult(list: List<FlightZone>){
filteredZones = list.toMutableList()
zoneListAdapter.submitList(filteredZones)
App.log("ZonelistAdapter: filteredList = ${filteredZones.size}")
App.log("ZonelistAdapter: count = ${zoneListAdapter.itemCount}")
}
Log:
app: ZonelistAdapter: filteredList = 10
app: ZonelistAdapter: count = 0
There is still some issue with adapter. So filter feature is working as intended but adapter and recyclerview is not displaying items for some reason.
I am using recyclerview with multi view type and using nested recyclerviews:
But its scrolling very slow. I also handled the child recyclerviews scroll position in onViewRecycled function:
override fun onViewRecycled(holder: RecyclerView.ViewHolder) {
super.onViewRecycled(holder)
//save horizontal scroll state
val key = getSectionID(holder.layoutPosition)
if (holder is HomeSectionsViewHolder) {
scrollStates[key] =
holder
.itemView
.findViewById<RecyclerView>(R.id.itemsList)
.layoutManager?.onSaveInstanceState()
}
}
And in the onBindViewHolder
val state = scrollStates[key]
if (state != null) {
itemBinding.itemsList.layoutManager?.onRestoreInstanceState(state)
} else {
itemBinding.itemsList.layoutManager?.scrollToPosition(0)
}
I also tried:
binding.rvHome.recycledViewPool.setMaxRecycledViews(0, 0);
I am using ListAdapter with DiffUtils. I also tried to set adapter to child recyclerviews in the onCreateViewHolder and submit the list from onBindViewHolder and also tried setting adapter from onBindViewHolder. But in all cases main recycler view recycling the views and lagging. I dont want to disable the recycling of the recyclerview.
Can anyone suggest me what i am doing wrong here.
Code:
class MainAdapter(
private val context: Context,
private val currentLocale: String,
private val currentCountry: String,
private val homeRepository: HomeRepository
) :
ListAdapter<Section, RecyclerView.ViewHolder>(Companion) {
var selectedCondition: List<Int?>? = emptyList()
var selectedBrand: MutableList<Int?>? = arrayListOf()
private var carousalListBinded: Boolean = false
private var carousalList: List<CarouselItem>? = null
private var banners: List<Banner>? = null
private var carousel: ImageCarousel? = null
private var COVIDMsg: String? = null
private var COVIDMsgColor: String? = null
private var tvCovidMessage: TextView? = null
private var categoryAdapter = CategoryAdapter(context)
companion object : DiffUtil.ItemCallback<Section>() {
override fun areItemsTheSame(oldItem: Section, newItem: Section): Boolean =
oldItem == newItem
override fun areContentsTheSame(oldItem: Section, newItem: Section): Boolean =
oldItem == newItem
const val VIEW_TYPE_CATEGORY = 0
const val VIEW_TYPE_ITEM_SECTION = 1
const val VIEW_TYPE_BRAND = 2
const val VIEW_TYPE_IMAGE = 3
const val VIEW_TYPE_ADVANCE_IMAGE = 4
const val VIEW_TYPE_ADVANCE_CATEGORY = 5
const val VIEW_TYPE_BANNER = 6
const val VIEW_TYPE_HOME_BOTTOM_SECTION = 7
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
when (viewType) {
VIEW_TYPE_CATEGORY -> {
val categoryViewHolder = CategoryViewHolder(
DataBindingUtil.inflate(
LayoutInflater.from(parent.context),
R.layout.home_categories_item,
parent,
false
)
)
categoryViewHolder.initRecView()
return categoryViewHolder
}
VIEW_TYPE_ITEM_SECTION -> {
val homeSectionsViewHolder = HomeSectionsViewHolder(
DataBindingUtil.inflate(
LayoutInflater.from(parent.context),
R.layout.home_item_section,
parent,
false
)
)
homeSectionsViewHolder.initRecView()
return homeSectionsViewHolder
}
VIEW_TYPE_BRAND -> {
val brandsViewHolder = BrandsViewHolder(
DataBindingUtil.inflate(
LayoutInflater.from(parent.context),
R.layout.home_brands_item,
parent,
false
)
)
brandsViewHolder.initRecView()
return brandsViewHolder
}
VIEW_TYPE_IMAGE -> {
val imagesViewHolder = ImagesViewHolder(
DataBindingUtil.inflate(
LayoutInflater.from(parent.context),
R.layout.home_brands_item,
parent,
false
)
)
imagesViewHolder.initRecView()
return imagesViewHolder
}
VIEW_TYPE_ADVANCE_IMAGE -> {
val advanceImagesViewHolder = AdvanceImagesViewHolder(
DataBindingUtil.inflate(
LayoutInflater.from(parent.context),
R.layout.home_brands_item,
parent,
false
)
)
advanceImagesViewHolder.initRecView()
return advanceImagesViewHolder
}
VIEW_TYPE_ADVANCE_CATEGORY -> {
val categorySectionViewHolder = CategorySectionViewHolder(
DataBindingUtil.inflate(
LayoutInflater.from(parent.context),
R.layout.home_item_section,
parent,
false
)
)
categorySectionViewHolder.initRecView()
return categorySectionViewHolder
}
VIEW_TYPE_BANNER -> {
val binding: HomeBannerItemBinding = DataBindingUtil.inflate(
LayoutInflater.from(parent.context),
R.layout.home_banner_item,
parent,
false
)
binding.carousel.post {
val numberItemsInColumn = 1
val collectionViewWidth = getWidth(context)
val widthPerCell = collectionViewWidth / numberItemsInColumn
val widthPerItem = widthPerCell
val cellHeight = getCellHeight(widthPerItem)
binding.carousel.layoutParams.width = widthPerItem
binding.carousel.layoutParams.height = cellHeight
binding.carousel.requestLayout()
}
return HomeBannerViewHolder(
binding
)
}
VIEW_TYPE_HOME_BOTTOM_SECTION -> {
return HomeBottomLayViewHolder(
DataBindingUtil.inflate(
LayoutInflater.from(parent.context),
R.layout.home_screen_bottom_layout,
parent,
false
)
)
}
else -> {
val categoryViewHolder = CategoryViewHolder(
DataBindingUtil.inflate(
LayoutInflater.from(parent.context),
R.layout.home_categories_item,
parent,
false
)
)
categoryViewHolder.initRecView()
return categoryViewHolder
}
}
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
when (getItemViewType(position)) {
VIEW_TYPE_CATEGORY -> {
(holder as CategoryViewHolder).bind(position)
}
VIEW_TYPE_ITEM_SECTION -> {
(holder as HomeSectionsViewHolder).bind(position)
}
VIEW_TYPE_BRAND -> {
(holder as BrandsViewHolder).bind(position)
}
//
VIEW_TYPE_IMAGE -> {
(holder as ImagesViewHolder).bind(position)
}
//
VIEW_TYPE_ADVANCE_IMAGE -> {
(holder as AdvanceImagesViewHolder).bind(position)
}
VIEW_TYPE_ADVANCE_CATEGORY -> {
(holder as CategorySectionViewHolder).bind(position)
}
VIEW_TYPE_BANNER -> {
// (holder as HomeBannerViewHolder).setIsRecyclable(false)
(holder as HomeBannerViewHolder).bind()
}
VIEW_TYPE_HOME_BOTTOM_SECTION -> {
(holder as HomeBottomLayViewHolder)
}
}
// holder.itemView.setFadeAnimation()
}
override fun getItemViewType(position: Int): Int {
return when (currentList[position].sectionType) {
SectionType.items -> {
VIEW_TYPE_ITEM_SECTION
}
SectionType.brands -> {
VIEW_TYPE_BRAND
}
SectionType.images -> {
VIEW_TYPE_IMAGE
}
SectionType.advanceimages -> {
VIEW_TYPE_ADVANCE_IMAGE
}
SectionType.category -> {
VIEW_TYPE_ADVANCE_CATEGORY
}
SectionType.banners -> {
VIEW_TYPE_BANNER
}
SectionType.homeCategories -> {
VIEW_TYPE_CATEGORY
}
SectionType.homeBottomView -> {
VIEW_TYPE_HOME_BOTTOM_SECTION
}
else -> {
VIEW_TYPE_CATEGORY
}
}
}
inner class CategoryViewHolder(private val itemBinding: HomeCategoriesItemBinding) :
RecyclerView.ViewHolder(
itemBinding.root
) {
fun initRecView() {
itemBinding.rvCategoryItem.adapter = categoryAdapter
}
fun bind(position: Int) {
// val newItem = (currentList[position] as CategorySection).items
// categoryAdapter.submitList(newItem)
}
}
inner class HomeSectionsViewHolder(private val itemBinding: HomeItemSectionBinding) :
RecyclerView.ViewHolder(
itemBinding.root
) {
private var sectionsAdapter = ItemSectionsAdapter(context)
fun initRecView() {
itemBinding.itemsList.adapter = sectionsAdapter
}
fun bind(position: Int) {
val section = getItem(position)
itemBinding.section = section
itemBinding.executePendingBindings()
sectionsAdapter.submitList(null)
val newItem = (currentList[position] as ItemSection).items
sectionsAdapter.submitList(newItem)
// val state = scrollStates[key]
// if (state != null) {
// itemBinding.rvProducts.layoutManager?.onRestoreInstanceState(state)
// } else {
// itemBinding.rvProducts.layoutManager?.scrollToPosition(0)
// }
}
}
inner class BrandsViewHolder(private val itemBinding: HomeBrandsItemBinding) :
RecyclerView.ViewHolder(itemBinding.root) {
private val brandsAdapter = BrandsAdapter()
fun initRecView() {
itemBinding.itemsList.adapter = brandsAdapter
}
fun bind(position: Int) {
itemBinding.sectionBtnViewAll.visibility = View.INVISIBLE
val section = getItem(position)
itemBinding.section = section
itemBinding.executePendingBindings()
brandsAdapter.submitList((currentList[position] as BrandSection).items)
}
}
inner class ImagesViewHolder(private val itemBinding: HomeBrandsItemBinding) :
RecyclerView.ViewHolder(itemBinding.root) {
private val imagesAdapter = ImagesAdapter(context)
val layoutManager = GridLayoutManager(context, 3)
fun initRecView() {
itemBinding.itemsList.let {
it.layoutManager = layoutManager
it.setHasFixedSize(true)
it.adapter = imagesAdapter
}
}
fun bind(position: Int) {
val numberOfColumns = getNumberOfColumns((currentList[position] as ImageSection).items)
itemBinding.itemsList.layoutManager = GridLayoutManager(context, numberOfColumns)
// layoutManager.spanSizeLookup = object : GridLayoutManager.SpanSizeLookup() {
// override fun getSpanSize(position: Int): Int {
// return numberOfColumns
// }
// }
itemBinding.sectionBtnViewAll.visibility = View.INVISIBLE
val section = getItem(position)
itemBinding.section = section
itemBinding.executePendingBindings()
imagesAdapter.submitList((currentList[position] as ImageSection).items)
}
}
inner class AdvanceImagesViewHolder(private val itemBinding: HomeBrandsItemBinding) :
RecyclerView.ViewHolder(itemBinding.root) {
private var imagesAdapter = AdvanceImagesAdapter(context, null, null)
fun initRecView() {
itemBinding.itemsList.let {
// val layoutManager = GridLayoutManager(context, getNumberOfColumns((currentList[position] as AdvanceImageSection).items))
val layoutManager = GridLayoutManager(context, 3)
it.layoutManager = layoutManager
it.setHasFixedSize(true)
it.adapter = imagesAdapter
}
}
fun bind(position: Int) {
val layoutManager = GridLayoutManager(
context,
getNumberOfColumns((currentList[position] as AdvanceImageSection).items)
)
itemBinding.itemsList.layoutManager = layoutManager
val section = getItem(position)
// var imagesAdapter = AdvanceImagesAdapter(context, section.columns, section.aspectRatio)
//
// itemBinding.itemsList.adapter = imagesAdapter
// val imagesAdapter = AdvanceImagesAdapter(section,context)
itemBinding.sectionBtnViewAll.visibility = View.INVISIBLE
itemBinding.section = section
itemBinding.executePendingBindings()
imagesAdapter.submitList((currentList[position] as AdvanceImageSection).items)
//
//
//
}
}
inner class CategorySectionViewHolder(private val itemBinding: HomeItemSectionBinding) :
RecyclerView.ViewHolder(itemBinding.root) {
private val categoryAdapter = HomeCategorySectionAdapter(context)
fun initRecView() {
itemBinding.itemsList.let {
val linearLayoutManager = LinearLayoutManager(
context,
LinearLayoutManager.HORIZONTAL,
false
)
it.layoutManager = linearLayoutManager
// it.setHasFixedSize(true)
it.adapter = categoryAdapter
}
}
fun bind(position: Int) {
// (currentList[position] as CategorySection)
val section = getItem(position)
itemBinding.section = section
itemBinding.executePendingBindings()
if (categoryAdapter.itemCount <= 0) {
itemBinding.pb.show()
GlobalScope.launch(Dispatchers.Main) {
val items = async(Dispatchers.IO) {
homeRepository.getSolarSearch(
getSolarSearchRequest(section)
)
}
when (items.await()) {
is Resource.Success -> {
itemBinding.pb.hide()
categoryAdapter.submitList((items.await() as Resource.Success<SolarSearchResponse>).value.items)
}
is Resource.Failure -> {
itemBinding.pb.hide()
}
is Resource.Loading -> {
}
}
}
}
// itemBinding.sectionBtnViewAll.setOnClickListener {
// homeSectionListener.onCatSectionViewAllClicked(section.categoryID.toString(),section)
// }
}
private fun getSolarSearchRequest(section: Section): SolarSearchRequest {
val result = section.categoryID!! % 100
if (result == 0) {
return SolarSearchRequest(
0,
null,
null,
25,
"popularity",
arrayListOf(section.categoryID),
emptyList<Int>(),
selectedCondition,
selectedBrand,
"1",
"15000"
)
// putIntegerArrayListExtra(CATEGORY_ID, arrayListOf(id))
} else {
// putIntegerArrayListExtra(SUB_CAT_ID, arrayListOf(id))
return SolarSearchRequest(
OFFSET,
null,
null,
PAGE_SIZE_LIMIT,
"popularity",
emptyList<Int>(),
arrayListOf(section.categoryID),
selectedCondition,
selectedBrand,
"1",
"15000"
)
}
}
}
inner class HomeBannerViewHolder(private val itemBinding: HomeBannerItemBinding) :
RecyclerView.ViewHolder(itemBinding.root) {
// private val handler: Handler? = null
// private val delay = 5000 //milliseconds
// private var page = 0
fun bind() {
// if (carousalListBinded) {
// return
// }
itemBinding.carousel.start()
carousalList?.let {
itemBinding.carousel.addData(it)
}
if (COVIDMsg.isNullOrEmpty()) {
itemBinding.covidMessage.visibility = View.GONE
} else {
itemBinding.covidMessage.visibility = View.VISIBLE
}
itemBinding.covidMessage.text = COVIDMsg
if (COVIDMsgColor != null) {
(itemBinding.covidMessage.background as GradientDrawable).setColor(
Color.parseColor(
COVIDMsgColor
)
)
} else {
(itemBinding.covidMessage.background as GradientDrawable).setColor(
context.getColor(
R.color.colorAccent
)
)
}
carousel = itemBinding.carousel
tvCovidMessage = itemBinding.covidMessage
if (carousalList != null) {
carousalListBinded = true
}
}
fun openNewTabWindow(urls: String, context: Context) {
val uris = Uri.parse(urls)
val intents = Intent(Intent.ACTION_VIEW, uris)
val b = Bundle()
b.putBoolean("new_window", true)
intents.putExtras(b)
context.startActivity(intents)
}
}
inner class HomeBottomLayViewHolder(private val itemBinding: HomeScreenBottomLayoutBinding) :
RecyclerView.ViewHolder(
itemBinding.root
) {
}
fun getNumberOfColumns(items: List<Image>): Int {
var numberItemsInColumn: Int = 3
if ((items.size) % 3 == 0) {
numberItemsInColumn = 3
} else if ((items.size) % 2 == 0) {
numberItemsInColumn = 2
} else if (items.size == 1) {
numberItemsInColumn = 1
} else {
numberItemsInColumn = 3
}
return numberItemsInColumn
}
#RequiresApi(Build.VERSION_CODES.M)
fun setBanners(
carousalList: List<CarouselItem>?,
bannersList: List<Banner>?,
COVIDMsg: String?,
COVIDMsgColor: String?
) {
this.carousalList = carousalList
this.banners = bannersList
this.COVIDMsg = COVIDMsg
this.COVIDMsgColor = COVIDMsgColor
carousalList?.let { carousel?.addData(it) }
if (COVIDMsg.isNullOrEmpty()) {
tvCovidMessage?.visibility = View.GONE
} else {
tvCovidMessage?.visibility = View.VISIBLE
}
tvCovidMessage?.text = COVIDMsg
if (COVIDMsgColor != null && tvCovidMessage != null) {
(tvCovidMessage?.background as GradientDrawable).setColor(Color.parseColor(COVIDMsgColor))
} else {
if (tvCovidMessage != null) {
(tvCovidMessage?.background as GradientDrawable).setColor(context.getColor(R.color.colorAccent))
}
}
}
fun getWidth(context: Context): Int {
var width: Int = 0
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
val displayMetrics = DisplayMetrics()
val display: Display? = context.display
display!!.getRealMetrics(displayMetrics)
return displayMetrics.widthPixels
} else {
val displayMetrics = DisplayMetrics()
(context as Activity).windowManager.defaultDisplay.getMetrics(displayMetrics)
width = displayMetrics.widthPixels
return width
}
}
fun getCellHeight(width: Int): Int {
var height = width
val ratio = 0.37
val height1 = height * ratio
height = height1.roundToInt()
return height
}
fun setCategories(categoriesList: List<Category>?) {
categoryAdapter.submitList(categoriesList)
}
}
I have implemented a onClicklistener in my recycleview which works but the onLongClickListener is not responding? I have added the code in the Adapter, which is being called from a fragment. The onClickListener works well. Whn I click onLongClick -> it needs to display an AlertDialog, but in this case on running the app, there are no errors and no longclick too. This is in Kotlin, what am I doing wrong - any thoughts please?
class UserMsgAdapter(
mContext: Context,
userMsgList: List<MessageList>,
mUsers: List<Users>,
isChatCheck: Boolean
): RecyclerView.Adapter<UserMsgAdapter.ViewHolder?>()
{
private val mContext: Context
private val userMsgList: List<MessageList>
private val mUsers:List<Users>
private var isChatCheck: Boolean
init{
this.mUsers = mUsers
this.userMsgList = userMsgList
this.mContext = mContext
this.isChatCheck = isChatCheck
}
var lastMsg: String = ""
var timeMsg: Long = 0
override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int): ViewHolder {
val view: View = LayoutInflater.from(mContext).inflate(
R.layout.user_search_item_layout,
viewGroup,
false
)
return ViewHolder(view)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val message: MessageList? = userMsgList[position]
//Accessing the receiverId from the ChatList
val receiverId = message!!.getId()
val ref = FirebaseDatabase.getInstance().reference.child("Users").child(receiverId!!)
ref.addListenerForSingleValueEvent(object : ValueEventListener {
override fun onDataChange(p0: DataSnapshot) {
val user = p0.getValue(Users::class.java)
holder.userNameText.text = user!!.getUserName()
Picasso.get().load(user.getProfile())
.placeholder(R.drawable.ic_baseline_whatshot_24).fit().centerCrop().into(
holder.profileImageView
)
//Showcasing Last Message
if (isChatCheck) {
retrieveLastMessage(
user.getUID(),
holder.lastMessagetxt,
holder.timestamptxt,
holder.new_message_count
)
} else {
holder.lastMessagetxt.visibility = View.GONE
}
//Calling the Message Activity
holder.itemView.setOnClickListener {
val intent = Intent(mContext, MessageActivity::class.java)
intent.putExtra("visit_id", user.getUID())
mContext.startActivity(intent)
}
//Menu on Search Fragment
holder.itemView.setOnLongClickListener {
val options = arrayOf<CharSequence>(
"Delete Chat",
"Visit Profile"
)
val builder: AlertDialog.Builder = AlertDialog.Builder(mContext)
builder.setTitle("What would you like to do?")
builder.setItems(options, DialogInterface.OnClickListener { _, which ->
if (which == 0) {
val intent = Intent(mContext, MessageActivity::class.java)
intent.putExtra("visit_id", user.getUID())
mContext.startActivity(intent)
}
if (which == 1) {
val intent = Intent(mContext, VisitUserProfile::class.java)
intent.putExtra("visit_id", user.getUID())
mContext.startActivity(intent)
}
})
builder.show()
true
}
}
override fun onCancelled(error: DatabaseError) {
}
})
}
override fun getItemCount(): Int {
return userMsgList.size
}
class ViewHolder(itemView: View): RecyclerView.ViewHolder(itemView)
{
var userNameText: TextView = itemView.findViewById(R.id.username)
var profileImageView: ShapeableImageView = itemView.findViewById(R.id.profile_image)
var lastMessagetxt: TextView = itemView.findViewById(R.id.last_message)
var timestamptxt: TextView = itemView.findViewById(R.id.time_stamp)
var new_message_count: TextView = itemView.findViewById(R.id.new_message_count)
}
//print last message and timestamp
private fun retrieveLastMessage(
messageUserId: String?, lastMessagetxt: TextView,
timestamptxt: TextView, new_message_count: TextView,
)
{
lastMsg = "defaultMsg"
timeMsg = 0
var countUnreadMessages = 0
val firebaseUser = FirebaseAuth.getInstance().currentUser
val reference = FirebaseDatabase.getInstance().reference.child("Chats")
reference.addValueEventListener(object : ValueEventListener {
override fun onDataChange(p0: DataSnapshot) {
for (dataSnapshot in p0.children) {
val message: Message? = dataSnapshot.getValue(Message::class.java)
if (firebaseUser != null && message != null) {
if (message.getReceiver() == firebaseUser.uid && message.getSender() == messageUserId ||
message.getReceiver() == messageUserId && message.getSender() == firebaseUser.uid
) {
lastMsg = message.getMessage()!!
timeMsg = message.getTimestamp()!!
}
if (message.getReceiver() == firebaseUser.uid && message.getSender() == messageUserId && !message.isIsSeen()) {
countUnreadMessages += 1
}
}
}
when (lastMsg) {
"defaultMsg" -> lastMessagetxt.text = ""
"Shared an image with you." -> lastMessagetxt.text = "Shared an image"
else -> lastMessagetxt.text = lastMsg
}
//Display count of unread messages
if (countUnreadMessages != 0) {
new_message_count.text = countUnreadMessages.toString()
new_message_count.setBackgroundResource(R.drawable.new_chat_bg)
} else {
new_message_count.setBackgroundResource(0)
new_message_count.text = ""
}
countUnreadMessages = 0
//Display formatted date and time
val time = dateFormatter(timeMsg)
when (time) {
"01-01-1970" -> timestamptxt.text = ""
else -> timestamptxt.text = time
}
}
override fun onCancelled(error: DatabaseError) {
}
})
}
}
I have two screens first one has recycler view list of data and searchView above it that's filter data in this recycler, the view Model code of the first fragment
class MscInspectionViewModel(val activity: LaunchActivity, val mRootView: MscInspectFragment) :
BaseViewModel(),
SwipeRefreshLayout.OnRefreshListener {
val toolBarTitle: MutableLiveData<String> = MutableLiveData()
private val getDataError = MutableLiveData<Boolean>()
var listType = MutableLiveData<Int>()
val hint = MutableLiveData<String>()
private var isRefreshing: Boolean = false
private var mSharedPreferences: SharedPreferences? = null
val dataListAdapter = ContainersUnderCheckAdapter(activity)
val backClickListener = View.OnClickListener { activity.supportFragmentManager.popBackStack() }
val filterDataByTab = object : TabLayout.OnTabSelectedListener {
override fun onTabReselected(tab: TabLayout.Tab?) {
}
override fun onTabUnselected(tab: TabLayout.Tab?) {
}
override fun onTabSelected(tab: TabLayout.Tab?) {
when (tab!!.text) {
activity.resources.getString(R.string.cidPending) -> {
listType.value = 0
getPendingData()
}
activity.resources.getString(R.string.cidDone) -> {
listType.value = 1
getDoneData()
}
}
}
}
val filterData = object : SearchView.OnQueryTextListener {
override fun onQueryTextSubmit(query: String): Boolean {
if (query.length > 2) {
val mQuery = Utility(activity).switchArabicNumerals(query)
dataListAdapter.getFilter(3, listType.value!!).filter(mQuery)
} else {
errorMessage.value = activity.resources.getString(R.string.addCorrectNumber)
}
return true
}
override fun onQueryTextChange(newText: String): Boolean {
if (newText.length > 2) {
val mQuery = Utility(activity).switchArabicNumerals(newText)
dataListAdapter.getFilter(3, listType.value!!).filter(mQuery)
}
return false;
}
}
val closeImgListener = View.OnClickListener {
mRootView.svSearchMSC.setQuery("", true)
if (listType.value == 1) {
dataListAdapter.getFilter(1, listType.value!!).filter("ANY")
} else if (listType.value == 0) {
dataListAdapter.getFilter(2, listType.value!!).filter("PENDING")
}
}
init {
listType.value = 0
mSharedPreferences = getDefaultSharedPreferences(activity.applicationContext)
toolBarTitle.value = activity.resources.getString(R.string.mscInspectTitle)
hint.value = activity.resources.getString(R.string.msc_search)
getData()
}
fun getData() {
onRetrievePostListStart()
subscription = apiAccount.getContainersUnderCheck(
"getContainersUnderCheck",
mSharedPreferences!!.getString(Constants.CFID, "")!!,
mSharedPreferences!!.getString(Constants.CFTOKEN, "")!!
)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.doOnSubscribe {}
.doOnTerminate {}
.subscribe({ result ->
result?.let {
if (result.ResponseCode != null && result.ResponseCode.trim() != "000") {
onRetrievePostListError(result.ResponseMessage)
} else {
result.ContainersData?.let { it1 -> onRetrievePostListSuccess(it1) }
}
}
}, { throwable ->
android.util.Log.e("getDataInquiry", throwable.message!!)
onRetrievePostListError(activity.resources.getString(R.string.general_error))
})
}
private fun getPendingData() {
val query = mRootView.svSearchMSC.query.toString()
if (query == "") {
dataListAdapter.getFilter(2, listType.value!!).filter("PENDING")
} else {
if (query.length > 2) {
dataListAdapter.getFilter(3, listType.value!!).filter(query)
} else {
errorMessage.value = activity.resources.getString(R.string.addCorrectNumber)
}
}
}
private fun getDoneData() {
val query = mRootView.svSearchMSC.query.toString()
if (query == "") {
dataListAdapter.getFilter(1, listType.value!!).filter("ANY")
} else {
if (query.length > 2) {
dataListAdapter.getFilter(3, listType.value!!).filter(query)
} else {
errorMessage.value = activity.resources.getString(R.string.addCorrectNumber)
}
}
}
private fun onRetrievePostListStart() {
loading.value = true
}
private fun onRetrievePostListFinish() {
loading.value = false
isRefreshing = false
}
private fun onRetrievePostListSuccess(containersData: List<ContainersData>) {
onRetrievePostListFinish()
dataListAdapter.updateInquiryAdapter(containersData as ArrayList<ContainersData>)
if (listType.value == 1) {
dataListAdapter.getFilter(1, listType.value!!).filter("ANY")
} else if (listType.value == 0) {
dataListAdapter.getFilter(2, listType.value!!).filter("PENDING")
}
}
private fun onRetrievePostListError(message: String?) {
onRetrievePostListFinish()
getDataError.value = true
errorMessage.value = message
}
override fun onCleared() {
super.onCleared()
subscription.dispose()
}
override fun onRefresh() {
isRefreshing = true
getData()
}
}
adapter is :
class ContainersUnderCheckAdapter(val activity: LaunchActivity) :
RecyclerView.Adapter<ContainersUnderCheckAdapter.ViewHolder>() {
private lateinit var mDataSet: ArrayList<ContainersData>
private lateinit var mDataSetFiltered: ArrayList<ContainersData>
fun updateInquiryAdapter(dataSet: ArrayList<ContainersData>) {
mDataSet = ArrayList()
mDataSet.clear()
mDataSet.addAll(dataSet)
mDataSetFiltered = mDataSet
getFilter(2, 1).filter("PENDING")
// notifyDataSetChanged()
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val binding: ContianerItemFieldLayoutBinding = DataBindingUtil
.inflate(
LayoutInflater.from(parent.context),
R.layout.contianer_item_field_layout,
parent,
false
)
return ViewHolder(binding, activity)
}
override fun getItemCount(): Int {
return if (::mDataSetFiltered.isInitialized) mDataSetFiltered.size else 0
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.bind(mDataSetFiltered[position])
}
operator fun get(position: Int): ContainersData {
return mDataSetFiltered.get(position)
}
/**
* #filterType :
* IF 1 : filter on Data Type RJCTD + APPROVED
* 2 : filter on Data Type PENDING
* 3 :
*/
fun getFilter(filterType: Int, listType: Int): Filter {
return object : Filter() {
override fun performFiltering(charSequence: CharSequence): FilterResults {
val charString = charSequence.toString()
mDataSetFiltered = if (charString.isEmpty()) {
mDataSet
} else {
val filteredList = ArrayList<ContainersData>()
for (row in mDataSet) {
when (filterType) {
1 -> {
if (row.status == "RJCTD" || row.status == "APPROVED") {
filteredList.add(row)
}
}
2 -> {
if (row.status == charString) {
filteredList.add(row)
}
}
3 -> {
when (listType) {
0 -> {
if ((row.CID!!.contains(charString.toUpperCase(Locale.ROOT)) || row.TN!!.contains(
charSequence
) || row.PN!!.contains(charSequence)) && row.status == "PENDING"
) {
filteredList.add(row)
}
}
1 -> {
if ((row.CID!!.contains(charString.toUpperCase(Locale.ROOT)) || row.TN!!.contains(
charSequence
) || row.PN!!.contains(charSequence)) && row.status != "PENDING"
) {
filteredList.add(row)
}
}
}
}
}
}
filteredList
}
val filterResults = FilterResults()
filterResults.values = mDataSetFiltered
return filterResults
}
override fun publishResults(
charSequence: CharSequence,
filterResults: FilterResults
) {
if (::mDataSetFiltered.isInitialized) {
mDataSetFiltered = try {
filterResults.values as ArrayList<ContainersData>
} catch (e: Exception) {
Log.e("mDataSetFiltered",e.message!!)
ArrayList()
}
when (filterType) {
1->{
mDataSetFiltered.sortWith(Comparator { p0, p1 -> p1!!.UpdateDate.compareTo(p0!!.UpdateDate) })
}
2->{
mDataSetFiltered.sortWith(Comparator { p0, p1 -> p0!!.ID!!.compareTo(p1.ID!!) })
}
}
}
// refresh the list with filtered data
notifyDataSetChanged()
}
}
}
class ViewHolder(
private val binding: ContianerItemFieldLayoutBinding,
val activity: LaunchActivity
) : RecyclerView.ViewHolder(binding.root) {
private val viewModel = MscInspectionListViewModel(activity)
fun bind(data: ContainersData) {
viewModel.bind(data)
binding.viewModel = viewModel
}
}
}
any data in this recycler on click go to fragment has tow recycler first one to show data, the second one to pick Images
the second-page code
class MSCDataFragment : Fragment() {
lateinit var rootView: View
lateinit var activity: LaunchActivity
lateinit var utility: Utility
lateinit var loadingView: LoadingView
private lateinit var viewModel: MSCDataViewModel
private lateinit var binding: FragmentMscdataBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
if (getActivity() != null) {
activity = getActivity() as LaunchActivity
utility = Utility(activity)
loadingView = LoadingView(activity)
}
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
binding = DataBindingUtil.inflate(inflater, R.layout.fragment_mscdata, container, false)
rootView = binding.root
initial()
return rootView
}
private fun initial() {
viewModel = ViewModelProvider(
this, ViewModelFactory(
activity,
arguments!!.getSerializable("Data") as ContainersData
)
).get(MSCDataViewModel::class.java)
binding.viewModel = viewModel
// binding.imgList.layoutManager = GridLayoutManager(activity, 3)
binding.containerInfo.layoutManager = LinearLayoutManager(activity)
binding.openCIDNotValid.typeface =
Typeface.createFromAsset(activity.assets, "Bahij_Janna-Regular.ttf")
binding.openCIDNotValid.setOnCheckedChangeListener(viewModel.onOpenCidNotValidListener)
viewModel.loading.observe(this, Observer { loading ->
loading?.let {
if (it) {
loadingView.show()
} else {
loadingView.dismiss()
}
}
})
viewModel.errorMessage.observe(this, Observer { msg ->
msg?.let {
utility.ShowToast(msg)
}
})
viewModel.imagesAdapters2.observe(this, Observer { msg ->
msg?.let {
binding.imgList.apply {
layoutManager = GridLayoutManager(activity, 3)
adapter = it
}
}
})
rootView.toolbar_Back.setOnClickListener(viewModel.backClickListener)
binding.btnAddImages.setOnClickListener(viewModel.pickImages)
binding.successContianer.setOnClickListener(viewModel.correctContainer)
binding.damagedContianer.setOnClickListener(viewModel.wrongContainer)
}
}
the view model is :
class MSCDataViewModel(val activity: LaunchActivity, val containersData: ContainersData) :
BaseViewModel(), GetImagesListener {
#Inject
lateinit var restApiAccount: RestApiAccount
val toolBarTitle: MutableLiveData<String> = MutableLiveData()
val ButtonText: MutableLiveData<String> = MutableLiveData()
var openCIDNotValidVisibility = MutableLiveData<Int>()
private val getDataError = MutableLiveData<Boolean>()
val btnImagesVisibility = MutableLiveData<Int>()
var imgeNoteVisibility = MutableLiveData<Int>()
var successVisibility = MutableLiveData<Int>()
var damagedVisibility = MutableLiveData<Int>()
var notesVisibility = MutableLiveData<Int>()
val btnVisibility = MutableLiveData<Int>()
var canNotOpen = MutableLiveData<Int>()
private val images = ArrayList<Image>()
var utility = Utility(activity)
private var CURRENTINDEX = 0
private var mSharedPreferences: SharedPreferences? = null
val DataListAdapter = ContainerDataAdapter(activity)
var imagesAdapter = ContainerImagesAdapter(activity, containersData.status!!, ArrayList())
val imagesAdapters2 = MutableLiveData<ContainerImagesAdapter2>()
val userInfo: UserInfo
val backClickListener = View.OnClickListener { activity.supportFragmentManager.popBackStack() }
val pickImages = View.OnClickListener {
pickImages()
}
val correctContainer = View.OnClickListener {}
val onOpenCidNotValidListener =
CompoundButton.OnCheckedChangeListener { buttonView, isChecked ->
if (isChecked) {
successVisibility.value = View.GONE
canNotOpen.value = 1
} else {
canNotOpen.value = 0
successVisibility.value = View.VISIBLE
}
}
val wrongContainer = View.OnClickListener {}
var mscNotes: ObservableField<String> = ObservableField("")
init {
canNotOpen.value = 0
mSharedPreferences =
PreferenceManager.getDefaultSharedPreferences(activity.applicationContext)
toolBarTitle.value = containersData.CID
ButtonText.value = activity.resources.getString(R.string.cleanContianer)
userInfo = utility.readObjectFromSharedPreferences(
mSharedPreferences,
Constants.USER_INFO_KEY,
UserInfo::class.java
) as UserInfo
openCIDNotValidVisibility.value = View.GONE
fillData()
}
private fun fillData() {
val data: LinkedHashMap<String, String> = containersData.data!!
val captionsMap = utility.readObjectFromSharedPreferences(
mSharedPreferences, Constants.CAPTIONS_MAP_KEY,
HashMap::class.java
) as HashMap<String, String>
if (containersData.data.size > 0) {
val list = ArrayList<KeyValueModel>()
for (inside in data.keys) {
val ky = captionsMap[inside]
val value = data[inside].toString()
ky?.let { KeyValueModel(it, value) }?.let { list.add(it) }
}
DataListAdapter.updateInquiryAdapter(list)
} else {
errorMessage.value = activity.resources.getString(R.string.no_data)
}
if (containersData.ImageList != null && containersData.ImageList.isNotEmpty()) {
imagesAdapter.updateContainerImagesAdapter(containersData.ImageList)
}
}
private fun pickImages() {
activity.setCallBack(this)
val pictureDialog: AlertDialog
val builder = activity.let { AlertDialog.Builder(it) }
val dialogView = View.inflate(activity, R.layout.choose_camera_method, null)
builder.setView(dialogView)
val nafithPopupContainer = dialogView.findViewById<RelativeLayout>(R.id.RLTitle)
nafithPopupContainer.setBackgroundColor(
ContextCompat.getColor(
activity,
R.color.mainColor
)
)
val popUpGallery = dialogView.findViewById<LinearLayout>(R.id.PopupGellary)
val popUpCamera = dialogView.findViewById<LinearLayout>(R.id.PopupCamera)
pictureDialog = builder.create()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
Objects.requireNonNull<Window>(pictureDialog.window)
.setLayout(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT
)
} else {
if (pictureDialog.window != null) {
pictureDialog.window!!.setLayout(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT
)
}
}
popUpGallery.setOnClickListener {
fromGallery()
pictureDialog.dismiss()
}
popUpCamera.setOnClickListener {
fromCamera()
pictureDialog.dismiss()
}
val popupClose = dialogView.findViewById<ImageView>(R.id.popupClose)
popupClose.setOnClickListener { pictureDialog.dismiss() }
pictureDialog.show()
}
private fun fromGallery() {
ImagePicker.create(activity)
.toolbarImageTitle(activity.resources.getString(R.string.get_image))
.toolbarArrowColor(ContextCompat.getColor(activity, R.color.colorWhite))
.showCamera(false)
.limit(6)
.start()
}
private fun fromCamera() {
ImagePicker.cameraOnly().start(activity)
}
override fun onGetImage(image: Image) {
imgeNoteVisibility.value = View.GONE
imagesAdapter.updateContainerImagesAdapter(image)
images.add(image)
}
override fun addingImagesDone(mImages: MutableList<Image>) {
images.clear()
images.addAll(mImages)
imgeNoteVisibility.value = View.GONE
val listString :ArrayList<String> = ArrayList()
for (i in mImages.indices){
listString.add(mImages[i].path)
}
imagesAdapters2.value = ContainerImagesAdapter2(activity,containersData.status!!,listString)
imagesAdapters2.value!!.notifyItemRangeChanged(0,listString.size)
}
override fun onImgDelete(image: String) {
var x = 0
try {
for (i in 0 until images.size) {
x = i
if (images[i].path == image) {
images.remove(images[i])
}
}
} catch (e: Exception) {
Log.e("errorImages", e.message!!)
Log.e("xx", x.toString())
}
}
private fun onRetrievePostListStart() {
loading.value = true
}
private fun onRetrievePostListFinish() {
loading.value = false
}
private fun onRetrievePostListSuccess(msg: String?) {
onRetrievePostListFinish()
}
private fun onRetrievePostListError(message: String?) {
onRetrievePostListFinish()
getDataError.value = true
errorMessage.value = message
}
}
Adapter code is :
class ContainerImagesAdapter2() : RecyclerView.Adapter<ContainerImagesAdapter2.ViewHolder>() {
var status: String = ""
lateinit var activity: LaunchActivity
lateinit var utility: Utility
constructor(
mActivity: LaunchActivity,
mStatus: String,
pathsList: ArrayList<String>
) : this() {
activity = mActivity
pathsDataSet = pathsList
status = mStatus
utility = Utility(activity)
}
private var pathsDataSet: ArrayList<String> = ArrayList()
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val binding: ContianerImageFieldBinding = DataBindingUtil
.inflate(
LayoutInflater.from(parent.context),
R.layout.contianer_image_field,
parent,
false
)
return ViewHolder(binding, activity)
}
override fun getItemCount(): Int {
return pathsDataSet.size
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.bindPath(pathsDataSet[position], position)
}
inner class ViewHolder(
private val binding: ContianerImageFieldBinding,
val activity: LaunchActivity
) : RecyclerView.ViewHolder(binding.root) {
private val viewModel = MscImagesListViewModel(activity)
fun bindPath(data: String, position: Int) {
viewModel.bindPath(data)
binding.viewModel = viewModel
if (status != "PENDING") {
binding.closeImg.visibility = View.GONE
}
binding.closeImg.setOnClickListener {}
binding.mainImg.setOnClickListener {
val fragment = FullImageFragment()
val bundle = Bundle()
val list = ArrayList<String>()
for (item in 0 until pathsDataSet.size) {
list.add(pathsDataSet[item])
}
bundle.putSerializable("ImageList", list)
bundle.putInt("Position", position)
fragment.arguments = bundle
activity.supportFragmentManager.beginTransaction()
.replace(R.id.fragment_container, fragment).addToBackStack(fragment.tag)
.commit()
}
}
}
}
if you filter data using search view in the first-page and pick images in the second page , list of picked images doesn't appear, if you going to the second page without filtering data everything ok
solve Problem found
Just Update constraint-layout library in gradle dependencies to version '2.0.0-beta4'
I have a list of user record sound
The user can click on the list and play the audio file
How can I handle the MediaPlayer and the RecyclerView item in the Seekbar as well in the MVVM correctly?
That is, when the user clicks, the visitor changes the item and updates itself, and when it is clicked on an item again, it updates itself.
I did it now, but unfortunately, to the dirtiest possible form
activity code :
class SoundListActivity : BaseActivity(), Observer<List<VoiceEntity>>, VoiceAdapter.OnClickItemListener,
OnMultiSelectVoiceListener {
private lateinit var viewModel: VoiceViewModel
private val adapter = VoiceAdapter()
private val player = MediaPlayer()
private var positionPlayItem = -1
companion object {
fun start(context: Context) {
context.startActivity(Intent(context, SoundListActivity::class.java))
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_sound_list)
viewModel = ViewModelProviders.of(this).get(VoiceViewModel::class.java)
viewModel.mutableList!!.observe(this, this)
adapter.onItemClickListener = this
adapter.listenerMultiSelect = this
recycler.layoutManager = LinearLayoutManager(this)
recycler.adapter = adapter
fabAdd.setOnClickListener {
stopPlay()
RecordSoundActivity.start(this)
}
toolbar.setIconLeftListener(View.OnClickListener {
stopPlay()
finish()
})
}
override fun onChanged(list: List<VoiceEntity>?) {
this.progressBar.visibility = View.GONE
this.layoutEmptyState.visibility = View.INVISIBLE
this.adapter.removeAll()
if (list == null || list.isEmpty()) {
layoutEmptyState.visibility = View.VISIBLE
return
}
adapter.addItems(ArrayList(list))
}
override fun onClickItem(item: VoiceEntity, position: Int) {
if (player.isPlaying) {
player.reset()
}
if (item.isPlaying) {
item.isPlaying = false
player.reset()
adapter.notifyDataSetChanged()
return
}
this.positionPlayItem = position
adapter.items!!.forEach {
if (it != item) {
it.isPlaying = false
}
}
player.setDataSource(item.path)
player.prepare()
player.start()
item.isPlaying = true
adapter.notifyDataSetChanged()
player.setOnCompletionListener {
player.reset()
adapter.notifyItemChanged(position)
item.isPlaying = false
}
}
private fun stopPlay() {
if (positionPlayItem == -1) {
return
}
player.reset()
adapter.items!![positionPlayItem].isPlaying = false
adapter.notifyItemChanged(positionPlayItem)
}
override fun onMultiSelectVoice(items: ArrayList<VoiceEntity>) {
stopPlay()
if (items.size == 0) {
layoutSelectItem.visibility = View.GONE
return
}
txtCounterSelect.text = String.format(getString(R.string.selected_number), items.size.toString())
setStatusBarColor(R.color.black)
if (layoutSelectItem.visibility == View.GONE) {
layoutSelectItem.visibility = View.VISIBLE
}
if (items.size > 1) {
imgShare.visibility = View.GONE
imgEdit.visibility = View.GONE
} else {
imgShare.visibility = View.VISIBLE
imgEdit.visibility = View.VISIBLE
}
imgCancelSelect.setOnClickListener {
resetData()
}
imgEdit.setOnClickListener {
edit(items.first())
}
imgShare.setOnClickListener {
if (items.isEmpty()) {
return#setOnClickListener
}
shareVoice(this, items[0].path)
}
imgDelete.setOnClickListener {
val alertDialog = AlertDialog.Builder(
supportFragmentManager,
getString(R.string.note), getString(R.string.do_you_sure_delete)
)
alertDialog.setBtnNegative(getString(R.string.no), View.OnClickListener {
alertDialog.dialog!!.dismiss()
})
alertDialog.setBtnPositive(getString(R.string.yes), View.OnClickListener {
val ex = Executors.newSingleThreadExecutor()
items.forEach { item ->
viewModel.remove(item)
ex.execute { File(item.path).deleteOnExit() }
}
items.clear()
layoutSelectItem.visibility = View.GONE
setStatusBarColor(R.color.colorPrimaryDark)
alertDialog.dialog!!.dismissAllowingStateLoss()
})
alertDialog.build().show()
}
}
private fun resetData() {
adapter.itemsSelected.clear()
adapter.items?.forEach { item ->
item.statusSelect = false
}
adapter.notifyDataSetChanged()
layoutSelectItem.visibility = View.GONE
setStatusBarColor(R.color.colorPrimaryDark)
}
private fun edit(item: VoiceEntity) {
val bottomSheet = NameBottomSheet(supportFragmentManager)
bottomSheet.listener = object : NameBottomSheet.OnTitleListener {
override fun onTitle(title: String) {
item.title = title
viewModel.update(item)
resetData()
}
}
bottomSheet.item = item
bottomSheet.show()
}
override fun onBackPressed() {
if (layoutSelectItem.visibility == View.VISIBLE) {
resetData()
return
}
stopPlay()
super.onBackPressed()
}
}
adapter class code :
class VoiceAdapter : AdapterRecyclerView<VoiceEntity>() {
var onItemClickListener: OnClickItemListener? = null
var itemsSelected: ArrayList<VoiceEntity> = ArrayList()
var listenerMultiSelect: OnMultiSelectVoiceListener? = null
override fun getItemLayout(viewType: Int): Int {
return R.layout.item_voice
}
override fun onBindView(
viewDataBinding: ViewDataBinding,
viewHolder: ItemViewHolder,
position: Int,
viewType: Int,
element: VoiceEntity
) {
val binding = viewDataBinding as ItemVoiceBinding
binding.txtTitle.text = element.title
binding.txtDate.text = element.date.toAgoTime(context!!)
binding.icPlay.setImageResource(if (element.isPlaying) R.drawable.ic_pause else R.drawable.ic_play)
binding.seekBar.max = element.duration / 60
val colorSelectItem =
ContextCompat.getColor(binding.rootLayout.context, R.color.color_background_select_item_recycler_view)
val color = if (element.statusSelect) colorSelectItem else Color.TRANSPARENT
binding.rootLayout.setBackgroundColor(color)
if (element.statusSelect) {
changeColorLight(binding)
} else {
changeColorDarker(binding)
}
if (element.isPlaying) {
binding.layoutPlaying.visibility = View.VISIBLE
binding.lottieLayer.playAnimation()
//TODO : change handled voice progressBar show
val t = object : Thread() {
override fun run() {
super.run()
for (i in 0..element.duration) {
Thread.sleep(60)
binding.seekBar.progress = i
if (!element.isPlaying) break
}
}
}
t.start()
} else {
binding.layoutPlaying.visibility = View.GONE
binding.lottieLayer.cancelAnimation()
}
binding.rootLayout.setOnClickListener {
if (itemsSelected.size > 0) {
val item = items!![viewHolder.adapterPosition]
if (itemsSelected.contains(item)) {
item.statusSelect = false
itemsSelected.remove(item)
binding.rootLayout.animatedColorBackgroundSelected(false)
listenerMultiSelect?.onMultiSelectVoice(itemsSelected)
changeColorDarker(binding)
return#setOnClickListener
}
item.statusSelect = true
itemsSelected.add(item)
binding.rootLayout.animatedColorBackgroundSelected()
listenerMultiSelect?.onMultiSelectVoice(itemsSelected)
changeColorLight(binding)
return#setOnClickListener
}
onItemClickListener?.onClickItem(element, position)!!
}
binding.rootLayout.setOnLongClickListener {
val item = items!![viewHolder.adapterPosition]
if (itemsSelected.contains(item)) {
item.statusSelect = false
itemsSelected.remove(item)
binding.rootLayout.animatedColorBackgroundSelected(false)
changeColorDarker(binding)
listenerMultiSelect?.onMultiSelectVoice(itemsSelected)
}
item.statusSelect = true
itemsSelected.add(item)
binding.rootLayout.animatedColorBackgroundSelected()
changeColorLight(binding)
listenerMultiSelect?.onMultiSelectVoice(itemsSelected)
true
}
}
private fun changeColorLight(binding: ItemVoiceBinding) {
binding.txtDate.setTextColor(ContextCompat.getColor(binding.root.context, R.color.color_subtitle_light))
binding.txtTitle.setTextColor(ContextCompat.getColor(binding.root.context, R.color.color_title_light))
}
private fun changeColorDarker(binding: ItemVoiceBinding) {
binding.txtDate.setTextColor(ContextCompat.getColor(binding.root.context, R.color.color_subtitle))
binding.txtTitle.setTextColor(ContextCompat.getColor(binding.root.context, R.color.color_title))
}
interface OnClickItemListener {
fun onClickItem(item: VoiceEntity, position: Int)
}
}
github repository (open source project)