Improve DeletableItemFragment and bankroll deletion

dev
Aurelien Hubert 7 years ago
parent 0bc502e468
commit 955206f00d
  1. 95
      app/src/main/java/net/pokeranalytics/android/ui/fragment/BankrollFragment.kt
  2. 1
      app/src/main/java/net/pokeranalytics/android/ui/fragment/DataListFragment.kt
  3. 59
      app/src/main/java/net/pokeranalytics/android/ui/fragment/DeletableItemFragment.kt
  4. 4
      app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/CustomizableRowRepresentable.kt
  5. 2
      app/src/main/res/layout/fragment_data_list.xml

@ -6,10 +6,8 @@ import android.os.Bundle
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.appcompat.app.AlertDialog
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import com.github.mikephil.charting.data.LineDataSet import com.github.mikephil.charting.data.LineDataSet
import io.realm.Realm
import io.realm.RealmObject import io.realm.RealmObject
import io.realm.RealmResults import io.realm.RealmResults
import kotlinx.android.synthetic.main.fragment_bankroll.* 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.BankrollReport
import net.pokeranalytics.android.calculus.bankroll.BankrollReportSetup import net.pokeranalytics.android.calculus.bankroll.BankrollReportSetup
import net.pokeranalytics.android.model.LiveData 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.model.realm.Bankroll
import net.pokeranalytics.android.ui.activity.BankrollDetailsActivity import net.pokeranalytics.android.ui.activity.BankrollDetailsActivity
import net.pokeranalytics.android.ui.activity.DataListActivity import net.pokeranalytics.android.ui.activity.DataListActivity
@ -66,9 +64,9 @@ class BankrollFragment : DeletableItemFragment(), StaticRowRepresentableDataSour
private var rows: ArrayList<RowRepresentable> = ArrayList() private var rows: ArrayList<RowRepresentable> = ArrayList()
private var bankrollReportForRow: HashMap<RowRepresentable, BankrollReport> = HashMap() private var bankrollReportForRow: HashMap<RowRepresentable, BankrollReport> = HashMap()
private var deletedItem: RealmObject? = null
private var lastDeletedItemPosition: Int = 0
private var lastItemClickedPosition: Int = 0 private var lastItemClickedPosition: Int = 0
private var lastItemClickedId: String = ""
private var deletedRow: RowRepresentable? = null
// Life Cycle // Life Cycle
@ -91,7 +89,7 @@ class BankrollFragment : DeletableItemFragment(), StaticRowRepresentableDataSour
if (needToDeleteItem) { if (needToDeleteItem) {
GlobalScope.launch(Dispatchers.Main) { GlobalScope.launch(Dispatchers.Main) {
delay(300) delay(300)
deleteItem(lastItemClickedPosition) deleteItem(bankrollAdapter, LiveData.BANKROLL.items(getRealm()), lastItemClickedId)
} }
} }
} else if (requestCode == REQUEST_CODE_CREATE && resultCode == Activity.RESULT_OK) { } else if (requestCode == REQUEST_CODE_CREATE && resultCode == Activity.RESULT_OK) {
@ -115,6 +113,7 @@ class BankrollFragment : DeletableItemFragment(), StaticRowRepresentableDataSour
if (bankrollReportForRow.containsKey(row)) { if (bankrollReportForRow.containsKey(row)) {
bankrollReportForRow[row]?.let { bankrollReport -> bankrollReportForRow[row]?.let { bankrollReport ->
lastItemClickedPosition = position lastItemClickedPosition = position
lastItemClickedId = (row as Identifiable).id
BankrollDetailsActivity.newInstanceForResult(this, bankrollReport, REQUEST_CODE_DETAILS) BankrollDetailsActivity.newInstanceForResult(this, bankrollReport, REQUEST_CODE_DETAILS)
} }
} }
@ -136,6 +135,9 @@ class BankrollFragment : DeletableItemFragment(), StaticRowRepresentableDataSour
launch(Dispatchers.Main) { launch(Dispatchers.Main) {
// TODO: Improve that
// We are in the main thread...
val startDate = Date() val startDate = Date()
// Graph // Graph
@ -152,14 +154,13 @@ class BankrollFragment : DeletableItemFragment(), StaticRowRepresentableDataSour
val bankrolls = LiveData.BANKROLL.items(getRealm()) as RealmResults<Bankroll> val bankrolls = LiveData.BANKROLL.items(getRealm()) as RealmResults<Bankroll>
bankrolls.forEach { bankrolls.forEach { bankroll ->
val bankrollReportSetup = BankrollReportSetup(bankroll)
Timber.d("Bankroll: ${it.name} => isValidForDelete: ${it.isValidForDelete(Realm.getDefaultInstance())}")
val bankrollReportSetup = BankrollReportSetup(it)
val bankrollReport = BankrollCalculator.computeReport(getRealm(), bankrollReportSetup) val bankrollReport = BankrollCalculator.computeReport(getRealm(), bankrollReportSetup)
val computedStat = ComputedStat(Stat.NET_RESULT, bankrollReport.total) 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) rows.add(row)
bankrollReportForRow[row] = bankrollReport 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 }
* Delete item deletedRow = rows.find { if (it is Identifiable) it.id == lastItemClickedId else false }
*/ rows.removeAt(lastItemClickedPosition)
private fun deleteItem(position: Int) { bankrollAdapter.notifyItemRemoved(lastItemClickedPosition)
//TODO: Get bankroll from bankrollReport and delete it
if (isDetached || activity == null) {
return
} }
// Save the delete position & create a copy of the object override fun updateUIAfterUndoDeletion(newItem: RealmObject) {
val bankrollReport = bankrollReportForRow[rowRepresentableForPosition(position)]
val mRecentlyDeletedItem = bankrollReport?.setup?.bankroll
lastDeletedItemPosition = position
if (mRecentlyDeletedItem is Bankroll) {
val deletableItem = (mRecentlyDeletedItem as Deletable)
// 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 // TODO: Improve that
initData() // We are recreating a Bankroll report because the last one if invalid => the bankroll of the setup has been deleted
} else { deletedRow?.let { row ->
bankrollAdapter.notifyItemChanged(position) val bankrollReportSetup = BankrollReportSetup(newItem as Bankroll)
val status = deletableItem.getDeleteStatus(this.getRealm()) val bankrollReport = BankrollCalculator.computeReport(getRealm(), bankrollReportSetup)
val errorMessage = deletableItem.getFailedDeleteMessage(status) bankrollReportForRow[row] = bankrollReport
val builder = AlertDialog.Builder(requireContext())
.setMessage(errorMessage)
.setNegativeButton(R.string.ok, null)
builder.show()
}
}
}
/** rows.add(lastItemClickedPosition, row)
* Show undo snack bar bankrollAdapter.notifyItemInserted(lastItemClickedPosition)
*/
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)
} }
} }
}
snackBar.show()
*/
}
} }

