From 89a3a4e9c189e968942e01e4ca0925c140a48ec9 Mon Sep 17 00:00:00 2001
From: Janne Koschinski <janne@kuschku.de>
Date: Sun, 25 Feb 2018 16:02:55 +0100
Subject: [PATCH] Fixed the selection bug in the account selector

---
 .../persistence/AccountDatabase.kt            |   4 +-
 .../ui/setup/accounts/AccountAdapter.kt       | 117 +++++++++++-------
 .../accounts/AccountSelectionActivity.kt      |   8 +-
 .../setup/accounts/AccountSelectionSlide.kt   |  17 +--
 .../ui/setup/accounts/AccountViewModel.kt     |   7 +-
 5 files changed, 89 insertions(+), 64 deletions(-)

diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/persistence/AccountDatabase.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/persistence/AccountDatabase.kt
index 3be55470e..e62a5c189 100644
--- a/app/src/main/java/de/kuschku/quasseldroid_ng/persistence/AccountDatabase.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid_ng/persistence/AccountDatabase.kt
@@ -1,6 +1,6 @@
 package de.kuschku.quasseldroid_ng.persistence
 
-import android.arch.paging.DataSource
+import android.arch.lifecycle.LiveData
 import android.arch.persistence.room.*
 import android.content.Context
 
