Improvements

powerreport
Laurent 3 years ago
parent af1024c7bc
commit f5115e53e4
  1. 11
      app/src/main/java/net/pokeranalytics/android/calculus/Calculator.kt
  2. 69
      app/src/main/java/net/pokeranalytics/android/calculus/ReportWhistleBlower.kt
  3. 2
      app/src/main/java/net/pokeranalytics/android/calculus/Stat.kt
  4. 297
      app/src/main/java/net/pokeranalytics/android/calculus/optimalduration/CashGameOptimalDurationCalculator.kt
  5. 38
      app/src/main/java/net/pokeranalytics/android/model/LiveOnline.kt
  6. 2
      app/src/main/java/net/pokeranalytics/android/model/extensions/SessionExtensions.kt
  7. 2
      app/src/main/java/net/pokeranalytics/android/model/migrations/PokerAnalyticsMigration.kt
  8. 24
      app/src/main/java/net/pokeranalytics/android/model/realm/Performance.kt
  9. 8
      app/src/main/java/net/pokeranalytics/android/ui/fragment/ReportsFragment.kt
  10. 5
      app/src/main/java/net/pokeranalytics/android/ui/modules/session/SessionFragment.kt
  11. 7
      app/src/main/java/net/pokeranalytics/android/ui/view/RowViewType.kt
  12. 11
      app/src/main/java/net/pokeranalytics/android/ui/view/rows/StaticReport.kt

@ -241,6 +241,11 @@ class Calculator {
val results = ComputedResults(computableGroup, options.shouldManageMultiGroupProgressValues) val results = ComputedResults(computableGroup, options.shouldManageMultiGroupProgressValues)
val computables = computableGroup.computables(realm, options.shouldSortValues) val computables = computableGroup.computables(realm, options.shouldSortValues)
if (computables.size == 0) { // we don't want to return stats with 0 as a value when comparing best performances
return results
}
// Timber.d("#### Start computing group, ${computables.size} computables") // Timber.d("#### Start computing group, ${computables.size} computables")
results.addStat(NUMBER_OF_GAMES, computables.size.toDouble()) results.addStat(NUMBER_OF_GAMES, computables.size.toDouble())
// computables.forEach { // computables.forEach {
@ -606,10 +611,10 @@ class SSStats(sessionSet: SessionSet, query: Query) { // Session Set Stats
if (setSessions.size == filteredSessions.size) { if (setSessions.size == filteredSessions.size) {
this.initStatsWithSet(sessionSet) this.initStatsWithSet(sessionSet)
} else { } else {
ratedNet = filteredSessions.sumByDouble { it.computableResult?.ratedNet ?: 0.0 } ratedNet = filteredSessions.sumOf { it.computableResult?.ratedNet ?: 0.0 }
bbSum = filteredSessions.sumByDouble { it.bbNet } bbSum = filteredSessions.sumOf { it.bbNet }
hourlyDuration = filteredSessions.hourlyDuration hourlyDuration = filteredSessions.hourlyDuration
estimatedHands = filteredSessions.sumByDouble { it.estimatedHands } estimatedHands = filteredSessions.sumOf { it.estimatedHands }
} }
} }
} }

