Merge remote-tracking branch 'origin/dev' into dev

feature/top10
Razmig Sarkissian 7 years ago
commit d574133ca1
  1. 5
      app/src/main/AndroidManifest.xml
  2. 70
      app/src/main/java/net/pokeranalytics/android/calculus/Calculator.kt
  3. 8
      app/src/main/java/net/pokeranalytics/android/model/realm/Session.kt
  4. 54
      app/src/main/java/net/pokeranalytics/android/ui/activity/CalendarDetailsActivity.kt
  5. 80
      app/src/main/java/net/pokeranalytics/android/ui/fragment/CalendarDetailsFragment.kt
  6. 23
      app/src/main/java/net/pokeranalytics/android/ui/fragment/CalendarFragment.kt
  7. 4
      app/src/main/java/net/pokeranalytics/android/ui/fragment/CurrenciesFragment.kt
  8. 117
      app/src/main/java/net/pokeranalytics/android/ui/fragment/GraphFragment.kt
  9. 52
      app/src/main/java/net/pokeranalytics/android/ui/fragment/StatsFragment.kt
  10. 4
      app/src/main/java/net/pokeranalytics/android/ui/view/RowViewType.kt
  11. 2
      app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/SeparatorRow.kt
  12. 8
      app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/SessionRow.kt
  13. 4
      app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/StatRow.kt
  14. 15
      app/src/main/res/layout/activity_calendar_details.xml
  15. 26
      app/src/main/res/layout/fragment_calendar_details.xml

@ -49,6 +49,11 @@
android:launchMode="singleTop" android:launchMode="singleTop"
android:screenOrientation="portrait" /> android:screenOrientation="portrait" />
<activity
android:name=".ui.activity.CalendarDetailsActivity"
android:launchMode="singleTop"
android:screenOrientation="portrait" />
<activity <activity
android:name=".ui.activity.ComparisonChartActivity" android:name=".ui.activity.ComparisonChartActivity"
android:launchMode="singleTop" android:launchMode="singleTop"

@ -7,7 +7,6 @@ import net.pokeranalytics.android.model.comparison.combined
import net.pokeranalytics.android.model.filter.QueryCondition import net.pokeranalytics.android.model.filter.QueryCondition
import net.pokeranalytics.android.model.filter.name import net.pokeranalytics.android.model.filter.name
import net.pokeranalytics.android.model.realm.ComputableResult import net.pokeranalytics.android.model.realm.ComputableResult
import net.pokeranalytics.android.model.realm.Filter
import net.pokeranalytics.android.model.realm.SessionSet import net.pokeranalytics.android.model.realm.SessionSet
import timber.log.Timber import timber.log.Timber
import java.util.* import java.util.*
@ -20,7 +19,11 @@ class Calculator {
/** /**
* The options used for calculations or display * The options used for calculations or display
*/ */
class Options { class Options(
display: Display = Display.TABLE,
evolutionValues: EvolutionValues = EvolutionValues.NONE,
stats: List<Stat> = listOf()
) {
/** /**
* The way the stats are going to be displayed * The way the stats are going to be displayed
@ -42,9 +45,9 @@ class Calculator {
TIMED TIMED
} }
var display: Display = Display.TABLE var display: Display = display
var evolutionValues: EvolutionValues = EvolutionValues.NONE var evolutionValues: EvolutionValues = evolutionValues
var displayedStats: List<Stat> = listOf() var displayedStats: List<Stat> = stats
/** /**
* This function determines whether the standard deviation should be computed * This function determines whether the standard deviation should be computed
@ -64,7 +67,36 @@ class Calculator {
companion object { companion object {
fun computeStatsWithComparators(realm: Realm, comparators: List<Comparator> = listOf(), conditions: List<QueryCondition> = listOf(), options: Options): Report { fun computeStatsWithEvolutionByAggregationType(
realm: Realm,
group: ComputableGroup,
aggregationType: AggregationType
): Report {
val options = Options(evolutionValues = Options.EvolutionValues.STANDARD)
if (aggregationType == AggregationType.DURATION) {
options.evolutionValues = Options.EvolutionValues.TIMED
}
return when (aggregationType) {
AggregationType.SESSION, AggregationType.DURATION -> this.computeGroups(realm, listOf(group), options)
AggregationType.MONTH -> {
val comparators: List<Comparator> = listOf(Comparator.YEAR, Comparator.MONTH_OF_YEAR)
this.computeStatsWithComparators(realm, comparators, group.conditions, options)
}
AggregationType.YEAR -> {
val comparators: List<Comparator> = listOf(Comparator.YEAR)
this.computeStatsWithComparators(realm, comparators, group.conditions, options)
}
}
}
fun computeStatsWithComparators(
realm: Realm,
comparators: List<Comparator> = listOf(),
conditions: List<QueryCondition> = listOf(),
options: Options
): Report {
val computableGroups: MutableList<ComputableGroup> = mutableListOf() val computableGroups: MutableList<ComputableGroup> = mutableListOf()
comparators.combined().forEach { comparatorConditions -> comparators.combined().forEach { comparatorConditions ->
@ -86,18 +118,6 @@ class Calculator {
return this.computeGroups(realm, computableGroups, options) return this.computeGroups(realm, computableGroups, options)
} }
fun computeStatsWithFilters(realm: Realm, filters: List<Filter>, options: Options): Report {
val computableGroups: MutableList<ComputableGroup> = mutableListOf()
filters.forEach { filter ->
val group = ComputableGroup(filter.name, filter.filterConditions.map { it.queryCondition })
computableGroups.add(group)
}
return Calculator.computeGroups(realm, computableGroups, options)
}
/** /**
* Computes all stats for list of Session sessionGroup * Computes all stats for list of Session sessionGroup
*/ */
@ -257,7 +277,12 @@ class Calculator {
Options.EvolutionValues.TIMED -> { Options.EvolutionValues.TIMED -> {
results.addEvolutionValue(tSum, tHourlyDuration, NETRESULT, sessionSet) results.addEvolutionValue(tSum, tHourlyDuration, NETRESULT, sessionSet)
results.addEvolutionValue(tHourlyRate, tHourlyDuration, HOURLY_RATE, sessionSet) results.addEvolutionValue(tHourlyRate, tHourlyDuration, HOURLY_RATE, sessionSet)
results.addEvolutionValue(tIndex.toDouble(), tHourlyDuration, NUMBER_OF_SETS, sessionSet) results.addEvolutionValue(
tIndex.toDouble(),
tHourlyDuration,
NUMBER_OF_SETS,
sessionSet
)
results.addEvolutionValue( results.addEvolutionValue(
sessionSet.netDuration.toDouble(), sessionSet.netDuration.toDouble(),
tHourlyDuration, tHourlyDuration,
@ -273,7 +298,12 @@ class Calculator {
results.addEvolutionValue(tHourlyRateBB, tHourlyDuration, HOURLY_RATE_BB, sessionSet) results.addEvolutionValue(tHourlyRateBB, tHourlyDuration, HOURLY_RATE_BB, sessionSet)
Stat.netBBPer100Hands(gBBSum, gTotalHands)?.let { netBB100 -> Stat.netBBPer100Hands(gBBSum, gTotalHands)?.let { netBB100 ->
results.addEvolutionValue(netBB100, tHourlyDuration, NET_BB_PER_100_HANDS, sessionSet) results.addEvolutionValue(
netBB100,
tHourlyDuration,
NET_BB_PER_100_HANDS,
sessionSet
)
} }
} }
} }

@ -30,7 +30,7 @@ import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.RowRepresentableEditDescriptor import net.pokeranalytics.android.ui.view.RowRepresentableEditDescriptor
import net.pokeranalytics.android.ui.view.RowViewType import net.pokeranalytics.android.ui.view.RowViewType
import net.pokeranalytics.android.ui.view.rowrepresentable.CustomizableRowRepresentable import net.pokeranalytics.android.ui.view.rowrepresentable.CustomizableRowRepresentable
import net.pokeranalytics.android.ui.view.rowrepresentable.SeparatorRowRepresentable import net.pokeranalytics.android.ui.view.rowrepresentable.SeparatorRow
import net.pokeranalytics.android.ui.view.rowrepresentable.SessionRow import net.pokeranalytics.android.ui.view.rowrepresentable.SessionRow
import net.pokeranalytics.android.util.NULL_TEXT import net.pokeranalytics.android.util.NULL_TEXT
import net.pokeranalytics.android.util.UserDefaults import net.pokeranalytics.android.util.UserDefaults
@ -584,7 +584,7 @@ open class Session : RealmObject(), Savable, Editable, StaticRowRepresentableDat
computedStat = ComputedStat(Stat.NETRESULT, result?.net ?: 0.0, currency) computedStat = ComputedStat(Stat.NETRESULT, result?.net ?: 0.0, currency)
) )
) )
rows.add(SeparatorRowRepresentable()) rows.add(SeparatorRow())
} }
SessionState.PAUSED -> { SessionState.PAUSED -> {
rows.add( rows.add(
@ -594,7 +594,7 @@ open class Session : RealmObject(), Savable, Editable, StaticRowRepresentableDat
computedStat = ComputedStat(Stat.NETRESULT, result?.net ?: 0.0, currency) computedStat = ComputedStat(Stat.NETRESULT, result?.net ?: 0.0, currency)
) )
) )
rows.add(SeparatorRowRepresentable()) rows.add(SeparatorRow())
} }
SessionState.FINISHED -> { SessionState.FINISHED -> {
rows.add( rows.add(
@ -621,7 +621,7 @@ open class Session : RealmObject(), Savable, Editable, StaticRowRepresentableDat
// ) // )
// ) // )
// } // }
rows.add(SeparatorRowRepresentable()) rows.add(SeparatorRow())
} }
else -> { else -> {
} }

@ -0,0 +1,54 @@
package net.pokeranalytics.android.ui.activity
import android.content.Context
import android.content.Intent
import android.os.Bundle
import net.pokeranalytics.android.R
import net.pokeranalytics.android.calculus.Report
import net.pokeranalytics.android.calculus.Stat
import net.pokeranalytics.android.ui.activity.components.PokerAnalyticsActivity
import net.pokeranalytics.android.ui.fragment.GraphParameters
class CalendarDetailsActivity : PokerAnalyticsActivity() {
private enum class IntentKey(val keyName: String) {
STAT("STAT"),
ENTRIES("ENTRIES"),
}
companion object {
// Unparcel fails when setting a custom Parcelable object on Entry so we use a static reference to passe objects
var parameters: GraphParameters? = null
/**
* Default constructor
*/
fun newInstance(context: Context) {
val intent = Intent(context, CalendarDetailsActivity::class.java)
context.startActivity(intent)
}
fun newInstance(context: Context, stat: Stat, report: Report) {
parameters = GraphParameters(stat, report)
val intent = Intent(context, CalendarDetailsActivity::class.java)
context.startActivity(intent)
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_calendar_details)
initUI()
}
/**
* Init UI
*/
private fun initUI() {
}
}

@ -0,0 +1,80 @@
package net.pokeranalytics.android.ui.fragment
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import com.github.mikephil.charting.data.Entry
import kotlinx.android.synthetic.main.fragment_calendar_details.*
import net.pokeranalytics.android.R
import net.pokeranalytics.android.calculus.Stat
import net.pokeranalytics.android.ui.activity.components.PokerAnalyticsActivity
import net.pokeranalytics.android.ui.fragment.components.PokerAnalyticsFragment
class CalendarDetailsFragment : PokerAnalyticsFragment() {
companion object {
fun newInstance(context: Context) {
val intent = Intent(context, CalendarDetailsFragment::class.java)
context.startActivity(intent)
}
}
private lateinit var parentActivity: PokerAnalyticsActivity
//private var stat: Stat = Stat.NETRESULT
//private var entries: List<Entry> = ArrayList()
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.fragment_calendar_details, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
initUI()
}
/**
* Init UI
*/
private fun initUI() {
parentActivity = activity as PokerAnalyticsActivity
// Avoid a bug during setting the title
toolbar.title = ""
parentActivity.setSupportActionBar(toolbar)
parentActivity.supportActionBar?.setDisplayHomeAsUpEnabled(true)
setHasOptionsMenu(true)
/*
toolbar.title = stat.localizedTitle(requireContext())
val fragmentManager = parentActivity.supportFragmentManager
val fragmentTransaction = fragmentManager.beginTransaction()
val fragment = GraphFragment()
fragmentTransaction.add(R.id.container, fragment)
fragmentTransaction.commit()
StatisticDetailsActivity.parameters?.let {
fragment.setData(it.stat, it.report)
StatisticDetailsActivity.parameters = null
} ?: run {
throw Exception("Missing graph parameters")
}
*/
}
/**
* Set data
*/
fun setData(stat: Stat, entries: List<Entry>) {
//this.stat = stat
//this.entries = entries
}
}

@ -18,6 +18,7 @@ import net.pokeranalytics.android.calculus.ComputedResults
import net.pokeranalytics.android.calculus.Stat import net.pokeranalytics.android.calculus.Stat
import net.pokeranalytics.android.model.comparison.Comparator import net.pokeranalytics.android.model.comparison.Comparator
import net.pokeranalytics.android.model.comparison.combined import net.pokeranalytics.android.model.comparison.combined
import net.pokeranalytics.android.ui.activity.CalendarDetailsActivity
import net.pokeranalytics.android.ui.adapter.RowRepresentableAdapter import net.pokeranalytics.android.ui.adapter.RowRepresentableAdapter
import net.pokeranalytics.android.ui.adapter.RowRepresentableDelegate import net.pokeranalytics.android.ui.adapter.RowRepresentableDelegate
import net.pokeranalytics.android.ui.adapter.StaticRowRepresentableDataSource import net.pokeranalytics.android.ui.adapter.StaticRowRepresentableDataSource
@ -35,8 +36,6 @@ import java.util.*
import kotlin.coroutines.CoroutineContext import kotlin.coroutines.CoroutineContext
class CalendarFragment : SessionObserverFragment(), CoroutineScope, StaticRowRepresentableDataSource, RowRepresentableDelegate { class CalendarFragment : SessionObserverFragment(), CoroutineScope, StaticRowRepresentableDataSource, RowRepresentableDelegate {
private enum class SessionType { private enum class SessionType {
@ -69,6 +68,7 @@ class CalendarFragment : SessionObserverFragment(), CoroutineScope, StaticRowRep
private var rows: ArrayList<CustomizableRowRepresentable> = ArrayList() private var rows: ArrayList<CustomizableRowRepresentable> = ArrayList()
private var sortedMonthlyReports: SortedMap<Date, ComputedResults> = HashMap<Date, ComputedResults>().toSortedMap() private var sortedMonthlyReports: SortedMap<Date, ComputedResults> = HashMap<Date, ComputedResults>().toSortedMap()
private var sortedYearlyReports: SortedMap<Date, ComputedResults> = HashMap<Date, ComputedResults>().toSortedMap() private var sortedYearlyReports: SortedMap<Date, ComputedResults> = HashMap<Date, ComputedResults>().toSortedMap()
private var datesForRows: HashMap<CustomizableRowRepresentable, Date> = HashMap()
private var currentSessionType = SessionType.ALL private var currentSessionType = SessionType.ALL
private var currentTimeFilter = TimeFilter.MONTH private var currentTimeFilter = TimeFilter.MONTH
@ -93,7 +93,8 @@ class CalendarFragment : SessionObserverFragment(), CoroutineScope, StaticRowRep
} }
override fun onRowSelected(position: Int, row: RowRepresentable, fromAction: Boolean) { override fun onRowSelected(position: Int, row: RowRepresentable, fromAction: Boolean) {
//toast("Open $row") Timber.d("Open ${datesForRows[row]}")
CalendarDetailsActivity.newInstance(requireContext())
} }
override fun sessionsChanged() { override fun sessionsChanged() {
@ -304,6 +305,7 @@ class CalendarFragment : SessionObserverFragment(), CoroutineScope, StaticRowRep
val startDate = Date() val startDate = Date()
datesForRows.clear()
rows.clear() rows.clear()
when (currentTimeFilter) { when (currentTimeFilter) {
@ -323,14 +325,16 @@ class CalendarFragment : SessionObserverFragment(), CoroutineScope, StaticRowRep
} }
sortedMonthlyReports[date]?.computedStat(currentStat)?.let { computedStat -> sortedMonthlyReports[date]?.computedStat(currentStat)?.let { computedStat ->
rows.add(
CustomizableRowRepresentable( val row = CustomizableRowRepresentable(
customViewType = RowViewType.TITLE_VALUE_ARROW, customViewType = RowViewType.TITLE_VALUE_ARROW,
title = date.getDateMonth(), title = date.getDateMonth(),
computedStat = computedStat, computedStat = computedStat,
isSelectable = true isSelectable = true
) )
)
rows.add(row)
datesForRows.put(row, date)
} }
} }
} }
@ -339,14 +343,15 @@ class CalendarFragment : SessionObserverFragment(), CoroutineScope, StaticRowRep
TimeFilter.YEAR -> { TimeFilter.YEAR -> {
sortedYearlyReports.keys.forEach { date -> sortedYearlyReports.keys.forEach { date ->
sortedYearlyReports[date]?.computedStat(currentStat)?.let { computedStat -> sortedYearlyReports[date]?.computedStat(currentStat)?.let { computedStat ->
rows.add( val row = CustomizableRowRepresentable(
CustomizableRowRepresentable(
customViewType = RowViewType.TITLE_VALUE_ARROW, customViewType = RowViewType.TITLE_VALUE_ARROW,
title = date.getDateYear(), title = date.getDateYear(),
computedStat = computedStat, computedStat = computedStat,
isSelectable = true isSelectable = true
) )
)
rows.add(row)
datesForRows.put(row, date)
} }
} }
} }

@ -16,7 +16,7 @@ import net.pokeranalytics.android.ui.adapter.StaticRowRepresentableDataSource
import net.pokeranalytics.android.ui.fragment.components.PokerAnalyticsFragment import net.pokeranalytics.android.ui.fragment.components.PokerAnalyticsFragment
import net.pokeranalytics.android.ui.view.RowRepresentable import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.RowViewType import net.pokeranalytics.android.ui.view.RowViewType
import net.pokeranalytics.android.ui.view.rowrepresentable.SeparatorRowRepresentable import net.pokeranalytics.android.ui.view.rowrepresentable.SeparatorRow
import java.util.* import java.util.*
class CurrenciesFragment : PokerAnalyticsFragment(), StaticRowRepresentableDataSource, RowRepresentableDelegate { class CurrenciesFragment : PokerAnalyticsFragment(), StaticRowRepresentableDataSource, RowRepresentableDelegate {
@ -28,7 +28,7 @@ class CurrenciesFragment : PokerAnalyticsFragment(), StaticRowRepresentableDataS
val rowRepresentation : List<RowRepresentable> by lazy { val rowRepresentation : List<RowRepresentable> by lazy {
val rows = ArrayList<RowRepresentable>() val rows = ArrayList<RowRepresentable>()
rows.addAll(mostUsedCurrencies) rows.addAll(mostUsedCurrencies)
rows.add(SeparatorRowRepresentable()) rows.add(SeparatorRow())
rows.addAll(availableCurrencies) rows.addAll(availableCurrencies)
rows rows
} }

@ -13,7 +13,9 @@ import com.github.mikephil.charting.highlight.Highlight
import com.github.mikephil.charting.listener.OnChartValueSelectedListener import com.github.mikephil.charting.listener.OnChartValueSelectedListener
import com.google.android.material.chip.Chip import com.google.android.material.chip.Chip
import com.google.android.material.chip.ChipGroup import com.google.android.material.chip.ChipGroup
import io.realm.Realm
import kotlinx.android.synthetic.main.fragment_evograph.* import kotlinx.android.synthetic.main.fragment_evograph.*
import kotlinx.coroutines.*
import net.pokeranalytics.android.R import net.pokeranalytics.android.R
import net.pokeranalytics.android.calculus.* import net.pokeranalytics.android.calculus.*
import net.pokeranalytics.android.ui.activity.components.PokerAnalyticsActivity import net.pokeranalytics.android.ui.activity.components.PokerAnalyticsActivity
@ -23,25 +25,32 @@ import net.pokeranalytics.android.ui.fragment.components.PokerAnalyticsFragment
import net.pokeranalytics.android.ui.graph.PALineDataSet import net.pokeranalytics.android.ui.graph.PALineDataSet
import net.pokeranalytics.android.ui.graph.setStyle import net.pokeranalytics.android.ui.graph.setStyle
import net.pokeranalytics.android.ui.view.LegendView import net.pokeranalytics.android.ui.view.LegendView
import timber.log.Timber
import java.text.DateFormat import java.text.DateFormat
import java.util.*
import kotlin.coroutines.CoroutineContext
class GraphParameters(var stat: Stat, var report: Report) { class GraphParameters(var stat: Stat, var report: Report) {
} }
class GraphFragment : PokerAnalyticsFragment(), OnChartValueSelectedListener { class GraphFragment : PokerAnalyticsFragment(), OnChartValueSelectedListener, CoroutineScope {
private lateinit var parentActivity: PokerAnalyticsActivity private lateinit var parentActivity: PokerAnalyticsActivity
private var stat: Stat = Stat.NETRESULT private var stat: Stat = Stat.NETRESULT
private var reports: Map<AggregationType, Report> = hashMapOf() private var reports: MutableMap<AggregationType, Report> = hashMapOf()
private var entries: List<Entry> = ArrayList()
private var selectedReport: Report? = null
lateinit var legendView: LegendView lateinit var legendView: LegendView
lateinit var chartView: BarLineChartBase<*> lateinit var chartView: BarLineChartBase<*>
private var aggregationTypes: List<AggregationType> = listOf() private var aggregationTypes: List<AggregationType> = listOf()
override val coroutineContext: CoroutineContext
get() = Dispatchers.Main
companion object { companion object {
} }
@ -50,10 +59,8 @@ class GraphFragment : PokerAnalyticsFragment(), OnChartValueSelectedListener {
this.stat = stat this.stat = stat
this.aggregationTypes = stat.aggregationTypes this.aggregationTypes = stat.aggregationTypes
// this.report = report this.reports[this.aggregationTypes.first()] = report
report.results.firstOrNull()?.defaultStatEntries(stat)?.let { this.selectedReport = report
this.entries = it
}
} }
@ -76,9 +83,78 @@ class GraphFragment : PokerAnalyticsFragment(), OnChartValueSelectedListener {
this.legendView = LegendView(requireContext()) this.legendView = LegendView(requireContext())
this.legendContainer.addView(this.legendView) this.legendContainer.addView(this.legendView)
this.legendView.prepareWithStat(this.stat, this.entries.size)
val dataSet = PALineDataSet(this.entries, this.stat.name, requireContext()) this.selectedReport?.let {
this.loadGraph(it)
}
this.aggregationTypes.forEach { type ->
val chip = Chip(requireContext())
chip.id = type.ordinal
chip.text = requireContext().getString(type.resId)
chip.chipStartPadding = 8f.px
chip.chipEndPadding = 8f.px
this.chipGroup.addView(chip)
}
this.chipGroup.check(this.stat.aggregationTypes.first().ordinal)
this.chipGroup.setOnCheckedChangeListener(object : ChipGroupExtension.SingleSelectionOnCheckedListener() {
override fun onCheckedChanged(group: ChipGroup, checkedId: Int) {
super.onCheckedChanged(group, checkedId)
val aggregationType = aggregationTypes[checkedId]
reports[aggregationType]?.let {
loadGraph(it)
} ?: run {
}
}
})
}
private fun launchStatComputation() {
GlobalScope.launch(coroutineContext) {
var r: Report? = null
val test = GlobalScope.async {
val s = Date()
Timber.d(">>> start...")
val realm = Realm.getDefaultInstance()
val aggregationType = stat.aggregationTypes.first()
// r = Calculator.computeStatsWithEvolutionByAggregationType(realm, computableGroup, aggregationType)
realm.close()
val e = Date()
val duration = (e.time - s.time) / 1000.0
Timber.d(">>> ended in $duration seconds")
}
test.await()
if (!isDetached) {
r?.let {
loadGraph(it)
}
}
}
}
fun loadGraph(report: Report) {
report.results.firstOrNull()?.defaultStatEntries(stat)?.let { entries ->
this.legendView.prepareWithStat(this.stat, entries.size)
val dataSet = PALineDataSet(entries, this.stat.name, requireContext())
val colors = arrayOf(R.color.green_light).toIntArray() val colors = arrayOf(R.color.green_light).toIntArray()
dataSet.setColors(colors, context) dataSet.setColors(colors, context)
dataSet.setDrawCircles(false) dataSet.setDrawCircles(false)
@ -101,26 +177,8 @@ class GraphFragment : PokerAnalyticsFragment(), OnChartValueSelectedListener {
this.chartView.setStyle(false, requireContext()) this.chartView.setStyle(false, requireContext())
this.chartView.setOnChartValueSelectedListener(this) this.chartView.setOnChartValueSelectedListener(this)
this.chartView.highlightValue((this.entries.size - 1).toFloat(), 0) this.chartView.highlightValue((entries.size - 1).toFloat(), 0)
this.aggregationTypes.forEach { type ->
val chip = Chip(requireContext())
chip.id = type.ordinal
chip.text = requireContext().getString(type.resId)
chip.chipStartPadding = 8f.px
chip.chipEndPadding = 8f.px
this.chipGroup.addView(chip)
}
this.chipGroup.check(this.stat.aggregationTypes.first().ordinal)
this.chipGroup.setOnCheckedChangeListener(object : ChipGroupExtension.SingleSelectionOnCheckedListener() {
override fun onCheckedChanged(group: ChipGroup, checkedId: Int) {
super.onCheckedChanged(group, checkedId)
val aggregationType = aggregationTypes[checkedId]
// toast("Show: ${this.aggregationTypes[group.getChildAt(checkedId).id].name}")
} }
})
} }
@ -133,7 +191,6 @@ class GraphFragment : PokerAnalyticsFragment(), OnChartValueSelectedListener {
override fun onValueSelected(e: Entry?, h: Highlight?) { override fun onValueSelected(e: Entry?, h: Highlight?) {
e?.let { entry -> e?.let { entry ->
h?.let { highlight ->
val identifier = entry.data as ObjectIdentifier val identifier = entry.data as ObjectIdentifier
val item = getRealm().where(identifier.clazz).equalTo("id", identifier.id).findAll().firstOrNull() val item = getRealm().where(identifier.clazz).equalTo("id", identifier.id).findAll().firstOrNull()
@ -145,7 +202,7 @@ class GraphFragment : PokerAnalyticsFragment(), OnChartValueSelectedListener {
this.legendView.setItemData(this.stat, formattedDate, entryValue, totalStatValue) this.legendView.setItemData(this.stat, formattedDate, entryValue, totalStatValue)
} }
}
} }
} }

@ -10,7 +10,7 @@ import kotlinx.android.synthetic.main.fragment_stats.*
import kotlinx.coroutines.* import kotlinx.coroutines.*
import net.pokeranalytics.android.R import net.pokeranalytics.android.R
import net.pokeranalytics.android.calculus.* import net.pokeranalytics.android.calculus.*
import net.pokeranalytics.android.model.StatRepresentable import net.pokeranalytics.android.ui.view.rowrepresentable.StatRow
import net.pokeranalytics.android.model.filter.QueryCondition import net.pokeranalytics.android.model.filter.QueryCondition
import net.pokeranalytics.android.ui.activity.StatisticDetailsActivity import net.pokeranalytics.android.ui.activity.StatisticDetailsActivity
import net.pokeranalytics.android.ui.adapter.DisplayDescriptor import net.pokeranalytics.android.ui.adapter.DisplayDescriptor
@ -74,7 +74,7 @@ class StatsFragment : SessionObserverFragment(), StaticRowRepresentableDataSourc
override fun contentDescriptorForRow(row: RowRepresentable): DisplayDescriptor? { override fun contentDescriptorForRow(row: RowRepresentable): DisplayDescriptor? {
val dc = DisplayDescriptor() val dc = DisplayDescriptor()
dc.textFormat = TextFormat(NULL_TEXT) dc.textFormat = TextFormat(NULL_TEXT)
if (row is StatRepresentable) { if (row is StatRow) {
context?.let { context -> context?.let { context ->
row.computedStat?.let { row.computedStat?.let {
dc.textFormat = it.format(context) dc.textFormat = it.format(context)
@ -85,7 +85,7 @@ class StatsFragment : SessionObserverFragment(), StaticRowRepresentableDataSourc
} }
override fun statFormatForRow(row: RowRepresentable): TextFormat { override fun statFormatForRow(row: RowRepresentable): TextFormat {
if (row is StatRepresentable) { if (row is StatRow) {
context?.let { context -> context?.let { context ->
row.computedStat?.let { return it.format(context) } row.computedStat?.let { return it.format(context) }
} }
@ -163,16 +163,38 @@ class StatsFragment : SessionObserverFragment(), StaticRowRepresentableDataSourc
private fun createSessionGroupsAndStartCompute(realm: Realm): Report { private fun createSessionGroupsAndStartCompute(realm: Realm): Report {
val allStats: List<Stat> = listOf(Stat.NETRESULT, Stat.HOURLY_RATE, Stat.AVERAGE, Stat.NUMBER_OF_SETS, Stat.AVERAGE_DURATION, Stat.DURATION) val allStats: List<Stat> = listOf(
Stat.NETRESULT,
Stat.HOURLY_RATE,
Stat.AVERAGE,
Stat.NUMBER_OF_SETS,
Stat.AVERAGE_DURATION,
Stat.DURATION
)
val allSessionGroup = ComputableGroup(stringAll, listOf(), allStats) val allSessionGroup = ComputableGroup(stringAll, listOf(), allStats)
val cgStats: List<Stat> = listOf(Stat.NETRESULT, 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 cgStats: List<Stat> = listOf(
Stat.NETRESULT,
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 cgSessionGroup = ComputableGroup(stringCashGame, listOf(QueryCondition.CASH), cgStats)
val tStats: List<Stat> = listOf(Stat.NETRESULT, Stat.HOURLY_RATE, Stat.ROI, Stat.WIN_RATIO, Stat.NUMBER_OF_GAMES, Stat.AVERAGE_BUYIN) val tStats: List<Stat> =
listOf(Stat.NETRESULT, Stat.HOURLY_RATE, Stat.ROI, Stat.WIN_RATIO, Stat.NUMBER_OF_GAMES, Stat.AVERAGE_BUYIN)
val tSessionGroup = ComputableGroup(stringTournament, listOf(QueryCondition.TOURNAMENT), tStats) val tSessionGroup = ComputableGroup(stringTournament, listOf(QueryCondition.TOURNAMENT), tStats)
Timber.d(">>>>> Start computations...") Timber.d(">>>>> Start computations...")
return Calculator.computeGroups(realm, listOf(allSessionGroup, cgSessionGroup, tSessionGroup), Calculator.Options()) return Calculator.computeGroups(
realm,
listOf(allSessionGroup, cgSessionGroup, tSessionGroup),
Calculator.Options()
)
} }
@ -188,7 +210,7 @@ class StatsFragment : SessionObserverFragment(), StaticRowRepresentableDataSourc
report.results.forEach { result -> report.results.forEach { result ->
rows.add(CustomizableRowRepresentable(title = result.group.name)) rows.add(CustomizableRowRepresentable(title = result.group.name))
result.group.stats?.forEach { stat -> result.group.stats?.forEach { stat ->
rows.add(StatRepresentable(stat, result.computedStat(stat), result.group.name)) rows.add(StatRow(stat, result.computedStat(stat), result.group.name))
} }
} }
@ -199,7 +221,7 @@ class StatsFragment : SessionObserverFragment(), StaticRowRepresentableDataSourc
override fun onRowSelected(position: Int, row: RowRepresentable, fromAction: Boolean) { override fun onRowSelected(position: Int, row: RowRepresentable, fromAction: Boolean) {
if (row is StatRepresentable && row.stat.hasEvolutionGraph) { if (row is StatRow && row.stat.hasEvolutionGraph) {
// filter groups // filter groups
val groupResults = this.report?.results?.filter { val groupResults = this.report?.results?.filter {
@ -223,10 +245,14 @@ class StatsFragment : SessionObserverFragment(), StaticRowRepresentableDataSourc
Timber.d(">>> start...") Timber.d(">>> start...")
val realm = Realm.getDefaultInstance() val realm = Realm.getDefaultInstance()
val options = Calculator.Options() // val options = Calculator.Options()
options.evolutionValues = Calculator.Options.EvolutionValues.STANDARD // options.evolutionValues = Calculator.Options.EvolutionValues.STANDARD
options.displayedStats = listOf(stat) // options.displayedStats = listOf(stat)
report = Calculator.computeGroups(realm, listOf(computableGroup), options)
val aggregationType = stat.aggregationTypes.first()
report = Calculator.computeStatsWithEvolutionByAggregationType(realm, computableGroup, aggregationType)
// report = Calculator.computeGroups(realm, listOf(computableGroup), options)
realm.close() realm.close()
val e = Date() val e = Date()

@ -13,7 +13,7 @@ import androidx.recyclerview.widget.RecyclerView
import kotlinx.android.synthetic.main.row_history_session.view.* import kotlinx.android.synthetic.main.row_history_session.view.*
import kotlinx.android.synthetic.main.row_transaction.view.* import kotlinx.android.synthetic.main.row_transaction.view.*
import net.pokeranalytics.android.R import net.pokeranalytics.android.R
import net.pokeranalytics.android.model.StatRepresentable import net.pokeranalytics.android.ui.view.rowrepresentable.StatRow
import net.pokeranalytics.android.model.realm.Session import net.pokeranalytics.android.model.realm.Session
import net.pokeranalytics.android.model.realm.Transaction import net.pokeranalytics.android.model.realm.Transaction
import net.pokeranalytics.android.ui.adapter.RowRepresentableAdapter import net.pokeranalytics.android.ui.adapter.RowRepresentableAdapter
@ -236,7 +236,7 @@ enum class RowViewType(private var layoutRes: Int) {
} }
} }
if (row is StatRepresentable) { if (row is StatRow) {
itemView.findViewById<AppCompatImageView?>(R.id.nextArrow)?.isVisible = row.stat.hasEvolutionGraph itemView.findViewById<AppCompatImageView?>(R.id.nextArrow)?.isVisible = row.stat.hasEvolutionGraph
} }

@ -6,6 +6,6 @@ import net.pokeranalytics.android.ui.view.RowViewType
/** /**
* A class to display separator as row representable * A class to display separator as row representable
*/ */
class SeparatorRowRepresentable(customViewType: RowViewType? = RowViewType.SEPARATOR) : RowRepresentable { class SeparatorRow(customViewType: RowViewType? = RowViewType.SEPARATOR) : RowRepresentable {
override val viewType: Int = customViewType?.ordinal ?: RowViewType.SEPARATOR.ordinal override val viewType: Int = customViewType?.ordinal ?: RowViewType.SEPARATOR.ordinal
} }

@ -68,7 +68,7 @@ enum class SessionRow : RowRepresentable {
POSITION, POSITION,
PLAYERS, PLAYERS,
TIPS, TIPS,
SeparatorRowRepresentable(), SeparatorRow(),
GAME, GAME,
INITIAL_BUY_IN, INITIAL_BUY_IN,
LOCATION, LOCATION,
@ -77,7 +77,7 @@ enum class SessionRow : RowRepresentable {
TOURNAMENT_TYPE, TOURNAMENT_TYPE,
TOURNAMENT_NAME, TOURNAMENT_NAME,
TOURNAMENT_FEATURE, TOURNAMENT_FEATURE,
SeparatorRowRepresentable(), SeparatorRow(),
START_DATE, START_DATE,
END_DATE, END_DATE,
BREAK_TIME, BREAK_TIME,
@ -98,7 +98,7 @@ enum class SessionRow : RowRepresentable {
CASHED_OUT, CASHED_OUT,
BUY_IN, BUY_IN,
TIPS, TIPS,
SeparatorRowRepresentable(), SeparatorRow(),
GAME, GAME,
BLINDS, BLINDS,
LOCATION, LOCATION,
@ -112,7 +112,7 @@ enum class SessionRow : RowRepresentable {
} else { } else {
arrayListOf( arrayListOf(
NET_RESULT, NET_RESULT,
SeparatorRowRepresentable(), SeparatorRow(),
GAME, GAME,
BLINDS, BLINDS,
LOCATION, LOCATION,

@ -1,4 +1,4 @@
package net.pokeranalytics.android.model package net.pokeranalytics.android.ui.view.rowrepresentable
import net.pokeranalytics.android.calculus.ComputedStat import net.pokeranalytics.android.calculus.ComputedStat
import net.pokeranalytics.android.calculus.Stat import net.pokeranalytics.android.calculus.Stat
@ -6,7 +6,7 @@ import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.RowViewType import net.pokeranalytics.android.ui.view.RowViewType
class StatRepresentable(stat: Stat, computedStat: ComputedStat?, groupName: String = "") : RowRepresentable { class StatRow(stat: Stat, computedStat: ComputedStat?, groupName: String = "") : RowRepresentable {
var stat: Stat = stat var stat: Stat = stat
var computedStat: ComputedStat? = computedStat var computedStat: ComputedStat? = computedStat

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical">
<fragment
android:id="@+id/calendarDetailsFragment"
android:name="net.pokeranalytics.android.ui.fragment.CalendarDetailsFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:layout="@layout/fragment_statistic_details" />
</LinearLayout>

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:title="@string/app_name" />
<FrameLayout
android:id="@+id/container"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/toolbar" />
</androidx.constraintlayout.widget.ConstraintLayout>
Loading…
Cancel
Save