# 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 |
||||
|
||||
import android.view.Menu |
||||
import android.view.MenuInflater |
||||
import android.view.MenuItem |
||||
import android.os.Bundle |
||||
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.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 |
||||
|
||||
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) |
||||
} |
||||
|
||||
/** |
||||
* 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 onViewCreated(view: View, savedInstanceState: Bundle?) { |
||||
super.onViewCreated(view, savedInstanceState) |
||||
|
||||
parentActivity = activity as PokerAnalyticsActivity |
||||
|
||||
// Avoid a bug during setting the titleResId |
||||
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) { |
||||
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) |
||||
} |
||||
|
||||
} |
||||
|
||||
} |
||||
@ -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