@@ -32,7 +32,7 @@ abstract class AccountDatabase : RoomDatabase() {
     fun findById(id: Long): AccountDatabase.Account?
 
     @Query("SELECT * FROM account ORDER BY lastUsed DESC")
-    fun all(): DataSource.Factory<Int, Account>
+    fun all(): LiveData<List<Account>>
 
     @Delete
     fun delete(account: AccountDatabase.Account)
diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/setup/accounts/AccountAdapter.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/setup/accounts/AccountAdapter.kt
index 542ce9a8a..4c6453927 100644
--- a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/setup/accounts/AccountAdapter.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/setup/accounts/AccountAdapter.kt
@@ -1,8 +1,11 @@
 package de.kuschku.quasseldroid_ng.ui.setup.accounts
 
 import android.annotation.SuppressLint
-import android.arch.paging.PagedListAdapter
-import android.support.v7.recyclerview.extensions.DiffCallback
+import android.arch.lifecycle.LifecycleOwner
+import android.arch.lifecycle.LiveData
+import android.arch.lifecycle.MutableLiveData
+import android.arch.lifecycle.Observer
+import android.support.v7.util.DiffUtil
 import android.support.v7.widget.AppCompatImageButton
 import android.support.v7.widget.AppCompatRadioButton
 import android.support.v7.widget.RecyclerView
@@ -14,16 +17,19 @@ import butterknife.BindView
 import butterknife.ButterKnife
 import de.kuschku.quasseldroid_ng.R
 import de.kuschku.quasseldroid_ng.persistence.AccountDatabase
+import de.kuschku.quasseldroid_ng.util.helper.zip
 
-class AccountAdapter :
-  PagedListAdapter<AccountDatabase.Account, AccountAdapter.AccountViewHolder>(DIFF_CALLBACK) {
+class AccountAdapter(
+  owner: LifecycleOwner,
+  val liveData: LiveData<List<AccountDatabase.Account>>,
+  val selectedItem: MutableLiveData<Pair<Long, Long>>
+) : RecyclerView.Adapter<AccountAdapter.AccountViewHolder>() {
   private val actionListeners = mutableSetOf<(Long) -> Unit>()
   private val addListeners = mutableSetOf<() -> Unit>()
   private val selectionListeners = mutableSetOf<(Long) -> Unit>()
 
   private val clickListener = object : ItemListener {
     override fun onAction(id: Long, pos: Int) {
-      notifySelectionChanged(selectedItemView, pos)
       selectionListener.invoke(id)
     }
   }
@@ -36,16 +42,65 @@ class AccountAdapter :
     }
   }
 
+  private fun updateSelection(id: Long) {
+    selectedItem.value = Pair(selectedItem.value?.second ?: -1, id)
+  }
+
   private val selectionListener = { id: Long ->
-    selectedItemId = id
+    updateSelection(id)
     for (selectionListener in selectionListeners) {
       selectionListener.invoke(id)
     }
   }
 
-  private var selectedItemView = -1
-  var selectedItemId = -1L
-    private set
+  val selectedItemId
+    get() = selectedItem.value?.second
+
+  private var list: List<Pair<Boolean, AccountDatabase.Account>> = emptyList()
+
+  init {
+    selectedItem.value = Pair(-1, -1)
+
+    liveData.zip(selectedItem).observe(owner, Observer { it ->
+      val list = it?.first
+      val oldSelected = it?.second?.first ?: -1
+      val selected = it?.second?.second ?: -1
+
+      val oldList = this.list
+      val newList: List<Pair<Boolean, AccountDatabase.Account>> = list.orEmpty().map {
+        Pair(selected == it.id, it)
+      }
+      this.list = newList
+
+      DiffUtil.calculateDiff(object : DiffUtil.Callback() {
+        override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
+          val oldItem = oldList[oldItemPosition].second
+          val newItem = newList[newItemPosition].second
+
+          return oldItem.id == newItem.id
+        }
+
+        override fun getOldListSize(): Int {
+          return oldList.size
+        }
+
+        override fun getNewListSize(): Int {
+          return newList.size
+        }
+
+        override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
+          val oldItem = oldList[oldItemPosition].second
+          val newItem = newList[newItemPosition].second
+
+          return oldItem == newItem &&
+                 oldItem.id != selected &&
+                 newItem.id != selected &&
+                 oldItem.id != oldSelected &&
+                 newItem.id != oldSelected
+        }
+      }).dispatchUpdatesTo(this)
+    })
+  }
 
   private val addListener = {
     for (addListener in addListeners) {
@@ -81,16 +136,8 @@ class AccountAdapter :
                                 @SuppressLint("RecyclerView") position: Int) {
     when (holder) {
       is AccountViewHolder.Item -> {
-        val account = getItem(position)
-        if (account == null) {
-          holder.clear()
-        } else {
-          val selected = account.id == selectedItemId
-          if (selected) {
-            selectedItemView = position
-          }
-          holder.bind(account, selected)
-        }
+        val item = list[position]
+        holder.bind(item.second, item.first)
       }
       is AccountViewHolder.Add  -> {
       }
@@ -98,8 +145,8 @@ class AccountAdapter :
   }
 
   override fun getItemViewType(position: Int) = when (position) {
-    super.getItemCount() -> TYPE_ADD
-    else                 -> TYPE_ACCOUNT
+    list.size -> TYPE_ADD
+    else      -> TYPE_ACCOUNT
   }
 
   override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): AccountViewHolder {
@@ -117,44 +164,18 @@ class AccountAdapter :
   }
 
   override fun getItemCount(): Int {
-    return super.getItemCount() + 1
+    return list.size + 1
   }
 
   companion object {
     private const val TYPE_ACCOUNT = 0
     private const val TYPE_ADD = 1
-
-    private val DIFF_CALLBACK = object : DiffCallback<AccountDatabase.Account>() {
-      override fun areContentsTheSame(oldItem: AccountDatabase.Account,
-                                      newItem: AccountDatabase.Account): Boolean {
-        return oldItem == newItem
-      }
-
-      override fun areItemsTheSame(oldItem: AccountDatabase.Account,
-                                   newItem: AccountDatabase.Account): Boolean {
-        return oldItem.id == newItem.id
-      }
-    }
   }
 
   fun selectAccount(id: Long) {
-    selectedItemView = -1
     selectionListener(id)
   }
 
-  fun notifySelectionChanged(from: Int?, to: Int?) {
-    val _from = from ?: -1
-    val _to = to ?: -1
-
-    if (_from != -1)
-      notifyItemChanged(_from)
-
-    selectedItemView = _to
-
-    if (_to != -1)
-      notifyItemChanged(_to)
-  }
-
   interface ItemListener {
     fun onAction(id: Long, pos: Int)
   }
diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/setup/accounts/AccountSelectionActivity.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/setup/accounts/AccountSelectionActivity.kt
index cb6891877..525ae03d1 100644
--- a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/setup/accounts/AccountSelectionActivity.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/setup/accounts/AccountSelectionActivity.kt
@@ -27,7 +27,9 @@ class AccountSelectionActivity : SetupActivity() {
       putLong(Keys.Status.selectedAccount, data.getLong(Keys.Status.selectedAccount, -1))
       putBoolean(Keys.Status.reconnect, true)
     }
-    startActivityForResult(Intent(this, ChatActivity::class.java), REQUEST_CHAT)
+    val intent = Intent(this, ChatActivity::class.java)
+    intent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP
+    startActivityForResult(intent, REQUEST_CHAT)
   }
 
   override fun onCreate(savedInstanceState: Bundle?) {
@@ -39,7 +41,9 @@ class AccountSelectionActivity : SetupActivity() {
     setInitData(data)
 
     if (statusPreferences.getBoolean(Keys.Status.reconnect, false) && selectedAccount != -1L) {
-      startActivityForResult(Intent(this, ChatActivity::class.java), REQUEST_CHAT)
+      val intent = Intent(this, ChatActivity::class.java)
+      intent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP
+      startActivityForResult(intent, REQUEST_CHAT)
     }
   }
 
diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/setup/accounts/AccountSelectionSlide.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/setup/accounts/AccountSelectionSlide.kt
index 78b14161a..6699c44eb 100644
--- a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/setup/accounts/AccountSelectionSlide.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/setup/accounts/AccountSelectionSlide.kt
@@ -3,7 +3,6 @@ package de.kuschku.quasseldroid_ng.ui.setup.accounts
 import android.app.Activity
 import android.arch.lifecycle.Observer
 import android.arch.lifecycle.ViewModelProviders
-import android.arch.paging.PagedList
 import android.content.Intent
 import android.os.Bundle
 import android.support.v7.widget.DefaultItemAnimator
@@ -24,21 +23,21 @@ class AccountSelectionSlide : SlideFragment() {
   @BindView(R.id.account_list)
   lateinit var accountList: RecyclerView
 
-  override fun isValid() = adapter.selectedItemId != -1L
+  override fun isValid() = adapter?.selectedItemId ?: -1L != -1L
 
   override val title = R.string.slideAccountSelectTitle
   override val description = R.string.slideAccountSelectDescription
 
   override fun setData(data: Bundle) {
     if (data.containsKey("selectedAccount"))
-      adapter.selectAccount(data.getLong("selectedAccount"))
+      adapter?.selectAccount(data.getLong("selectedAccount"))
   }
 
   override fun getData(data: Bundle) {
-    data.putLong("selectedAccount", adapter.selectedItemId)
+    data.putLong("selectedAccount", adapter?.selectedItemId ?: -1L)
   }
 
-  private val adapter = AccountAdapter()
+  private var adapter: AccountAdapter? = null
   override fun onCreateContent(inflater: LayoutInflater, container: ViewGroup?,
                                savedInstanceState: Bundle?): View {
     val view = inflater.inflate(R.layout.setup_select_account, container, false)
@@ -46,8 +45,8 @@ class AccountSelectionSlide : SlideFragment() {
     val accountViewModel = ViewModelProviders.of(this).get(
       AccountViewModel::class.java
     )
-    val firstObserver = object : Observer<PagedList<AccountDatabase.Account>?> {
-      override fun onChanged(t: PagedList<AccountDatabase.Account>?) {
+    val firstObserver = object : Observer<List<AccountDatabase.Account>?> {
+      override fun onChanged(t: List<AccountDatabase.Account>?) {
         if (t?.isEmpty() != false)
           startActivityForResult(
             Intent(context, AccountSetupActivity::class.java),
@@ -57,10 +56,12 @@ class AccountSelectionSlide : SlideFragment() {
       }
     }
     accountViewModel.accounts.observe(this, firstObserver)
-    accountViewModel.accounts.observe(this, Observer(adapter::setList))
     accountList.layoutManager = LinearLayoutManager(context)
     accountList.itemAnimator = DefaultItemAnimator()
+    val adapter = AccountAdapter(this, accountViewModel.accounts, accountViewModel.selectedItem)
+    this.adapter = adapter
     accountList.adapter = adapter
+
     adapter.addAddListener {
       startActivityForResult(Intent(context, AccountSetupActivity::class.java), -1)
     }
diff --git a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/setup/accounts/AccountViewModel.kt b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/setup/accounts/AccountViewModel.kt
index d873980ca..087b38577 100644
--- a/app/src/main/java/de/kuschku/quasseldroid_ng/ui/setup/accounts/AccountViewModel.kt
+++ b/app/src/main/java/de/kuschku/quasseldroid_ng/ui/setup/accounts/AccountViewModel.kt
@@ -3,14 +3,13 @@ package de.kuschku.quasseldroid_ng.ui.setup.accounts
 import android.app.Application
 import android.arch.lifecycle.AndroidViewModel
 import android.arch.lifecycle.LiveData
-import android.arch.paging.LivePagedListBuilder
-import android.arch.paging.PagedList
+import android.arch.lifecycle.MutableLiveData
 import de.kuschku.quasseldroid_ng.persistence.AccountDatabase
 
 class AccountViewModel(application: Application) : AndroidViewModel(application) {
   private val database: AccountDatabase = AccountDatabase.Creator.init(
     getApplication()
   )
-  val accounts: LiveData<PagedList<AccountDatabase.Account>>
-    = LivePagedListBuilder(database.accounts().all(), 20).build()
+  val accounts: LiveData<List<AccountDatabase.Account>> = database.accounts().all()
+  val selectedItem = MutableLiveData<Pair<Long, Long>>()
 }
-- 
GitLab