From 955206f00db49e3a6c1ffe4dfec6cd99a23e4491 Mon Sep 17 00:00:00 2001 From: Aurelien Hubert Date: Thu, 9 May 2019 15:45:10 +0200 Subject: [PATCH] Improve DeletableItemFragment and bankroll deletion --- .../android/ui/fragment/BankrollFragment.kt | 97 ++++++------------- .../android/ui/fragment/DataListFragment.kt | 1 - .../ui/fragment/DeletableItemFragment.kt | 63 +++++++++--- .../CustomizableRowRepresentable.kt | 4 +- .../main/res/layout/fragment_data_list.xml | 2 +- 5 files changed, 84 insertions(+), 83 deletions(-) diff --git a/app/src/main/java/net/pokeranalytics/android/ui/fragment/BankrollFragment.kt b/app/src/main/java/net/pokeranalytics/android/ui/fragment/BankrollFragment.kt index 3e0eed9f..d2315be1 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/fragment/BankrollFragment.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/fragment/BankrollFragment.kt @@ -6,10 +6,8 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import androidx.appcompat.app.AlertDialog import androidx.recyclerview.widget.LinearLayoutManager import com.github.mikephil.charting.data.LineDataSet -import io.realm.Realm import io.realm.RealmObject import io.realm.RealmResults import kotlinx.android.synthetic.main.fragment_bankroll.* @@ -25,7 +23,7 @@ import net.pokeranalytics.android.calculus.bankroll.BankrollCalculator import net.pokeranalytics.android.calculus.bankroll.BankrollReport import net.pokeranalytics.android.calculus.bankroll.BankrollReportSetup import net.pokeranalytics.android.model.LiveData -import net.pokeranalytics.android.model.interfaces.Deletable +import net.pokeranalytics.android.model.interfaces.Identifiable import net.pokeranalytics.android.model.realm.Bankroll import net.pokeranalytics.android.ui.activity.BankrollDetailsActivity import net.pokeranalytics.android.ui.activity.DataListActivity @@ -66,9 +64,9 @@ class BankrollFragment : DeletableItemFragment(), StaticRowRepresentableDataSour private var rows: ArrayList = ArrayList() private var bankrollReportForRow: HashMap = HashMap() - private var deletedItem: RealmObject? = null - private var lastDeletedItemPosition: Int = 0 private var lastItemClickedPosition: Int = 0 + private var lastItemClickedId: String = "" + private var deletedRow: RowRepresentable? = null // Life Cycle @@ -91,7 +89,7 @@ class BankrollFragment : DeletableItemFragment(), StaticRowRepresentableDataSour if (needToDeleteItem) { GlobalScope.launch(Dispatchers.Main) { delay(300) - deleteItem(lastItemClickedPosition) + deleteItem(bankrollAdapter, LiveData.BANKROLL.items(getRealm()), lastItemClickedId) } } } else if (requestCode == REQUEST_CODE_CREATE && resultCode == Activity.RESULT_OK) { @@ -115,6 +113,7 @@ class BankrollFragment : DeletableItemFragment(), StaticRowRepresentableDataSour if (bankrollReportForRow.containsKey(row)) { bankrollReportForRow[row]?.let { bankrollReport -> lastItemClickedPosition = position + lastItemClickedId = (row as Identifiable).id BankrollDetailsActivity.newInstanceForResult(this, bankrollReport, REQUEST_CODE_DETAILS) } } @@ -136,6 +135,9 @@ class BankrollFragment : DeletableItemFragment(), StaticRowRepresentableDataSour launch(Dispatchers.Main) { + // TODO: Improve that + // We are in the main thread... + val startDate = Date() // Graph @@ -152,14 +154,13 @@ class BankrollFragment : DeletableItemFragment(), StaticRowRepresentableDataSour val bankrolls = LiveData.BANKROLL.items(getRealm()) as RealmResults - bankrolls.forEach { - - Timber.d("Bankroll: ${it.name} => isValidForDelete: ${it.isValidForDelete(Realm.getDefaultInstance())}") - - val bankrollReportSetup = BankrollReportSetup(it) + bankrolls.forEach { bankroll -> + val bankrollReportSetup = BankrollReportSetup(bankroll) val bankrollReport = BankrollCalculator.computeReport(getRealm(), bankrollReportSetup) val computedStat = ComputedStat(Stat.NET_RESULT, bankrollReport.total) - val row = CustomizableRowRepresentable(RowViewType.TITLE_VALUE_ARROW, title = it.name, computedStat = computedStat, isSelectable = true) + val row = + CustomizableRowRepresentable(RowViewType.TITLE_VALUE_ARROW, title = bankroll.name, computedStat = computedStat, isSelectable = true) + row.id = bankroll.id rows.add(row) bankrollReportForRow[row] = bankrollReport @@ -201,68 +202,26 @@ class BankrollFragment : DeletableItemFragment(), StaticRowRepresentableDataSour } } + override fun updateUIAfterDeletion(itemPosition: Int) { + lastItemClickedPosition = rows.indexOfFirst { if (it is Identifiable) it.id == lastItemClickedId else false } + deletedRow = rows.find { if (it is Identifiable) it.id == lastItemClickedId else false } + rows.removeAt(lastItemClickedPosition) + bankrollAdapter.notifyItemRemoved(lastItemClickedPosition) + } - /** - * Delete item - */ - private fun deleteItem(position: Int) { - - //TODO: Get bankroll from bankrollReport and delete it - - if (isDetached || activity == null) { - return - } - - // Save the delete position & create a copy of the object - val bankrollReport = bankrollReportForRow[rowRepresentableForPosition(position)] - val mRecentlyDeletedItem = bankrollReport?.setup?.bankroll - lastDeletedItemPosition = position - - if (mRecentlyDeletedItem is Bankroll) { + override fun updateUIAfterUndoDeletion(newItem: RealmObject) { - val deletableItem = (mRecentlyDeletedItem as Deletable) + // TODO: Improve that + // We are recreating a Bankroll report because the last one if invalid => the bankroll of the setup has been deleted - // Check if the object is valid for the deletion - if (deletableItem.isValidForDelete(this.getRealm())) { - deletedItem = getRealm().copyFromRealm(mRecentlyDeletedItem) - getRealm().executeTransaction { - mRecentlyDeletedItem.deleteFromRealm() - } - //bankrollAdapter.notifyItemRemoved(position) - //showUndoSnackBar() - - //TODO: Refresh bankrolls - initData() - - } else { - bankrollAdapter.notifyItemChanged(position) - val status = deletableItem.getDeleteStatus(this.getRealm()) - val errorMessage = deletableItem.getFailedDeleteMessage(status) - val builder = AlertDialog.Builder(requireContext()) - .setMessage(errorMessage) - .setNegativeButton(R.string.ok, null) - builder.show() - } - } - } + deletedRow?.let { row -> + val bankrollReportSetup = BankrollReportSetup(newItem as Bankroll) + val bankrollReport = BankrollCalculator.computeReport(getRealm(), bankrollReportSetup) + bankrollReportForRow[row] = bankrollReport - /** - * Show undo snack bar - */ - private fun showUndoSnackBar() { - /* - val message = String.format(getString(R.string.data_deleted), getString(R.string.bankroll)) - val snackBar = Snackbar.make(coordinatorLayout, message, Snackbar.LENGTH_INDEFINITE) - snackBar.setAction(R.string.cancel) { - getRealm().executeTransaction { realm -> - deletedItem?.let { - realm.copyToRealmOrUpdate(it) - bankrollAdapter.notifyItemInserted(lastDeletedItemPosition) - } - } + rows.add(lastItemClickedPosition, row) + bankrollAdapter.notifyItemInserted(lastItemClickedPosition) } - snackBar.show() - */ } } \ No newline at end of file diff --git a/app/src/main/java/net/pokeranalytics/android/ui/fragment/DataListFragment.kt b/app/src/main/java/net/pokeranalytics/android/ui/fragment/DataListFragment.kt index 6ebaf518..95c7b5fe 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/fragment/DataListFragment.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/fragment/DataListFragment.kt @@ -40,7 +40,6 @@ class DataListFragment : DeletableItemFragment(), LiveRowRepresentableDataSource private lateinit var dataListAdapter: RowRepresentableAdapter private var lastItemClickedId: String = "" - override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { super.onCreateView(inflater, container, savedInstanceState) return inflater.inflate(R.layout.fragment_data_list, container, false) diff --git a/app/src/main/java/net/pokeranalytics/android/ui/fragment/DeletableItemFragment.kt b/app/src/main/java/net/pokeranalytics/android/ui/fragment/DeletableItemFragment.kt index 365109c6..ec02f805 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/fragment/DeletableItemFragment.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/fragment/DeletableItemFragment.kt @@ -1,22 +1,45 @@ package net.pokeranalytics.android.ui.fragment +import android.os.Bundle +import android.view.View import androidx.appcompat.app.AlertDialog +import androidx.coordinatorlayout.widget.CoordinatorLayout import com.google.android.material.snackbar.Snackbar import io.realm.RealmObject -import kotlinx.android.synthetic.main.fragment_data_list.* import net.pokeranalytics.android.R import net.pokeranalytics.android.model.interfaces.Deletable import net.pokeranalytics.android.model.interfaces.Identifiable import net.pokeranalytics.android.ui.adapter.RowRepresentableAdapter import net.pokeranalytics.android.ui.fragment.components.RealmFragment +/** + * Deletable Item Fragment + * Don't forget to add a CoordinatorLayout at the top of your XML if you want to display correctly the snack bar + */ open class DeletableItemFragment : RealmFragment() { private var deletedItem: RealmObject? = null private var lastDeletedItemPosition: Int = 0 + private var dataListAdapter: RowRepresentableAdapter? = null + private var coordinatorLayout: CoordinatorLayout? = null + private var snackBar: Snackbar? = null + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + this.coordinatorLayout = view.findViewById(R.id.coordinatorLayout) + } + + override fun onPause() { + super.onPause() + snackBar?.dismiss() + } /** * Delete item + * [dataListAdapter]: Adapter to update + * [items]: List of items which contains the element to delete + * [itemId]: Id of the item to delete + * [container]: View to display the Snackbar */ fun deleteItem(dataListAdapter: RowRepresentableAdapter, items: List<*>, itemId: String) { @@ -24,6 +47,8 @@ open class DeletableItemFragment : RealmFragment() { return } + this.dataListAdapter = dataListAdapter + // Save the delete position & create a copy of the object val itemPosition = items.indexOfFirst { (it as Identifiable).id == itemId } val itemToDelete = items.find { (it as Identifiable).id == itemId } @@ -39,8 +64,8 @@ open class DeletableItemFragment : RealmFragment() { getRealm().executeTransaction { itemToDelete.deleteFromRealm() } - dataListAdapter.notifyItemRemoved(itemPosition) - showUndoSnackBar(dataListAdapter) + updateUIAfterDeletion(itemPosition) + showUndoSnackBar() } else { dataListAdapter.notifyItemChanged(itemPosition) val status = deletableItem.getDeleteStatus(this.getRealm()) @@ -56,18 +81,34 @@ open class DeletableItemFragment : RealmFragment() { /** * Show undo snack bar */ - private fun showUndoSnackBar(dataListAdapter: RowRepresentableAdapter) { + private fun showUndoSnackBar() { val message = String.format(getString(R.string.data_deleted)) - val snackBar = Snackbar.make(constraintLayout, message, Snackbar.LENGTH_INDEFINITE) - snackBar.setAction(R.string.cancel) { - getRealm().executeTransaction { realm -> - deletedItem?.let { - realm.copyToRealmOrUpdate(it) - dataListAdapter.notifyItemInserted(lastDeletedItemPosition) + this.coordinatorLayout?.let { view -> + snackBar = Snackbar.make(view, message, Snackbar.LENGTH_INDEFINITE) + snackBar?.setAction(R.string.cancel) { + getRealm().executeTransaction { realm -> + deletedItem?.let { + val item = realm.copyToRealmOrUpdate(it) + updateUIAfterUndoDeletion(item) + } } } + snackBar?.show() } - snackBar.show() + } + + /** + * Called once the object has been deleted + */ + open fun updateUIAfterDeletion(itemPosition: Int) { + dataListAdapter?.notifyItemRemoved(itemPosition) + } + + /** + * Called once the object has been restored + */ + open fun updateUIAfterUndoDeletion(newItem: RealmObject) { + dataListAdapter?.notifyItemInserted(lastDeletedItemPosition) } } \ No newline at end of file diff --git a/app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/CustomizableRowRepresentable.kt b/app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/CustomizableRowRepresentable.kt index 50a23ee9..3b6da0ce 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/CustomizableRowRepresentable.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/CustomizableRowRepresentable.kt @@ -2,6 +2,7 @@ package net.pokeranalytics.android.ui.view.rowrepresentable import android.content.Context import net.pokeranalytics.android.calculus.ComputedStat +import net.pokeranalytics.android.model.interfaces.Identifiable import net.pokeranalytics.android.ui.view.RowRepresentable import net.pokeranalytics.android.ui.view.RowViewType @@ -15,7 +16,7 @@ class CustomizableRowRepresentable( var value: String? = null, var computedStat: ComputedStat? = null, var isSelectable: Boolean? = false - ) : RowRepresentable { + ) : RowRepresentable, Identifiable { override fun localizedTitle(context: Context): String { @@ -30,4 +31,5 @@ class CustomizableRowRepresentable( override val viewType: Int = customViewType?.ordinal ?: RowViewType.HEADER_TITLE.ordinal + override var id: String = "" } diff --git a/app/src/main/res/layout/fragment_data_list.xml b/app/src/main/res/layout/fragment_data_list.xml index eae259fb..03650077 100644 --- a/app/src/main/res/layout/fragment_data_list.xml +++ b/app/src/main/res/layout/fragment_data_list.xml @@ -2,7 +2,7 @@