Skip to content

Commit 4bbd058

Browse files
committed
Android GUI: Prepare for Material Expressive list
1 parent cace568 commit 4bbd058

1 file changed

Lines changed: 103 additions & 33 deletions

File tree

Source/GUI/Android/app/src/main/java/net/mediaarea/mediainfo/ReportListActivity.kt

Lines changed: 103 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,11 @@ import androidx.lifecycle.lifecycleScope
2626
import androidx.lifecycle.repeatOnLifecycle
2727
import androidx.lifecycle.ViewModelProvider
2828
import androidx.preference.PreferenceManager.getDefaultSharedPreferences
29+
import androidx.recyclerview.widget.DiffUtil
30+
import androidx.recyclerview.widget.ListAdapter
2931
import androidx.recyclerview.widget.RecyclerView
3032
import com.google.android.material.dialog.MaterialAlertDialogBuilder
3133

32-
import android.annotation.SuppressLint
3334
import android.os.Build
3435
import android.os.Bundle
3536
import android.net.Uri
@@ -422,6 +423,14 @@ class ReportListActivity : AppCompatActivity(), ReportActivityListener {
422423

423424
startShowReportForResult.launch(intent)
424425
}
426+
if (twoPane) activityReportListBinding.reportListLayout.reportList.post {
427+
val itemRecyclerViewAdapter = activityReportListBinding.reportListLayout.reportList.adapter as? ItemRecyclerViewAdapter
428+
itemRecyclerViewAdapter?.setSelectedId(id)
429+
val position = reports.indexOfFirst { it.id == id }
430+
if (position != -1) {
431+
activityReportListBinding.reportListLayout.reportList.smoothScrollToPosition(position)
432+
}
433+
}
425434
}
426435

