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 4f39dee0..0b029716 100644 --- a/app/src/main/java/net/pokeranalytics/android/calculus/Calculator.kt +++ b/app/src/main/java/net/pokeranalytics/android/calculus/Calculator.kt @@ -241,6 +241,11 @@ class Calculator { val results = ComputedResults(computableGroup, options.shouldManageMultiGroupProgressValues) 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") results.addStat(NUMBER_OF_GAMES, computables.size.toDouble()) // computables.forEach { @@ -606,10 +611,10 @@ class SSStats(sessionSet: SessionSet, query: Query) { // Session Set Stats if (setSessions.size == filteredSessions.size) { this.initStatsWithSet(sessionSet) } else { - ratedNet = filteredSessions.sumByDouble { it.computableResult?.ratedNet ?: 0.0 } - bbSum = filteredSessions.sumByDouble { it.bbNet } + ratedNet = filteredSessions.sumOf { it.computableResult?.ratedNet ?: 0.0 } + bbSum = filteredSessions.sumOf { it.bbNet } hourlyDuration = filteredSessions.hourlyDuration - estimatedHands = filteredSessions.sumByDouble { it.estimatedHands } + estimatedHands = filteredSessions.sumOf { it.estimatedHands } } } } diff --git a/app/src/main/java/net/pokeranalytics/android/calculus/ReportWhistleBlower.kt b/app/src/main/java/net/pokeranalytics/android/calculus/ReportWhistleBlower.kt index 44890270..6e92d52c 100644 --- a/app/src/main/java/net/pokeranalytics/android/calculus/ReportWhistleBlower.kt +++ b/app/src/main/java/net/pokeranalytics/android/calculus/ReportWhistleBlower.kt @@ -7,11 +7,15 @@ import io.realm.RealmResults import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers 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.Performance import net.pokeranalytics.android.model.realm.Result 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.util.extensions.formattedHourlyDuration import timber.log.Timber import kotlin.coroutines.CoroutineContext @@ -137,21 +141,28 @@ class ReportTask(private var whistleBlower: ReportWhistleBlower, var context: Co 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( stats = report.stats, criterias = report.criteria ) val result = Calculator.computeStats(realm, options = options) - analyseReport(realm, report, result) - + analyseDefaultReport(realm, report, result) } - private fun analyseReport(realm: Realm, staticReport: StaticReport, result: Report) { - - when (staticReport.uniqueIdentifier) { - StaticReport.OptimalDuration.uniqueIdentifier -> analyseOptimalDuration(staticReport, result) - else -> analyseDefaultReport(realm, staticReport, result) + private fun launchOptimalDuration(realm: Realm, report: StaticReport) { + LiveOnline.values().forEach { key -> + val duration = CashGameOptimalDurationCalculator.start(key.isLive) + duration?.let { + analyseOptimalDuration(realm, report, key, it) + } } } @@ -166,7 +177,7 @@ class ReportTask(private var whistleBlower: ReportWhistleBlower, var context: Co val customField: CustomField? = (staticReport as? StaticReport.CustomFieldList)?.customField var query = realm.where(Performance::class.java) - .equalTo("statId", stat.uniqueIdentifier) + .equalTo("key", stat.uniqueIdentifier) .equalTo("reportId", staticReport.uniqueIdentifier) customField?.let { @@ -174,15 +185,16 @@ class ReportTask(private var whistleBlower: ReportWhistleBlower, var context: Co } val currentPerf = query.findFirst() + val performanceQuery = computedResults.group.query + val performanceName = performanceQuery.getName(this.context, " ") + var storePerf = true currentPerf?.let { - Timber.d("cr name = ${computedResults.group.query.getName(this.context)}") currentPerf.name?.let { if (computedResults.group.query.defaultName == it) { storePerf = false } } - Timber.d("cr objectId = ${computedResults.group.query.objectId}") currentPerf.objectId?.let { if (computedResults.group.query.objectId == it) { storePerf = false @@ -191,8 +203,8 @@ class ReportTask(private var whistleBlower: ReportWhistleBlower, var context: Co if (storePerf) { realm.executeTransaction { - currentPerf.name = computedResults.group.query.getName(this.context) - currentPerf.objectId = computedResults.group.query.objectId + currentPerf.name = performanceName + currentPerf.objectId = performanceQuery.objectId currentPerf.customFieldId = customField?.id } this.whistleBlower.notify(currentPerf) @@ -204,8 +216,8 @@ class ReportTask(private var whistleBlower: ReportWhistleBlower, var context: Co val performance = Performance( staticReport, stat, - computedResults.group.query.getName(this.context), - computedResults.group.query.objectId, + performanceName, + performanceQuery.objectId, customField?.id, 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) + } } diff --git a/app/src/main/java/net/pokeranalytics/android/calculus/Stat.kt b/app/src/main/java/net/pokeranalytics/android/calculus/Stat.kt index ce2f7019..7e31bab9 100644 --- a/app/src/main/java/net/pokeranalytics/android/calculus/Stat.kt +++ b/app/src/main/java/net/pokeranalytics/android/calculus/Stat.kt @@ -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? get() { diff --git a/app/src/main/java/net/pokeranalytics/android/calculus/optimalduration/CashGameOptimalDurationCalculator.kt b/app/src/main/java/net/pokeranalytics/android/calculus/optimalduration/CashGameOptimalDurationCalculator.kt index bd5e91a3..1ec0797d 100644 --- a/app/src/main/java/net/pokeranalytics/android/calculus/optimalduration/CashGameOptimalDurationCalculator.kt +++ b/app/src/main/java/net/pokeranalytics/android/calculus/optimalduration/CashGameOptimalDurationCalculator.kt @@ -21,150 +21,163 @@ import kotlin.math.round */ class CashGameOptimalDurationCalculator { - companion object { - - 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 minimumValidityCount = 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 - private const val polynomialDegree = 7 // the degree of the computed polynomial - - /*** - * Starts the calculation - * [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 - */ - fun start(isLive: Boolean): Double? { - - val realm = Realm.getDefaultInstance() - - val query = Query().add(QueryCondition.IsCash) // cash game - query.add(if (isLive) { QueryCondition.IsLive } 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 + companion object { + + 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 minimumValidityCount = + 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 + private const val polynomialDegree = 7 // the degree of the computed polynomial + + /*** + * Starts the calculation + * [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 + */ + fun start(isLive: Boolean): Double? { + + val realm = Realm.getDefaultInstance() + + val query = Query().add(QueryCondition.IsCash) // cash game + query.add( + if (isLive) { + QueryCondition.IsLive + } 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") - dur - } - - // define validity interval - var start: Double? = null - var end: Double? = null - var validBuckets = 0 - - val hkeys = sessionsByDuration.keys.map { it / 3600 / 1000.0 }.sorted() - Timber.d("Stop notif > keys: $hkeys ") - for (key in sessionsByDuration.keys.sorted()) { - val sessionCount = sessionsByDuration[key]?.size ?: 0 - if (start == null && sessionCount >= minimumValidityCount) { - start = key - } - if (sessionCount >= minimumValidityCount) { - end = key - validBuckets++ - } - } - Timber.d("Stop notif > validBuckets: $validBuckets ") - if (!(start != null && end != null && (end - start) >= intervalValidity)) { - Timber.d("Stop notif > invalid setup: $start / $end ") - return null - } - - // define if we have enough sessions - if (sessions.size < 50) { - Timber.d("Stop notif > not enough sessions: ${sessions.size} ") - return null - } - - val options = Calculator.Options() - options.query = query - val report = Calculator.computeStats(realm, options) - val stdBB = report.results.firstOrNull()?.computedStat(Stat.STANDARD_DEVIATION_BB)?.value - - val p = polynomialRegression(sessions, stdBB) - - var bestAverage = 0.0 - var bestHourlyRate = 0.0 - var bestDuration = 0.0 - var maxDuration = 0.0 - - val keys = sessionsByDuration.keys.filter { it >= start && it <= end }.sorted() - - for (key in keys) { - - val sessionCount = sessionsByDuration[key]?.size ?: 0 - - if (sessionCount < minimumValidityCount / 2) continue // if too few sessions we don't consider the duration valid - - for (i in 0 until bucketInterval) { - - val duration = key + i * bucket / bucketInterval - - val averageResult = getBB(duration, p) - val hourly = averageResult / duration - if (averageResult > bestAverage && hourly > 2 / 3 * bestHourlyRate) { - bestAverage = averageResult - bestDuration = duration - } - - if (duration > 0 && hourly > bestHourlyRate) { - bestHourlyRate = hourly - } - if (duration > maxDuration){ - maxDuration = duration - } - } - - } - - if (bestDuration > 0.0) { - return bestDuration - } - - Timber.d("Stop notif > not found, best duration: $bestDuration") - realm.close() - return null - } - - private fun getBB(netDuration: Double, polynomial: DoubleArray): Double { - var y = 0.0 - for (i in polynomial.indices) { - y += polynomial[i] * netDuration.pow(i) - } - return y - } - - private fun polynomialRegression(sessions: List, bbStandardDeviation: Double?): DoubleArray { - - val stdBB = bbStandardDeviation ?: Double.MAX_VALUE - - val points = WeightedObservedPoints() - val now = Date().time - - sessions.forEach { - var weight = 5.0 - - val endTime = it.endDate?.time ?: 0L - - val age = now - endTime - if (age > 2 * 365 * 24 * 3600 * 1000L) { // if more than 2 years loses 1 point - weight -= 1.0 - } - if (it.bbNet > 2 * stdBB) { // if very big result loses 3 points - weight -= 3.0 - } - - points.add(weight, it.netDuration.toDouble(), it.bbNet) - - } + dur + } + + // define validity interval + var start: Double? = null + var end: Double? = null + var validBuckets = 0 + + val hkeys = sessionsByDuration.keys.map { it / 3600 / 1000.0 }.sorted() + Timber.d("Stop notif > keys: $hkeys ") + for (key in sessionsByDuration.keys.sorted()) { + val sessionCount = sessionsByDuration[key]?.size ?: 0 + if (start == null && sessionCount >= minimumValidityCount) { + start = key + } + if (sessionCount >= minimumValidityCount) { + end = key + validBuckets++ + } + } + Timber.d("Stop notif > validBuckets: $validBuckets ") + if (!(start != null && end != null && (end - start) >= intervalValidity)) { + Timber.d("Stop notif > invalid setup: $start / $end ") + return null + } + + // define if we have enough sessions + if (sessions.size < 50) { + Timber.d("Stop notif > not enough sessions: ${sessions.size} ") + return null + } + + val options = Calculator.Options() + options.query = query + val report = Calculator.computeStats(realm, options) + val stdBB = + report.results.firstOrNull()?.computedStat(Stat.STANDARD_DEVIATION_BB)?.value + + val p = polynomialRegression(sessions, stdBB) + + var bestAverage = 0.0 + var bestHourlyRate = 0.0 + var bestDuration = 0.0 + var maxDuration = 0.0 + + val keys = sessionsByDuration.keys.filter { it >= start && it <= end }.sorted() + + for (key in keys) { + + val sessionCount = sessionsByDuration[key]?.size ?: 0 + + if (sessionCount < minimumValidityCount / 2) continue // if too few sessions we don't consider the duration valid + + for (i in 0 until bucketInterval) { + + val duration = key + i * bucket / bucketInterval + + val averageResult = getBB(duration, p) + val hourly = averageResult / duration + if (averageResult > bestAverage && hourly > 2 / 3 * bestHourlyRate) { + bestAverage = averageResult + bestDuration = duration + } + + if (duration > 0 && hourly > bestHourlyRate) { + bestHourlyRate = hourly + } + if (duration > maxDuration) { + maxDuration = duration + } + } + + } + + if (bestDuration > 0.0) { + return bestDuration + } + + Timber.d("Stop notif > not found, best duration: $bestDuration") + realm.close() + return null + } + + private fun getBB(netDuration: Double, polynomial: DoubleArray): Double { + var y = 0.0 + for (i in polynomial.indices) { + y += polynomial[i] * netDuration.pow(i) + } + return y + } + + private fun polynomialRegression( + sessions: List, + bbStandardDeviation: Double? + ): DoubleArray { + + val stdBB = bbStandardDeviation ?: Double.MAX_VALUE + + val points = WeightedObservedPoints() + val now = Date().time + + sessions.forEach { + var weight = 5.0 + + val endTime = it.endDate?.time ?: 0L + + val age = now - endTime + if (age > 2 * 365 * 24 * 3600 * 1000L) { // if more than 2 years loses 1 point + weight -= 1.0 + } + 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 - return PolynomialCurveFitter.create(polynomialDegree).fit(points.toList()) - } + // polynomial of 7 degree, same as iOS + return PolynomialCurveFitter.create(polynomialDegree).fit(points.toList()) + } - } + } } \ No newline at end of file diff --git a/app/src/main/java/net/pokeranalytics/android/model/LiveOnline.kt b/app/src/main/java/net/pokeranalytics/android/model/LiveOnline.kt new file mode 100644 index 00000000..459a4b59 --- /dev/null +++ b/app/src/main/java/net/pokeranalytics/android/model/LiveOnline.kt @@ -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 { + + override fun valuesInternal(): Array { + 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) + } + +} \ No newline at end of file diff --git a/app/src/main/java/net/pokeranalytics/android/model/extensions/SessionExtensions.kt b/app/src/main/java/net/pokeranalytics/android/model/extensions/SessionExtensions.kt index 325a9200..f490a97b 100644 --- a/app/src/main/java/net/pokeranalytics/android/model/extensions/SessionExtensions.kt +++ b/app/src/main/java/net/pokeranalytics/android/model/extensions/SessionExtensions.kt @@ -130,7 +130,7 @@ val AbstractList.hourlyDuration: Double val interval = TimeInterval(it.startDate!!, it.endDate!!, it.breakDuration) intervals.update(interval) } - return intervals.sumByDouble { it.hourlyDuration } + return intervals.sumOf { it.hourlyDuration } } class TimeInterval(var start: Date, var end: Date, var breakDuration: Long) { diff --git a/app/src/main/java/net/pokeranalytics/android/model/migrations/PokerAnalyticsMigration.kt b/app/src/main/java/net/pokeranalytics/android/model/migrations/PokerAnalyticsMigration.kt index 318ad366..dc2d5914 100644 --- a/app/src/main/java/net/pokeranalytics/android/model/migrations/PokerAnalyticsMigration.kt +++ b/app/src/main/java/net/pokeranalytics/android/model/migrations/PokerAnalyticsMigration.kt @@ -301,7 +301,7 @@ class PokerAnalyticsMigration : RealmMigration { schema.addField("id", String::class.java).setRequired("id", true) schema.addPrimaryKey("id") 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("objectId", String::class.java).setNullable("objectId", true) schema.addField("customFieldId", String::class.java).setNullable("customFieldId", true) diff --git a/app/src/main/java/net/pokeranalytics/android/model/realm/Performance.kt b/app/src/main/java/net/pokeranalytics/android/model/realm/Performance.kt index f7207ce1..0fa336d9 100644 --- a/app/src/main/java/net/pokeranalytics/android/model/realm/Performance.kt +++ b/app/src/main/java/net/pokeranalytics/android/model/realm/Performance.kt @@ -3,20 +3,20 @@ package net.pokeranalytics.android.model.realm import io.realm.Realm import io.realm.RealmObject import net.pokeranalytics.android.calculus.Stat +import net.pokeranalytics.android.model.LiveOnline 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.util.NULL_TEXT import net.pokeranalytics.android.util.extensions.lookupForNameInAllTablesById import java.util.* -open class Performance() : RealmObject(), RowRepresentable { +open class Performance() : RealmObject() { var id: String = UUID.randomUUID().toString() constructor( report: StaticReport, - stat: Stat, + key: PerformanceKey, name: String? = null, objectId: String? = null, customFieldId: String? = null, @@ -24,7 +24,7 @@ open class Performance() : RealmObject(), RowRepresentable { ) : this() { this.reportId = report.uniqueIdentifier - this.statId = stat.uniqueIdentifier + this.key = key.value this.name = name this.objectId = objectId this.customFieldId = customFieldId @@ -33,7 +33,7 @@ open class Performance() : RealmObject(), RowRepresentable { } var reportId: Int = 0 - var statId: Int = 0 + var key: Int = 0 var name: String? = null var objectId: String? = null var customFieldId: String? = null @@ -49,19 +49,17 @@ open class Performance() : RealmObject(), RowRepresentable { return NULL_TEXT } - val performanceKey: PerformanceKey - get() { - return Stat.valueByIdentifier(this.statId) - } - val stat: Stat get() { - return Stat.valueByIdentifier(this.statId) + return Stat.valueByIdentifier(this.key.toInt()) } - override val resId: Int? + val resId: Int? get() { - return this.performanceKey.resId + return when (this.reportId) { + StaticReport.OptimalDuration.uniqueIdentifier -> LiveOnline.valueByIdentifier(this.key).resId + else -> stat.resId + } } } \ No newline at end of file diff --git a/app/src/main/java/net/pokeranalytics/android/ui/fragment/ReportsFragment.kt b/app/src/main/java/net/pokeranalytics/android/ui/fragment/ReportsFragment.kt index bdcbea8a..cffb9dea 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/fragment/ReportsFragment.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/fragment/ReportsFragment.kt @@ -44,7 +44,7 @@ import java.util.* interface PerformanceKey { val resId: Int? - val value: String + val value: Int } data class ReportSection(var report: StaticReport, var performances: MutableList) @@ -167,7 +167,6 @@ class ReportsFragment : DeletableItemFragment(), StaticRowRepresentableDataSourc } - // Rows private fun updateRows() { @@ -234,7 +233,10 @@ class ReportsFragment : DeletableItemFragment(), StaticRowRepresentableDataSourc when (row) { is PerformanceRow -> { 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 -> { val display = ReportDisplay.values()[row.display] diff --git a/app/src/main/java/net/pokeranalytics/android/ui/modules/session/SessionFragment.kt b/app/src/main/java/net/pokeranalytics/android/ui/modules/session/SessionFragment.kt index 9ae44b4c..fa0f1518 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/modules/session/SessionFragment.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/modules/session/SessionFragment.kt @@ -11,6 +11,7 @@ import androidx.appcompat.content.res.AppCompatResources import androidx.interpolator.view.animation.FastOutSlowInInterpolator import androidx.lifecycle.ViewModelProvider import androidx.recyclerview.widget.DiffUtil +import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.async import kotlinx.coroutines.launch @@ -405,13 +406,13 @@ class SessionFragment : RealmFragment(), RowRepresentableDelegate, StaticRowRepr Timber.d("Start optimal duration finding attempt...") val isLive = this.currentSession.isLive - GlobalScope.launch(coroutineContext) { + CoroutineScope(coroutineContext).launch { var optimalDuration: Double? = null val cr = GlobalScope.async { - optimalDuration = CashGameOptimalDurationCalculator.start(isLive) } + optimalDuration = CashGameOptimalDurationCalculator.start(isLive) cr.await() if (!isDetached) { diff --git a/app/src/main/java/net/pokeranalytics/android/ui/view/RowViewType.kt b/app/src/main/java/net/pokeranalytics/android/ui/view/RowViewType.kt index 3a3e94f3..5bed6aed 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/view/RowViewType.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/view/RowViewType.kt @@ -686,6 +686,13 @@ enum class RowViewType(private var layoutRes: Int) : ViewIdentifier { itemView.findViewById(R.id.badge)?.let { it.isVisible = row.badge } + itemView.findViewById(R.id.nextArrow)?.let { + it.visibility = if (row.report.hasGraph) { + View.VISIBLE + } else { + View.GONE + } + } val listener = View.OnClickListener { adapter.delegate?.onRowSelected(position, row) diff --git a/app/src/main/java/net/pokeranalytics/android/ui/view/rows/StaticReport.kt b/app/src/main/java/net/pokeranalytics/android/ui/view/rows/StaticReport.kt index 7b9a647a..b1d0e5bd 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/view/rows/StaticReport.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/view/rows/StaticReport.kt @@ -56,8 +56,7 @@ sealed class StaticReport(override var uniqueIdentifier: Int) : RowRepresentable } - val basicReports: Set = setOf(General, Blinds, TournamentBuyin, - DayOfWeek, Location, TournamentType, Game, TableSize, Duration, OptimalDuration) + val basicReports: Set = setOf(General) } @@ -114,4 +113,12 @@ sealed class StaticReport(override var uniqueIdentifier: Int) : RowRepresentable } } + val hasGraph: Boolean + get() { + return when (this) { + OptimalDuration -> false + else -> true + } + } + } \ No newline at end of file