diff --git a/app/src/main/java/net/pokeranalytics/android/calculus/Calculator.kt b/app/src/main/java/net/pokeranalytics/android/calculus/Calculator.kt index 5e4de50f..9146b446 100644 --- a/app/src/main/java/net/pokeranalytics/android/calculus/Calculator.kt +++ b/app/src/main/java/net/pokeranalytics/android/calculus/Calculator.kt @@ -116,7 +116,7 @@ class Calculator { return when (aggregationType) { AggregationType.SESSION, AggregationType.DURATION -> this.computeGroups(realm, listOf(group), options) AggregationType.MONTH -> { - val comparators: List = listOf(Comparator.YEAR, Comparator.MONTH_OF_YEAR) + val comparators: List = listOf(Comparator.MONTH_OF_YEAR, Comparator.YEAR) this.computeStatsWithComparators(realm, comparators, group.conditions, options) } AggregationType.YEAR -> { @@ -392,6 +392,7 @@ class Calculator { results.addEvolutionValue(tHourlyRate, stat = HOURLY_RATE, data = sessionSet) results.addEvolutionValue(tIndex.toDouble(), stat = NUMBER_OF_SETS, data = sessionSet) results.addEvolutionValue( + (sessionSet.startDate.time / 3600000).toDouble(), sessionSet.netDuration.toDouble(), stat = DURATION, data = sessionSet diff --git a/app/src/main/java/net/pokeranalytics/android/calculus/Report.kt b/app/src/main/java/net/pokeranalytics/android/calculus/Report.kt index eab4fff7..97580595 100644 --- a/app/src/main/java/net/pokeranalytics/android/calculus/Report.kt +++ b/app/src/main/java/net/pokeranalytics/android/calculus/Report.kt @@ -342,6 +342,7 @@ class ComputedResults(group: ComputableGroup, shouldManageMultiGroupProgressValu return when (stat) { Stat.NUMBER_OF_SETS, Stat.NUMBER_OF_GAMES -> this.barEntries(stat) Stat.STANDARD_DEVIATION -> this.distributionEntries(stat, context) + Stat.DURATION -> this.barEntries(stat) else -> this.singleLineEntries(stat, context) } } diff --git a/app/src/main/java/net/pokeranalytics/android/model/filter/QueryCondition.kt b/app/src/main/java/net/pokeranalytics/android/model/filter/QueryCondition.kt index 256459f3..65a390c6 100644 --- a/app/src/main/java/net/pokeranalytics/android/model/filter/QueryCondition.kt +++ b/app/src/main/java/net/pokeranalytics/android/model/filter/QueryCondition.kt @@ -1,23 +1,20 @@ package net.pokeranalytics.android.model.filter -import android.content.Context -import io.realm.* -import io.realm.kotlin.where +import io.realm.Realm import io.realm.RealmQuery -import io.realm.internal.Table -import net.pokeranalytics.android.R -import net.pokeranalytics.android.calculus.Stat +import io.realm.RealmResults +import io.realm.Sort +import io.realm.kotlin.where import net.pokeranalytics.android.exceptions.PokerAnalyticsException import net.pokeranalytics.android.model.Limit import net.pokeranalytics.android.model.TableSize import net.pokeranalytics.android.model.TournamentType import net.pokeranalytics.android.model.interfaces.Identifiable -import net.pokeranalytics.android.model.interfaces.Manageable import net.pokeranalytics.android.model.interfaces.NameManageable import net.pokeranalytics.android.model.realm.* import net.pokeranalytics.android.ui.view.RowRepresentable -import net.pokeranalytics.android.ui.view.rowrepresentable.FilterSectionRow import net.pokeranalytics.android.ui.view.rowrepresentable.FilterElementRow +import net.pokeranalytics.android.ui.view.rowrepresentable.FilterSectionRow import net.pokeranalytics.android.util.NULL_TEXT import net.pokeranalytics.android.util.extensions.endOfDay import net.pokeranalytics.android.util.extensions.startOfDay @@ -26,7 +23,7 @@ import java.util.* import kotlin.collections.ArrayList fun List.name() : String { - return this.map { it.getDisplayName() }.joinToString(" / ") + return this.map { it.getDisplayName() }.joinToString(" : ") } //inline fun List.query(realm: Realm): RealmQuery { diff --git a/app/src/main/java/net/pokeranalytics/android/ui/adapter/ComparisonChartPagerAdapter.kt b/app/src/main/java/net/pokeranalytics/android/ui/adapter/ComparisonChartPagerAdapter.kt index 193065c5..2b900480 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/adapter/ComparisonChartPagerAdapter.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/adapter/ComparisonChartPagerAdapter.kt @@ -6,7 +6,9 @@ import android.view.ViewGroup import androidx.fragment.app.FragmentManager import androidx.fragment.app.FragmentStatePagerAdapter import net.pokeranalytics.android.R -import net.pokeranalytics.android.ui.fragment.* +import net.pokeranalytics.android.ui.fragment.CalendarFragment +import net.pokeranalytics.android.ui.fragment.GraphFragment +import net.pokeranalytics.android.ui.fragment.HistoryFragment import net.pokeranalytics.android.ui.fragment.components.PokerAnalyticsFragment import java.lang.ref.WeakReference @@ -51,20 +53,7 @@ class ComparisonChartPagerAdapter(val context: Context, fragmentManager: Fragmen } override fun getItemPosition(obj: Any): Int { - return when (obj) { - //CLEAN - /* - HistoryFragment::class.java -> 0 - StatsFragment::class.java -> 1 - SettingsFragment::class.java -> 2 - */ - HistoryFragment::class.java -> 0 - StatsFragment::class.java -> 1 - CalendarFragment::class.java -> 2 - ReportsFragment::class.java -> 3 - MoreFragment::class.java -> 4 - else -> -1 - } + return POSITION_UNCHANGED } /** diff --git a/app/src/main/java/net/pokeranalytics/android/ui/adapter/HomePagerAdapter.kt b/app/src/main/java/net/pokeranalytics/android/ui/adapter/HomePagerAdapter.kt index e1b32d35..f749a4db 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/adapter/HomePagerAdapter.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/adapter/HomePagerAdapter.kt @@ -18,7 +18,7 @@ class HomePagerAdapter(fragmentManager: FragmentManager) : FragmentStatePagerAda override fun getItem(position: Int): PokerAnalyticsFragment { return when (position) { 0 -> HistoryFragment.newInstance() - 1 -> StatsFragment.newInstance() + 1 -> StatisticsFragment.newInstance() 2 -> CalendarFragment.newInstance() 3 -> ReportsFragment.newInstance() 4 -> MoreFragment.newInstance() @@ -44,7 +44,7 @@ class HomePagerAdapter(fragmentManager: FragmentManager) : FragmentStatePagerAda override fun getItemPosition(obj: Any): Int { return when (obj) { HistoryFragment::class.java -> 0 - StatsFragment::class.java -> 1 + StatisticsFragment::class.java -> 1 CalendarFragment::class.java -> 2 ReportsFragment::class.java -> 3 MoreFragment::class.java -> 4 diff --git a/app/src/main/java/net/pokeranalytics/android/ui/adapter/ReportPagerAdapter.kt b/app/src/main/java/net/pokeranalytics/android/ui/adapter/ReportPagerAdapter.kt index 08126835..ce2e3941 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/adapter/ReportPagerAdapter.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/adapter/ReportPagerAdapter.kt @@ -9,6 +9,7 @@ import androidx.viewpager.widget.PagerAdapter import net.pokeranalytics.android.R import net.pokeranalytics.android.calculus.Report import net.pokeranalytics.android.ui.fragment.GraphFragment +import net.pokeranalytics.android.ui.fragment.TableReportFragment import net.pokeranalytics.android.ui.fragment.components.PokerAnalyticsFragment import java.lang.ref.WeakReference @@ -26,14 +27,11 @@ class ReportPagerAdapter(val context: Context, val fragmentManager: FragmentMana GraphFragment.newInstance(dataSetList) } 1 -> { - val dataSetList = listOf(report.lineEntries(context = context)) + val dataSetList = report.multiLineEntries(context = context) GraphFragment.newInstance(dataSetList) - PokerAnalyticsFragment() } 2 -> { - //val dataSetList = listOf(report.barEntries()) - //GraphFragment.newInstance(dataSetList) - PokerAnalyticsFragment() + TableReportFragment.newInstance(report) } else -> PokerAnalyticsFragment() } diff --git a/app/src/main/java/net/pokeranalytics/android/ui/fragment/StatisticsFragment.kt b/app/src/main/java/net/pokeranalytics/android/ui/fragment/StatisticsFragment.kt new file mode 100644 index 00000000..285f76f5 --- /dev/null +++ b/app/src/main/java/net/pokeranalytics/android/ui/fragment/StatisticsFragment.kt @@ -0,0 +1,145 @@ +package net.pokeranalytics.android.ui.fragment + +import android.os.Bundle +import android.view.View +import io.realm.Realm +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.GlobalScope +import kotlinx.coroutines.async +import kotlinx.coroutines.launch +import net.pokeranalytics.android.R +import net.pokeranalytics.android.calculus.Calculator +import net.pokeranalytics.android.calculus.ComputableGroup +import net.pokeranalytics.android.calculus.Report +import net.pokeranalytics.android.calculus.Stat +import net.pokeranalytics.android.model.filter.QueryCondition +import net.pokeranalytics.android.ui.view.RowRepresentable +import net.pokeranalytics.android.ui.view.rowrepresentable.CustomizableRowRepresentable +import net.pokeranalytics.android.ui.view.rowrepresentable.StatRow +import timber.log.Timber +import java.util.* +import kotlin.coroutines.CoroutineContext + +class StatisticsFragment : TableReportFragment() { + + override val coroutineContext: CoroutineContext + get() = Dispatchers.Main + + private var stringAll = "" + private var stringCashGame = "" + private var stringTournament = "" + + companion object { + + /** + * Create new instance + */ + fun newInstance(report: Report? = null): StatisticsFragment { + val fragment = StatisticsFragment() + report?.let { + fragment.report = it + } + val bundle = Bundle() + fragment.arguments = bundle + return fragment + } + } + + // Life Cycle + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + launchStatComputation() + } + + override fun sessionsChanged() { + this.launchStatComputation() + this.statsAdapter?.notifyDataSetChanged() + } + + override fun initData() { + super.initData() + + this.stringAll = getString(R.string.all) + this.stringCashGame = getString(R.string.cash_game) + this.stringTournament = getString(R.string.tournament) + } + + override fun convertReportIntoRepresentables(report: Report): ArrayList { + val rows: ArrayList = ArrayList() + report.results.forEach { result -> + rows.add(CustomizableRowRepresentable(title = result.group.name)) + result.group.stats?.forEach { stat -> + rows.add(StatRow(stat, result.computedStat(stat), result.group.name)) + } + } + return rows + } + + + // Business + + /** + * Launch stat computation + */ + private fun launchStatComputation() { + + GlobalScope.launch(coroutineContext) { + + val test = GlobalScope.async { + val s = Date() + Timber.d(">>> start...") + + val realm = Realm.getDefaultInstance() + report = createSessionGroupsAndStartCompute(realm) + realm.close() + + val e = Date() + val duration = (e.time - s.time) / 1000.0 + Timber.d(">>> ended in $duration seconds") + + } + test.await() + + if (!isDetached) { + showResults() + } + } + } + + /** + * Create session groups and start computations + */ + private fun createSessionGroupsAndStartCompute(realm: Realm): Report { + + val allStats: List = listOf( + Stat.NET_RESULT, + Stat.HOURLY_RATE, + Stat.AVERAGE, + Stat.NUMBER_OF_SETS, + Stat.AVERAGE_DURATION, + Stat.DURATION + ) + val allSessionGroup = ComputableGroup(stringAll, listOf(), allStats) + val cgStats: List = listOf( + Stat.NET_RESULT, + Stat.HOURLY_RATE, + Stat.NET_BB_PER_100_HANDS, + Stat.HOURLY_RATE_BB, + Stat.AVERAGE, + Stat.STANDARD_DEVIATION_HOURLY, + Stat.WIN_RATIO, + Stat.NUMBER_OF_GAMES, + Stat.AVERAGE_BUYIN + ) + val cgSessionGroup = ComputableGroup(stringCashGame, listOf(QueryCondition.CASH), cgStats) + val tStats: List = + listOf(Stat.NET_RESULT, Stat.HOURLY_RATE, Stat.ROI, Stat.WIN_RATIO, Stat.NUMBER_OF_GAMES, Stat.AVERAGE_BUYIN) + val tSessionGroup = ComputableGroup(stringTournament, listOf(QueryCondition.TOURNAMENT), tStats) + + Timber.d(">>>>> Start computations...") + + return Calculator.computeGroups(realm, listOf(allSessionGroup, cgSessionGroup, tSessionGroup), Calculator.Options()) + } + +} \ No newline at end of file diff --git a/app/src/main/java/net/pokeranalytics/android/ui/fragment/StatsFragment.kt b/app/src/main/java/net/pokeranalytics/android/ui/fragment/TableReportFragment.kt similarity index 59% rename from app/src/main/java/net/pokeranalytics/android/ui/fragment/StatsFragment.kt rename to app/src/main/java/net/pokeranalytics/android/ui/fragment/TableReportFragment.kt index 94993c8a..07cdc63c 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/fragment/StatsFragment.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/fragment/TableReportFragment.kt @@ -10,7 +10,6 @@ import kotlinx.android.synthetic.main.fragment_stats.* import kotlinx.coroutines.* import net.pokeranalytics.android.R import net.pokeranalytics.android.calculus.* -import net.pokeranalytics.android.model.filter.QueryCondition import net.pokeranalytics.android.ui.activity.StatisticDetailsActivity import net.pokeranalytics.android.ui.adapter.DisplayDescriptor import net.pokeranalytics.android.ui.adapter.RowRepresentableAdapter @@ -25,27 +24,27 @@ import timber.log.Timber import java.util.* import kotlin.coroutines.CoroutineContext -class StatsFragment : SessionObserverFragment(), StaticRowRepresentableDataSource, CoroutineScope, +open class TableReportFragment : SessionObserverFragment(), StaticRowRepresentableDataSource, CoroutineScope, RowRepresentableDelegate { override val coroutineContext: CoroutineContext get() = Dispatchers.Main private var rowRepresentables: ArrayList = ArrayList() - private var stringAll = "" - private var stringCashGame = "" - private var stringTournament = "" - private lateinit var statsAdapter: RowRepresentableAdapter - private var report : Report? = null + var statsAdapter: RowRepresentableAdapter? = null + var report : Report? = null companion object { /** * Create new instance */ - fun newInstance(): StatsFragment { - val fragment = StatsFragment() + fun newInstance(report: Report? = null): TableReportFragment { + val fragment = TableReportFragment() + report?.let { + fragment.report = it + } val bundle = Bundle() fragment.arguments = bundle return fragment @@ -62,7 +61,10 @@ class StatsFragment : SessionObserverFragment(), StaticRowRepresentableDataSourc super.onViewCreated(view, savedInstanceState) initData() initUI() - launchStatComputation() + + report?.let { + showResults() + } } // Row Representable DS @@ -75,7 +77,7 @@ class StatsFragment : SessionObserverFragment(), StaticRowRepresentableDataSourc val dc = DisplayDescriptor() dc.textFormat = TextFormat(NULL_TEXT) if (row is StatRow) { - context?.let { context -> + context?.let { _ -> row.computedStat?.let { dc.textFormat = it.format() } @@ -86,7 +88,7 @@ class StatsFragment : SessionObserverFragment(), StaticRowRepresentableDataSourc override fun statFormatForRow(row: RowRepresentable): TextFormat { if (row is StatRow) { - context?.let { context -> + context?.let { _ -> row.computedStat?.let { return it.format() } } } @@ -95,14 +97,7 @@ class StatsFragment : SessionObserverFragment(), StaticRowRepresentableDataSourc override fun onResume() { super.onResume() - statsAdapter.notifyDataSetChanged() - } - - // Override - - override fun sessionsChanged() { - this.launchStatComputation() - this.statsAdapter.notifyDataSetChanged() + statsAdapter?.notifyDataSetChanged() } // Business @@ -110,22 +105,15 @@ class StatsFragment : SessionObserverFragment(), StaticRowRepresentableDataSourc /** * Init data */ - private fun initData() { - - this.stringAll = getString(R.string.all) - this.stringCashGame = getString(R.string.cash_game) - this.stringTournament = getString(R.string.tournament) - + open fun initData() { this.statsAdapter = RowRepresentableAdapter(this, this) } /** * Init UI */ - private fun initUI() { - + open fun initUI() { val viewManager = LinearLayoutManager(requireContext()) - recyclerView.apply { setHasFixedSize(true) layoutManager = viewManager @@ -133,87 +121,26 @@ class StatsFragment : SessionObserverFragment(), StaticRowRepresentableDataSourc } } - private fun launchStatComputation() { - - GlobalScope.launch(coroutineContext) { - - val test = GlobalScope.async { - val s = Date() - Timber.d(">>> start...") - - val realm = Realm.getDefaultInstance() - report = createSessionGroupsAndStartCompute(realm) - realm.close() - - val e = Date() - val duration = (e.time - s.time) / 1000.0 - Timber.d(">>> ended in $duration seconds") - - } - test.await() - - if (!isDetached) { - showResults() - } - } - - } - - private fun createSessionGroupsAndStartCompute(realm: Realm): Report { - - val allStats: List = listOf( - Stat.NET_RESULT, - Stat.HOURLY_RATE, - Stat.AVERAGE, - Stat.NUMBER_OF_SETS, - Stat.AVERAGE_DURATION, - Stat.DURATION - ) - val allSessionGroup = ComputableGroup(stringAll, listOf(), allStats) - val cgStats: List = listOf( - Stat.NET_RESULT, - Stat.HOURLY_RATE, - Stat.NET_BB_PER_100_HANDS, - Stat.HOURLY_RATE_BB, - Stat.AVERAGE, - Stat.STANDARD_DEVIATION_HOURLY, - Stat.WIN_RATIO, - Stat.NUMBER_OF_GAMES, - Stat.AVERAGE_BUYIN - ) - val cgSessionGroup = ComputableGroup(stringCashGame, listOf(QueryCondition.CASH), cgStats) - val tStats: List = - listOf(Stat.NET_RESULT, Stat.HOURLY_RATE, Stat.ROI, Stat.WIN_RATIO, Stat.NUMBER_OF_GAMES, Stat.AVERAGE_BUYIN) - val tSessionGroup = ComputableGroup(stringTournament, listOf(QueryCondition.TOURNAMENT), tStats) - - Timber.d(">>>>> Start computations...") - - return Calculator.computeGroups( - realm, - listOf(allSessionGroup, cgSessionGroup, tSessionGroup), - Calculator.Options() - ) - - } - - private fun showResults() { + /** + * Show results + */ + fun showResults() { report?.let { this.rowRepresentables = this.convertReportIntoRepresentables(it) - statsAdapter.notifyDataSetChanged() + statsAdapter?.notifyDataSetChanged() } } - private fun convertReportIntoRepresentables(report: Report): ArrayList { - + open fun convertReportIntoRepresentables(report: Report): ArrayList { val rows: ArrayList = ArrayList() + report.options.displayedStats.forEach {stat -> + rows.add(CustomizableRowRepresentable(title = stat.localizedTitle(requireContext()))) + report.results.forEach { + val title = it.group.name + rows.add(StatRow(stat, it.computedStat(stat), it.group.name, title)) + } - report.results.forEach { result -> - rows.add(CustomizableRowRepresentable(title = result.group.name)) - result.group.stats?.forEach { stat -> - rows.add(StatRow(stat, result.computedStat(stat), result.group.name)) - } - } - + } return rows } @@ -237,6 +164,8 @@ class StatsFragment : SessionObserverFragment(), StaticRowRepresentableDataSourc private fun launchStatComputationWithEvolution(stat: Stat, computableGroup: ComputableGroup) { + showLoader() + GlobalScope.launch(coroutineContext) { var report: Report? = null @@ -259,12 +188,12 @@ class StatsFragment : SessionObserverFragment(), StaticRowRepresentableDataSourc test.await() if (!isDetached) { + hideLoader() report?.let { StatisticDetailsActivity.newInstance(requireContext(), stat, computableGroup, it) } } } - } } \ No newline at end of file diff --git a/app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/StatRow.kt b/app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/StatRow.kt index 44abd20e..390d0656 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/StatRow.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/StatRow.kt @@ -1,12 +1,13 @@ package net.pokeranalytics.android.ui.view.rowrepresentable +import android.content.Context import net.pokeranalytics.android.calculus.ComputedStat import net.pokeranalytics.android.calculus.Stat import net.pokeranalytics.android.ui.view.RowRepresentable import net.pokeranalytics.android.ui.view.RowViewType -class StatRow(stat: Stat, computedStat: ComputedStat?, groupName: String = "") : RowRepresentable { +class StatRow(stat: Stat, computedStat: ComputedStat?, groupName: String = "", var title: String? = null) : RowRepresentable { var stat: Stat = stat var computedStat: ComputedStat? = computedStat @@ -18,4 +19,16 @@ class StatRow(stat: Stat, computedStat: ComputedStat?, groupName: String = "") : override val resId: Int? get() = this.stat.resId + + override fun localizedTitle(context: Context): String { + + this.title?.let { + return it + } + this.resId?.let { + return context.getString(it) + } + return "LOCALISATION NOT FOUND" + } + } diff --git a/app/src/main/res/layout/fragment_evograph.xml b/app/src/main/res/layout/fragment_evograph.xml index 8c937fd5..39d8185c 100644 --- a/app/src/main/res/layout/fragment_evograph.xml +++ b/app/src/main/res/layout/fragment_evograph.xml @@ -17,8 +17,7 @@ android:id="@+id/chartContainer" android:layout_width="0dp" android:layout_height="0dp" - android:layout_marginTop="8dp" - android:layout_marginBottom="8dp" + android:layout_margin="8dp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent"