Adds ability to save & delete custom reports

dev
Laurent 7 years ago
parent 1a4535ae59
commit f290b21a31
  1. 40
      app/src/main/java/net/pokeranalytics/android/calculus/Calculator.kt
  2. 5
      app/src/main/java/net/pokeranalytics/android/model/LiveData.kt
  3. 20
      app/src/main/java/net/pokeranalytics/android/model/realm/ReportSetup.kt
  4. 45
      app/src/main/java/net/pokeranalytics/android/ui/activity/ComparisonReportActivity.kt
  5. 11
      app/src/main/java/net/pokeranalytics/android/ui/activity/ProgressReportActivity.kt
  6. 52
      app/src/main/java/net/pokeranalytics/android/ui/activity/TableReportActivity.kt
  7. 38
      app/src/main/java/net/pokeranalytics/android/ui/activity/components/ReportActivity.kt
  8. 7
      app/src/main/java/net/pokeranalytics/android/ui/fragment/BankrollFragment.kt
  9. 9
      app/src/main/java/net/pokeranalytics/android/ui/fragment/DataListFragment.kt
  10. 29
      app/src/main/java/net/pokeranalytics/android/ui/fragment/ReportsFragment.kt
  11. 10
      app/src/main/java/net/pokeranalytics/android/ui/fragment/components/DeletableItemFragment.kt
  12. 4
      app/src/main/java/net/pokeranalytics/android/ui/fragment/data/BankrollDataFragment.kt
  13. 154
      app/src/main/java/net/pokeranalytics/android/ui/fragment/data/DataManagerFragment.kt
  14. 162
      app/src/main/java/net/pokeranalytics/android/ui/fragment/data/EditableDataFragment.kt
  15. 2
      app/src/main/java/net/pokeranalytics/android/ui/fragment/data/LocationDataFragment.kt
  16. 96
      app/src/main/java/net/pokeranalytics/android/ui/fragment/report/AbstractReportFragment.kt
  17. 8
      app/src/main/java/net/pokeranalytics/android/ui/fragment/report/ComparisonReportFragment.kt
  18. 2
      app/src/main/java/net/pokeranalytics/android/ui/fragment/report/ProgressReportFragment.kt
  19. 5
      app/src/main/java/net/pokeranalytics/android/ui/fragment/report/TableReportFragment.kt
  20. 21
      app/src/main/res/layout/dialog_edit_text.xml
  21. 2
      app/src/main/res/layout/fragment_bankroll.xml
  22. 2
      app/src/main/res/layout/fragment_data_list.xml
  23. 2
      app/src/main/res/layout/fragment_reports.xml
  24. 1
      app/src/main/res/values/strings.xml
  25. 2
      build.gradle

@ -11,7 +11,6 @@ import net.pokeranalytics.android.model.filter.Query
import net.pokeranalytics.android.model.filter.filter
import net.pokeranalytics.android.model.realm.ComputableResult
import net.pokeranalytics.android.model.realm.Filter
import net.pokeranalytics.android.model.realm.ReportSetup
import net.pokeranalytics.android.model.realm.SessionSet
import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.util.extensions.startOfDay
@ -35,7 +34,8 @@ class Calculator {
query: Query = Query(),
filter: Filter? = null,
var aggregationType: AggregationType? = null,
var userGenerated: Boolean = false
var userGenerated: Boolean = false,
var reportSetupId: String? = null
) {
var evolutionValues: EvolutionValues = evolutionValues
@ -47,17 +47,17 @@ class Calculator {
}
private var _query: Query = query
private var _filter: Filter? = filter
var filter: Filter? = filter
init {
if (!this._query.conditions.isEmpty() && this._filter != null) {
if (!this._query.conditions.isEmpty() && this.filter != null) {
throw IllegalStateException("Can't specify a query with conditions AND a filter")
}
}
val query: Query
get() {
this._filter?.let {
this.filter?.let {
return it.query
}
return this._query
@ -134,21 +134,21 @@ class Calculator {
}
}
fun reportSetup(name: String): ReportSetup {
val rs = ReportSetup()
rs.name = name
rs.display = this.display.ordinal
this.stats.forEach {
rs.statIds.add(it.uniqueIdentifier)
}
this.criterias.forEach {
rs.criteriaIds.add(it.uniqueIdentifier)
}
rs.filter = this._filter
return rs
}
// fun reportSetup(name: String): ReportSetup {
//
// val rs = ReportSetup()
// rs.name = name
// rs.display = this.display.ordinal
// this.stats.forEach {
// rs.statIds.add(it.uniqueIdentifier)
// }
// this.criterias.forEach {
// rs.criteriaIds.add(it.uniqueIdentifier)
// }
// rs.filter = this.filter
//
// return rs
// }
/**
* Returns some default name

@ -24,7 +24,8 @@ enum class LiveData : Localizable {
TRANSACTION,
TRANSACTION_TYPE,
FILTER,
CUSTOM_FIELD;
CUSTOM_FIELD,
REPORT_SETUP;
fun items(realm: Realm, fieldName: String? = null, sortOrder: Sort? = null): RealmResults<*> {
val results = realm.where(this.relatedEntity).findAll().sort(fieldName ?: this.sortingFieldName, sortOrder ?: this.sorting)
@ -105,6 +106,7 @@ enum class LiveData : Localizable {
TRANSACTION_TYPE -> TransactionType::class.java
FILTER -> Filter::class.java
CUSTOM_FIELD -> CustomField::class.java
REPORT_SETUP -> ReportSetup::class.java
}
}
@ -148,6 +150,7 @@ enum class LiveData : Localizable {
TRANSACTION_TYPE -> R.string.operation_types
FILTER -> R.string.filter
CUSTOM_FIELD -> R.string.custom_fields
REPORT_SETUP -> R.string.custom
}
}

@ -1,6 +1,7 @@
package net.pokeranalytics.android.model.realm
import android.content.Context
import io.realm.Realm
import io.realm.RealmList
import io.realm.RealmObject
import io.realm.annotations.Ignore
@ -8,15 +9,17 @@ import io.realm.annotations.PrimaryKey
import net.pokeranalytics.android.calculus.Calculator
import net.pokeranalytics.android.calculus.Stat
import net.pokeranalytics.android.model.Criteria
import net.pokeranalytics.android.model.interfaces.Deletable
import net.pokeranalytics.android.model.interfaces.DeleteValidityStatus
import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.RowViewType
import java.util.*
open class ReportSetup : RealmObject(), RowRepresentable {
open class ReportSetup : RealmObject(), RowRepresentable, Deletable {
@PrimaryKey
var id = UUID.randomUUID().toString()
override var id = UUID.randomUUID().toString()
// The name of the report
var name: String = ""
@ -60,8 +63,19 @@ open class ReportSetup : RealmObject(), RowRepresentable {
stats = stats,
criterias = criteria,
filter = this.filter,
userGenerated = true
userGenerated = true,
reportSetupId = this.id
)
}
// Deletable
override fun isValidForDelete(realm: Realm): Boolean {
return true
}
override fun getFailedDeleteMessage(status: DeleteValidityStatus): Int {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
}

@ -1,35 +1,32 @@
package net.pokeranalytics.android.ui.activity
import android.content.Context
import android.content.Intent
import android.os.Bundle
import net.pokeranalytics.android.R
import net.pokeranalytics.android.calculus.Report
import net.pokeranalytics.android.ui.activity.components.PokerAnalyticsActivity
import net.pokeranalytics.android.ui.activity.components.ReportActivity
import net.pokeranalytics.android.ui.fragment.report.ComparisonReportFragment
class ComparisonReportActivity : PokerAnalyticsActivity() {
companion object {
// Unparcel fails when setting a custom Parcelable object on Entry so we use a static reference to passe objects
private var report: Report? = null
private var reportTitle: String = ""
/**
* Default constructor
*/
fun newInstance(context: Context, report: Report, reportTitle: String) {
//parameters = GraphParameters(stat, group, report)
this.report = report
this.reportTitle = reportTitle
val intent = Intent(context, ComparisonReportActivity::class.java)
context.startActivity(intent)
}
}
class ComparisonReportActivity : ReportActivity() {
// companion object {
//
// // Unparcel fails when setting a custom Parcelable object on Entry so we use a static reference to passe objects
// private var report: Report? = null
// private var reportTitle: String = ""
//
// /**
// * Default constructor
// */
// fun newInstance(context: Context, report: Report, reportTitle: String) {
// //parameters = GraphParameters(stat, group, report)
// this.report = report
// this.reportTitle = reportTitle
// val intent = Intent(context, ComparisonReportActivity::class.java)
// context.startActivity(intent)
// }
//
// }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

@ -3,10 +3,12 @@ package net.pokeranalytics.android.ui.activity
import android.content.Context
import android.content.Intent
import android.os.Bundle
import androidx.fragment.app.Fragment
import net.pokeranalytics.android.R
import net.pokeranalytics.android.calculus.Report
import net.pokeranalytics.android.calculus.Stat
import net.pokeranalytics.android.ui.activity.components.PokerAnalyticsActivity
import net.pokeranalytics.android.ui.activity.components.ReportActivity
import net.pokeranalytics.android.ui.fragment.report.ProgressReportFragment
@ -24,12 +26,19 @@ class ProgressReportActivity : PokerAnalyticsActivity() {
* Default constructor
*/
fun newInstance(context: Context, stat: Stat, report: Report, displayAggregationChoices: Boolean = true, title: String? = null) {
parameters = StatisticsDetailsParameters(stat, report, title)
this.parameters = StatisticsDetailsParameters(stat, report, title)
this.displayAggregationChoices = displayAggregationChoices
val intent = Intent(context, ProgressReportActivity::class.java)
context.startActivity(intent)
}
fun newInstanceForResult(fragment: Fragment, stat: Stat, report: Report, displayAggregationChoices: Boolean = true, title: String? = null) {
this.parameters = StatisticsDetailsParameters(stat, report, title)
this.displayAggregationChoices = displayAggregationChoices
val intent = Intent(fragment.context, ProgressReportActivity::class.java)
fragment.startActivityForResult(intent, ReportActivity.DEFAULT_REQUEST_CODE)
}
}
override fun onCreate(savedInstanceState: Bundle?) {

@ -1,32 +1,38 @@
package net.pokeranalytics.android.ui.activity
import android.content.Context
import android.content.Intent
import android.os.Bundle
import net.pokeranalytics.android.R
import net.pokeranalytics.android.calculus.Report
import net.pokeranalytics.android.ui.activity.components.PokerAnalyticsActivity
import net.pokeranalytics.android.ui.activity.components.ReportActivity
import net.pokeranalytics.android.ui.fragment.report.TableReportFragment
class TableReportActivity : PokerAnalyticsActivity() {
companion object {
// Unparcel fails when setting a custom Parcelable object on Entry so we use a static reference to passe objects
private var report: Report? = null
private var reportTitle: String = ""
/**
* Default constructor
*/
fun newInstance(context: Context, report: Report, reportTitle: String) {
this.report = report
this.reportTitle = reportTitle
val intent = Intent(context, TableReportActivity::class.java)
context.startActivity(intent)
}
}
class TableReportActivity : ReportActivity() {
// companion object {
// const val DEFAULT_REQUEST_CODE = 1000
//
// // Unparcel fails when setting a custom Parcelable object on Entry so we use a static reference to passe objects
// private var report: Report? = null
// private var reportTitle: String = ""
//
// /**
// * Default constructor
// */
// fun newInstance(context: Context, report: Report, reportTitle: String) {
// this.report = report
// this.reportTitle = reportTitle
// val intent = Intent(context, TableReportActivity::class.java)
// context.startActivity(intent)
// }
//
// fun newInstanceForResult(fragment: Fragment, report: Report, reportTitle: String) {
// this.report = report
// this.reportTitle = reportTitle
//
// val intent = Intent(fragment.requireContext(), TableReportActivity::class.java)
// fragment.startActivityForResult(intent, DEFAULT_REQUEST_CODE)
// }
//
// }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

@ -0,0 +1,38 @@
package net.pokeranalytics.android.ui.activity.components
import android.content.Context
import android.content.Intent
import androidx.fragment.app.Fragment
import net.pokeranalytics.android.calculus.Report
abstract class ReportActivity : PokerAnalyticsActivity() {
companion object {
const val DEFAULT_REQUEST_CODE = 999
// Unparcel fails when setting a custom Parcelable object on Entry so we use a static reference to passe objects
var report: Report? = null
var reportTitle: String = ""
/**
* Default constructor
*/
fun newInstance(context: Context, report: Report, reportTitle: String) {
this.report = report
this.reportTitle = reportTitle
val intent = Intent(context, this::class.java)
context.startActivity(intent)
}
fun newInstanceForResult(fragment: Fragment, clazz: Class<*>, report: Report, reportTitle: String) {
this.report = report
this.reportTitle = reportTitle
val intent = Intent(fragment.requireContext(), clazz)
fragment.startActivityForResult(intent, DEFAULT_REQUEST_CODE)
}
}
}

@ -85,13 +85,14 @@ class BankrollFragment : DeletableItemFragment(), StaticRowRepresentableDataSour
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == REQUEST_CODE_DETAILS && resultCode == Activity.RESULT_OK) {
val needToDeleteItem = data?.getBooleanExtra(DataListActivity.IntentKey.ITEM_DELETED.keyName, false) ?: false
if (needToDeleteItem) {
val itemToDeleteId = data?.getStringExtra(DataListActivity.IntentKey.ITEM_DELETED.keyName)
itemToDeleteId?.let { id ->
GlobalScope.launch(Dispatchers.Main) {
delay(300)
deleteItem(bankrollAdapter, LiveData.BANKROLL.items(getRealm()), lastItemClickedId)
deleteItem(bankrollAdapter, LiveData.BANKROLL.items(getRealm()), id)
}
}
} else if (requestCode == REQUEST_CODE_CREATE && resultCode == Activity.RESULT_OK) {
//TODO: Refresh bankrolls
initData()

@ -108,14 +108,15 @@ class DataListFragment : DeletableItemFragment(), LiveRowRepresentableDataSource
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == REQUEST_CODE_DETAILS && resultCode == Activity.RESULT_OK) {
val needToDeleteItem =
data?.getBooleanExtra(DataListActivity.IntentKey.ITEM_DELETED.keyName, false) ?: false
if (needToDeleteItem) {
val itemToDeleteId = data?.getStringExtra(DataListActivity.IntentKey.ITEM_DELETED.keyName)
itemToDeleteId?.let { id ->
GlobalScope.launch(Dispatchers.Main) {
delay(300)
deleteItem(dataListAdapter, items, lastItemClickedId)
deleteItem(dataListAdapter, LiveData.BANKROLL.items(getRealm()), id)
}
}
}
}

@ -13,21 +13,21 @@ import io.realm.RealmResults
import kotlinx.android.synthetic.main.fragment_data_list.*
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import net.pokeranalytics.android.R
import net.pokeranalytics.android.calculus.Calculator
import net.pokeranalytics.android.calculus.Stat
import net.pokeranalytics.android.model.Criteria
import net.pokeranalytics.android.model.LiveData
import net.pokeranalytics.android.model.combined
import net.pokeranalytics.android.model.realm.ReportSetup
import net.pokeranalytics.android.ui.activity.ComparisonReportActivity
import net.pokeranalytics.android.ui.activity.ProgressReportActivity
import net.pokeranalytics.android.ui.activity.ReportCreationActivity
import net.pokeranalytics.android.ui.activity.TableReportActivity
import net.pokeranalytics.android.ui.activity.*
import net.pokeranalytics.android.ui.activity.components.ReportActivity
import net.pokeranalytics.android.ui.adapter.RowRepresentableAdapter
import net.pokeranalytics.android.ui.adapter.RowRepresentableDelegate
import net.pokeranalytics.android.ui.adapter.StaticRowRepresentableDataSource
import net.pokeranalytics.android.ui.fragment.components.RealmFragment
import net.pokeranalytics.android.ui.fragment.components.DeletableItemFragment
import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.RowViewType
import net.pokeranalytics.android.ui.view.rowrepresentable.CustomizableRowRepresentable
@ -35,7 +35,7 @@ import net.pokeranalytics.android.ui.view.rowrepresentable.ReportRow
import timber.log.Timber
import java.util.*
class ReportsFragment : RealmFragment(), StaticRowRepresentableDataSource, RowRepresentableDelegate {
class ReportsFragment : DeletableItemFragment(), StaticRowRepresentableDataSource, RowRepresentableDelegate {
private lateinit var reportsAdapter: RowRepresentableAdapter
private lateinit var reportSetups: RealmResults<ReportSetup>
@ -77,9 +77,17 @@ class ReportsFragment : RealmFragment(), StaticRowRepresentableDataSource, RowRe
this.launchReportWithOptions(options, options.getName(requireContext()))
}
ReportCreationActivity.options = null
} else if (requestCode == ReportActivity.DEFAULT_REQUEST_CODE && resultCode == Activity.RESULT_OK) {
val itemToDeleteId = data?.getStringExtra(DataListActivity.IntentKey.ITEM_DELETED.keyName)
itemToDeleteId?.let { id ->
GlobalScope.launch(Dispatchers.Main) {
delay(300)
deleteItem(reportsAdapter, LiveData.REPORT_SETUP.items(getRealm()), id)
}
}
}
}
// Business
@ -188,13 +196,16 @@ class ReportsFragment : RealmFragment(), StaticRowRepresentableDataSource, RowRe
when (options.display) {
Calculator.Options.Display.TABLE -> {
TableReportActivity.newInstance(requireContext(), report, reportName)
ReportActivity.newInstanceForResult(this@ReportsFragment, TableReportActivity::class.java, report, reportName)
// TableReportActivity.newInstanceForResult(this@ReportsFragment, report, reportName)
// TableReportActivity.newInstance(requireContext(), report, reportName)
}
Calculator.Options.Display.PROGRESS -> {
ProgressReportActivity.newInstance(requireContext(), options.stats.first(), report)
ProgressReportActivity.newInstanceForResult(this@ReportsFragment, options.stats.first(), report)
}
Calculator.Options.Display.COMPARISON -> {
ComparisonReportActivity.newInstance(requireContext(), report, reportName)
// ComparisonReportActivity.newInstance(requireContext(), report, reportName)
ReportActivity.newInstanceForResult(this@ReportsFragment, ComparisonReportActivity::class.java, report, reportName)
}
else -> {
Timber.d("Report type not handled at the moment")

@ -2,8 +2,8 @@ package net.pokeranalytics.android.ui.fragment.components
import android.os.Bundle
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.app.AlertDialog
import androidx.coordinatorlayout.widget.CoordinatorLayout
import com.google.android.material.snackbar.Snackbar
import io.realm.RealmObject
import net.pokeranalytics.android.R
@ -20,12 +20,12 @@ 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 mainLayout: ViewGroup? = null
private var snackBar: Snackbar? = null
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
this.coordinatorLayout = view.findViewById(R.id.coordinatorLayout)
this.mainLayout = view.findViewById(R.id.mainLayout)
}
override fun onPause() {
@ -82,7 +82,7 @@ open class DeletableItemFragment : RealmFragment() {
*/
private fun showUndoSnackBar() {
val message = String.format(getString(R.string.data_deleted))
this.coordinatorLayout?.let { view ->
this.mainLayout?.let { view ->
snackBar = Snackbar.make(view, message, Snackbar.LENGTH_INDEFINITE)
snackBar?.setAction(R.string.cancel) {
getRealm().executeTransaction { realm ->
@ -93,6 +93,8 @@ open class DeletableItemFragment : RealmFragment() {
}
}
snackBar?.show()
} ?: run {
throw IllegalStateException("mainLayout is not defined")
}
}

@ -157,11 +157,11 @@ class BankrollDataFragment : EditableDataFragment(), StaticRowRepresentableDataS
/**
* Init data
*/
private fun initData() {
override fun initData() {
defaultCurrency = UserDefaults.currency
if (!isUpdating) {
if (!deleteButtonShouldAppear) {
bankroll.currency = net.pokeranalytics.android.model.realm.Currency()
bankroll.currency?.code = defaultCurrency.currencyCode
bankroll.currency?.rate = 1.0

@ -0,0 +1,154 @@
package net.pokeranalytics.android.ui.fragment.data
import android.app.Activity
import android.content.Intent
import android.os.Bundle
import android.view.Menu
import android.view.MenuInflater
import android.view.MenuItem
import android.view.View
import androidx.appcompat.app.AlertDialog
import io.realm.RealmObject
import net.pokeranalytics.android.R
import net.pokeranalytics.android.exceptions.ConfigurationException
import net.pokeranalytics.android.model.LiveData
import net.pokeranalytics.android.model.interfaces.Deletable
import net.pokeranalytics.android.model.interfaces.Savable
import net.pokeranalytics.android.model.interfaces.SaveValidityStatus
import net.pokeranalytics.android.ui.activity.DataListActivity
import net.pokeranalytics.android.ui.activity.EditableDataActivity
import net.pokeranalytics.android.ui.fragment.components.RealmFragment
open class DataManagerFragment : RealmFragment() {
lateinit var item: RealmObject
lateinit var liveDataType: LiveData
protected var primaryKey: String? = null
var deleteButtonShouldAppear = false
set(value) {
field = value
this.updateMenuUI()
}
var saveButtonShouldAppear = true
set(value) {
field = value
this.updateMenuUI()
}
protected var dataType: Int? = null
private var editableMenu: Menu? = null
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
initData()
}
override fun onCreateOptionsMenu(menu: Menu?, inflater: MenuInflater?) {
menu?.clear()
inflater?.inflate(R.menu.toolbar_editable_data, menu)
this.editableMenu = menu
updateMenuUI()
super.onCreateOptionsMenu(menu, inflater)
}
/**
* Update menu UI
*/
private fun updateMenuUI() {
editableMenu?.findItem(R.id.delete)?.isVisible = this.deleteButtonShouldAppear
editableMenu?.findItem(R.id.save)?.isVisible = this.saveButtonShouldAppear
}
override fun onOptionsItemSelected(item: MenuItem?): Boolean {
when (item!!.itemId) {
R.id.save -> saveData()
R.id.delete -> deleteData()
}
return true
}
/**
* Init data
*/
protected open fun initData() {
this.item = this.liveDataType.updateOrCreate(this.getRealm(), primaryKey)
}
/**
* Save data
*/
protected open fun saveData() {
val savable = this.item
when (savable) {
is Savable -> {
val status = savable.getSaveValidityStatus(realm = this.getRealm())
when (status) {
SaveValidityStatus.VALID -> {
this.getRealm().executeTransaction {
val managedItem = it.copyToRealmOrUpdate(this.item)
if (managedItem is Savable) {
val uniqueIdentifier = (managedItem as Savable).id
finishActivityWithResult(uniqueIdentifier)
}
}
}
else -> {
val message = savable.getFailedSaveMessage(status)
val builder = AlertDialog.Builder(requireContext())
.setMessage(message)
.setNegativeButton(R.string.ok, null)
builder.show()
}
}
} else -> {
throw ConfigurationException("Save action called on un-Savable object")
}
}
}
/**
* Delete data
*/
protected open fun deleteData() {
val deletable = this.item as Deletable
val realm = this.getRealm()
if (deletable.isValidForDelete(realm)) {
val intent = Intent()
intent.putExtra(DataListActivity.IntentKey.ITEM_DELETED.keyName, deletable.id)
activity?.setResult(Activity.RESULT_OK, intent)
activity?.finish()
} else {
val status = deletable.getDeleteStatus(realm)
val message = deletable.getFailedDeleteMessage(status)
val builder = AlertDialog.Builder(requireContext())
.setMessage(message)
.setNegativeButton(R.string.ok, null)
builder.show()
}
}
/**
* Finish the activity with a result
*/
private fun finishActivityWithResult(uniqueIdentifier: String) {
val intent = Intent()
intent.putExtra(EditableDataActivity.IntentKey.DATA_TYPE.keyName, dataType)
intent.putExtra(EditableDataActivity.IntentKey.PRIMARY_KEY.keyName, uniqueIdentifier)
activity?.setResult(Activity.RESULT_OK, intent)
activity?.finish()
}
}

@ -1,44 +1,29 @@
package net.pokeranalytics.android.ui.fragment.data
import android.app.Activity.RESULT_OK
import android.content.Intent
import android.os.Bundle
import android.view.*
import androidx.appcompat.app.AlertDialog
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.LinearLayoutManager
import io.realm.RealmObject
import kotlinx.android.synthetic.main.fragment_editable_data.*
import kotlinx.android.synthetic.main.fragment_editable_data.view.*
import net.pokeranalytics.android.R
import net.pokeranalytics.android.exceptions.ConfigurationException
import net.pokeranalytics.android.model.LiveData
import net.pokeranalytics.android.model.interfaces.Deletable
import net.pokeranalytics.android.model.interfaces.Editable
import net.pokeranalytics.android.model.interfaces.Savable
import net.pokeranalytics.android.model.interfaces.SaveValidityStatus
import net.pokeranalytics.android.ui.activity.DataListActivity
import net.pokeranalytics.android.ui.activity.EditableDataActivity
import net.pokeranalytics.android.ui.activity.components.PokerAnalyticsActivity
import net.pokeranalytics.android.ui.adapter.RowRepresentableAdapter
import net.pokeranalytics.android.ui.adapter.RowRepresentableDataSource
import net.pokeranalytics.android.ui.adapter.RowRepresentableDelegate
import net.pokeranalytics.android.ui.fragment.components.RealmFragment
import net.pokeranalytics.android.ui.fragment.components.bottomsheet.BottomSheetFragment
import net.pokeranalytics.android.ui.view.RowRepresentable
open class EditableDataFragment : RealmFragment(), RowRepresentableDelegate {
open class EditableDataFragment : DataManagerFragment(), RowRepresentableDelegate {
lateinit var parentActivity: PokerAnalyticsActivity
lateinit var item: RealmObject
lateinit var liveDataType: LiveData
lateinit var rowRepresentableAdapter: RowRepresentableAdapter
private var editableMenu: Menu? = null
private var dataType: Int? = null
private var primaryKey: String? = null
var isUpdating = false
var shouldOpenKeyboard = true
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
@ -49,24 +34,15 @@ open class EditableDataFragment : RealmFragment(), RowRepresentableDelegate {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
initUI()
initData()
}
override fun onCreateOptionsMenu(menu: Menu?, inflater: MenuInflater?) {
menu?.clear()
inflater?.inflate(R.menu.toolbar_editable_data, menu)
this.editableMenu = menu
updateMenuUI()
super.onCreateOptionsMenu(menu, inflater)
}
override fun onOptionsItemSelected(item: MenuItem?): Boolean {
when (item!!.itemId) {
R.id.save -> saveData()
R.id.delete -> deleteData()
}
return true
/**
* Set fragment data
*/
fun setData(dataType: Int, primaryKey: String?) {
this.dataType = dataType
this.liveDataType = LiveData.values()[dataType]
this.primaryKey = primaryKey
}
override fun onRowSelected(position: Int, row: RowRepresentable, fromAction: Boolean) {
@ -90,6 +66,16 @@ open class EditableDataFragment : RealmFragment(), RowRepresentableDelegate {
parentActivity.supportActionBar?.setDisplayHomeAsUpEnabled(true)
setHasOptionsMenu(true)
val proxyItem: RealmObject? = this.liveDataType.getData(this.getRealm(), primaryKey)
proxyItem?.let {
//TODO: Localize
this.appBar.toolbar.title = "Update ${this.liveDataType.localizedTitle(requireContext()).toLowerCase().capitalize()}"
deleteButtonShouldAppear = true
} ?: run {
//TODO: Localize
this.appBar.toolbar.title = this.liveDataType.newEntityLocalizedTitle(requireContext())
}
val viewManager = LinearLayoutManager(requireContext())
recyclerView.apply {
@ -105,121 +91,21 @@ open class EditableDataFragment : RealmFragment(), RowRepresentableDelegate {
return this.item as RowRepresentableDataSource
}
/**
* Init data
*/
private fun initData() {
if (this.dataType != null) {
val proxyItem: RealmObject? = this.liveDataType.getData(this.getRealm(), primaryKey)
proxyItem?.let {
//TODO: Localize
this.appBar.toolbar.title = "Update ${this.liveDataType.localizedTitle(this.parentActivity).toLowerCase().capitalize()}"
isUpdating = true
} ?: run {
//TODO: Localize
this.appBar.toolbar.title = this.liveDataType.newEntityLocalizedTitle(requireContext())
}
this.item = this.liveDataType.updateOrCreate(this.getRealm(), primaryKey)
override fun initData() {
super.initData()
val dataSource = getDataSource()
this.rowRepresentableAdapter = RowRepresentableAdapter(getDataSource(), this)
this.recyclerView.adapter = rowRepresentableAdapter
// When creating an object, open automatically the keyboard for the first row
if (!isUpdating && shouldOpenKeyboard) {
if (!deleteButtonShouldAppear && shouldOpenKeyboard) {
val row = dataSource.adapterRows()?.firstOrNull()
row?.let {
onRowSelected(0, it)
}
}
}
}
/**
* Update menu UI
*/
private fun updateMenuUI() {
editableMenu?.findItem(R.id.delete)?.isVisible = isUpdating
editableMenu?.findItem(R.id.save)?.isVisible = true
}
/**
* Save data
*/
fun saveData() {
val savable = this.item
when (savable) {
is Savable -> {
val status = savable.getSaveValidityStatus(realm = this.getRealm())
when (status) {
SaveValidityStatus.VALID -> {
this.getRealm().executeTransaction {
val managedItem = it.copyToRealmOrUpdate(this.item)
if (managedItem is Savable) {
val uniqueIdentifier = (managedItem as Savable).id
finishActivityWithResult(uniqueIdentifier)
}
}
}
else -> {
val message = savable.getFailedSaveMessage(status)
val builder = AlertDialog.Builder(requireContext())
.setMessage(message)
.setNegativeButton(R.string.ok, null)
builder.show()
}
}
} else -> {
throw ConfigurationException("Save action called on un-Savable object")
}
}
}
/**
* Delete data
*/
private fun deleteData() {
val deletable = this.item as Deletable
val realm = this.getRealm()
if (deletable.isValidForDelete(realm)) {
val intent = Intent()
intent.putExtra(DataListActivity.IntentKey.ITEM_DELETED.keyName, true)
activity?.setResult(RESULT_OK, intent)
activity?.finish()
} else {
val status = deletable.getDeleteStatus(realm)
val message = deletable.getFailedDeleteMessage(status)
val builder = AlertDialog.Builder(requireContext())
.setMessage(message)
.setNegativeButton(R.string.ok, null)
builder.show()
}
}
/**
* Finish the activity with a result
*/
private fun finishActivityWithResult(uniqueIdentifier: String) {
val intent = Intent()
intent.putExtra(EditableDataActivity.IntentKey.DATA_TYPE.keyName, dataType)
intent.putExtra(EditableDataActivity.IntentKey.PRIMARY_KEY.keyName, uniqueIdentifier)
activity?.setResult(RESULT_OK, intent)
activity?.finish()
}
/**
* Set fragment data
*/
fun setData(dataType: Int, primaryKey: String?) {
this.dataType = dataType
this.liveDataType = LiveData.values()[dataType]
this.primaryKey = primaryKey
}
}

@ -40,7 +40,7 @@ class LocationDataFragment : EditableDataFragment(), StaticRowRepresentableDataS
shouldOpenKeyboard = false
locationActivated = parentActivity.hasLocationPermissionGranted()
if (isUpdating) {
if (deleteButtonShouldAppear) {
// If we update a location, we set the switch to the correct value
locationActivated = location.latitude != null && location.longitude != null

@ -1,37 +1,41 @@
package net.pokeranalytics.android.ui.fragment.report
import android.os.Bundle
import android.view.Menu
import android.view.MenuInflater
import android.view.MenuItem
import android.view.View
import android.widget.EditText
import androidx.appcompat.app.AlertDialog
import kotlinx.android.synthetic.main.fragment_progress_report.*
import net.pokeranalytics.android.R
import net.pokeranalytics.android.calculus.Report
import net.pokeranalytics.android.model.LiveData
import net.pokeranalytics.android.model.realm.ReportSetup
import net.pokeranalytics.android.ui.activity.components.PokerAnalyticsActivity
import net.pokeranalytics.android.ui.fragment.components.RealmFragment
import net.pokeranalytics.android.ui.fragment.data.DataManagerFragment
abstract class AbstractReportFragment : RealmFragment() {
abstract class AbstractReportFragment : DataManagerFragment() {
protected lateinit var selectedReport: Report
private lateinit var _selectedReport: Report
val selectedReport: Report
get() {
return this._selectedReport
}
fun setReport(report: Report) {
this._selectedReport = report
this.primaryKey = report.options.reportSetupId
}
protected var reportTitle: String? = null
private var editableMenu: Menu? = null
protected lateinit var parentActivity: PokerAnalyticsActivity
override fun onCreateOptionsMenu(menu: Menu?, inflater: MenuInflater?) {
menu?.clear()
inflater?.inflate(R.menu.toolbar_report, menu)
this.editableMenu = menu
updateMenuUI()
super.onCreateOptionsMenu(menu, inflater)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
override fun onOptionsItemSelected(item: MenuItem?): Boolean {
when (item!!.itemId) {
R.id.save -> this.saveReportRequest()
}
return true
this.liveDataType = LiveData.REPORT_SETUP
this.saveButtonShouldAppear = this._selectedReport.options.userGenerated
this.deleteButtonShouldAppear = (this.primaryKey != null)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
@ -39,25 +43,57 @@ abstract class AbstractReportFragment : RealmFragment() {
parentActivity = activity as PokerAnalyticsActivity
}
/**
* Update menu UI
*/
private fun updateMenuUI() {
editableMenu?.findItem(R.id.save)?.let {
it.isVisible = this.selectedReport.options.userGenerated
it.icon.setTint(requireContext().getColor(R.color.white))
override fun saveData() {
activity?.let {
val builder = AlertDialog.Builder(it)
// Get the layout inflater
val inflater = requireActivity().layoutInflater;
// Inflate and set the layout for the dialog
// Pass null as the parent view because its going in the dialog layout
val view = inflater.inflate(R.layout.dialog_edit_text, null)
val nameEditText = view.findViewById<EditText>(R.id.reportName)
builder.setView(view)
// Add action buttons
.setPositiveButton(R.string.save) { dialog, id ->
saveReport(nameEditText.text.toString())
dialog.dismiss()
}
.setNegativeButton(R.string.cancel) { dialog, id ->
dialog.cancel()
}
private fun saveReportRequest() {
val dialog = builder.create()
dialog.show()
} ?: throw IllegalStateException("Activity cannot be null")
}
private fun saveReport(name: String) {
getRealm().executeTransaction {
val report = this.selectedReport.options.reportSetup(name)
it.insert(report)
getRealm().executeTransaction { realm ->
val rs = this.item as ReportSetup
val options = this._selectedReport.options
rs.name = name
rs.display = options.display.ordinal
options.stats.forEach {
rs.statIds.add(it.uniqueIdentifier)
}
options.criterias.forEach {
rs.criteriaIds.add(it.uniqueIdentifier)
}
rs.filter = options.filter
this.item = rs
this.deleteButtonShouldAppear = true
toolbar.title = name
realm.copyToRealmOrUpdate(rs)
}
}
}

@ -18,7 +18,7 @@ class ComparisonReportFragment : AbstractReportFragment() {
val fragment = ComparisonReportFragment()
fragment.reportTitle = reportTitle
report?.let {
fragment.selectedReport = it
fragment.setReport(it)
}
val bundle = Bundle()
fragment.arguments = bundle
@ -27,15 +27,11 @@ class ComparisonReportFragment : AbstractReportFragment() {
}
}
// private var reports: MutableMap<AggregationType, Report> = hashMapOf()
// private var stat: Stat = Stat.NET_RESULT
// private var displayAggregationChoices: Boolean = true
/**
* Set data
*/
fun setData(report: Report) {
this.selectedReport = report
this.setReport(report)
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {

@ -66,7 +66,7 @@ class ProgressReportFragment : AbstractReportFragment() {
*/
fun setData(stat: Stat, report: Report, displayAggregationChoices: Boolean, title: String? = null) {
this.stat = stat
this.selectedReport = report
this.setReport(report)
this.displayAggregationChoices = displayAggregationChoices
this.reportTitle = title

@ -14,14 +14,11 @@ class TableReportFragment : AbstractReportFragment() {
companion object {
/**
* Create new instance
*/
fun newInstance(report: Report? = null, title: String? = null): TableReportFragment {
val fragment = TableReportFragment()
fragment.reportTitle = title
report?.let {
fragment.selectedReport = it
fragment.setReport(it)
}
val bundle = Bundle()
fragment.arguments = bundle

@ -0,0 +1,21 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="24dp">
<androidx.appcompat.widget.AppCompatTextView
android:text="@string/save_report"
style="@style/PokerAnalyticsTheme.TextView.Title"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<androidx.appcompat.widget.AppCompatEditText
android:id="@+id/reportName"
style="@style/PokerAnalyticsTheme.EditText"
android:layout_width="240dp"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:hint="@string/name" />
</LinearLayout>

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/coordinatorLayout"
android:id="@+id/mainLayout"
android:layout_width="match_parent"
android:layout_height="match_parent">

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

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

@ -30,6 +30,7 @@
<string name="new_report_step_filter">Select a filter or launch report</string>
<string name="launch_report">Launch Report</string>
<string name="progress">Progress</string>
<string name="save_report">Save Report</string>
<string name="address">Address</string>
<string name="suggestions">Naming suggestions</string>

@ -10,7 +10,7 @@ buildscript {
}
}
dependencies {
classpath 'com.android.tools.build:gradle:3.4.0'
classpath 'com.android.tools.build:gradle:3.4.1'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath 'io.realm:realm-gradle-plugin:5.8.0'
classpath 'com.google.gms:google-services:4.2.0'

Loading…
Cancel
Save