@ -40,7 +40,6 @@ class DataListFragment : DeletableItemFragment(), LiveRowRepresentableDataSource
private lateinit var dataListAdapter: RowRepresentableAdapter private lateinit var dataListAdapter: RowRepresentableAdapter
private var lastItemClickedId: String = "" private var lastItemClickedId: String = ""
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
super.onCreateView(inflater, container, savedInstanceState) super.onCreateView(inflater, container, savedInstanceState)
return inflater.inflate(R.layout.fragment_data_list, container, false) return inflater.inflate(R.layout.fragment_data_list, container, false)

@ -1,22 +1,45 @@
package net.pokeranalytics.android.ui.fragment package net.pokeranalytics.android.ui.fragment
import android.os.Bundle
import android.view.View
import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AlertDialog
import androidx.coordinatorlayout.widget.CoordinatorLayout
import com.google.android.material.snackbar.Snackbar import com.google.android.material.snackbar.Snackbar
import io.realm.RealmObject import io.realm.RealmObject
import kotlinx.android.synthetic.main.fragment_data_list.*
import net.pokeranalytics.android.R import net.pokeranalytics.android.R
import net.pokeranalytics.android.model.interfaces.Deletable import net.pokeranalytics.android.model.interfaces.Deletable
import net.pokeranalytics.android.model.interfaces.Identifiable import net.pokeranalytics.android.model.interfaces.Identifiable
import net.pokeranalytics.android.ui.adapter.RowRepresentableAdapter import net.pokeranalytics.android.ui.adapter.RowRepresentableAdapter
import net.pokeranalytics.android.ui.fragment.components.RealmFragment 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() { open class DeletableItemFragment : RealmFragment() {
private var deletedItem: RealmObject? = null private var deletedItem: RealmObject? = null
private var lastDeletedItemPosition: Int = 0 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 * 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) { fun deleteItem(dataListAdapter: RowRepresentableAdapter, items: List<*>, itemId: String) {
@ -24,6 +47,8 @@ open class DeletableItemFragment : RealmFragment() {
return return
} }
this.dataListAdapter = dataListAdapter
// Save the delete position & create a copy of the object // Save the delete position & create a copy of the object
val itemPosition = items.indexOfFirst { (it as Identifiable).id == itemId } val itemPosition = items.indexOfFirst { (it as Identifiable).id == itemId }
val itemToDelete = items.find { (it as Identifiable).id == itemId } val itemToDelete = items.find { (it as Identifiable).id == itemId }
@ -39,8 +64,8 @@ open class DeletableItemFragment : RealmFragment() {
getRealm().executeTransaction { getRealm().executeTransaction {
itemToDelete.deleteFromRealm() itemToDelete.deleteFromRealm()
} }
dataListAdapter.notifyItemRemoved(itemPosition) updateUIAfterDeletion(itemPosition)
showUndoSnackBar(dataListAdapter) showUndoSnackBar()
} else { } else {
dataListAdapter.notifyItemChanged(itemPosition) dataListAdapter.notifyItemChanged(itemPosition)
val status = deletableItem.getDeleteStatus(this.getRealm()) val status = deletableItem.getDeleteStatus(this.getRealm())
@ -56,18 +81,34 @@ open class DeletableItemFragment : RealmFragment() {
/** /**
* Show undo snack bar * Show undo snack bar
*/ */
private fun showUndoSnackBar(dataListAdapter: RowRepresentableAdapter) { private fun showUndoSnackBar() {
val message = String.format(getString(R.string.data_deleted)) val message = String.format(getString(R.string.data_deleted))
val snackBar = Snackbar.make(constraintLayout, message, Snackbar.LENGTH_INDEFINITE) this.coordinatorLayout?.let { view ->
snackBar.setAction(R.string.cancel) { snackBar = Snackbar.make(view, message, Snackbar.LENGTH_INDEFINITE)
snackBar?.setAction(R.string.cancel) {
getRealm().executeTransaction { realm -> getRealm().executeTransaction { realm ->
deletedItem?.let { deletedItem?.let {
realm.copyToRealmOrUpdate(it) val item = realm.copyToRealmOrUpdate(it)
dataListAdapter.notifyItemInserted(lastDeletedItemPosition) 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)
} }
} }

@ -2,6 +2,7 @@ package net.pokeranalytics.android.ui.view.rowrepresentable
import android.content.Context import android.content.Context
import net.pokeranalytics.android.calculus.ComputedStat 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.RowRepresentable
import net.pokeranalytics.android.ui.view.RowViewType import net.pokeranalytics.android.ui.view.RowViewType
@ -15,7 +16,7 @@ class CustomizableRowRepresentable(
var value: String? = null, var value: String? = null,
var computedStat: ComputedStat? = null, var computedStat: ComputedStat? = null,
var isSelectable: Boolean? = false var isSelectable: Boolean? = false
) : RowRepresentable { ) : RowRepresentable, Identifiable {
override fun localizedTitle(context: Context): String { override fun localizedTitle(context: Context): String {
@ -30,4 +31,5 @@ class CustomizableRowRepresentable(
override val viewType: Int = customViewType?.ordinal ?: RowViewType.HEADER_TITLE.ordinal override val viewType: Int = customViewType?.ordinal ?: RowViewType.HEADER_TITLE.ordinal
override var id: String = ""
} }

@ -2,7 +2,7 @@
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android" <androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/container" android:id="@+id/coordinatorLayout"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent">

Loading…
Cancel
Save