@@ -26,10 +26,11 @@ import androidx.lifecycle.lifecycleScope
2626import androidx.lifecycle.repeatOnLifecycle
2727import androidx.lifecycle.ViewModelProvider
2828import androidx.preference.PreferenceManager.getDefaultSharedPreferences
29+ import androidx.recyclerview.widget.DiffUtil
30+ import androidx.recyclerview.widget.ListAdapter
2931import androidx.recyclerview.widget.RecyclerView
3032import com.google.android.material.dialog.MaterialAlertDialogBuilder
3133
32- import android.annotation.SuppressLint
3334import android.os.Build
3435import android.os.Bundle
3536import 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