From 4c79b32c1f4ecf0f40858dab28448f2384e434e7 Mon Sep 17 00:00:00 2001 From: Laurent Date: Tue, 11 Jun 2019 18:07:20 +0200 Subject: [PATCH] Fixing bankroll report updates --- .../android/PokerAnalyticsApplication.kt | 2 +- .../pokeranalytics/android/calculus/Stat.kt | 1 + .../calculus/bankroll/BankrollCalculator.kt | 9 +- .../calculus/bankroll/BankrollReport.kt | 93 ++----- .../bankroll/BankrollReportManager.kt | 114 ++++++++ .../android/exceptions/Exceptions.kt | 1 + .../android/ui/activity/BankrollActivity.kt | 41 --- .../android/ui/activity/components/Codes.kt | 2 + .../ui/fragment/BankrollDetailsFragment.kt | 135 +++++++--- .../android/ui/fragment/BankrollFragment.kt | 127 ++++----- .../android/ui/fragment/FeedFragment.kt | 13 +- .../android/ui/fragment/SessionFragment.kt | 4 + .../components/DeletableItemFragment.kt | 4 +- .../ui/fragment/data/DataManagerFragment.kt | 4 + .../fragment/data/TransactionDataFragment.kt | 8 + .../android/ui/view/RowViewType.kt | 251 ++++++++++-------- .../view/rowrepresentable/BankrollMainRow.kt | 12 + .../CustomizableRowRepresentable.kt | 11 + .../ui/view/rowrepresentable/GraphRow.kt | 9 +- 19 files changed, 502 insertions(+), 339 deletions(-) create mode 100644 app/src/main/java/net/pokeranalytics/android/calculus/bankroll/BankrollReportManager.kt create mode 100644 app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/BankrollMainRow.kt diff --git a/app/src/main/java/net/pokeranalytics/android/PokerAnalyticsApplication.kt b/app/src/main/java/net/pokeranalytics/android/PokerAnalyticsApplication.kt index 35ea4536..1b81d955 100644 --- a/app/src/main/java/net/pokeranalytics/android/PokerAnalyticsApplication.kt +++ b/app/src/main/java/net/pokeranalytics/android/PokerAnalyticsApplication.kt @@ -60,7 +60,7 @@ class PokerAnalyticsApplication : Application() { if (BuildConfig.DEBUG) { Timber.d("UserPreferences.defaultCurrency: ${UserDefaults.currency.symbol}") -// this.createFakeSessions() + this.createFakeSessions() } Patcher.patchAll(this.applicationContext) diff --git a/app/src/main/java/net/pokeranalytics/android/calculus/Stat.kt b/app/src/main/java/net/pokeranalytics/android/calculus/Stat.kt index d065af5f..2b8a30c8 100644 --- a/app/src/main/java/net/pokeranalytics/android/calculus/Stat.kt +++ b/app/src/main/java/net/pokeranalytics/android/calculus/Stat.kt @@ -177,6 +177,7 @@ enum class Stat(override var uniqueIdentifier: Int) : IntIdentifiable, RowRepres private val threshold: Double get() { return when (this) { + RISK_OF_RUIN -> 5.0 WIN_RATIO -> 50.0 else -> 0.0 } diff --git a/app/src/main/java/net/pokeranalytics/android/calculus/bankroll/BankrollCalculator.kt b/app/src/main/java/net/pokeranalytics/android/calculus/bankroll/BankrollCalculator.kt index 2f889e24..3f7b144a 100644 --- a/app/src/main/java/net/pokeranalytics/android/calculus/bankroll/BankrollCalculator.kt +++ b/app/src/main/java/net/pokeranalytics/android/calculus/bankroll/BankrollCalculator.kt @@ -5,7 +5,9 @@ import net.pokeranalytics.android.calculus.Calculator import net.pokeranalytics.android.calculus.ComputableGroup import net.pokeranalytics.android.calculus.ComputedResults import net.pokeranalytics.android.calculus.Stat +import net.pokeranalytics.android.exceptions.PAIllegalStateException import net.pokeranalytics.android.model.realm.* +import net.pokeranalytics.android.util.extensions.findById class BankrollCalculator { @@ -18,7 +20,10 @@ class BankrollCalculator { val report = BankrollReport(setup) val bankrolls: List = - if (setup.bankroll != null) listOf(setup.bankroll) + if (setup.bankrollId != null) { + val bankroll = realm.findById(setup.bankrollId) ?: throw PAIllegalStateException("Bankroll not found with id=${setup.bankrollId}") + listOf(bankroll) + } else realm.where(Bankroll::class.java).findAll() var initialValue = 0.0 @@ -41,7 +46,7 @@ class BankrollCalculator { report.transactionsNet = transactionNet report.initial = initialValue - val query = setup.query + val query = setup.query(realm) val transactions = Filter.queryOn(realm, query) report.addDatedItems(transactions) diff --git a/app/src/main/java/net/pokeranalytics/android/calculus/bankroll/BankrollReport.kt b/app/src/main/java/net/pokeranalytics/android/calculus/bankroll/BankrollReport.kt index 2b7e4724..b6c079d6 100644 --- a/app/src/main/java/net/pokeranalytics/android/calculus/bankroll/BankrollReport.kt +++ b/app/src/main/java/net/pokeranalytics/android/calculus/bankroll/BankrollReport.kt @@ -3,54 +3,22 @@ package net.pokeranalytics.android.calculus.bankroll import android.content.Context import com.github.mikephil.charting.data.Entry import com.github.mikephil.charting.data.LineDataSet +import io.realm.Realm import net.pokeranalytics.android.model.filter.Query import net.pokeranalytics.android.model.filter.QueryCondition import net.pokeranalytics.android.model.interfaces.DatedValue import net.pokeranalytics.android.model.realm.Bankroll import net.pokeranalytics.android.model.realm.Transaction import net.pokeranalytics.android.ui.graph.DataSetFactory -import net.pokeranalytics.android.ui.view.RowRepresentable -import net.pokeranalytics.android.ui.view.RowViewType +import net.pokeranalytics.android.util.extensions.findById import java.util.* import kotlin.collections.HashMap -//object BankrollReportManager { -// -// var mainReport: BankrollReport? = null -// var reports: MutableMap = mutableMapOf() -// -// fun udpateBankrolls(bankrolls: List) { -// this.invalidateMainReport() -// bankrolls.forEach { -// this.reports.remove(it.id) -// } -// } -// -// fun deleteBankrolls(bankrolls: List) { -// this.invalidateMainReport() -// bankrolls.forEach { -// this.reports.remove(it.id) -// } -// } -// -// private fun invalidateMainReport() { -// this.mainReport = null -// } -// -// private fun launchReports(bankrolls: List) { -// -// this.mainReport = BankrollCalculator.computeReport() -// -// -// } -// -//} - /** * This class holds the results from the BankrollCalculator computations * It has all the information required for the Bankroll various displays */ -class BankrollReport(var setup: BankrollReportSetup) : RowRepresentable { +class BankrollReport(var setup: BankrollReportSetup) { /** * The value of the bankroll @@ -150,15 +118,6 @@ class BankrollReport(var setup: BankrollReportSetup) : RowRepresentable { */ private var evolutionItems: MutableList = mutableListOf() - override val viewType: Int - get() { - return if (setup.bankroll == null) { - RowViewType.LEGEND_DEFAULT.ordinal - } else { - RowViewType.TITLE_VALUE_ARROW.ordinal - } - } - /** * Adds a list of dated items to the evolution items used to get the bankroll graph */ @@ -176,7 +135,7 @@ class BankrollReport(var setup: BankrollReportSetup) : RowRepresentable { var bucket = this.transactionBuckets[type.id] if (bucket == null) { - val b = TransactionBucket(this.setup.virtualBankroll) + val b = TransactionBucket(type.name, this.setup.virtualBankroll) this.transactionBuckets[type.id] = b bucket = b } @@ -200,7 +159,7 @@ class BankrollReport(var setup: BankrollReportSetup) : RowRepresentable { this.evolutionItems.sortBy { it.date } - var total = 0.0 + var total = this.initial this.evolutionItems.forEach { total += it.amount val point = BRGraphPoint(total, it.date, it) @@ -228,7 +187,7 @@ class BankrollReport(var setup: BankrollReportSetup) : RowRepresentable { * A class describing the parameters required to launch a bankroll report * */ -class BankrollReportSetup(val bankroll: Bankroll? = null, val from: Date? = null, val to: Date? = null) { +class BankrollReportSetup(val bankrollId: String? = null, val from: Date? = null, val to: Date? = null) { /** * Returns whether the setup concerns the virtual bankroll, @@ -236,32 +195,32 @@ class BankrollReportSetup(val bankroll: Bankroll? = null, val from: Date? = null */ val virtualBankroll: Boolean get() { - return this.bankroll == null + return this.bankrollId == null } /** * the query used to get bankroll transactions */ - val query: Query - get() { - val query = Query() + fun query(realm: Realm): Query { + val query = Query() - this.bankroll?.let { - val bankrollCondition = QueryCondition.AnyBankroll(bankroll) - query.add(bankrollCondition) - } - this.from?.let { - val fromCondition = QueryCondition.StartedFromDate() - fromCondition.singleValue = it - query.add(fromCondition) - } - this.to?.let { - val toCondition = QueryCondition.StartedToDate() - toCondition.singleValue = it - query.add(toCondition) - } - return query + this.bankrollId?.let { + val bankroll = realm.findById(it) ?: throw IllegalStateException("Bankroll not found with id $it") + val bankrollCondition = QueryCondition.AnyBankroll(bankroll) + query.add(bankrollCondition) } + this.from?.let { + val fromCondition = QueryCondition.StartedFromDate() + fromCondition.singleValue = it + query.add(fromCondition) + } + this.to?.let { + val toCondition = QueryCondition.StartedToDate() + toCondition.singleValue = it + query.add(toCondition) + } + return query + } /** * Returns whether or not the initial value should be added for the bankroll total @@ -276,7 +235,7 @@ class BankrollReportSetup(val bankroll: Bankroll? = null, val from: Date? = null /** * A TransactionBucket holds a list of _transactions and computes its amount sum */ -class TransactionBucket(useRate: Boolean = false) { +class TransactionBucket(var name: String, useRate: Boolean = false) { /** * Whether the bankroll rate should be used diff --git a/app/src/main/java/net/pokeranalytics/android/calculus/bankroll/BankrollReportManager.kt b/app/src/main/java/net/pokeranalytics/android/calculus/bankroll/BankrollReportManager.kt new file mode 100644 index 00000000..9f68008f --- /dev/null +++ b/app/src/main/java/net/pokeranalytics/android/calculus/bankroll/BankrollReportManager.kt @@ -0,0 +1,114 @@ +package net.pokeranalytics.android.calculus.bankroll + +import io.realm.Realm +import io.realm.RealmResults +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.GlobalScope +import kotlinx.coroutines.async +import kotlinx.coroutines.launch +import net.pokeranalytics.android.model.realm.Bankroll +import net.pokeranalytics.android.model.realm.ComputableResult +import net.pokeranalytics.android.model.realm.Transaction +import timber.log.Timber +import java.util.* +import kotlin.coroutines.CoroutineContext + +object BankrollReportManager { + + val coroutineContext: CoroutineContext + get() = Dispatchers.Main + + private var reports: MutableMap = mutableMapOf() + + private var computableResults: RealmResults + private var bankrolls: RealmResults + private var transactions: RealmResults + + init { + + val realm = Realm.getDefaultInstance() + computableResults = realm.where(ComputableResult::class.java).findAll() + bankrolls = realm.where(Bankroll::class.java).findAll() + transactions = realm.where(Transaction::class.java).findAll() + + initializeListeners() + realm.close() + } + + /** + * Listens to all objects that might have an impact on any bankroll report + */ + private fun initializeListeners() { + + this.computableResults.addChangeListener { t, changeSet -> + val indexes = changeSet.changes.plus(changeSet.insertions).toList() + val bankrolls = indexes.mapNotNull { t[it]?.session?.bankroll }.toSet() + this.updateBankrolls(bankrolls) + } + this.bankrolls.addChangeListener { t, changeSet -> + val indexes = changeSet.changes.plus(changeSet.insertions).toList() + val bankrolls = indexes.mapNotNull { t[it] }.toSet() + this.updateBankrolls(bankrolls) + } + this.transactions.addChangeListener { t, changeSet -> + val indexes = changeSet.changes.plus(changeSet.insertions).toList() + val bankrolls = indexes.mapNotNull { t[it]?.bankroll }.toSet() + this.updateBankrolls(bankrolls) + } + } + + fun reportForBankroll(bankrollId: String?, handler: (BankrollReport) -> Unit) { + + // if the report exists, return it + val existingReport: BankrollReport? = this.reports[bankrollId] + if (existingReport != null) { + handler(existingReport) + return + } + + // otherwise compute it + GlobalScope.launch(coroutineContext) { + + var report: BankrollReport? = null + val scope = GlobalScope.async { + val s = Date() + Timber.d(">>>>> start computing bankroll...") + + val realm = Realm.getDefaultInstance() + + val setup = BankrollReportSetup(bankrollId) + report = BankrollCalculator.computeReport(realm, setup) + + realm.close() + + val e = Date() + val duration = (e.time - s.time) / 1000.0 + Timber.d(">>>>> ended in $duration seconds") + + } + scope.await() + report?.let { handler(it) } + + } + } + + /** + * Notifies the manager of cases not managed by RealmResults listener, such as deletions + */ + fun notifyBankrollReportImpact(bankrollId: String) { + this.reports.remove(bankrollId) + this.reports.remove(null) + } + + private fun updateBankrolls(bankrolls: Set) { + this.invalidateReport(bankrolls) + } + + private fun invalidateReport(bankrolls: Set) { + this.reports.remove(null) + bankrolls.forEach { br -> + this.reports.remove(br.id) + } + } + +} diff --git a/app/src/main/java/net/pokeranalytics/android/exceptions/Exceptions.kt b/app/src/main/java/net/pokeranalytics/android/exceptions/Exceptions.kt index 7716e745..b8358605 100644 --- a/app/src/main/java/net/pokeranalytics/android/exceptions/Exceptions.kt +++ b/app/src/main/java/net/pokeranalytics/android/exceptions/Exceptions.kt @@ -10,6 +10,7 @@ class ConfigurationException(message: String) : Exception(message) class EnumIdentifierNotFoundException(message: String) : Exception(message) class MisconfiguredSavableEnumException(message: String) : Exception(message) +class PAIllegalStateException(message: String) : Exception(message) sealed class PokerAnalyticsException(message: String) : Exception(message) { object FilterElementUnknownName : PokerAnalyticsException(message = "No filterElement name was found to identify the queryCondition") diff --git a/app/src/main/java/net/pokeranalytics/android/ui/activity/BankrollActivity.kt b/app/src/main/java/net/pokeranalytics/android/ui/activity/BankrollActivity.kt index 0f37c4d8..db9237b3 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/activity/BankrollActivity.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/activity/BankrollActivity.kt @@ -37,47 +37,6 @@ class BankrollActivity : PokerAnalyticsActivity() { super.onCreate(savedInstanceState) setContentView(R.layout.activity_bankroll) -// this.computableResults = getRealm().where(ComputableResult::class.java).findAll() // ComputableResult are existing only if sessions are ended -// this.computableResults.addChangeListener { t, changeSet -> -// -// val bankrolls = mutableSetOf() -// val indexes = mutableSetOf() -// indexes.addAll(changeSet.changes.toList()) -// indexes.addAll(changeSet.insertions.toList()) -// indexes.addAll(changeSet.deletions.toList()) -// indexes.forEach { index -> -// t[index]?.session?.bankroll?.let { br -> -// bankrolls.add(br) -// } -// } -// this.computeBankrollReports(bankrolls) -// } -// this.bankrolls = getRealm().where(Bankroll::class.java).findAll() // ComputableResult are existing only if sessions are ended -// this.bankrolls.addChangeListener { _, changeSet -> -// -// -// -// -// -// } -// this.transactions = getRealm().where(Transaction::class.java).findAll() // ComputableResult are existing only if sessions are ended -// this.transactions.addChangeListener { t, changeSet -> -// -// val bankrolls = mutableSetOf() -// val indexes = mutableSetOf() -// indexes.addAll(changeSet.changes.toList()) -// indexes.addAll(changeSet.insertions.toList()) -// indexes.addAll(changeSet.deletions.toList()) -// indexes.forEach { index -> -// if (t.isNotEmpty()) { -// t[index]?.bankroll?.let { br -> -// bankrolls.add(br) -// } -// } -// } -// this.computeBankrollReports(bankrolls) -// } - } fun computeBankrollReports(bankrolls: Collection) { diff --git a/app/src/main/java/net/pokeranalytics/android/ui/activity/components/Codes.kt b/app/src/main/java/net/pokeranalytics/android/ui/activity/components/Codes.kt index ed11d47f..23cb64f8 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/activity/components/Codes.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/activity/components/Codes.kt @@ -2,6 +2,8 @@ package net.pokeranalytics.android.ui.activity.components enum class RequestCode(var value: Int) { DEFAULT(1), + BANKROLL_DETAILS(700), + BANKROLL_CREATE(701), NEW_SESSION(800), NEW_TRANSACTION(801), NEW_REPORT(802), diff --git a/app/src/main/java/net/pokeranalytics/android/ui/fragment/BankrollDetailsFragment.kt b/app/src/main/java/net/pokeranalytics/android/ui/fragment/BankrollDetailsFragment.kt index ab2175f2..923695d5 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/fragment/BankrollDetailsFragment.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/fragment/BankrollDetailsFragment.kt @@ -10,18 +10,22 @@ import net.pokeranalytics.android.R import net.pokeranalytics.android.calculus.ComputedStat import net.pokeranalytics.android.calculus.Stat import net.pokeranalytics.android.calculus.bankroll.BankrollReport +import net.pokeranalytics.android.calculus.bankroll.BankrollReportManager +import net.pokeranalytics.android.exceptions.PAIllegalStateException import net.pokeranalytics.android.model.LiveData +import net.pokeranalytics.android.model.realm.Bankroll import net.pokeranalytics.android.ui.activity.DataListActivity import net.pokeranalytics.android.ui.activity.EditableDataActivity 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.PokerAnalyticsFragment +import net.pokeranalytics.android.ui.fragment.components.RealmFragment import net.pokeranalytics.android.ui.view.RowRepresentable import net.pokeranalytics.android.ui.view.RowViewType import net.pokeranalytics.android.ui.view.rowrepresentable.CustomizableRowRepresentable +import net.pokeranalytics.android.util.extensions.findById -class BankrollDetailsFragment : PokerAnalyticsFragment(), StaticRowRepresentableDataSource, RowRepresentableDelegate { +class BankrollDetailsFragment : RealmFragment(), StaticRowRepresentableDataSource, RowRepresentableDelegate { companion object { @@ -32,27 +36,32 @@ class BankrollDetailsFragment : PokerAnalyticsFragment(), StaticRowRepresentable */ fun newInstance(bankrollReport: BankrollReport): BankrollDetailsFragment { val fragment = BankrollDetailsFragment() - fragment.bankrollReport = bankrollReport + fragment.bankrollId = bankrollReport.setup.bankrollId +// fragment.bankrollReport = bankrollReport return fragment } } + private var bankrollId: String? = null + private lateinit var bankroll: Bankroll + + private var rows: ArrayList = ArrayList() private lateinit var bankrollAdapter: RowRepresentableAdapter - private lateinit var bankrollReport: BankrollReport +// private lateinit var bankrollReport: BankrollReport private var bankrollDetailsMenu: Menu? = null - private var rows: ArrayList = ArrayList() // Life Cycle override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { + super.onCreateView(inflater, container, savedInstanceState) return inflater.inflate(R.layout.fragment_bankroll_details, container, false) } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - initUI() initData() + initUI() } override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { @@ -62,40 +71,35 @@ class BankrollDetailsFragment : PokerAnalyticsFragment(), StaticRowRepresentable activity?.setResult(RESULT_OK, data) activity?.finish() } else { - updateMenuUI() + BankrollReportManager.reportForBankroll(this.bankrollId) { + updateUI(it) + } } } } - override fun adapterRows(): List? { - return rows + private fun updateUI(bankrollReport: BankrollReport) { + this.initRows(bankrollReport) + this.updateMenuUI(bankrollReport) + this.bankrollAdapter.notifyDataSetChanged() } - override fun onRowSelected(position: Int, row: RowRepresentable, fromAction: Boolean) { - - } + /** + * Init data + */ + private fun initData() { - override fun onCreateOptionsMenu(menu: Menu?, inflater: MenuInflater?) { - menu?.clear() - inflater?.inflate(R.menu.toolbar_comparison_chart, menu) - this.bankrollDetailsMenu = menu - updateMenuUI() - super.onCreateOptionsMenu(menu, inflater) - } + this.bankrollId?.let { id -> + this.bankroll = getRealm().findById(id) ?: throw PAIllegalStateException("Bankroll not found, id=$id") + } - override fun onOptionsItemSelected(item: MenuItem?): Boolean { - when (item!!.itemId) { - R.id.settings -> editBankroll() + BankrollReportManager.reportForBankroll(this.bankrollId) { + updateUI(it) } - return true - } - // Business + } - /** - * Init data - */ - private fun initData() { + private fun initRows(bankrollReport: BankrollReport) { rows.clear() @@ -105,23 +109,47 @@ class BankrollDetailsFragment : PokerAnalyticsFragment(), StaticRowRepresentable val netComputedStat = ComputedStat(Stat.NET_RESULT, bankrollReport.netResult) val netBankedComputedStat = ComputedStat(Stat.NET_RESULT, bankrollReport.netBanked) - rows.add(CustomizableRowRepresentable(RowViewType.TITLE_VALUE, resId = R.string.bankroll, computedStat = totalComputedStat)) - rows.add(CustomizableRowRepresentable(RowViewType.TITLE_VALUE, resId = R.string.net_result, computedStat = netComputedStat)) - rows.add(CustomizableRowRepresentable(RowViewType.TITLE_VALUE, resId = R.string.net_banked, computedStat = netBankedComputedStat)) + rows.add( + CustomizableRowRepresentable( + RowViewType.TITLE_VALUE, + resId = R.string.bankroll, + computedStat = totalComputedStat + ) + ) + rows.add( + CustomizableRowRepresentable( + RowViewType.TITLE_VALUE, + resId = R.string.net_result, + computedStat = netComputedStat + ) + ) + rows.add( + CustomizableRowRepresentable( + RowViewType.TITLE_VALUE, + resId = R.string.net_banked, + computedStat = netBankedComputedStat + ) + ) if (bankrollReport.transactionBuckets.isNotEmpty()) { rows.add(CustomizableRowRepresentable(RowViewType.HEADER_TITLE, resId = R.string.operations)) bankrollReport.transactionBuckets.keys.forEach { key -> bankrollReport.transactionBuckets[key]?.let { transactionBucket -> - val typeName = transactionBucket.transactions.firstOrNull()?.type?.getDisplayName(requireContext()) + val typeName = transactionBucket.name val computedStat = ComputedStat(Stat.NET_RESULT, transactionBucket.total) - rows.add(CustomizableRowRepresentable(RowViewType.TITLE_VALUE, title = typeName, computedStat = computedStat)) + rows.add( + CustomizableRowRepresentable( + RowViewType.TITLE_VALUE, + title = typeName, + computedStat = computedStat + ) + ) } } } - } + /** * Init UI */ @@ -129,8 +157,6 @@ class BankrollDetailsFragment : PokerAnalyticsFragment(), StaticRowRepresentable setDisplayHomeAsUpEnabled(true) - updateMenuUI() - bankrollAdapter = RowRepresentableAdapter(this, this) val viewManager = LinearLayoutManager(requireContext()) @@ -145,23 +171,52 @@ class BankrollDetailsFragment : PokerAnalyticsFragment(), StaticRowRepresentable /** * Update menu UI */ - private fun updateMenuUI() { + private fun updateMenuUI(bankrollReport: BankrollReport) { if (bankrollReport.setup.virtualBankroll) { setToolbarTitle(getString(R.string.total)) bankrollDetailsMenu?.findItem(R.id.settings)?.isVisible = false } else { - setToolbarTitle(bankrollReport.setup.bankroll?.name) + setToolbarTitle(this.bankroll.name) bankrollDetailsMenu?.findItem(R.id.settings)?.isVisible = true } } + // StaticRowRepresentableDataSource + + override fun adapterRows(): List? { + return rows + } + + // RowRepresentableDelegate + + override fun onRowSelected(position: Int, row: RowRepresentable, fromAction: Boolean) { + + } + + override fun onCreateOptionsMenu(menu: Menu?, inflater: MenuInflater?) { + menu?.clear() + inflater?.inflate(R.menu.toolbar_comparison_chart, menu) + this.bankrollDetailsMenu = menu +// updateMenuUI() + super.onCreateOptionsMenu(menu, inflater) + } + + override fun onOptionsItemSelected(item: MenuItem?): Boolean { + when (item!!.itemId) { + R.id.settings -> editBankroll() + } + return true + } + + // Business + /** * Open Bankroll edit activity */ private fun editBankroll() { - EditableDataActivity.newInstanceForResult(this, LiveData.BANKROLL, bankrollReport.setup.bankroll?.id, REQUEST_CODE_EDIT) + EditableDataActivity.newInstanceForResult(this, LiveData.BANKROLL, this.bankrollId, REQUEST_CODE_EDIT) } } \ No newline at end of file diff --git a/app/src/main/java/net/pokeranalytics/android/ui/fragment/BankrollFragment.kt b/app/src/main/java/net/pokeranalytics/android/ui/fragment/BankrollFragment.kt index 58e954a9..0524f996 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/fragment/BankrollFragment.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/fragment/BankrollFragment.kt @@ -16,39 +16,34 @@ import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.delay import kotlinx.coroutines.launch import net.pokeranalytics.android.R -import net.pokeranalytics.android.calculus.ComputedStat -import net.pokeranalytics.android.calculus.Stat -import net.pokeranalytics.android.calculus.bankroll.BankrollCalculator -import net.pokeranalytics.android.calculus.bankroll.BankrollReport -import net.pokeranalytics.android.calculus.bankroll.BankrollReportSetup +import net.pokeranalytics.android.calculus.bankroll.BankrollReportManager 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.ui.activity.BankrollDetailsActivity import net.pokeranalytics.android.ui.activity.DataListActivity import net.pokeranalytics.android.ui.activity.EditableDataActivity import net.pokeranalytics.android.ui.activity.GraphActivity +import net.pokeranalytics.android.ui.activity.components.RequestCode 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.DeletableItemFragment import net.pokeranalytics.android.ui.view.RowRepresentable import net.pokeranalytics.android.ui.view.RowViewType -import net.pokeranalytics.android.ui.view.rowrepresentable.CustomizableRowRepresentable -import net.pokeranalytics.android.ui.view.rowrepresentable.GraphRow +import net.pokeranalytics.android.ui.view.rowrepresentable.* import net.pokeranalytics.android.util.extensions.sorted -import timber.log.Timber import java.util.* import kotlin.collections.ArrayList +interface BankrollRowRepresentable : RowRepresentable { + var bankrollId: String? +} + class BankrollFragment : DeletableItemFragment(), StaticRowRepresentableDataSource, RowRepresentableDelegate { companion object { - const val REQUEST_CODE_DETAILS = 100 - const val REQUEST_CODE_CREATE = 101 - /** * Create new instance */ @@ -61,14 +56,14 @@ class BankrollFragment : DeletableItemFragment(), StaticRowRepresentableDataSour } private var rows: ArrayList = ArrayList() - private var bankrollReportForRow: HashMap = HashMap() + private var bankrollRowRepresentables: HashMap> = HashMap() private var lastItemClickedPosition: Int = 0 - private var lastItemClickedId: String = "" +// private var lastItemClickedId: String = "" private var deletedRow: RowRepresentable? = null private lateinit var bankrolls: RealmResults - override fun deletableItems() : List { + override fun deletableItems(): List { return this.bankrolls } @@ -85,21 +80,26 @@ class BankrollFragment : DeletableItemFragment(), StaticRowRepresentableDataSour initData() } - override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { super.onActivityResult(requestCode, resultCode, data) - if (requestCode == REQUEST_CODE_DETAILS && resultCode == Activity.RESULT_OK) { + if (requestCode == RequestCode.BANKROLL_DETAILS.value && resultCode == Activity.RESULT_OK) { val itemToDeleteId = data?.getStringExtra(DataListActivity.IntentKey.ITEM_DELETED.keyName) itemToDeleteId?.let { id -> GlobalScope.launch(Dispatchers.Main) { delay(300) deleteItem(dataListAdapter, bankrolls, id) + + // update view + BankrollReportManager.notifyBankrollReportImpact(id) + dataListAdapter.notifyDataSetChanged() } } - } else if (requestCode == REQUEST_CODE_CREATE && resultCode == Activity.RESULT_OK) { + } else if (requestCode == RequestCode.BANKROLL_CREATE.value && resultCode == Activity.RESULT_OK) { //TODO: Refresh bankrolls initData() + } else { + dataListAdapter.notifyDataSetChanged() } } @@ -109,20 +109,19 @@ class BankrollFragment : DeletableItemFragment(), StaticRowRepresentableDataSour } override fun onRowSelected(position: Int, row: RowRepresentable, fromAction: Boolean) { + lastItemClickedPosition = position when (row) { + is BankrollRowRepresentable -> { + BankrollReportManager.reportForBankroll(row.bankrollId) { bankrollReport -> + +// lastItemClickedId = row.bankrollId ?: "" + BankrollDetailsActivity.newInstanceForResult(this, bankrollReport, RequestCode.BANKROLL_DETAILS.value) + } + } is GraphRow -> { val lineDataSet = row.dataSet as LineDataSet GraphActivity.newInstance(requireContext(), listOf(lineDataSet), title = getString(R.string.bankroll)) } - else -> { - if (bankrollReportForRow.containsKey(row)) { - bankrollReportForRow[row]?.let { bankrollReport -> - lastItemClickedPosition = position - lastItemClickedId = (row as? Identifiable)?.id ?: "" - BankrollDetailsActivity.newInstanceForResult(this, bankrollReport, REQUEST_CODE_DETAILS) - } - } - } } } @@ -137,49 +136,26 @@ class BankrollFragment : DeletableItemFragment(), StaticRowRepresentableDataSour this.bankrolls = realm.sorted() rows.clear() - bankrollReportForRow.clear() - - GlobalScope.launch { - - launch(Dispatchers.Main) { - // TODO: Improve that - // We are in the main thread... + // Virtual bankroll + val graphRow = BankrollGraphRow() + rows.add(0, graphRow) + val mainRow = BankrollMainRow() + rows.add(mainRow) - val startDate = Date() + bankrollRowRepresentables[null] = listOf(graphRow, mainRow) - // Graph - val globalBankrollReportSetup = BankrollReportSetup() - val globalBankrollReport = BankrollCalculator.computeReport(getRealm(), globalBankrollReportSetup) - rows.add(0, GraphRow(dataSet = globalBankrollReport.lineDataSet(requireContext()))) - rows.add(globalBankrollReport) - bankrollReportForRow[globalBankrollReport] = globalBankrollReport + // Bankrolls + rows.add(CustomizableRowRepresentable(RowViewType.HEADER_TITLE, resId = R.string.bankrolls)) - // Bankrolls - rows.add(CustomizableRowRepresentable(RowViewType.HEADER_TITLE, resId = R.string.bankrolls)) - - Timber.d("initData: ${System.currentTimeMillis() - startDate.time}ms") - -// val bankrolls = LiveData.Bankroll.items(getRealm()) as RealmResults - - bankrolls.forEach { bankroll -> - val bankrollReportSetup = BankrollReportSetup(bankroll) - val bankrollReport = BankrollCalculator.computeReport(getRealm(), bankrollReportSetup) - val computedStat = ComputedStat(Stat.NET_RESULT, bankrollReport.total) - val row = - CustomizableRowRepresentable(RowViewType.TITLE_VALUE_ARROW, title = bankroll.name, computedStat = computedStat, isSelectable = true) - row.id = bankroll.id - - rows.add(row) - bankrollReportForRow[row] = bankrollReport - } - - if (!isDetached) { - dataListAdapter.notifyDataSetChanged() - } - } + bankrolls.forEach { bankroll -> + val row = BankrollTotalRow(bankroll.id, bankroll.name) + rows.add(row) + bankrollRowRepresentables[bankroll.id] = listOf(row) } + dataListAdapter.notifyDataSetChanged() + } /** @@ -200,13 +176,18 @@ class BankrollFragment : DeletableItemFragment(), StaticRowRepresentableDataSour } addButton.setOnClickListener { - EditableDataActivity.newInstanceForResult(this@BankrollFragment, dataType = LiveData.BANKROLL, primaryKey = null, requestCode = REQUEST_CODE_CREATE) + EditableDataActivity.newInstanceForResult( + this@BankrollFragment, + dataType = LiveData.BANKROLL, + primaryKey = null, + requestCode = RequestCode.BANKROLL_CREATE.value + ) } } - override fun updateUIAfterDeletion(itemPosition: Int) { - lastItemClickedPosition = rows.indexOfFirst { if (it is Identifiable) it.id == lastItemClickedId else false } - deletedRow = rows.find { if (it is Identifiable) it.id == lastItemClickedId else false } + override fun updateUIAfterDeletion(itemId: String, itemPosition: Int) { + lastItemClickedPosition = rows.indexOfFirst { if (it is BankrollRowRepresentable) it.bankrollId == itemId else false } + deletedRow = rows.find { if (it is BankrollRowRepresentable) it.bankrollId == itemId else false } rows.removeAt(lastItemClickedPosition) dataListAdapter.notifyItemRemoved(lastItemClickedPosition) } @@ -217,12 +198,14 @@ class BankrollFragment : DeletableItemFragment(), StaticRowRepresentableDataSour // We are recreating a Bankroll report because the last one is invalid => the bankroll of the setup has been deleted deletedRow?.let { row -> - val bankrollReportSetup = BankrollReportSetup(newItem as Bankroll) - val bankrollReport = BankrollCalculator.computeReport(getRealm(), bankrollReportSetup) - bankrollReportForRow[row] = bankrollReport +// val bankrollReportSetup = BankrollReportSetup(newItem as Bankroll) +// val bankrollReport = BankrollCalculator.computeReport(getRealm(), bankrollReportSetup) +// bankrollReportForRow[row] = bankrollReport rows.add(lastItemClickedPosition, row) - dataListAdapter.notifyItemInserted(lastItemClickedPosition) + dataListAdapter.notifyDataSetChanged() // update both virtual + ex-deleted + +// dataListAdapter.notifyItemInserted(lastItemClickedPosition) } } diff --git a/app/src/main/java/net/pokeranalytics/android/ui/fragment/FeedFragment.kt b/app/src/main/java/net/pokeranalytics/android/ui/fragment/FeedFragment.kt index 3d026bfa..cd33cc31 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/fragment/FeedFragment.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/fragment/FeedFragment.kt @@ -33,6 +33,7 @@ import net.pokeranalytics.android.ui.interfaces.FilterableType import net.pokeranalytics.android.ui.view.RowRepresentable import net.pokeranalytics.android.ui.view.SmoothScrollLinearLayoutManager import net.pokeranalytics.android.util.Preferences +import net.pokeranalytics.android.util.billing.AppGuard import java.text.SimpleDateFormat import java.util.* @@ -274,12 +275,12 @@ class FeedFragment : FilterableFragment(), RowRepresentableDelegate { */ private fun createNewSession(isTournament: Boolean) { -// val sessionCount = this.feedSessionAdapter.realmResults.size -// if (!AppGuard.isProUser && sessionCount >= AppGuard.MAX_SESSIONS_BEFORE_REQUESTING_SUBSCRIPTION) { // && !BuildConfig.DEBUG -// Toast.makeText(context, "Please subscribe!", Toast.LENGTH_LONG).show() -// BillingActivity.newInstanceForResult(requireContext()) -// return -// } + val sessionCount = this.feedSessionAdapter.realmResults.size + if (!AppGuard.isProUser && sessionCount >= AppGuard.MAX_SESSIONS_BEFORE_REQUESTING_SUBSCRIPTION) { // && !BuildConfig.DEBUG + Toast.makeText(context, "Please subscribe!", Toast.LENGTH_LONG).show() + BillingActivity.newInstance(requireContext()) + return + } if (Date().after(betaLimitDate)) { this.showEndOfBetaMessage() diff --git a/app/src/main/java/net/pokeranalytics/android/ui/fragment/SessionFragment.kt b/app/src/main/java/net/pokeranalytics/android/ui/fragment/SessionFragment.kt index aefaa32d..0f1a2da3 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/fragment/SessionFragment.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/fragment/SessionFragment.kt @@ -10,6 +10,7 @@ import androidx.interpolator.view.animation.FastOutSlowInInterpolator import androidx.recyclerview.widget.DiffUtil import kotlinx.android.synthetic.main.fragment_session.* import net.pokeranalytics.android.R +import net.pokeranalytics.android.calculus.bankroll.BankrollReportManager import net.pokeranalytics.android.model.LiveData import net.pokeranalytics.android.model.extensions.SessionState import net.pokeranalytics.android.model.extensions.getState @@ -344,6 +345,9 @@ class SessionFragment : RealmFragment(), RowRepresentableDelegate { * Delete a session */ private fun deleteSession() { + currentSession.bankroll?.id?.let { id -> + BankrollReportManager.notifyBankrollReportImpact(id) + } currentSession.delete() activity?.finish() } diff --git a/app/src/main/java/net/pokeranalytics/android/ui/fragment/components/DeletableItemFragment.kt b/app/src/main/java/net/pokeranalytics/android/ui/fragment/components/DeletableItemFragment.kt index 71cea8c1..07595c6d 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/fragment/components/DeletableItemFragment.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/fragment/components/DeletableItemFragment.kt @@ -92,7 +92,7 @@ abstract class DeletableItemFragment : RealmFragment() { itemToDelete.deleteFromRealm() } itemHasBeenReInserted = false - updateUIAfterDeletion(itemPosition) + updateUIAfterDeletion(itemId, itemPosition) showUndoSnackBar() } else { dataListAdapter.notifyItemChanged(itemPosition) @@ -133,7 +133,7 @@ abstract class DeletableItemFragment : RealmFragment() { /** * Called once the object has been deleted */ - open fun updateUIAfterDeletion(itemPosition: Int) { + open fun updateUIAfterDeletion(itemId: String, itemPosition: Int) { dataListAdapter.notifyItemRemoved(itemPosition) } diff --git a/app/src/main/java/net/pokeranalytics/android/ui/fragment/data/DataManagerFragment.kt b/app/src/main/java/net/pokeranalytics/android/ui/fragment/data/DataManagerFragment.kt index a7ee9216..1234528b 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/fragment/data/DataManagerFragment.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/fragment/data/DataManagerFragment.kt @@ -128,6 +128,8 @@ open class DataManagerFragment : RealmFragment() { */ protected open fun deleteData() { + this.willDeleteData() + val realm = this.getRealm() if (this.item.isValidForDelete(realm)) { @@ -145,6 +147,8 @@ open class DataManagerFragment : RealmFragment() { } } + open fun willDeleteData() { } + /** * Finish the activity with a result */ diff --git a/app/src/main/java/net/pokeranalytics/android/ui/fragment/data/TransactionDataFragment.kt b/app/src/main/java/net/pokeranalytics/android/ui/fragment/data/TransactionDataFragment.kt index 789c00ed..9d60fe96 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/fragment/data/TransactionDataFragment.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/fragment/data/TransactionDataFragment.kt @@ -6,6 +6,7 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.delay import kotlinx.coroutines.launch +import net.pokeranalytics.android.calculus.bankroll.BankrollReportManager import net.pokeranalytics.android.model.realm.Bankroll import net.pokeranalytics.android.model.realm.Transaction import net.pokeranalytics.android.model.realm.TransactionType @@ -115,4 +116,11 @@ class TransactionDataFragment : EditableDataFragment(), StaticRowRepresentableDa } } + override fun willDeleteData() { + super.willDeleteData() + this.transaction?.bankroll?.id?.let { id -> + BankrollReportManager.notifyBankrollReportImpact(id) + } + } + } \ No newline at end of file diff --git a/app/src/main/java/net/pokeranalytics/android/ui/view/RowViewType.kt b/app/src/main/java/net/pokeranalytics/android/ui/view/RowViewType.kt index 12ccaece..42e6da6f 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/view/RowViewType.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/view/RowViewType.kt @@ -14,10 +14,7 @@ import androidx.core.widget.ContentLoadingProgressBar import androidx.recyclerview.widget.RecyclerView import com.github.mikephil.charting.charts.BarChart import com.github.mikephil.charting.charts.LineChart -import com.github.mikephil.charting.data.BarData -import com.github.mikephil.charting.data.BarDataSet -import com.github.mikephil.charting.data.LineData -import com.github.mikephil.charting.data.LineDataSet +import com.github.mikephil.charting.data.* import com.google.android.material.chip.Chip import com.google.android.material.chip.ChipGroup import kotlinx.android.synthetic.main.row_feed_session.view.* @@ -25,7 +22,7 @@ import kotlinx.android.synthetic.main.row_transaction.view.* import net.pokeranalytics.android.R import net.pokeranalytics.android.calculus.ComputedStat import net.pokeranalytics.android.calculus.Stat -import net.pokeranalytics.android.calculus.bankroll.BankrollReport +import net.pokeranalytics.android.calculus.bankroll.BankrollReportManager import net.pokeranalytics.android.model.realm.CustomField import net.pokeranalytics.android.model.realm.Session import net.pokeranalytics.android.model.realm.Transaction @@ -34,6 +31,7 @@ import net.pokeranalytics.android.ui.extensions.ChipGroupExtension import net.pokeranalytics.android.ui.extensions.addCircleRipple import net.pokeranalytics.android.ui.extensions.px import net.pokeranalytics.android.ui.extensions.setTextFormat +import net.pokeranalytics.android.ui.fragment.BankrollRowRepresentable import net.pokeranalytics.android.ui.graph.AxisFormatting import net.pokeranalytics.android.ui.graph.setStyle import net.pokeranalytics.android.ui.view.rowrepresentable.* @@ -139,93 +137,118 @@ enum class RowViewType(private var layoutRes: Int) { inner class RowViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView), BindableHolder { override fun bind(position: Int, row: RowRepresentable, adapter: RowRepresentableAdapter) { - if (row is CustomizableRowRepresentable) { + when (row) { - // Customizable Row + is BankrollRowRepresentable -> { - // Title - itemView.findViewById(R.id.title)?.let { - it.text = row.localizedTitle(itemView.context) - } - - // Value - itemView.findViewById(R.id.value)?.let { - if (row.computedStat != null) { - val format = row.computedStat!!.format() - it.setTextFormat(format, itemView.context) - } else if (row.value != null) { - it.text = row.value + // Title + itemView.findViewById(R.id.title)?.let { + it.text = row.localizedTitle(itemView.context) } - } - // Listener - row.isSelectable?.let { isSelectable -> - if (isSelectable) { - val listener = View.OnClickListener { - adapter.delegate?.onRowSelected(position, row) + BankrollReportManager.reportForBankroll(row.bankrollId) { report -> + + itemView.findViewById(R.id.title)?.let { + it.text = row.localizedTitle(itemView.context) } - itemView.findViewById(R.id.container)?.setOnClickListener(listener) + val computedStat = ComputedStat(Stat.NET_RESULT, report.total) + itemView.findViewById(R.id.value)?.setTextFormat(computedStat.format(), itemView.context) } - } - } else { + val listener = View.OnClickListener { + adapter.delegate?.onRowSelected(position, row) + } + itemView.findViewById(R.id.container)?.setOnClickListener(listener) + } + is CustomizableRowRepresentable -> { - // Classic row + // Customizable Row - // Title - itemView.findViewById(R.id.title)?.let { - if (row.resId != null) { + // Title + itemView.findViewById(R.id.title)?.let { it.text = row.localizedTitle(itemView.context) - } else { - it.text = row.getDisplayName(itemView.context) } - } - // Value - itemView.findViewById(R.id.value)?.let { - it.text = adapter.dataSource.stringForRow(row, itemView.context) - } + // Value + itemView.findViewById(R.id.value)?.let { + if (row.computedStat != null) { + val format = row.computedStat!!.format() + it.setTextFormat(format, itemView.context) + } else if (row.value != null) { + it.text = row.value + } + } - // Icon - itemView.findViewById(R.id.icon)?.let { imageView -> - imageView.setImageDrawable(null) - row.imageRes?.let { imageRes -> - imageView.setImageResource(imageRes) + // Listener + row.isSelectable?.let { isSelectable -> + if (isSelectable) { + val listener = View.OnClickListener { + adapter.delegate?.onRowSelected(position, row) + } + itemView.findViewById(R.id.container)?.setOnClickListener(listener) + } } + } + else -> { - // Action - itemView.findViewById(R.id.action)?.let { imageView -> - imageView.setImageDrawable(null) - row.imageRes?.let { imageRes -> - imageView.visibility = View.VISIBLE - imageView.setImageResource(imageRes) + // Classic row + + // Title + itemView.findViewById(R.id.title)?.let { + if (row.resId != null) { + it.text = row.localizedTitle(itemView.context) + } else { + it.text = row.getDisplayName(itemView.context) + } } - row.imageTint?.let { color -> - imageView.setColorFilter(ContextCompat.getColor(imageView.context, color)) + + // Value + itemView.findViewById(R.id.value)?.let { + it.text = adapter.dataSource.stringForRow(row, itemView.context) } - if (row.imageClickable == true) { - imageView.addCircleRipple() - imageView.setOnClickListener { - adapter.delegate?.onRowSelected(position, row, true) + + // Icon + itemView.findViewById(R.id.icon)?.let { imageView -> + imageView.setImageDrawable(null) + row.imageRes?.let { imageRes -> + imageView.setImageResource(imageRes) } - } else { - imageView.setBackgroundResource(0) } - } - // Listener - val listener = View.OnClickListener { - itemView.findViewById(R.id.switchView)?.let { - if (adapter.dataSource.isEnabled(row)) { - it.isChecked = !it.isChecked + // Action + itemView.findViewById(R.id.action)?.let { imageView -> + imageView.setImageDrawable(null) + row.imageRes?.let { imageRes -> + imageView.visibility = View.VISIBLE + imageView.setImageResource(imageRes) + } + row.imageTint?.let { color -> + imageView.setColorFilter(ContextCompat.getColor(imageView.context, color)) + } + if (row.imageClickable == true) { + imageView.addCircleRipple() + imageView.setOnClickListener { + adapter.delegate?.onRowSelected(position, row, true) + } + } else { + imageView.setBackgroundResource(0) + } + } + + // Listener + val listener = View.OnClickListener { + itemView.findViewById(R.id.switchView)?.let { + if (adapter.dataSource.isEnabled(row)) { + it.isChecked = !it.isChecked + } + } ?: run { + adapter.delegate?.onRowSelected(position, row) } - } ?: run { - adapter.delegate?.onRowSelected(position, row) } - } - itemView.findViewById(R.id.container)?.setOnClickListener(listener) + itemView.findViewById(R.id.container)?.setOnClickListener(listener) + } } // Switch @@ -346,43 +369,52 @@ enum class RowViewType(private var layoutRes: Int) { /** * Display a graph */ - inner class GraphViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView), - BindableHolder { - override fun bind(position: Int, row: RowRepresentable, adapter: RowRepresentableAdapter) { + inner class GraphViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView), BindableHolder { - if (row is GraphRow) { + private fun loadWithDataSet(dataSet: DataSet<*>) { + val context = itemView.context - row.dataSet?.let { dataSet -> + val chartView = when (dataSet) { + is LineDataSet -> { + val lineChart = LineChart(context) + lineChart.data = LineData(dataSet) + lineChart + } + is BarDataSet -> { + val barChart = BarChart(context) + barChart.data = BarData(dataSet) + barChart + } + else -> null + } - val context = itemView.context + itemView.findViewById(R.id.chartContainer)?.let { + it.removeAllViews() + it.addView(chartView) + } - val chartView = when (dataSet) { - is LineDataSet -> { - val lineChart = LineChart(context) - lineChart.data = LineData(dataSet) - lineChart - } - is BarDataSet -> { - val barChart = BarChart(context) - barChart.data = BarData(dataSet) - barChart - } - else -> null - } + chartView?.let { + chartView.setStyle(true, AxisFormatting.DEFAULT, context) + chartView.setTouchEnabled(false) + } - itemView.findViewById(R.id.chartContainer)?.let { - it.removeAllViews() - it.addView(chartView) - } + } - chartView?.let { - chartView.setStyle(true, AxisFormatting.DEFAULT, context) - chartView.setTouchEnabled(false) - } + override fun bind(position: Int, row: RowRepresentable, adapter: RowRepresentableAdapter) { -// chartView.highlightValue((entries.size - 1).toFloat(), 0) + when (row) { + is BankrollGraphRow -> { + BankrollReportManager.reportForBankroll(row.bankrollId) { report -> + val dataSet = report.lineDataSet(itemView.context) + row.dataSet = dataSet + loadWithDataSet(dataSet) + } + } + is GraphRow -> { + row.dataSet?.let { dataSet -> + loadWithDataSet(dataSet) + } } - } // Listener @@ -400,22 +432,27 @@ enum class RowViewType(private var layoutRes: Int) { BindableHolder { override fun bind(position: Int, row: RowRepresentable, adapter: RowRepresentableAdapter) { - if (row is BankrollReport) { + if (row is BankrollRowRepresentable) { + + BankrollReportManager.reportForBankroll(row.bankrollId) { report -> + + itemView.findViewById(R.id.stat1Value)?.let { + val formattedStat = ComputedStat(Stat.NET_RESULT, report.total).format() + it.setTextFormat(formattedStat, itemView.context) + } + itemView.findViewById(R.id.stat2Value)?.let { + val riskOfRuin = report.riskOfRuin ?: 0.0 + val formattedStat = ComputedStat(Stat.RISK_OF_RUIN, riskOfRuin).format() + it.setTextFormat(formattedStat, itemView.context) + } + } + itemView.findViewById(R.id.stat1Name)?.let { it.text = itemView.context.getString(R.string.total) } - itemView.findViewById(R.id.stat1Value)?.let { - val formattedStat = ComputedStat(Stat.NET_RESULT, row.total).format() - it.setTextFormat(formattedStat, itemView.context) - } itemView.findViewById(R.id.stat2Name)?.let { it.text = itemView.context.getString(R.string.risk_of_ruin) } - itemView.findViewById(R.id.stat2Value)?.let { - val riskOfRuin = row.riskOfRuin ?: 0.0 - val formattedStat = ComputedStat(Stat.RISK_OF_RUIN, riskOfRuin).format() - it.setTextFormat(formattedStat, itemView.context) - } val listener = View.OnClickListener { adapter.delegate?.onRowSelected(position, row) } diff --git a/app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/BankrollMainRow.kt b/app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/BankrollMainRow.kt new file mode 100644 index 00000000..1e42445f --- /dev/null +++ b/app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/BankrollMainRow.kt @@ -0,0 +1,12 @@ +package net.pokeranalytics.android.ui.view.rowrepresentable + +import net.pokeranalytics.android.ui.fragment.BankrollRowRepresentable +import net.pokeranalytics.android.ui.view.RowViewType + +class BankrollMainRow : BankrollRowRepresentable { + + override var bankrollId: String? = null + + override val viewType: Int = RowViewType.LEGEND_DEFAULT.ordinal + +} \ No newline at end of file diff --git a/app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/CustomizableRowRepresentable.kt b/app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/CustomizableRowRepresentable.kt index 3cdc0ace..84d223f6 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/CustomizableRowRepresentable.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/CustomizableRowRepresentable.kt @@ -3,9 +3,20 @@ package net.pokeranalytics.android.ui.view.rowrepresentable import android.content.Context import net.pokeranalytics.android.calculus.ComputedStat import net.pokeranalytics.android.model.interfaces.Identifiable +import net.pokeranalytics.android.ui.fragment.BankrollRowRepresentable import net.pokeranalytics.android.ui.view.RowRepresentable import net.pokeranalytics.android.ui.view.RowViewType +class BankrollTotalRow(override var bankrollId: String?, var name: String) : BankrollRowRepresentable { + + override val viewType: Int = RowViewType.TITLE_VALUE_ARROW.ordinal + + override fun localizedTitle(context: Context): String { + return name + } + +} + /** * A class to display a titleResId (and a value) as a Row Representable object */ diff --git a/app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/GraphRow.kt b/app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/GraphRow.kt index 7af17e6b..3f8f185b 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/GraphRow.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/GraphRow.kt @@ -3,11 +3,18 @@ package net.pokeranalytics.android.ui.view.rowrepresentable import com.github.mikephil.charting.data.DataSet import net.pokeranalytics.android.calculus.Report import net.pokeranalytics.android.calculus.Stat +import net.pokeranalytics.android.ui.fragment.BankrollRowRepresentable import net.pokeranalytics.android.ui.view.RowRepresentable import net.pokeranalytics.android.ui.view.RowViewType -class GraphRow(var dataSet: DataSet<*>?, var title: String? = null, var report: Report? = null, var stat: Stat? = null) : RowRepresentable { +class BankrollGraphRow : GraphRow(null, null, null, null), BankrollRowRepresentable { + + override var bankrollId: String? = null + +} + +open class GraphRow(var dataSet: DataSet<*>? = null, var title: String? = null, var report: Report? = null, var stat: Stat? = null) : RowRepresentable { override val viewType: Int get() = RowViewType.GRAPH.ordinal