@ -7,11 +7,15 @@ import io.realm.RealmResults
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import net.pokeranalytics.android.calculus.optimalduration.CashGameOptimalDurationCalculator
import net.pokeranalytics.android.model.LiveOnline
import net.pokeranalytics.android.model.realm.CustomField import net.pokeranalytics.android.model.realm.CustomField
import net.pokeranalytics.android.model.realm.Performance import net.pokeranalytics.android.model.realm.Performance
import net.pokeranalytics.android.model.realm.Result import net.pokeranalytics.android.model.realm.Result
import net.pokeranalytics.android.model.realm.Session import net.pokeranalytics.android.model.realm.Session
import net.pokeranalytics.android.ui.fragment.PerformanceKey
import net.pokeranalytics.android.ui.view.rows.StaticReport import net.pokeranalytics.android.ui.view.rows.StaticReport
import net.pokeranalytics.android.util.extensions.formattedHourlyDuration
import timber.log.Timber import timber.log.Timber
import kotlin.coroutines.CoroutineContext import kotlin.coroutines.CoroutineContext
@ -137,21 +141,28 @@ class ReportTask(private var whistleBlower: ReportWhistleBlower, var context: Co
Timber.d(">>> launch report = $report") Timber.d(">>> launch report = $report")
when (report) {
StaticReport.OptimalDuration -> launchOptimalDuration(realm, report)
else -> launchDefaultReport(realm, report)
}
}
private fun launchDefaultReport(realm: Realm, report: StaticReport) {
val options = Calculator.Options( val options = Calculator.Options(
stats = report.stats, stats = report.stats,
criterias = report.criteria criterias = report.criteria
) )
val result = Calculator.computeStats(realm, options = options) val result = Calculator.computeStats(realm, options = options)
analyseReport(realm, report, result) analyseDefaultReport(realm, report, result)
} }
private fun analyseReport(realm: Realm, staticReport: StaticReport, result: Report) { private fun launchOptimalDuration(realm: Realm, report: StaticReport) {
LiveOnline.values().forEach { key ->
when (staticReport.uniqueIdentifier) { val duration = CashGameOptimalDurationCalculator.start(key.isLive)
StaticReport.OptimalDuration.uniqueIdentifier -> analyseOptimalDuration(staticReport, result) duration?.let {
else -> analyseDefaultReport(realm, staticReport, result) analyseOptimalDuration(realm, report, key, it)
}
} }
} }
@ -166,7 +177,7 @@ class ReportTask(private var whistleBlower: ReportWhistleBlower, var context: Co
val customField: CustomField? = val customField: CustomField? =
(staticReport as? StaticReport.CustomFieldList)?.customField (staticReport as? StaticReport.CustomFieldList)?.customField
var query = realm.where(Performance::class.java) var query = realm.where(Performance::class.java)
.equalTo("statId", stat.uniqueIdentifier) .equalTo("key", stat.uniqueIdentifier)
.equalTo("reportId", staticReport.uniqueIdentifier) .equalTo("reportId", staticReport.uniqueIdentifier)
customField?.let { customField?.let {
@ -174,15 +185,16 @@ class ReportTask(private var whistleBlower: ReportWhistleBlower, var context: Co
} }
val currentPerf = query.findFirst() val currentPerf = query.findFirst()
val performanceQuery = computedResults.group.query
val performanceName = performanceQuery.getName(this.context, " ")
var storePerf = true var storePerf = true
currentPerf?.let { currentPerf?.let {
Timber.d("cr name = ${computedResults.group.query.getName(this.context)}")
currentPerf.name?.let { currentPerf.name?.let {
if (computedResults.group.query.defaultName == it) { if (computedResults.group.query.defaultName == it) {
storePerf = false storePerf = false
} }
} }
Timber.d("cr objectId = ${computedResults.group.query.objectId}")
currentPerf.objectId?.let { currentPerf.objectId?.let {
if (computedResults.group.query.objectId == it) { if (computedResults.group.query.objectId == it) {
storePerf = false storePerf = false
@ -191,8 +203,8 @@ class ReportTask(private var whistleBlower: ReportWhistleBlower, var context: Co
if (storePerf) { if (storePerf) {
realm.executeTransaction { realm.executeTransaction {
currentPerf.name = computedResults.group.query.getName(this.context) currentPerf.name = performanceName
currentPerf.objectId = computedResults.group.query.objectId currentPerf.objectId = performanceQuery.objectId
currentPerf.customFieldId = customField?.id currentPerf.customFieldId = customField?.id
} }
this.whistleBlower.notify(currentPerf) this.whistleBlower.notify(currentPerf)
@ -204,8 +216,8 @@ class ReportTask(private var whistleBlower: ReportWhistleBlower, var context: Co
val performance = Performance( val performance = Performance(
staticReport, staticReport,
stat, stat,
computedResults.group.query.getName(this.context), performanceName,
computedResults.group.query.objectId, performanceQuery.objectId,
customField?.id, customField?.id,
null null
) )
@ -219,7 +231,34 @@ class ReportTask(private var whistleBlower: ReportWhistleBlower, var context: Co
} }
private fun analyseOptimalDuration(staticReport: StaticReport, result: Report) { private fun analyseOptimalDuration(realm: Realm, staticReport: StaticReport, key: PerformanceKey, duration: Double) {
var storePerf: Boolean = true
val performance = realm.where(Performance::class.java)
.equalTo("reportId", staticReport.uniqueIdentifier)
.equalTo("key", key.value)
.findFirst()
val formattedDuration = (duration / 3600 / 1000).formattedHourlyDuration()
performance?.let { perf ->
if (perf.value == duration) {
storePerf = false
}
if (storePerf) {
realm.executeTransaction {
perf.name = formattedDuration
perf.value = duration
}
}
}
if (storePerf) {
val perf = Performance(staticReport, key, name = formattedDuration, value = duration)
realm.executeTransaction { it.copyToRealm(perf) }
this.whistleBlower.notify(perf)
}
} }

@ -103,7 +103,7 @@ enum class Stat(override var uniqueIdentifier: Int) : IntIdentifiable, RowRepres
} }
override val value: String = this.uniqueIdentifier.toString() override val value: Int = this.uniqueIdentifier
override val resId: Int? override val resId: Int?
get() { get() {

@ -21,150 +21,163 @@ import kotlin.math.round
*/ */
class CashGameOptimalDurationCalculator { class CashGameOptimalDurationCalculator {
companion object { companion object {
private const val bucket = 60 * 60 * 1000L // the duration of bucket private const val bucket = 60 * 60 * 1000L // the duration of bucket
private const val bucketInterval = 4 // number of duration tests inside the bucket to find the best duration private const val bucketInterval =
private const val minimumValidityCount = 10 // the number of sessions inside a bucket to start having a reasonable average 4 // number of duration tests inside the bucket to find the best duration
private const val intervalValidity = 3 // the minimum number of unit between the shortest & longest valid buckets private const val minimumValidityCount =
private const val polynomialDegree = 7 // the degree of the computed polynomial 10 // the number of sessions inside a bucket to start having a reasonable average
private const val intervalValidity =
/*** 3 // the minimum number of unit between the shortest & longest valid buckets
* Starts the calculation private const val polynomialDegree = 7 // the degree of the computed polynomial
* [isLive] is a boolean to indicate if we're looking at live or online games
* return a duration or null if it could not be computed /***
*/ * Starts the calculation
fun start(isLive: Boolean): Double? { * [isLive] is a boolean to indicate if we're looking at live or online games
* return a duration or null if it could not be computed
val realm = Realm.getDefaultInstance() */
fun start(isLive: Boolean): Double? {
val query = Query().add(QueryCondition.IsCash) // cash game
query.add(if (isLive) { QueryCondition.IsLive } else { QueryCondition.IsOnline }) // live / online val realm = Realm.getDefaultInstance()
query.add(QueryCondition.EndDateNotNull) // ended
query.add(QueryCondition.BiggestBetNotNull) // has BB value val query = Query().add(QueryCondition.IsCash) // cash game
query.add(
val sessions = query.queryWith(realm.where(Session::class.java)).findAll() if (isLive) {
val sessionsByDuration = sessions.groupBy { QueryCondition.IsLive
val dur = round((it.netDuration / bucket).toDouble()) * bucket } else {
QueryCondition.IsOnline
}
) // live / online
query.add(QueryCondition.EndDateNotNull) // ended
query.add(QueryCondition.BiggestBetNotNull) // has BB value
val sessions = query.queryWith(realm.where(Session::class.java)).findAll()
val sessionsByDuration = sessions.groupBy {
val dur = round((it.netDuration / bucket).toDouble()) * bucket
// Timber.d("Stop notif > key: $dur") // Timber.d("Stop notif > key: $dur")
dur dur
} }
// define validity interval // define validity interval
var start: Double? = null var start: Double? = null
var end: Double? = null var end: Double? = null
var validBuckets = 0 var validBuckets = 0
val hkeys = sessionsByDuration.keys.map { it / 3600 / 1000.0 }.sorted() val hkeys = sessionsByDuration.keys.map { it / 3600 / 1000.0 }.sorted()
Timber.d("Stop notif > keys: $hkeys ") Timber.d("Stop notif > keys: $hkeys ")
for (key in sessionsByDuration.keys.sorted()) { for (key in sessionsByDuration.keys.sorted()) {
val sessionCount = sessionsByDuration[key]?.size ?: 0 val sessionCount = sessionsByDuration[key]?.size ?: 0
if (start == null && sessionCount >= minimumValidityCount) { if (start == null && sessionCount >= minimumValidityCount) {
start = key start = key
} }
if (sessionCount >= minimumValidityCount) { if (sessionCount >= minimumValidityCount) {
end = key end = key
validBuckets++ validBuckets++
} }
} }
Timber.d("Stop notif > validBuckets: $validBuckets ") Timber.d("Stop notif > validBuckets: $validBuckets ")
if (!(start != null && end != null && (end - start) >= intervalValidity)) { if (!(start != null && end != null && (end - start) >= intervalValidity)) {
Timber.d("Stop notif > invalid setup: $start / $end ") Timber.d("Stop notif > invalid setup: $start / $end ")
return null return null
} }
// define if we have enough sessions // define if we have enough sessions
if (sessions.size < 50) { if (sessions.size < 50) {
Timber.d("Stop notif > not enough sessions: ${sessions.size} ") Timber.d("Stop notif > not enough sessions: ${sessions.size} ")
return null return null
} }
val options = Calculator.Options() val options = Calculator.Options()
options.query = query options.query = query
val report = Calculator.computeStats(realm, options) val report = Calculator.computeStats(realm, options)
val stdBB = report.results.firstOrNull()?.computedStat(Stat.STANDARD_DEVIATION_BB)?.value val stdBB =
report.results.firstOrNull()?.computedStat(Stat.STANDARD_DEVIATION_BB)?.value
val p = polynomialRegression(sessions, stdBB)
val p = polynomialRegression(sessions, stdBB)
var bestAverage = 0.0
var bestHourlyRate = 0.0 var bestAverage = 0.0
var bestDuration = 0.0 var bestHourlyRate = 0.0
var maxDuration = 0.0 var bestDuration = 0.0
var maxDuration = 0.0
val keys = sessionsByDuration.keys.filter { it >= start && it <= end }.sorted()
val keys = sessionsByDuration.keys.filter { it >= start && it <= end }.sorted()
for (key in keys) {
for (key in keys) {
val sessionCount = sessionsByDuration[key]?.size ?: 0
val sessionCount = sessionsByDuration[key]?.size ?: 0
if (sessionCount < minimumValidityCount / 2) continue // if too few sessions we don't consider the duration valid
if (sessionCount < minimumValidityCount / 2) continue // if too few sessions we don't consider the duration valid
for (i in 0 until bucketInterval) {
for (i in 0 until bucketInterval) {
val duration = key + i * bucket / bucketInterval
val duration = key + i * bucket / bucketInterval
val averageResult = getBB(duration, p)
val hourly = averageResult / duration val averageResult = getBB(duration, p)
if (averageResult > bestAverage && hourly > 2 / 3 * bestHourlyRate) { val hourly = averageResult / duration
bestAverage = averageResult if (averageResult > bestAverage && hourly > 2 / 3 * bestHourlyRate) {
bestDuration = duration bestAverage = averageResult
} bestDuration = duration
}
if (duration > 0 && hourly > bestHourlyRate) {
bestHourlyRate = hourly if (duration > 0 && hourly > bestHourlyRate) {
} bestHourlyRate = hourly
if (duration > maxDuration){ }
maxDuration = duration if (duration > maxDuration) {
} maxDuration = duration
} }
}
}
}
if (bestDuration > 0.0) {
return bestDuration if (bestDuration > 0.0) {
} return bestDuration
}
Timber.d("Stop notif > not found, best duration: $bestDuration")
realm.close() Timber.d("Stop notif > not found, best duration: $bestDuration")
return null realm.close()
} return null
}
private fun getBB(netDuration: Double, polynomial: DoubleArray): Double {
var y = 0.0 private fun getBB(netDuration: Double, polynomial: DoubleArray): Double {
for (i in polynomial.indices) { var y = 0.0
y += polynomial[i] * netDuration.pow(i) for (i in polynomial.indices) {
} y += polynomial[i] * netDuration.pow(i)
return y }
} return y
}
private fun polynomialRegression(sessions: List<Session>, bbStandardDeviation: Double?): DoubleArray {
private fun polynomialRegression(
val stdBB = bbStandardDeviation ?: Double.MAX_VALUE sessions: List<Session>,
bbStandardDeviation: Double?
val points = WeightedObservedPoints() ): DoubleArray {
val now = Date().time
val stdBB = bbStandardDeviation ?: Double.MAX_VALUE
sessions.forEach {
var weight = 5.0 val points = WeightedObservedPoints()
val now = Date().time
val endTime = it.endDate?.time ?: 0L
sessions.forEach {
val age = now - endTime var weight = 5.0
if (age > 2 * 365 * 24 * 3600 * 1000L) { // if more than 2 years loses 1 point
weight -= 1.0 val endTime = it.endDate?.time ?: 0L
}
if (it.bbNet > 2 * stdBB) { // if very big result loses 3 points val age = now - endTime
weight -= 3.0 if (age > 2 * 365 * 24 * 3600 * 1000L) { // if more than 2 years loses 1 point
} weight -= 1.0
}
points.add(weight, it.netDuration.toDouble(), it.bbNet) if (it.bbNet > 2 * stdBB) { // if very big result loses 3 points
weight -= 3.0
} }
points.add(weight, it.netDuration.toDouble(), it.bbNet)
}
// polynomial of 7 degree, same as iOS // polynomial of 7 degree, same as iOS
return PolynomialCurveFitter.create(polynomialDegree).fit(points.toList()) return PolynomialCurveFitter.create(polynomialDegree).fit(points.toList())
} }
} }
} }

@ -0,0 +1,38 @@
package net.pokeranalytics.android.model
import net.pokeranalytics.android.R
import net.pokeranalytics.android.ui.fragment.PerformanceKey
import net.pokeranalytics.android.util.enumerations.IntIdentifiable
import net.pokeranalytics.android.util.enumerations.IntSearchable
enum class LiveOnline(override var uniqueIdentifier: Int) : PerformanceKey, IntIdentifiable {
LIVE(0),
ONLINE(1);
companion object : IntSearchable<LiveOnline> {
override fun valuesInternal(): Array<LiveOnline> {
return values()
}
}
override val resId: Int?
get() {
return when (this) {
LIVE -> R.string.live
ONLINE -> R.string.online
}
}
override val value: Int
get() {
return this.uniqueIdentifier
}
val isLive: Boolean
get() {
return (this == LIVE)
}
}

@ -130,7 +130,7 @@ val AbstractList<Session>.hourlyDuration: Double
val interval = TimeInterval(it.startDate!!, it.endDate!!, it.breakDuration) val interval = TimeInterval(it.startDate!!, it.endDate!!, it.breakDuration)
intervals.update(interval) intervals.update(interval)
} }
return intervals.sumByDouble { it.hourlyDuration } return intervals.sumOf { it.hourlyDuration }
} }
class TimeInterval(var start: Date, var end: Date, var breakDuration: Long) { class TimeInterval(var start: Date, var end: Date, var breakDuration: Long) {

@ -301,7 +301,7 @@ class PokerAnalyticsMigration : RealmMigration {
schema.addField("id", String::class.java).setRequired("id", true) schema.addField("id", String::class.java).setRequired("id", true)
schema.addPrimaryKey("id") schema.addPrimaryKey("id")
schema.addField("reportId", Int::class.java).setRequired("report", true) schema.addField("reportId", Int::class.java).setRequired("report", true)
schema.addField("statId", Int::class.java).setRequired("stat", true) schema.addField("key", Int::class.java).setRequired("key", true)
schema.addField("name", String::class.java).setNullable("name", true) schema.addField("name", String::class.java).setNullable("name", true)
schema.addField("objectId", String::class.java).setNullable("objectId", true) schema.addField("objectId", String::class.java).setNullable("objectId", true)
schema.addField("customFieldId", String::class.java).setNullable("customFieldId", true) schema.addField("customFieldId", String::class.java).setNullable("customFieldId", true)

@ -3,20 +3,20 @@ package net.pokeranalytics.android.model.realm
import io.realm.Realm import io.realm.Realm
import io.realm.RealmObject import io.realm.RealmObject
import net.pokeranalytics.android.calculus.Stat import net.pokeranalytics.android.calculus.Stat
import net.pokeranalytics.android.model.LiveOnline
import net.pokeranalytics.android.ui.fragment.PerformanceKey import net.pokeranalytics.android.ui.fragment.PerformanceKey
import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.rows.StaticReport import net.pokeranalytics.android.ui.view.rows.StaticReport
import net.pokeranalytics.android.util.NULL_TEXT import net.pokeranalytics.android.util.NULL_TEXT
import net.pokeranalytics.android.util.extensions.lookupForNameInAllTablesById import net.pokeranalytics.android.util.extensions.lookupForNameInAllTablesById
import java.util.* import java.util.*
open class Performance() : RealmObject(), RowRepresentable { open class Performance() : RealmObject() {
var id: String = UUID.randomUUID().toString() var id: String = UUID.randomUUID().toString()
constructor( constructor(
report: StaticReport, report: StaticReport,
stat: Stat, key: PerformanceKey,
name: String? = null, name: String? = null,
objectId: String? = null, objectId: String? = null,
customFieldId: String? = null, customFieldId: String? = null,
@ -24,7 +24,7 @@ open class Performance() : RealmObject(), RowRepresentable {
) : this() { ) : this() {
this.reportId = report.uniqueIdentifier this.reportId = report.uniqueIdentifier
this.statId = stat.uniqueIdentifier this.key = key.value
this.name = name this.name = name
this.objectId = objectId this.objectId = objectId
this.customFieldId = customFieldId this.customFieldId = customFieldId
@ -33,7 +33,7 @@ open class Performance() : RealmObject(), RowRepresentable {
} }
var reportId: Int = 0 var reportId: Int = 0
var statId: Int = 0 var key: Int = 0
var name: String? = null var name: String? = null
var objectId: String? = null var objectId: String? = null
var customFieldId: String? = null var customFieldId: String? = null
@ -49,19 +49,17 @@ open class Performance() : RealmObject(), RowRepresentable {
return NULL_TEXT return NULL_TEXT
} }
val performanceKey: PerformanceKey
get() {
return Stat.valueByIdentifier(this.statId)
}
val stat: Stat val stat: Stat
get() { get() {
return Stat.valueByIdentifier(this.statId) return Stat.valueByIdentifier(this.key.toInt())
} }
override val resId: Int? val resId: Int?
get() { get() {
return this.performanceKey.resId return when (this.reportId) {
StaticReport.OptimalDuration.uniqueIdentifier -> LiveOnline.valueByIdentifier(this.key).resId
else -> stat.resId
}
} }
} }

@ -44,7 +44,7 @@ import java.util.*
interface PerformanceKey { interface PerformanceKey {
val resId: Int? val resId: Int?
val value: String val value: Int
} }
data class ReportSection(var report: StaticReport, var performances: MutableList<PerformanceRow>) data class ReportSection(var report: StaticReport, var performances: MutableList<PerformanceRow>)
@ -167,7 +167,6 @@ class ReportsFragment : DeletableItemFragment(), StaticRowRepresentableDataSourc
} }
// Rows // Rows
private fun updateRows() { private fun updateRows() {
@ -234,7 +233,10 @@ class ReportsFragment : DeletableItemFragment(), StaticRowRepresentableDataSourc
when (row) { when (row) {
is PerformanceRow -> { is PerformanceRow -> {
val reportName = row.localizedTitle(requireContext()) val reportName = row.localizedTitle(requireContext())
launchComputation(row.report.criteria, reportName, row.performance.stat) val report = row.report
if (report.hasGraph) {
launchComputation(report.criteria, reportName, row.performance.stat)
}
} }
is ReportSetup -> { is ReportSetup -> {
val display = ReportDisplay.values()[row.display] val display = ReportDisplay.values()[row.display]

@ -11,6 +11,7 @@ import androidx.appcompat.content.res.AppCompatResources
import androidx.interpolator.view.animation.FastOutSlowInInterpolator import androidx.interpolator.view.animation.FastOutSlowInInterpolator
import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProvider
import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.DiffUtil
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.async import kotlinx.coroutines.async
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@ -405,13 +406,13 @@ class SessionFragment : RealmFragment(), RowRepresentableDelegate, StaticRowRepr
Timber.d("Start optimal duration finding attempt...") Timber.d("Start optimal duration finding attempt...")
val isLive = this.currentSession.isLive val isLive = this.currentSession.isLive
GlobalScope.launch(coroutineContext) { CoroutineScope(coroutineContext).launch {
var optimalDuration: Double? = null var optimalDuration: Double? = null
val cr = GlobalScope.async { val cr = GlobalScope.async {
optimalDuration = CashGameOptimalDurationCalculator.start(isLive)
} }
optimalDuration = CashGameOptimalDurationCalculator.start(isLive)
cr.await() cr.await()
if (!isDetached) { if (!isDetached) {

@ -686,6 +686,13 @@ enum class RowViewType(private var layoutRes: Int) : ViewIdentifier {
itemView.findViewById<AppCompatImageView>(R.id.badge)?.let { itemView.findViewById<AppCompatImageView>(R.id.badge)?.let {
it.isVisible = row.badge it.isVisible = row.badge
} }
itemView.findViewById<AppCompatImageView>(R.id.nextArrow)?.let {
it.visibility = if (row.report.hasGraph) {
View.VISIBLE
} else {
View.GONE
}
}
val listener = View.OnClickListener { val listener = View.OnClickListener {
adapter.delegate?.onRowSelected(position, row) adapter.delegate?.onRowSelected(position, row)

@ -56,8 +56,7 @@ sealed class StaticReport(override var uniqueIdentifier: Int) : RowRepresentable
} }
val basicReports: Set<StaticReport> = setOf(General, Blinds, TournamentBuyin, val basicReports: Set<StaticReport> = setOf(General)
DayOfWeek, Location, TournamentType, Game, TableSize, Duration, OptimalDuration)
} }
@ -114,4 +113,12 @@ sealed class StaticReport(override var uniqueIdentifier: Int) : RowRepresentable
} }
} }
val hasGraph: Boolean
get() {
return when (this) {
OptimalDuration -> false
else -> true
}
}
} }
Loading…
Cancel
Save