Repository: horizontalsystems/unstoppable-wallet-android
Issue: App crashes when enabling/disabling coins

Changing the list of coins (enabling, disabling, ordering) sometimes crashes app with Exception "tryGetViewHolderForPositionByDeadline", "Inconsistency detected. Invalid item position 2(offset:2).state:3".

Possible solution: https://stackoverflow.com/questions/30220771/recyclerview-inconsistency-detected-invalid-item-position

Changed files:
app/src/main/java/io/horizontalsystems/bankwallet/modules/balance/BalanceFragment.kt
app/src/main/java/io/horizontalsystems/bankwallet/core/storage/StorableCoinsRepository.kt
app/src/main/java/io/horizontalsystems/bankwallet/core/storage/StorableCoinsDao.kt
app/src/main/java/io/horizontalsystems/bankwallet/modules/transactions/TransactionsFragment.kt

diff --git a/app/src/main/java/io/horizontalsystems/bankwallet/core/storage/StorableCoinsDao.kt b/app/src/main/java/io/horizontalsystems/bankwallet/core/storage/StorableCoinsDao.kt
index 1ed32eee5..74832b044 100644
--- a/app/src/main/java/io/horizontalsystems/bankwallet/core/storage/StorableCoinsDao.kt
+++ b/app/src/main/java/io/horizontalsystems/bankwallet/core/storage/StorableCoinsDao.kt
@@ -1,9 +1,6 @@
 package io.horizontalsystems.bankwallet.core.storage
 
-import android.arch.persistence.room.Dao
-import android.arch.persistence.room.Insert
-import android.arch.persistence.room.OnConflictStrategy
-import android.arch.persistence.room.Query
+import android.arch.persistence.room.*
 import io.horizontalsystems.bankwallet.entities.StorableCoin
 import io.reactivex.Flowable
 
@@ -28,4 +25,10 @@ interface StorableCoinsDao {
     @Query("UPDATE StorableCoin SET enabled = 0, `order` = null")
     fun resetCoinsState()
 
+    @Transaction
+    fun setEnabledCoins(coins: List<StorableCoin>) {
+        resetCoinsState()
+        coins.forEach { insert(it) }
+    }
+
 }
diff --git a/app/src/main/java/io/horizontalsystems/bankwallet/core/storage/StorableCoinsRepository.kt b/app/src/main/java/io/horizontalsystems/bankwallet/core/storage/StorableCoinsRepository.kt
index 5110ebac1..ca1913f21 100644
--- a/app/src/main/java/io/horizontalsystems/bankwallet/core/storage/StorableCoinsRepository.kt
+++ b/app/src/main/java/io/horizontalsystems/bankwallet/core/storage/StorableCoinsRepository.kt
@@ -25,21 +25,10 @@ class StorableCoinsRepository(private val appDatabase: AppDatabase) : ICoinStora
     }
 
     override fun save(coins: List<Coin>) {
-
         executor.execute {
-            //update stored coins enabled as false, and order as null
-            appDatabase.coinsDao().resetCoinsState()
-
-            //save coin list
-            coins.forEachIndexed { index, coin ->
-                val storableCoin = StorableCoin(
-                        coinCode = coin.code,
-                        coinTitle = coin.title,
-                        coinType = coin.type,
-                        enabled = true,
-                        order = index)
-                appDatabase.coinsDao().insert(storableCoin)
-            }
+            appDatabase.coinsDao().setEnabledCoins(coins.mapIndexed { index, coin ->
+                StorableCoin(coin.code, coin.title, coin.type, true, index)
+            })
         }
     }
 
diff --git a/app/src/main/java/io/horizontalsystems/bankwallet/modules/balance/BalanceFragment.kt b/app/src/main/java/io/horizontalsystems/bankwallet/modules/balance/BalanceFragment.kt
index 0c7d13543..585ef6693 100644
--- a/app/src/main/java/io/horizontalsystems/bankwallet/modules/balance/BalanceFragment.kt
+++ b/app/src/main/java/io/horizontalsystems/bankwallet/modules/balance/BalanceFragment.kt
@@ -100,7 +100,11 @@ class BalanceFragment : android.support.v4.app.Fragment(), CoinsAdapter.Listener
 
         coinsAdapter.viewDelegate = viewModel.delegate
         recyclerCoins.adapter = coinsAdapter
-        recyclerCoins.layoutManager = LinearLayoutManager(context)
+        recyclerCoins.layoutManager = object : LinearLayoutManager(context) {
+            override fun supportsPredictiveItemAnimations(): Boolean {
+                return false
+            }
+        }
         (recyclerCoins.itemAnimator as? SimpleItemAnimator)?.supportsChangeAnimations = false
 
         manageCoins.setOnSingleClickListener { viewModel.delegate.openManageCoins() }
diff --git a/app/src/main/java/io/horizontalsystems/bankwallet/modules/transactions/TransactionsFragment.kt b/app/src/main/java/io/horizontalsystems/bankwallet/modules/transactions/TransactionsFragment.kt
index 2ad7a6941..5eb695b38 100644
--- a/app/src/main/java/io/horizontalsystems/bankwallet/modules/transactions/TransactionsFragment.kt
+++ b/app/src/main/java/io/horizontalsystems/bankwallet/modules/transactions/TransactionsFragment.kt
@@ -60,8 +60,7 @@ class TransactionsFragment : android.support.v4.app.Fragment(), TransactionsAdap
 
         viewModel.filterItems.observe(this, Observer { filters ->
             filters?.let {
-                filterAdapter.filters = it
-                filterAdapter.notifyDataSetChanged()
+                filterAdapter.setFilters(it)
             }
         })
 
@@ -267,10 +266,17 @@ class FilterAdapter(private var listener: Listener) : RecyclerView.Adapter<Recyc
         fun onFilterItemClick(item: String?)
     }
 
-    private var selectedFilterId: String? = null
-    var filters: List<String?> = listOf()
     var filterChangeable = true
 
+    private var selectedFilterId: String? = null
+    private var filters: List<String?> = listOf()
+
+    fun setFilters(filters: List<String?>) {
+        this.filters = filters
+        selectedFilterId = null
+        notifyDataSetChanged()
+    }
+
     override fun getItemCount() = filters.size
 
     override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder =