Merge branch 'dev' of gitlab.com:stax-river/poker-analytics into dev

feature/top10
Aurelien Hubert 7 years ago
commit 9906626d80
  1. 15
      app/src/main/java/net/pokeranalytics/android/calculus/Calculator.kt
  2. 86
      app/src/main/java/net/pokeranalytics/android/calculus/Report.kt
  3. 18
      app/src/main/java/net/pokeranalytics/android/calculus/Stat.kt
  4. 4
      app/src/main/java/net/pokeranalytics/android/ui/fragment/CalendarDetailsFragment.kt
  5. 123
      app/src/main/java/net/pokeranalytics/android/ui/fragment/GraphFragment.kt
  6. 7
      app/src/main/java/net/pokeranalytics/android/ui/graph/ChartDataSet.kt
  7. 43
      app/src/main/java/net/pokeranalytics/android/ui/view/RowViewType.kt
  8. 2
      app/src/main/java/net/pokeranalytics/android/util/FakeDataManager.kt

@ -177,7 +177,7 @@ class Calculator {
results.computeStatVariations(comparedResults)
}
if (options.shouldManageMultiGroupProgressValues == true) {
if (options.shouldManageMultiGroupProgressValues) {
group.comparedComputedResults = report.results.lastOrNull()
}
@ -268,15 +268,15 @@ class Calculator {
// Iterate for each session
if (shouldIterateOverComputables) {
var index: Int = 0
var index = 0
var tSum = 0.0
var tBBSum = 0.0
var tBBSessionCount = 0
var tWinningSessionCount = 0
var tBuyinSum = 0.0
var tHands = 0.0
var longestWinStreak = 0;
var longestLoseStreak = 0;
var longestWinStreak = 0
var longestLoseStreak = 0
var currentStreak = 0
computables.forEach { computable ->
@ -316,6 +316,7 @@ class Calculator {
data = session
)
results.addEvolutionValue(tBuyinSum / index, stat = AVERAGE_BUYIN, data = session)
results.addEvolutionValue(computable.ratedNet, stat = STANDARD_DEVIATION, data = session)
Stat.netBBPer100Hands(tBBSum, tHands)?.let { netBB100 ->
results.addEvolutionValue(netBB100, stat = NET_BB_PER_100_HANDS, data = session)
@ -355,7 +356,7 @@ class Calculator {
}
}
val shouldIterateOverSets = computableGroup.conditions.size > 0 ||
val shouldIterateOverSets = computableGroup.conditions.isNotEmpty() ||
options.evolutionValues != Options.EvolutionValues.NONE ||
options.computeDaysPlayed
@ -366,8 +367,8 @@ class Calculator {
var tRatedNetSum = 0.0
var tBBSum = 0.0
var tTotalHands = 0.0
var tHourlyRate = 0.0
var tHourlyRateBB = 0.0
var tHourlyRate: Double
var tHourlyRateBB: Double
val daysSet = mutableSetOf<Date>()
var tMaxDuration = 0.0

@ -1,15 +1,17 @@
package net.pokeranalytics.android.calculus
import android.content.Context
import com.github.mikephil.charting.data.BarEntry
import com.github.mikephil.charting.data.Entry
import com.github.mikephil.charting.data.*
import io.realm.Realm
import io.realm.RealmResults
import net.pokeranalytics.android.R
import net.pokeranalytics.android.model.filter.QueryCondition
import net.pokeranalytics.android.model.interfaces.Timed
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.ui.graph.PALineDataSet
import kotlin.math.abs
/**
* The class returned after performing calculation in the Calculator object
@ -34,7 +36,7 @@ class Report(var options: Calculator.Options) {
* Returns the list of entries corresponding to the provided [stat]
* One value will be returned by result
*/
fun lineEntries(stat: Stat): List<Entry> {
fun lineEntries(stat: Stat, context: Context): LineDataSet {
val entries = mutableListOf<Entry>()
this._results.forEachIndexed { index, results ->
@ -42,11 +44,11 @@ class Report(var options: Calculator.Options) {
entries.add(Entry(index.toFloat(), progressValue.toFloat(), results))
}
}
return entries
return PALineDataSet(entries, stat.name, context)
}
fun barEntries(stat: Stat? = null): List<Entry> {
val entries = mutableListOf<Entry>()
fun barEntries(stat: Stat? = null): BarDataSet {
val entries = mutableListOf<BarEntry>()
val statToUse = stat ?: options.displayedStats.firstOrNull()
statToUse?.let {
@ -59,16 +61,16 @@ class Report(var options: Calculator.Options) {
}
}
return entries
return BarDataSet(entries, stat?.name)
}
fun multiLineEntries(): List<List<Entry>> {
fun multiLineEntries(context: Context): List<List<Entry>> {
val entries = mutableListOf<List<Entry>>()
options.displayedStats.forEach { stat ->
this._results.forEach { result ->
val entryList = result.singleLineEntries(stat)
entries.add(entryList)
val dataSet = result.singleLineEntries(stat, context)
// entries.add(entryList)
}
}
@ -328,48 +330,39 @@ class ComputedResults(group: ComputableGroup, shouldManageMultiGroupProgressValu
this.consolidateProgressStats()
if (options.evolutionValues != Calculator.Options.EvolutionValues.NONE) {
// Sort points as a distribution
this._computedStats.keys.filter { it.hasDistributionSorting() }.forEach { _ ->
// @todo sort
// var evolutionValues = this._evolutionValues[stat]
// evolutionValues.so
}
}
}
// MPAndroidChart
fun defaultStatEntries(stat: Stat): List<Entry> {
fun defaultStatEntries(stat: Stat, context: Context): DataSet<out Entry> {
return when (stat) {
Stat.NUMBER_OF_SETS, Stat.NUMBER_OF_GAMES -> this.barEntries(stat)
else -> this.singleLineEntries(stat)
Stat.STANDARD_DEVIATION -> this.distributionEntries(stat, context)
else -> this.singleLineEntries(stat, context)
}
}
fun singleLineEntries(stat: Stat): List<Entry> {
fun singleLineEntries(stat: Stat, context: Context): LineDataSet {
val entries = mutableListOf<Entry>()
this._evolutionValues[stat]?.let { points ->
points.forEachIndexed { index, p ->
entries.add(Entry(index.toFloat(), p.y.toFloat(), p.data))
}
}
return entries
return PALineDataSet(entries, stat.name, context)
}
fun durationEntries(stat: Stat): List<Entry> {
fun durationEntries(stat: Stat, context: Context): LineDataSet {
val entries = mutableListOf<Entry>()
this._evolutionValues[stat]?.let { points ->
points.forEach { p ->
entries.add(Entry(p.x.toFloat(), p.y.toFloat(), p.data))
}
}
return entries
return PALineDataSet(entries, stat.name, context)
}
fun barEntries(stat: Stat): List<BarEntry> {
fun barEntries(stat: Stat): BarDataSet {
val entries = mutableListOf<BarEntry>()
this._evolutionValues[stat]?.let { points ->
@ -377,7 +370,44 @@ class ComputedResults(group: ComputableGroup, shouldManageMultiGroupProgressValu
entries.add(BarEntry(p.x.toFloat(), p.y.toFloat(), p.data))
}
}
return entries
val dataSet = BarDataSet(entries, stat.name)
dataSet.setDrawValues(false)
return dataSet
}
fun distributionEntries(stat: Stat, context: Context): BarDataSet {
val colors = mutableListOf<Int>()
val entries = mutableListOf<BarEntry>()
this._evolutionValues[stat]?.let { points ->
val negative = mutableListOf<Point>()
val positive = mutableListOf<Point>()
points.sortByDescending { it.y }
points.forEach {
if (it.y < 0) {
negative.add(it)
} else {
positive.add(it)
}
}
negative.forEachIndexed { index, p ->
entries.add(BarEntry(index.toFloat(), abs(p.y.toFloat()), p.data))
colors.add(context.getColor(R.color.red))
}
positive.forEachIndexed { index, p ->
val x = negative.size + index.toFloat()
entries.add(BarEntry(x, p.y.toFloat(), p.data))
colors.add(context.getColor(R.color.green))
}
}
val dataSet = BarDataSet(entries, stat.name)
dataSet.colors = colors
dataSet.setDrawValues(false)
return dataSet
}
val isEmpty: Boolean

@ -94,16 +94,6 @@ enum class Stat : RowRepresentable {
TOTAL_BUYIN,
;
/**
* Returns whether the stat evolution numericValues requires a distribution sorting
*/
fun hasDistributionSorting(): Boolean {
return when (this) {
STANDARD_DEVIATION, STANDARD_DEVIATION_HOURLY, STANDARD_DEVIATION_BB_PER_100_HANDS -> true
else -> false
}
}
companion object {
fun returnOnInvestment(netResult: Double, buyin: Double): Double? {
@ -224,14 +214,6 @@ enum class Stat : RowRepresentable {
}
}
val graphType: GraphType
get() {
return when (this) {
NUMBER_OF_SETS, NUMBER_OF_GAMES -> GraphType.BAR
else -> GraphType.LINE
}
}
val aggregationTypes: List<AggregationType>
get() {
return when (this) {

@ -187,10 +187,10 @@ class CalendarDetailsFragment : PokerAnalyticsFragment(), StaticRowRepresentable
rowRepresentables.add(StatDoubleRow(it.computedStat(Stat.NET_RESULT), it.computedStat(Stat.HOURLY_RATE)))
rowRepresentables.add(StatDoubleRow(it.computedStat(Stat.LOCATIONS_PLAYED), it.computedStat(Stat.LONGEST_STREAKS)))
rowRepresentables.add(CustomizableRowRepresentable(RowViewType.HEADER_TITLE, resId = R.string.distribution))
rowRepresentables.add(GraphRow(report, Stat.NET_RESULT))
rowRepresentables.add(GraphRow(report, Stat.STANDARD_DEVIATION))
rowRepresentables.add(StatDoubleRow(it.computedStat(Stat.WIN_RATIO), it.computedStat(Stat.MAXIMUM_NETRESULT)))
rowRepresentables.add(CustomizableRowRepresentable(RowViewType.HEADER_TITLE, resId = R.string.volume))
rowRepresentables.add(GraphRow(report, Stat.NET_RESULT))
rowRepresentables.add(GraphRow(report, Stat.DURATION))
rowRepresentables.add(StatDoubleRow(it.computedStat(Stat.DURATION), it.computedStat(Stat.AVERAGE_DURATION)))
rowRepresentables.add(StatDoubleRow(it.computedStat(Stat.DAYS_PLAYED), it.computedStat(Stat.MAXIMUM_DURATION)))
}

@ -17,7 +17,6 @@ import net.pokeranalytics.android.R
import net.pokeranalytics.android.calculus.*
import net.pokeranalytics.android.ui.activity.components.PokerAnalyticsActivity
import net.pokeranalytics.android.ui.fragment.components.PokerAnalyticsFragment
import net.pokeranalytics.android.ui.graph.PALineDataSet
import net.pokeranalytics.android.ui.graph.setStyle
import net.pokeranalytics.android.ui.view.LegendView
import kotlin.coroutines.CoroutineContext
@ -46,7 +45,7 @@ class GraphFragment : PokerAnalyticsFragment(), OnChartValueSelectedListener, Co
private lateinit var parentActivity: PokerAnalyticsActivity
private lateinit var selectedReport: Report
private lateinit var legendView: LegendView
private lateinit var chartView: BarLineChartBase<*>
private var chartView: BarLineChartBase<*>? = null
private var stat: Stat = Stat.NET_RESULT
private var aggregationType: AggregationType = AggregationType.SESSION
@ -65,33 +64,20 @@ class GraphFragment : PokerAnalyticsFragment(), OnChartValueSelectedListener, Co
loadGraph()
}
// OnChartValueSelectedListener
override fun onNothingSelected() {
// nothing to do
}
override fun onValueSelected(e: Entry?, h: Highlight?) {
e?.let { entry ->
val statEntry = when (entry.data) {
is ObjectIdentifier -> {
val identifier = entry.data as ObjectIdentifier
getRealm().where(identifier.clazz).equalTo("id", identifier.id).findAll().firstOrNull()
}
is StatEntry -> entry.data as StatEntry?
else -> null
}
statEntry?.let {
/**
* Set data
*/
fun setData(report: Report, stat: Stat, aggregationType: AggregationType) {
val formattedDate = it.entryTitle
val entryValue = it.formattedValue(this.stat, requireContext())
val totalStatValue = this.stat.format(entry.y.toDouble(), currency = null)
this.selectedReport = report
this.aggregationType = aggregationType
this.stat = stat
this.legendView.setItemData(this.stat, formattedDate, entryValue, totalStatValue)
}
if (isAdded && !isDetached) {
loadGraph()
}
}
/**
* Init UI
*/
@ -103,14 +89,6 @@ class GraphFragment : PokerAnalyticsFragment(), OnChartValueSelectedListener, Co
this.legendView = LegendView(requireContext())
this.legendContainer.addView(this.legendView)
this.chartView = when (stat.graphType) {
GraphType.LINE -> LineChart(context)
GraphType.BAR -> BarChart(context)
}
val axisFormatting = aggregationType.axisFormatting
this.chartView.setStyle(false, axisFormatting, requireContext())
this.chartContainer.addView(this.chartView)
}
/**
@ -118,38 +96,41 @@ class GraphFragment : PokerAnalyticsFragment(), OnChartValueSelectedListener, Co
*/
private fun loadGraph() {
val graphEntries = when (aggregationType) {
AggregationType.SESSION -> selectedReport.results.firstOrNull()?.defaultStatEntries(stat)
val ds = when (aggregationType) {
AggregationType.SESSION -> selectedReport.results.firstOrNull()?.defaultStatEntries(stat, requireContext())
AggregationType.DURATION -> {
selectedReport.results.firstOrNull()?.durationEntries(stat)
selectedReport.results.firstOrNull()?.durationEntries(stat, requireContext())
}
AggregationType.MONTH, AggregationType.YEAR -> {
when (this.stat) {
Stat.NUMBER_OF_GAMES, Stat.NUMBER_OF_SETS -> selectedReport.barEntries(this.stat)
else -> selectedReport.lineEntries(this.stat)
else -> selectedReport.lineEntries(this.stat, requireContext())
}
}
}
graphEntries?.let { entries ->
ds?.let { dataSet ->
this.legendView.prepareWithStat(this.stat, entries.size)
this.legendView.prepareWithStat(this.stat, dataSet.entryCount)
when (stat.graphType) {
GraphType.LINE -> {
val lineChart: LineChart = this.chartView as LineChart
// initialize chart
if (this.chartView == null) {
this.chartView = when (dataSet) {
is LineDataSet -> LineChart(context)
is BarDataSet -> BarChart(context)
else -> null
}
this.chartContainer.addView(this.chartView)
}
val dataSet = PALineDataSet(entries, this.stat.name, requireContext())
val colors = arrayOf(R.color.green_light).toIntArray()
dataSet.setColors(colors, context)
dataSet.setDrawCircles(false)
when (dataSet) {
is LineDataSet -> {
val lineChart: LineChart = this.chartView as LineChart
val lineData = LineData(listOf(dataSet))
lineChart.data = lineData
}
GraphType.BAR -> {
is BarDataSet -> {
val barChart = this.chartView as BarChart
val dataSet = BarDataSet(entries as List<BarEntry>, this.stat.name)
val colors = arrayOf(R.color.green_light).toIntArray()
dataSet.setColors(colors, context)
val barData = BarData(listOf(dataSet))
@ -158,26 +139,48 @@ class GraphFragment : PokerAnalyticsFragment(), OnChartValueSelectedListener, Co
}
val axisFormatting = aggregationType.axisFormatting
this.chartView.setStyle(false, axisFormatting, requireContext())
this.chartView.setOnChartValueSelectedListener(this)
this.chartView.highlightValue((entries.size - 1).toFloat(), 0)
this.chartView?.let {
it.setStyle(false, axisFormatting, requireContext())
it.setOnChartValueSelectedListener(this)
}
this.selectValue(dataSet.getEntryForIndex(dataSet.entryCount - 1))
}
}
/**
* Set data
*/
fun setData(report: Report, stat: Stat, aggregationType: AggregationType) {
// OnChartValueSelectedListener
override fun onNothingSelected() {
// nothing to do
}
this.selectedReport = report
this.aggregationType = aggregationType
this.stat = stat
override fun onValueSelected(e: Entry?, h: Highlight?) {
e?.let { entry ->
this.selectValue(entry)
}
}
if (isAdded && !isDetached) {
loadGraph()
private fun selectValue(entry: Entry) {
val statEntry = when (entry.data) {
is ObjectIdentifier -> {
val identifier = entry.data as ObjectIdentifier
getRealm().where(identifier.clazz).equalTo("id", identifier.id).findAll().firstOrNull()
}
is StatEntry -> entry.data as StatEntry?
else -> null
}
statEntry?.let {
val formattedDate = it.entryTitle
val entryValue = it.formattedValue(this.stat, requireContext())
val totalStatValue = this.stat.format(entry.y.toDouble(), currency = null)
this.legendView.setItemData(this.stat, formattedDate, entryValue, totalStatValue)
}
}
}

@ -10,10 +10,17 @@ class PALineDataSet(yVals: List<Entry>, label: String, context: Context) : LineD
init {
this.highLightColor = context.getColor(R.color.chart_highlight_indicator)
this.setDrawValues(false)
this.setDrawCircles(false)
val colors = arrayOf(R.color.green_light).toIntArray()
this.setColors(colors, context)
}
}
//class PABarDataSet(yVals: List<BarEntry>, label: String, context: Context) : BarDataSet(yVals, label) {
//
// init {

@ -13,17 +13,18 @@ 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 kotlinx.android.synthetic.main.row_history_session.view.*
import kotlinx.android.synthetic.main.row_transaction.view.*
import net.pokeranalytics.android.R
import net.pokeranalytics.android.calculus.GraphType
import net.pokeranalytics.android.model.realm.Session
import net.pokeranalytics.android.model.realm.Transaction
import net.pokeranalytics.android.ui.adapter.RowRepresentableAdapter
import net.pokeranalytics.android.ui.extensions.setTextFormat
import net.pokeranalytics.android.ui.graph.AxisFormatting
import net.pokeranalytics.android.ui.graph.PALineDataSet
import net.pokeranalytics.android.ui.graph.setStyle
import net.pokeranalytics.android.ui.view.rowrepresentable.CustomizableRowRepresentable
import net.pokeranalytics.android.ui.view.rowrepresentable.GraphRow
@ -149,9 +150,7 @@ enum class RowViewType(private var layoutRes: Int) {
val listener = View.OnClickListener {
adapter.delegate?.onRowSelected(position, row)
}
itemView.findViewById<View?>(R.id.container)?.let {
it.setOnClickListener(listener)
}
itemView.findViewById<View?>(R.id.container)?.setOnClickListener(listener)
}
}
@ -189,9 +188,7 @@ enum class RowViewType(private var layoutRes: Int) {
}
}
itemView.findViewById<View?>(R.id.container)?.let {
it.setOnClickListener(listener)
}
itemView.findViewById<View?>(R.id.container)?.setOnClickListener(listener)
}
// Switch
@ -318,31 +315,24 @@ enum class RowViewType(private var layoutRes: Int) {
BindableHolder {
override fun bind(position: Int, row: RowRepresentable, adapter: RowRepresentableAdapter) {
//TODO: Implementation
if (row is GraphRow) {
row.report.results.firstOrNull()?.defaultStatEntries(row.stat)?.let { entries ->
row.report.results.firstOrNull()?.defaultStatEntries(row.stat, itemView.context)?.let { dataSet ->
val context = itemView.context
val dataSet = PALineDataSet(entries, row.stat.name, context)
val colors = arrayOf(R.color.green_light).toIntArray()
dataSet.setColors(colors, context)
dataSet.setDrawCircles(false)
dataSet.setDrawValues(false)
val lineData = LineData(listOf(dataSet))
val chartView = when (row.stat.graphType) {
GraphType.LINE -> {
val chartView = when (dataSet) {
is LineDataSet -> {
val lineChart = LineChart(context)
lineChart.data = lineData
lineChart.data = LineData(dataSet)
lineChart
}
GraphType.BAR -> {
is BarDataSet -> {
val barChart = BarChart(context)
barChart.data = BarData(dataSet)
barChart
}
else -> null
}
itemView.findViewById<FrameLayout?>(R.id.chartContainer)?.let {
@ -350,9 +340,12 @@ enum class RowViewType(private var layoutRes: Int) {
it.addView(chartView)
}
chartView.setStyle(true, AxisFormatting.DEFAULT, context)
chartView.setTouchEnabled(false)
chartView.highlightValue((entries.size - 1).toFloat(), 0)
chartView?.let {
chartView.setStyle(true, AxisFormatting.DEFAULT, context)
chartView.setTouchEnabled(false)
}
// chartView.highlightValue((entries.size - 1).toFloat(), 0)
}
}

@ -77,7 +77,7 @@ class FakeDataManager {
session.result?.let { result ->
val buyin = buyinList.random()
result.buyin = buyinList.random()
result.netResult = resultsList.random() + buyin
result.cashout = resultsList.random() + buyin
}
}

Loading…
Cancel
Save