# Conflicts: # app/src/main/java/net/pokeranalytics/android/ui/fragment/BankrollFragment.kt # app/src/main/java/net/pokeranalytics/android/ui/fragment/DataListFragment.kt # app/src/main/java/net/pokeranalytics/android/ui/fragment/data/EditableDataFragment.kt # app/src/main/java/net/pokeranalytics/android/ui/fragment/report/AbstractReportFragment.kt # app/src/main/java/net/pokeranalytics/android/ui/fragment/report/ComparisonReportFragment.kt # app/src/main/java/net/pokeranalytics/android/ui/fragment/report/ProgressReportFragment.kt # app/src/main/java/net/pokeranalytics/android/ui/fragment/report/TableReportFragment.kt # app/src/main/res/layout/fragment_reports.xmldev
commit
885671be31
@ -0,0 +1,39 @@ |
|||||||
|
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 |
||||||
|
import net.pokeranalytics.android.calculus.Stat |
||||||
|
|
||||||
|
class ReportParameters(var report: Report, var title: String, var stat: Stat? = null, var showAggregationChoices: Boolean = true) |
||||||
|
|
||||||
|
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 parameters: ReportParameters? = null |
||||||
|
|
||||||
|
/** |
||||||
|
* Default constructor |
||||||
|
*/ |
||||||
|
fun newInstance(context: Context, report: Report, reportTitle: String, stat: Stat? = null) { |
||||||
|
val options = report.options |
||||||
|
this.parameters = ReportParameters(report, reportTitle, stat) |
||||||
|
val intent = Intent(context, options.display.activityClass) |
||||||
|
context.startActivity(intent) |
||||||
|
} |
||||||
|
|
||||||
|
fun newInstanceForResult(fragment: Fragment, report: Report, reportTitle: String, stat: Stat? = null) { |
||||||
|
val options = report.options |
||||||
|
this.parameters = ReportParameters(report, reportTitle, stat) |
||||||
|
val intent = Intent(fragment.requireContext(), options.display.activityClass) |
||||||
|
fragment.startActivityForResult(intent, DEFAULT_REQUEST_CODE) |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
@ -0,0 +1,158 @@ |
|||||||
|
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.RealmModel |
||||||
|
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: RealmModel |
||||||
|
|
||||||
|
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.deleteButtonShouldAppear = this.primaryKey != null |
||||||
|
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) |
||||||
|
} |
||||||
|
} |
||||||
|
onDataSaved() |
||||||
|
} |
||||||
|
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() |
||||||
|
} |
||||||
|
|
||||||
|
open fun onDataSaved() {} |
||||||
|
|
||||||
|
|
||||||
|
} |
||||||
@ -1,53 +1,110 @@ |
|||||||
package net.pokeranalytics.android.ui.fragment.report |
package net.pokeranalytics.android.ui.fragment.report |
||||||
|
|
||||||
import android.view.Menu |
import android.os.Bundle |
||||||
import android.view.MenuInflater |
import android.view.View |
||||||
import android.view.MenuItem |
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.R |
||||||
import net.pokeranalytics.android.calculus.Report |
import net.pokeranalytics.android.calculus.Report |
||||||
import net.pokeranalytics.android.ui.fragment.components.RealmFragment |
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.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 |
protected var reportTitle: String? = null |
||||||
|
|
||||||
private var editableMenu: Menu? = null |
protected lateinit var parentActivity: PokerAnalyticsActivity |
||||||
|
|
||||||
override fun onCreateOptionsMenu(menu: Menu?, inflater: MenuInflater?) { |
override fun onCreate(savedInstanceState: Bundle?) { |
||||||
menu?.clear() |
super.onCreate(savedInstanceState) |
||||||
inflater?.inflate(R.menu.toolbar_report, menu) |
|
||||||
this.editableMenu = menu |
|
||||||
updateMenuUI() |
|
||||||
super.onCreateOptionsMenu(menu, inflater) |
|
||||||
} |
|
||||||
|
|
||||||
override fun onOptionsItemSelected(item: MenuItem?): Boolean { |
this.liveDataType = LiveData.REPORT_SETUP |
||||||
when (item!!.itemId) { |
this.saveButtonShouldAppear = this._selectedReport.options.userGenerated |
||||||
R.id.save -> this.saveReportRequest() |
this.deleteButtonShouldAppear = (this.primaryKey != null) |
||||||
} |
|
||||||
return true |
|
||||||
} |
} |
||||||
|
|
||||||
/** |
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { |
||||||
* Update menu UI |
super.onViewCreated(view, savedInstanceState) |
||||||
*/ |
|
||||||
private fun updateMenuUI() { |
parentActivity = activity as PokerAnalyticsActivity |
||||||
editableMenu?.findItem(R.id.save)?.let { |
|
||||||
it.isVisible = this.selectedReport.options.userGenerated |
// Avoid a bug during setting the titleResId |
||||||
it.icon.setTint(requireContext().getColor(R.color.white)) |
toolbar.title = "" |
||||||
} |
|
||||||
|
parentActivity.setSupportActionBar(toolbar) |
||||||
|
parentActivity.supportActionBar?.setDisplayHomeAsUpEnabled(true) |
||||||
|
setHasOptionsMenu(true) |
||||||
|
|
||||||
|
toolbar.title = reportTitle |
||||||
|
|
||||||
} |
} |
||||||
|
|
||||||
private fun saveReportRequest() { |
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() |
||||||
|
} |
||||||
|
|
||||||
|
val dialog = builder.create() |
||||||
|
dialog.show() |
||||||
|
|
||||||
|
} ?: throw IllegalStateException("Activity cannot be null") |
||||||
|
|
||||||
} |
} |
||||||
|
|
||||||
private fun saveReport(name: String) { |
private fun saveReport(name: String) { |
||||||
getRealm().executeTransaction { |
getRealm().executeTransaction { realm -> |
||||||
val report = this.selectedReport.options.reportSetup(name) |
|
||||||
it.insert(report) |
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) |
||||||
} |
} |
||||||
|
|
||||||
} |
} |
||||||
|
|
||||||
} |
} |
||||||
@ -0,0 +1,71 @@ |
|||||||
|
package net.pokeranalytics.android.util |
||||||
|
|
||||||
|
import io.realm.Realm |
||||||
|
import io.realm.RealmModel |
||||||
|
import io.realm.RealmResults |
||||||
|
import io.realm.Sort |
||||||
|
import io.realm.kotlin.where |
||||||
|
import net.pokeranalytics.android.model.interfaces.CountableUsage |
||||||
|
import net.pokeranalytics.android.model.realm.Session |
||||||
|
import net.pokeranalytics.android.model.realm.TournamentFeature |
||||||
|
import net.pokeranalytics.android.model.realm.Transaction |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns all entities of the [clazz] sorted with their default sorting |
||||||
|
*/ |
||||||
|
fun <T : RealmModel> Realm.sorted(clazz: Class<T>) : RealmResults<T> { |
||||||
|
|
||||||
|
if (clazz is CountableUsage) { |
||||||
|
this.updateUsageCount(clazz) |
||||||
|
} |
||||||
|
|
||||||
|
val sortField = when (clazz) { |
||||||
|
is CountableUsage -> "useCount" |
||||||
|
is Transaction -> "date" |
||||||
|
else -> "name" |
||||||
|
} |
||||||
|
val resultSort = when (clazz) { |
||||||
|
is CountableUsage -> Sort.DESCENDING |
||||||
|
is Transaction -> Sort.DESCENDING |
||||||
|
else -> Sort.ASCENDING |
||||||
|
} |
||||||
|
|
||||||
|
return this.where(clazz).findAll().sort(sortField, resultSort) |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns all entities of the [clazz] sorted with their default sorting |
||||||
|
*/ |
||||||
|
inline fun <reified C : RealmModel> Realm.sorted() : RealmResults<C> { |
||||||
|
return this.sorted(C::class.java) |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Updates the useCount variable of the CountableUsage entity |
||||||
|
*/ |
||||||
|
fun <T : RealmModel>Realm.updateUsageCount(clazz: Class<T>) { |
||||||
|
|
||||||
|
val results = this.where(clazz).findAll() |
||||||
|
this.executeTransaction { |
||||||
|
results.forEach { countableUsage -> |
||||||
|
|
||||||
|
val countable = (countableUsage as CountableUsage) |
||||||
|
when (clazz) { |
||||||
|
is TournamentFeature -> { |
||||||
|
countable.useCount = it.where<Session>().contains( |
||||||
|
"tournamentFeatures.id", |
||||||
|
countable.id |
||||||
|
).count().toInt() |
||||||
|
} |
||||||
|
else -> { |
||||||
|
countable.useCount = it.where<Session>().equalTo( |
||||||
|
"${clazz.simpleName.decapitalize()}.id", |
||||||
|
countable.id |
||||||
|
).count().toInt() |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
@ -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> |
||||||
Loading…
Reference in new issue