Add clean deletion for CustomField

dev
Aurelien Hubert 7 years ago
parent 813186b023
commit 13e6fed951
  1. 5
      app/src/main/java/net/pokeranalytics/android/model/interfaces/Manageable.kt
  2. 38
      app/src/main/java/net/pokeranalytics/android/model/realm/CustomField.kt
  3. 44
      app/src/main/java/net/pokeranalytics/android/model/realm/CustomFieldEntry.kt
  4. 24
      app/src/main/java/net/pokeranalytics/android/ui/extensions/UIExtensions.kt
  5. 1
      app/src/main/java/net/pokeranalytics/android/ui/fragment/components/DeletableItemFragment.kt
  6. 47
      app/src/main/java/net/pokeranalytics/android/ui/fragment/data/CustomFieldDataFragment.kt
  7. 4
      app/src/main/java/net/pokeranalytics/android/ui/fragment/data/EditableDataFragment.kt

@ -121,4 +121,9 @@ interface Deletable : Identifiable {
*/
fun getFailedDeleteMessage(status: DeleteValidityStatus): Int
/**
* A method to override if we need to delete linked objects or other stuff
*/
fun deleteDependencies() {}
}

@ -7,6 +7,7 @@ import io.realm.RealmList
import io.realm.RealmObject
import io.realm.annotations.Ignore
import io.realm.annotations.PrimaryKey
import io.realm.kotlin.where
import net.pokeranalytics.android.R
import net.pokeranalytics.android.model.interfaces.DeleteValidityStatus
import net.pokeranalytics.android.model.interfaces.NameManageable
@ -60,13 +61,9 @@ open class CustomField : RealmObject(), NameManageable, StaticRowRepresentableDa
updateRowRepresentation()
}
override fun localizedTitle(context: Context): String {
return this.name
}
override fun getDisplayName(context: Context): String {
return this.name
}
@Ignore
private var entriesToDelete: ArrayList<CustomFieldEntry> = ArrayList()
@Ignore
override var viewType: Int = RowViewType.TITLE_VALUE_ARROW.ordinal
@ -74,6 +71,15 @@ open class CustomField : RealmObject(), NameManageable, StaticRowRepresentableDa
@Ignore
private var rowRepresentation: List<RowRepresentable> = mutableListOf()
override fun localizedTitle(context: Context): String {
return this.name
}
override fun getDisplayName(context: Context): String {
return this.name
}
override fun adapterRows(): List<RowRepresentable>? {
return rowRepresentation
}
@ -119,6 +125,13 @@ open class CustomField : RealmObject(), NameManageable, StaticRowRepresentableDa
}
}
override fun deleteDependencies() {
if (isValid) {
val entries = realm.where<CustomFieldEntry>().equalTo("customField.id", id).findAll()
entries.deleteAllFromRealm()
}
}
override fun editDescriptors(row: RowRepresentable): ArrayList<RowRepresentableEditDescriptor>? {
return when (row) {
is CustomFieldEntry -> row.editingDescriptors(
@ -208,8 +221,21 @@ open class CustomField : RealmObject(), NameManageable, StaticRowRepresentableDa
*/
fun deleteEntry(entry: CustomFieldEntry) {
entries.remove(entry)
entriesToDelete.add(entry)
sortEntries()
updateRowRepresentation()
}
/**
* Remove the deleted entries from realm
*/
fun cleanDeletedEntries(realm: Realm) {
realm.executeTransaction {
entriesToDelete.forEach {
realm.where<CustomFieldEntry>().equalTo("id", it.id).findFirst()?.deleteFromRealm()
}
entriesToDelete.clear()
}
}
}

@ -2,10 +2,16 @@ package net.pokeranalytics.android.model.realm
import android.content.Context
import android.text.InputType
import io.realm.Realm
import io.realm.RealmObject
import io.realm.annotations.Ignore
import io.realm.annotations.PrimaryKey
import io.realm.kotlin.where
import net.pokeranalytics.android.R
import net.pokeranalytics.android.exceptions.ModelException
import net.pokeranalytics.android.model.interfaces.DeleteValidityStatus
import net.pokeranalytics.android.model.interfaces.Manageable
import net.pokeranalytics.android.model.interfaces.SaveValidityStatus
import net.pokeranalytics.android.ui.fragment.components.bottomsheet.BottomSheetType
import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.RowRepresentableEditDescriptor
@ -16,10 +22,10 @@ import java.util.*
import java.util.Currency
open class CustomFieldEntry : RealmObject(), RowRepresentable {
open class CustomFieldEntry : RealmObject(), Manageable, RowRepresentable {
@PrimaryKey
var id = UUID.randomUUID().toString()
override var id = UUID.randomUUID().toString()
var order: Int = 0
var customField: CustomField? = null
@ -60,6 +66,40 @@ open class CustomFieldEntry : RealmObject(), RowRepresentable {
)
}
override fun isValidForSave(): Boolean {
return true
}
override fun alreadyExists(realm: Realm): Boolean {
return realm.where(this::class.java).notEqualTo("id", this.id).findAll().isNotEmpty()
}
override fun getFailedSaveMessage(status: SaveValidityStatus): Int {
throw ModelException("${this::class.java} getFailedSaveMessage for $status not handled")
}
override fun getFailedDeleteMessage(status: DeleteValidityStatus): Int {
return R.string.cf_entry_delete_popup_message
}
override fun deleteDependencies() {
if (isValid) {
val entries = realm.where<CustomFieldEntry>().equalTo("customField.id", id).findAll()
entries.deleteAllFromRealm()
}
}
override fun updateValue(value: Any?, row: RowRepresentable) {
this.value = value as String? ?: ""
}
override fun isValidForDelete(realm: Realm): Boolean {
if (realm.where<Session>().contains("customFieldEntries.id", id).findAll().isNotEmpty()) {
return false
}
return true
}
/**
* Return the amount
*/

@ -24,10 +24,6 @@ import net.pokeranalytics.android.util.billing.AppGuard
import java.io.File
// Sizes
val Int.dp: Int
get() = (this / Resources.getSystem().displayMetrics.density).toInt()
@ -70,8 +66,9 @@ fun PokerAnalyticsActivity.openPlayStorePage() {
}
// Open email for "Contact us"
fun PokerAnalyticsActivity.openContactMail(subjectStringRes: Int, filePath: String?= null) {
val info = "v${BuildConfig.VERSION_NAME}(${BuildConfig.VERSION_CODE}) - ${AppGuard.isProUser}, Android ${android.os.Build.VERSION.SDK_INT}, ${DeviceUtils.getDeviceName()}"
fun PokerAnalyticsActivity.openContactMail(subjectStringRes: Int, filePath: String? = null) {
val info =
"v${BuildConfig.VERSION_NAME}(${BuildConfig.VERSION_CODE}) - ${AppGuard.isProUser}, Android ${android.os.Build.VERSION.SDK_INT}, ${DeviceUtils.getDeviceName()}"
val emailIntent = Intent(Intent.ACTION_SEND)
@ -105,6 +102,7 @@ fun PokerAnalyticsActivity.openUrl(url: String) {
fun PokerAnalyticsActivity.showAlertDialog(title: Int? = null, message: Int? = null) {
showAlertDialog(this, title, message)
}
fun PokerAnalyticsFragment.showAlertDialog(title: Int? = null, message: Int? = null) {
context?.let {
showAlertDialog(it, title, message)
@ -114,7 +112,10 @@ fun PokerAnalyticsFragment.showAlertDialog(title: Int? = null, message: Int? = n
/**
* Create and show an alert dialog
*/
fun showAlertDialog(context: Context, title: Int? = null, message: Int? = null) {
fun showAlertDialog(
context: Context, title: Int? = null, message: Int? = null, showCancelButton: Boolean = false,
positiveAction: (() -> Unit)? = null, negativeAction: (() -> Unit)? = null
) {
val builder = AlertDialog.Builder(context)
title?.let {
builder.setTitle(title)
@ -122,7 +123,14 @@ fun showAlertDialog(context: Context, title: Int? = null, message: Int? = null)
message?.let {
builder.setMessage(message)
}
builder.setPositiveButton(net.pokeranalytics.android.R.string.ok, null)
builder.setPositiveButton(net.pokeranalytics.android.R.string.ok) { _, _ ->
positiveAction?.invoke()
}
if (showCancelButton) {
builder.setNegativeButton(R.string.cancel) { _, _ ->
negativeAction?.invoke()
}
}
builder.show()
}

@ -62,6 +62,7 @@ open class DeletableItemFragment : RealmFragment() {
deletedItem = getRealm().copyFromRealm(itemToDelete)
lastDeletedItemPosition = itemPosition
getRealm().executeTransaction {
itemToDelete.deleteDependencies()
itemToDelete.deleteFromRealm()
}
itemHasBeenReInserted = false

@ -8,20 +8,24 @@ import androidx.interpolator.view.animation.FastOutSlowInInterpolator
import androidx.recyclerview.widget.ItemTouchHelper
import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.chip.ChipGroup
import io.realm.kotlin.where
import kotlinx.android.synthetic.main.fragment_custom_view.*
import net.pokeranalytics.android.R
import net.pokeranalytics.android.model.realm.CustomField
import net.pokeranalytics.android.model.realm.CustomFieldEntry
import net.pokeranalytics.android.model.realm.Session
import net.pokeranalytics.android.ui.adapter.RowRepresentableDataSource
import net.pokeranalytics.android.ui.adapter.StaticRowRepresentableDataSource
import net.pokeranalytics.android.ui.extensions.ChipGroupExtension
import net.pokeranalytics.android.ui.extensions.px
import net.pokeranalytics.android.ui.extensions.showAlertDialog
import net.pokeranalytics.android.ui.fragment.components.bottomsheet.BottomSheetFragment
import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.RowRepresentableEditDescriptor
import net.pokeranalytics.android.ui.view.rowrepresentable.CustomFieldRow
import net.pokeranalytics.android.ui.view.rowrepresentable.SimpleRow
import net.pokeranalytics.android.util.NULL_TEXT
import timber.log.Timber
import java.util.*
import kotlin.collections.ArrayList
@ -36,8 +40,7 @@ class CustomFieldDataFragment : EditableDataFragment(), StaticRowRepresentableDa
return this.item as CustomField
}
private val oldRows: ArrayList<RowRepresentable> = ArrayList()
private val currentEntriesOrder: ArrayList<CustomFieldEntry> = ArrayList()
private val deletedCustomFieldEntries: ArrayList<CustomFieldEntry> = ArrayList()
private val itemTouchHelper = ItemTouchHelper(object : ItemTouchHelper.Callback() {
@ -74,7 +77,15 @@ class CustomFieldDataFragment : EditableDataFragment(), StaticRowRepresentableDa
return true
}
override fun onMoved(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder, fromPos: Int, target: RecyclerView.ViewHolder, toPos: Int, x: Int, y: Int) {
override fun onMoved(
recyclerView: RecyclerView,
viewHolder: RecyclerView.ViewHolder,
fromPos: Int,
target: RecyclerView.ViewHolder,
toPos: Int,
x: Int,
y: Int
) {
super.onMoved(recyclerView, viewHolder, fromPos, target, toPos, x, y)
Collections.swap(customField.entries, fromPos - (CustomFieldRow.values().size + 1), toPos - (CustomFieldRow.values().size + 1))
@ -157,7 +168,7 @@ class CustomFieldDataFragment : EditableDataFragment(), StaticRowRepresentableDa
override fun onRowValueChanged(value: Any?, row: RowRepresentable) {
when (row) {
is CustomFieldEntry -> {
row.value = value as String? ?: ""
row.updateValue(value, row)
customField.updateRowRepresentation()
rowRepresentableAdapter.notifyDataSetChanged()
}
@ -174,12 +185,26 @@ class CustomFieldDataFragment : EditableDataFragment(), StaticRowRepresentableDa
super.onRowDeleted(row)
when (row) {
is CustomFieldEntry -> {
if (!row.isValidForDelete(getRealm())) {
val status = row.getDeleteStatus(getRealm())
val message = row.getFailedDeleteMessage(status)
showAlertDialog(requireContext(), R.string.cf_entry_delete_popup_title, message, showCancelButton = true, positiveAction = {
customField.deleteEntry(row)
rowRepresentableAdapter.notifyDataSetChanged()
})
return
}
customField.deleteEntry(row)
rowRepresentableAdapter.notifyDataSetChanged()
}
}
}
override fun onDataSaved() {
super.onDataSaved()
customField.cleanDeletedEntries(getRealm())
}
/**
* Init UI
*/
@ -194,7 +219,7 @@ class CustomFieldDataFragment : EditableDataFragment(), StaticRowRepresentableDa
itemTouchHelper.attachToRecyclerView(null)
}
when(customField.sortCondition) {
when (customField.sortCondition) {
CustomField.Sort.DEFAULT.uniqueIdentifier -> sortDefault.isChecked = true
CustomField.Sort.ASCENDING.uniqueIdentifier -> sortAscending.isChecked = true
CustomField.Sort.DESCENDING.uniqueIdentifier -> sortDescending.isChecked = true
@ -215,7 +240,7 @@ class CustomFieldDataFragment : EditableDataFragment(), StaticRowRepresentableDa
return
}
when(checkedId) {
when (checkedId) {
R.id.sortDefault -> customField.sortCondition = CustomField.Sort.DEFAULT.uniqueIdentifier
R.id.sortAscending -> customField.sortCondition = CustomField.Sort.ASCENDING.uniqueIdentifier
R.id.sortDescending -> customField.sortCondition = CustomField.Sort.DESCENDING.uniqueIdentifier
@ -238,8 +263,18 @@ class CustomFieldDataFragment : EditableDataFragment(), StaticRowRepresentableDa
onRowSelected(0, it)
}
}
val entries = getRealm().where<CustomFieldEntry>().equalTo("customField.id", customField.id).findAll()
Timber.d("delete customField: entries: ${entries.size}")
entries.forEach {
val sessions = getRealm().where<Session>().contains("customFieldEntries.id", it.id).findAll()
Timber.d("Sessions: ${sessions.size} with entry value: ${it.value}")
}
}
/**
* Update UI
*/

@ -161,8 +161,8 @@ open class EditableDataFragment : RealmFragment(), RowRepresentableDelegate {
val uniqueIdentifier = (managedItem as Savable).id
finishActivityWithResult(uniqueIdentifier)
}
}
onDataSaved()
}
else -> {
val message = savable.getFailedSaveMessage(status)
@ -223,4 +223,6 @@ open class EditableDataFragment : RealmFragment(), RowRepresentableDelegate {
this.primaryKey = primaryKey
}
open fun onDataSaved() {}
}
Loading…
Cancel
Save