427436
fun deleteReport(id: Int) {
@@ -628,7 +637,7 @@ class ReportListActivity : AppCompatActivity(), ReportActivityListener {
628637
launch {
629638
reportModel.getAllReports().collectLatest {
630639
reports = it
631-
setupRecyclerView(activityReportListBinding.reportListLayout.reportList)
640+
(activityReportListBinding.reportListLayout.reportList.adapter as? ItemRecyclerViewAdapter)?.updateList(reports)
632641

633642
val rootLayout: FrameLayout = findViewById(R.id.frame_layout)
634643
if (reports.isEmpty()) {
@@ -693,67 +702,128 @@ class ReportListActivity : AppCompatActivity(), ReportActivityListener {
693702
}
694703
}
695704

696-
@SuppressLint("NotifyDataSetChanged")
697705
private fun setupRecyclerView(recyclerView: RecyclerView) {
698706
recyclerView.adapter = ItemRecyclerViewAdapter()
699-
recyclerView.adapter?.notifyDataSetChanged()
700707
}
701708

702-
inner class ItemRecyclerViewAdapter : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
709+
sealed class ReportListItem {
710+
data class ReportData(val report: Report) : ReportListItem()
711+
object ClearButton : ReportListItem()
712+
}
713+
class ReportDiffCallback : DiffUtil.ItemCallback<ReportListItem>() {
714+
override fun areItemsTheSame(oldItem: ReportListItem, newItem: ReportListItem): Boolean {
715+
return if (oldItem is ReportListItem.ReportData && newItem is ReportListItem.ReportData) {
716+
oldItem.report.id == newItem.report.id
717+
} else {
718+
oldItem is ReportListItem.ClearButton && newItem is ReportListItem.ClearButton
719+
}
720+
}
721+
override fun areContentsTheSame(oldItem: ReportListItem, newItem: ReportListItem): Boolean {
722+
return if (oldItem is ReportListItem.ReportData && newItem is ReportListItem.ReportData) {
723+
oldItem.report.id == newItem.report.id &&
724+
oldItem.report.filename == newItem.report.filename &&
725+
oldItem.report.version == newItem.report.version
726+
} else {
727+
oldItem == newItem
728+
}
729+
}
730+
}
731+
inner class ItemRecyclerViewAdapter : ListAdapter<ReportListItem, RecyclerView.ViewHolder>(ReportDiffCallback()) {
703732
private val onClickListener: View.OnClickListener = View.OnClickListener {
704733
showReport((it.tag as Report).id)
705734
}
706735

736+
private var selectedId: Int? = null
737+
738+
fun updateList(newList: List<Report>) {
739+
val oldSize = currentList.size
740+
val items = if (newList.isEmpty()) {
741+
emptyList()
742+
} else {
743+
newList.map { report -> ReportListItem.ReportData(report) } + ReportListItem.ClearButton
744+
}
745+
submitList(items) {
746+
// notify to update the rounded corners of first and last items
747+
notifyItemChanged(0)
748+
if (oldSize > 1) {
749+
notifyItemChanged(oldSize - 2)
750+
}
751+
val newSize = items.size
752+
if (newSize > 1) {
753+
notifyItemChanged(newSize - 2)
754+
}
755+
}
756+
}
757+
758+
fun setSelectedId(id: Int?) {
759+
val oldId = selectedId
760+
selectedId = id
761+
currentList.forEachIndexed { index, item ->
762+
if (item is ReportListItem.ReportData) {
763+
if (item.report.id == oldId || item.report.id == id) {
764+
notifyItemChanged(index)
765+
}
766+
}
767+
}
768+
}
769+
707770
override fun getItemViewType(position: Int): Int {
708-
return if (position == reports.size) BUTTON_VIEW_TYPE else ITEM_VIEW_TYPE
771+
return when (getItem(position)) {
772+
is ReportListItem.ReportData -> ITEM_VIEW_TYPE
773+
is ReportListItem.ClearButton -> BUTTON_VIEW_TYPE
774+
}
709775
}
710776

711777
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
712778
if (viewType == ITEM_VIEW_TYPE) {
713779
val binding = ReportListContentBinding.inflate(layoutInflater, parent, false)
714-
return ViewHolder(binding)
780+
return ListViewHolder(binding)
715781
} else {
716782
val binding = ClearButtonBinding.inflate(layoutInflater, parent, false)
717783
return ButtonViewHolder(binding)
718784
}
719785
}
720786

721787
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
722-
when (holder) {
723-
is ViewHolder -> {
724-
val report: Report = reports[position]
725-
holder.name.text = report.filename
726-
holder.id = report.id
727-
with(holder.itemView) {
728-
tag = report
729-
setOnClickListener(onClickListener)
788+
when (val item = getItem(position)) {
789+
is ReportListItem.ReportData -> {
790+
if (holder is ListViewHolder) {
791+
val report: Report = item.report
792+
holder.name.text = report.filename
793+
holder.id = report.id
794+
with(holder.itemView) {
795+
tag = report
796+
setOnClickListener(onClickListener)
797+
}
798+
holder.itemView.isActivated = (report.id == selectedId)
730799
}
731800
}
732-
is ButtonViewHolder -> {
733-
holder.binding.clearBtn.setOnClickListener {
734-
reportModel.deleteAllReports()
735-
intent.putExtra(Core.ARG_REPORT_ID, -1)
736-
if (twoPane) {
737-
val fragment = supportFragmentManager.findFragmentById(R.id.report_detail_container)
738-
if (fragment != null) {
739-
supportFragmentManager
740-
.beginTransaction()
741-
.detach(fragment)
742-
.commit()
743-
744-
title = getString(R.string.app_name)
801+
is ReportListItem.ClearButton -> {
802+
if (holder is ButtonViewHolder) {
803+
with(holder.itemView) {
804+
setOnClickListener {
805+
reportModel.deleteAllReports()
806+
intent.putExtra(Core.ARG_REPORT_ID, -1)
807+
if (twoPane) {
808+
val fragment =
809+
supportFragmentManager.findFragmentById(R.id.report_detail_container)
810+
if (fragment != null) {
811+
supportFragmentManager
812+
.beginTransaction()
813+
.detach(fragment)
814+
.commit()
815+
816+
title = getString(R.string.app_name)
817+
}
818+
}
745819
}
746820
}
747821
}
748822
}
749823
}
750824
}
751825

752-
override fun getItemCount(): Int {
753-
return if (reports.isEmpty()) 0 else reports.size + 1
754-
}
755-
756-
inner class ViewHolder(binding: ReportListContentBinding) : RecyclerView.ViewHolder(binding.root) {
826+
inner class ListViewHolder(binding: ReportListContentBinding) : RecyclerView.ViewHolder(binding.root) {
757827
val name: TextView = binding.nameText
758828
var id: Int = -1
759829

0 commit comments

Comments
 (0)