Early graphs

feature/top10
Laurent 7 years ago
parent b12949a077
commit aabd5da0de
  1. 5
      app/src/main/AndroidManifest.xml
  2. 126
      app/src/main/java/net/pokeranalytics/android/calculus/Calculator.kt
  3. 76
      app/src/main/java/net/pokeranalytics/android/calculus/ComputableGroup.kt
  4. 4
      app/src/main/java/net/pokeranalytics/android/model/migrations/PokerAnalyticsMigration.kt
  5. 37
      app/src/main/java/net/pokeranalytics/android/model/realm/ComputableResult.kt
  6. 4
      app/src/main/java/net/pokeranalytics/android/model/realm/Filter.kt
  7. 40
      app/src/main/java/net/pokeranalytics/android/model/realm/SessionSet.kt
  8. 26
      app/src/main/java/net/pokeranalytics/android/ui/activity/GraphActivity.kt
  9. 13
      app/src/main/java/net/pokeranalytics/android/ui/fragment/GraphFragment.kt
  10. 32
      app/src/main/java/net/pokeranalytics/android/ui/fragment/StatsFragment.kt

@ -64,6 +64,11 @@
android:launchMode="singleTop" android:launchMode="singleTop"
android:screenOrientation="portrait" /> android:screenOrientation="portrait" />
<activity
android:name=".ui.activity.GraphActivity"
android:launchMode="singleTop"
android:screenOrientation="portrait" />
<meta-data <meta-data
android:name="preloaded_fonts" android:name="preloaded_fonts"
android:resource="@array/preloaded_fonts" /> android:resource="@array/preloaded_fonts" />

@ -1,5 +1,8 @@
package net.pokeranalytics.android.calculus package net.pokeranalytics.android.calculus
import android.os.Parcel
import android.os.Parcelable
import io.realm.Realm
import net.pokeranalytics.android.calculus.Stat.* import net.pokeranalytics.android.calculus.Stat.*
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.Filter
@ -7,6 +10,31 @@ import net.pokeranalytics.android.model.realm.SessionSet
import timber.log.Timber import timber.log.Timber
import java.util.* import java.util.*
class ParcelableString(var string: String) : Parcelable {
constructor(parcel: Parcel) : this(parcel.readString()) {
}
override fun writeToParcel(parcel: Parcel, flags: Int) {
parcel.writeString(string)
}
override fun describeContents(): Int {
return 0
}
companion object CREATOR : Parcelable.Creator<ParcelableString> {
override fun createFromParcel(parcel: Parcel): ParcelableString {
return ParcelableString(parcel)
}
override fun newArray(size: Int): Array<ParcelableString?> {
return arrayOfNulls(size)
}
}
}
/** /**
* The class performing stats computation * The class performing stats computation
*/ */
@ -59,35 +87,39 @@ class Calculator {
companion object { companion object {
fun computeStatsWithFilters(filters: List<Filter>, options: Options): List<ComputedResults> { fun computeStatsWithFilters(realm: Realm, filters: List<Filter>, options: Options): List<ComputedResults> {
var computableGroups: MutableList<ComputableGroup> = mutableListOf() var computableGroups: MutableList<ComputableGroup> = mutableListOf()
filters.forEach { filter -> filters.forEach { filter ->
val results = filter.results<ComputableResult>() val results = filter.results<ComputableResult>()
val sets = filter.results<SessionSet>() val sets = filter.results<SessionSet>()
val group = ComputableGroup(filter.name, results, sets) val group = ComputableGroup(filter.name, filter.filterConditions.map { it.queryCondition })
computableGroups.add(group) computableGroups.add(group)
} }
return Calculator.computeGroups(computableGroups, options) return Calculator.computeGroups(realm, computableGroups, options)
} }
/** /**
* Computes all stats for list of Session sessionGroup * Computes all stats for list of Session sessionGroup
*/ */
fun computeGroups(groups: List<ComputableGroup>, options: Options): List<ComputedResults> { fun computeGroups(realm: Realm, groups: List<ComputableGroup>, options: Options): List<ComputedResults> {
val computedResults = mutableListOf<ComputedResults>() val computedResults = mutableListOf<ComputedResults>()
groups.forEach { group -> groups.forEach { group ->
val s = Date() val s = Date()
// Clean existing computables / sessionSets if group is reused
group.cleanup()
// Computes actual sessionGroup stats // Computes actual sessionGroup stats
val results: ComputedResults = Calculator.compute(group, options = options) val results: ComputedResults = Calculator.compute(realm, group, options = options)
// Computes the compared sessionGroup if existing // Computes the compared sessionGroup if existing
val comparedGroup = group.comparedComputables val comparedGroup = group.comparedComputables
if (comparedGroup != null) { if (comparedGroup != null) {
val comparedResults = Calculator.compute(comparedGroup, options = options) val comparedResults = Calculator.compute(realm, comparedGroup, options = options)
group.comparedComputedResults = comparedResults group.comparedComputedResults = comparedResults
results.computeStatVariations(comparedResults) results.computeStatVariations(comparedResults)
} }
@ -107,11 +139,10 @@ class Calculator {
/** /**
* Computes stats for a SessionSet * Computes stats for a SessionSet
*/ */
fun compute(computableGroup: ComputableGroup, options: Options): ComputedResults { fun compute(realm: Realm, computableGroup: ComputableGroup, options: Options): ComputedResults {
Timber.d(">>>> Start computing group ${computableGroup.name}, ${computableGroup.computables.size} computables")
val computables = computableGroup.computables val computables = computableGroup.computables(realm)
Timber.d(">>>> Start computing group ${computableGroup.name}, ${computables.size} computables")
val results: ComputedResults = ComputedResults(computableGroup) val results: ComputedResults = ComputedResults(computableGroup)
@ -135,30 +166,29 @@ class Calculator {
var tBuyinSum = 0.0 var tBuyinSum = 0.0
var tHands = 0.0 var tHands = 0.0
computables.forEach { s -> computables.forEach { computable ->
index++ index++
tSum += s.ratedNet tSum += computable.ratedNet
tBBSum += s.bbNet tBBSum += computable.bbNet
tBBSessionCount += s.hasBigBlind tBBSessionCount += computable.hasBigBlind
tWinningSessionCount += s.isPositive tWinningSessionCount += computable.isPositive
tBuyinSum += s.ratedBuyin tBuyinSum += computable.ratedBuyin
tHands += s.estimatedHands tHands += computable.estimatedHands
results.addEvolutionValue(tSum, NETRESULT, s) val sessionId = ParcelableString(computable.session?.id ?: throw IllegalStateException("Computing lone ComputableResult"))
results.addEvolutionValue(tSum / index, AVERAGE, s) results.addEvolutionValue(tSum, NETRESULT, sessionId)
results.addEvolutionValue(index.toDouble(), NUMBER_OF_GAMES, s) results.addEvolutionValue(tSum / index, AVERAGE, sessionId)
results.addEvolutionValue(tBBSum / tBBSessionCount, AVERAGE_NET_BB, s) results.addEvolutionValue(index.toDouble(), NUMBER_OF_GAMES, sessionId)
results.addEvolutionValue((tWinningSessionCount / index).toDouble(), WIN_RATIO, s) results.addEvolutionValue(tBBSum / tBBSessionCount, AVERAGE_NET_BB, sessionId)
results.addEvolutionValue(tBuyinSum / index, AVERAGE_BUYIN, s) results.addEvolutionValue((tWinningSessionCount / index).toDouble(), WIN_RATIO, sessionId)
results.addEvolutionValue(tBuyinSum / index, AVERAGE_BUYIN, sessionId)
val netBB100 = Stat.netBBPer100Hands(tBBSum, tHands)
if (netBB100 != null) { Stat.netBBPer100Hands(tBBSum, tHands)?.let { netBB100 ->
results.addEvolutionValue(netBB100, NET_BB_PER_100_HANDS, s) results.addEvolutionValue(netBB100, NET_BB_PER_100_HANDS, sessionId)
} }
val roi = Stat.returnOnInvestment(tSum, tBuyinSum) Stat.returnOnInvestment(tSum, tBuyinSum)?.let { roi ->
if (roi != null) { results.addEvolutionValue(roi, ROI, sessionId)
results.addEvolutionValue(roi, ROI, s)
} }
} }
@ -168,7 +198,7 @@ class Calculator {
} }
} }
val sessionSets = computableGroup.sets val sessionSets = computableGroup.sessionSets(realm)
// Compute for each serie // Compute for each serie
val gHourlyDuration = val gHourlyDuration =
@ -201,20 +231,19 @@ class Calculator {
tHourlyRate = gSum / tHourlyDuration tHourlyRate = gSum / tHourlyDuration
tHourlyRateBB = gBBSum / tHourlyDuration tHourlyRateBB = gBBSum / tHourlyDuration
results.addEvolutionValue(tSum, tHourlyDuration, NETRESULT, sessionSet) val id = ParcelableString(sessionSet.id)
results.addEvolutionValue(tSum / tHourlyDuration, tHourlyDuration, HOURLY_RATE, sessionSet) results.addEvolutionValue(tSum, tHourlyDuration, NETRESULT, id)
results.addEvolutionValue(tHourlyRate, tHourlyDuration, HOURLY_RATE, sessionSet) results.addEvolutionValue(tSum / tHourlyDuration, tHourlyDuration, HOURLY_RATE, id)
results.addEvolutionValue(tIndex.toDouble(), tHourlyDuration, NUMBER_OF_SETS, sessionSet) results.addEvolutionValue(tHourlyRate, tHourlyDuration, HOURLY_RATE, id)
results.addEvolutionValue(sessionSet.netDuration.toDouble(), tHourlyDuration, DURATION, sessionSet) results.addEvolutionValue(tIndex.toDouble(), tHourlyDuration, NUMBER_OF_SETS, id)
results.addEvolutionValue(tHourlyDuration / tIndex, tHourlyDuration, AVERAGE_DURATION, sessionSet) results.addEvolutionValue(sessionSet.netDuration.toDouble(), tHourlyDuration, DURATION, id)
results.addEvolutionValue(tHourlyRateBB, tHourlyDuration, HOURLY_RATE_BB, sessionSet) results.addEvolutionValue(tHourlyDuration / tIndex, tHourlyDuration, AVERAGE_DURATION, id)
results.addEvolutionValue(tHourlyRateBB, tHourlyDuration, HOURLY_RATE_BB, id)
val netBB100 = Stat.netBBPer100Hands(gBBSum, gTotalHands)
if (netBB100 != null) { 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, id)
} else { //@todo maybe not
results.addEvolutionValue(0.0, tHourlyDuration, NET_BB_PER_100_HANDS, sessionSet)
} }
} }
} }
else -> { else -> {
@ -261,13 +290,10 @@ class Calculator {
) )
) )
val roi = Stat.returnOnInvestment(sum, totalBuyin) Stat.returnOnInvestment(sum, totalBuyin)?.let { roi ->
val netBB100 = Stat.netBBPer100Hands(bbSum, totalHands)
if (roi != null) {
results.addStats(setOf(ComputedStat(ROI, roi))) results.addStats(setOf(ComputedStat(ROI, roi)))
} }
if (netBB100 != null) { Stat.netBBPer100Hands(bbSum, totalHands)?.let { netBB100 ->
results.addStats(setOf(ComputedStat(NET_BB_PER_100_HANDS, netBB100))) results.addStats(setOf(ComputedStat(NET_BB_PER_100_HANDS, netBB100)))
} }

@ -2,14 +2,17 @@ package net.pokeranalytics.android.calculus
import com.github.mikephil.charting.data.BarEntry import com.github.mikephil.charting.data.BarEntry
import com.github.mikephil.charting.data.Entry import com.github.mikephil.charting.data.Entry
import io.realm.Realm
import io.realm.RealmResults import io.realm.RealmResults
import net.pokeranalytics.android.model.filter.QueryCondition
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
/** /**
* A sessionGroup of computable items identified by a name * A sessionGroup of computable items identified by a name
*/ */
class ComputableGroup(name: String, computables: RealmResults<ComputableResult>, sets: RealmResults<SessionSet>, stats: List<Stat>? = null) { class ComputableGroup(name: String, conditions: List<QueryCondition>, stats: List<Stat>? = null) {
/** /**
* The display name of the group * The display name of the group
@ -17,14 +20,52 @@ class ComputableGroup(name: String, computables: RealmResults<ComputableResult>,
var name: String = name var name: String = name
/** /**
* The list of endedSessions to compute * A list of conditions to get
*/ */
var computables: RealmResults<ComputableResult> = computables var conditions: List<QueryCondition> = conditions
/** /**
* The list of endedSessions to compute * The list of endedSessions to compute
*/ */
var sets: RealmResults<SessionSet> = sets private var _computables: RealmResults<ComputableResult>? = null
/**
* Retrieves the computables on the relative [realm] filtered with the provided [conditions]
*/
fun computables(realm: Realm): RealmResults<ComputableResult> {
// if computables exists and is valid (previous realm not closed)
this._computables?.let {
if (it.isValid) {
return it
}
}
val computables: RealmResults<ComputableResult> = Filter.queryOn(realm, this.conditions)
this._computables = computables
return computables
}
/**
* The list of sets to compute
*/
private var _sessionSets: RealmResults<SessionSet>? = null
/**
* Retrieves the session sets on the relative [realm] filtered with the provided [conditions]
*/
fun sessionSets(realm: Realm): RealmResults<SessionSet> {
// if computables exists and is valid (previous realm not closed)
this._sessionSets?.let {
if (it.isValid) {
return it
}
}
val sets: RealmResults<SessionSet> = Filter.queryOn(realm, this.conditions)
this._sessionSets = sets
return sets
}
/** /**
* The list of stats to display * The list of stats to display
@ -41,6 +82,11 @@ class ComputableGroup(name: String, computables: RealmResults<ComputableResult>,
*/ */
var comparedComputedResults: ComputedResults? = null var comparedComputedResults: ComputedResults? = null
fun cleanup() {
this._computables = null
this._sessionSets = null
}
} }
class ComputedResults(group: ComputableGroup) { class ComputedResults(group: ComputableGroup) {
@ -56,7 +102,7 @@ class ComputedResults(group: ComputableGroup) {
// The map containing all evolution numericValues for all stats // The map containing all evolution numericValues for all stats
private var _evolutionValues: MutableMap<Stat, MutableList<Point>> = mutableMapOf() private var _evolutionValues: MutableMap<Stat, MutableList<Point>> = mutableMapOf()
fun allStats() : Collection<ComputedStat> { fun allStats(): Collection<ComputedStat> {
return this._computedStats.values return this._computedStats.values
} }
@ -87,7 +133,7 @@ class ComputedResults(group: ComputableGroup) {
} }
} }
fun computedStat(stat: Stat) : ComputedStat? { fun computedStat(stat: Stat): ComputedStat? {
return this._computedStats[stat] return this._computedStats[stat]
} }
@ -117,46 +163,46 @@ class ComputedResults(group: ComputableGroup) {
/** /**
* Returns the number of computed stats * Returns the number of computed stats
*/ */
fun numberOfStats() : Int { fun numberOfStats(): Int {
return this._computedStats.size return this._computedStats.size
} }
// MPAndroidChart // MPAndroidChart
fun defaultStatEntries(stat: Stat) : Array<out Entry> { fun defaultStatEntries(stat: Stat): List<out Entry> {
return when (stat) { return when (stat) {
Stat.NUMBER_OF_SETS, Stat.NUMBER_OF_GAMES -> this.barEntries(stat) Stat.NUMBER_OF_SETS, Stat.NUMBER_OF_GAMES -> this.barEntries(stat)
else -> this.singleLineEntries(stat) else -> this.singleLineEntries(stat)
} }
} }
fun singleLineEntries(stat: Stat) : Array<Entry> { fun singleLineEntries(stat: Stat): List<Entry> {
var entries = mutableListOf<Entry>() var entries = mutableListOf<Entry>()
this._evolutionValues[stat]?.let { points -> this._evolutionValues[stat]?.let { points ->
points.forEachIndexed { index, p -> points.forEachIndexed { index, p ->
entries.add(Entry(index.toFloat(), p.y.toFloat(), p.data)) entries.add(Entry(index.toFloat(), p.y.toFloat(), p.data))
} }
} }
return entries.toTypedArray() return entries
} }
fun durationEntries(stat: Stat) : Array<Entry> { fun durationEntries(stat: Stat): List<Entry> {
var entries = mutableListOf<Entry>() var entries = mutableListOf<Entry>()
this._evolutionValues[stat]?.let { points -> this._evolutionValues[stat]?.let { points ->
points.forEach { p -> points.forEach { p ->
entries.add(Entry(p.x.toFloat(), p.y.toFloat(), p.data)) entries.add(Entry(p.x.toFloat(), p.y.toFloat(), p.data))
} }
} }
return entries.toTypedArray() return entries
} }
fun barEntries(stat: Stat) : Array<BarEntry> { fun barEntries(stat: Stat): List<BarEntry> {
var entries = arrayOf<BarEntry>() var entries = mutableListOf<BarEntry>()
this._evolutionValues[stat]?.let { points -> this._evolutionValues[stat]?.let { points ->
points.forEach { p -> points.forEach { p ->
entries[0] = BarEntry(p.x.toFloat(), p.y.toFloat(), p.data) entries.add(BarEntry(p.x.toFloat(), p.y.toFloat(), p.data))
} }
} }
return entries return entries

@ -40,6 +40,10 @@ class PokerAnalyticsMigration : RealmMigration {
schema.get("Filter")?.let { schema.get("Filter")?.let {
it.renameField("filterElements", "filterConditions") it.renameField("filterElements", "filterConditions")
} }
schema.get("SessionSet")?.let {
it.addPrimaryKey("id")
}
currentVersion++ currentVersion++
} }

@ -1,13 +1,11 @@
package net.pokeranalytics.android.model.realm package net.pokeranalytics.android.model.realm
import android.os.Parcel
import android.os.Parcelable
import io.realm.RealmObject import io.realm.RealmObject
import net.pokeranalytics.android.calculus.interfaces.Computable import net.pokeranalytics.android.calculus.interfaces.Computable
import net.pokeranalytics.android.model.filter.Filterable import net.pokeranalytics.android.model.filter.Filterable
import net.pokeranalytics.android.model.filter.QueryCondition import net.pokeranalytics.android.model.filter.QueryCondition
open class ComputableResult() : RealmObject(), Computable, Filterable, Parcelable { open class ComputableResult() : RealmObject(), Computable, Filterable {
override var ratedNet: Double = 0.0 override var ratedNet: Double = 0.0
@ -27,16 +25,6 @@ open class ComputableResult() : RealmObject(), Computable, Filterable, Parcelabl
var session: Session? = null var session: Session? = null
constructor(parcel: Parcel) : this() {
ratedNet = parcel.readDouble()
bbNet = parcel.readDouble()
hasBigBlind = parcel.readInt()
isPositive = parcel.readInt()
ratedBuyin = parcel.readDouble()
estimatedHands = parcel.readDouble()
bbPer100Hands = parcel.readDouble()
}
fun updateWith(session: Session) { fun updateWith(session: Session) {
this.sessionSet = session.sessionSet this.sessionSet = session.sessionSet
@ -66,28 +54,7 @@ open class ComputableResult() : RealmObject(), Computable, Filterable, Parcelabl
BB_PER100HANDS("bbPer100Hands") BB_PER100HANDS("bbPer100Hands")
} }
override fun writeToParcel(parcel: Parcel, flags: Int) { companion object : Filterable {
parcel.writeDouble(ratedNet)
parcel.writeDouble(bbNet)
parcel.writeInt(hasBigBlind)
parcel.writeInt(isPositive)
parcel.writeDouble(ratedBuyin)
parcel.writeDouble(estimatedHands)
parcel.writeDouble(bbPer100Hands)
}
override fun describeContents(): Int {
return 0
}
companion object CREATOR : Parcelable.Creator<ComputableResult>, Filterable {
override fun createFromParcel(parcel: Parcel): ComputableResult {
return ComputableResult(parcel)
}
override fun newArray(size: Int): Array<ComputableResult?> {
return arrayOfNulls(size)
}
fun fieldNameForQueryType(queryCondition: QueryCondition): String? { fun fieldNameForQueryType(queryCondition: QueryCondition): String? {
return "session." + Session.fieldNameForQueryType(queryCondition) return "session." + Session.fieldNameForQueryType(queryCondition)

@ -10,6 +10,7 @@ import net.pokeranalytics.android.ui.view.rowrepresentable.FilterCategoryRow
import net.pokeranalytics.android.ui.view.rowrepresentable.FilterElementRow import net.pokeranalytics.android.ui.view.rowrepresentable.FilterElementRow
import net.pokeranalytics.android.ui.view.rowrepresentable.FilterSectionRow import net.pokeranalytics.android.ui.view.rowrepresentable.FilterSectionRow
import org.jetbrains.annotations.TestOnly import org.jetbrains.annotations.TestOnly
import timber.log.Timber
import java.util.* import java.util.*
/** /**
@ -43,8 +44,9 @@ open class Filter : RealmObject() {
inline fun <reified T : Filterable> queryOn(realm: Realm, queries: List<QueryCondition>): RealmResults<T> { inline fun <reified T : Filterable> queryOn(realm: Realm, queries: List<QueryCondition>): RealmResults<T> {
var realmQuery = realm.where<T>() var realmQuery = realm.where<T>()
queries.forEach { queries.forEach {
realmQuery = it.filter<T>(realmQuery) realmQuery = it.filter(realmQuery)
} }
Timber.d(">>> Filter query: ${realmQuery.description}")
return realmQuery.findAll() return realmQuery.findAll()
} }
} }

@ -1,19 +1,21 @@
package net.pokeranalytics.android.model.realm package net.pokeranalytics.android.model.realm
import android.os.Parcel
import android.os.Parcelable
import io.realm.Realm import io.realm.Realm
import io.realm.RealmObject import io.realm.RealmObject
import io.realm.RealmResults import io.realm.RealmResults
import io.realm.annotations.Ignore import io.realm.annotations.Ignore
import io.realm.annotations.LinkingObjects import io.realm.annotations.LinkingObjects
import io.realm.annotations.PrimaryKey
import net.pokeranalytics.android.model.filter.Filterable import net.pokeranalytics.android.model.filter.Filterable
import net.pokeranalytics.android.model.filter.QueryCondition import net.pokeranalytics.android.model.filter.QueryCondition
import net.pokeranalytics.android.model.interfaces.Timed import net.pokeranalytics.android.model.interfaces.Timed
import java.util.* import java.util.*
open class SessionSet() : RealmObject(), Timed, Filterable, Parcelable { open class SessionSet() : RealmObject(), Timed, Filterable {
@PrimaryKey
var id = UUID.randomUUID().toString()
var startDate: Date = Date() var startDate: Date = Date()
set(value) { set(value) {
@ -72,13 +74,6 @@ open class SessionSet() : RealmObject(), Timed, Filterable, Parcelable {
var bbNet: Double = 0.0 var bbNet: Double = 0.0
constructor(parcel: Parcel) : this() {
netDuration = parcel.readLong()
ratedNet = parcel.readDouble()
estimatedHands = parcel.readDouble()
bbNet = parcel.readDouble()
}
enum class Field(val identifier: String) { enum class Field(val identifier: String) {
RATED_NET("ratedNet"), RATED_NET("ratedNet"),
HOURLY_RATE("hourlyRate"), HOURLY_RATE("hourlyRate"),
@ -87,31 +82,10 @@ open class SessionSet() : RealmObject(), Timed, Filterable, Parcelable {
NET_DURATION("netDuration") NET_DURATION("netDuration")
} }
override fun writeToParcel(parcel: Parcel, flags: Int) { companion object : Filterable {
parcel.writeLong(netDuration)
parcel.writeDouble(ratedNet)
parcel.writeDouble(estimatedHands)
parcel.writeDouble(bbNet)
}
override fun describeContents(): Int {
return 0
}
companion object CREATOR : Parcelable.Creator<SessionSet>, Filterable {
override fun createFromParcel(parcel: Parcel): SessionSet {
return SessionSet(parcel)
}
override fun newArray(size: Int): Array<SessionSet?> {
return arrayOfNulls(size)
}
// Filterable
fun newInstance(realm: Realm) : SessionSet { fun newInstance(realm: Realm) : SessionSet {
val sessionSet: SessionSet = realm.createObject(SessionSet::class.java) val sessionSet = SessionSet()
return realm.copyToRealm(sessionSet) return realm.copyToRealm(sessionSet)
} }

@ -9,6 +9,11 @@ import net.pokeranalytics.android.calculus.Stat
import net.pokeranalytics.android.ui.activity.components.PokerAnalyticsActivity import net.pokeranalytics.android.ui.activity.components.PokerAnalyticsActivity
import net.pokeranalytics.android.ui.fragment.GraphFragment import net.pokeranalytics.android.ui.fragment.GraphFragment
class GraphParameters(stat: Stat, entries: List<out Entry>) {
var stat: Stat = stat
var entries: List<out Entry> = entries
}
class GraphActivity : PokerAnalyticsActivity() { class GraphActivity : PokerAnalyticsActivity() {
private enum class IntentKey(val keyName: String) { private enum class IntentKey(val keyName: String) {
@ -18,13 +23,17 @@ class GraphActivity : PokerAnalyticsActivity() {
companion object { 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 * Default constructor
*/ */
fun newInstance(context: Context, stat: Stat, entries: Array<out Entry>) { fun newInstance(context: Context, stat: Stat, entries: List<Entry>) {
GraphActivity.parameters = GraphParameters(stat, entries)
val intent = Intent(context, GraphActivity::class.java) val intent = Intent(context, GraphActivity::class.java)
intent.putExtra(IntentKey.STAT.keyName, stat.name)
intent.putExtra(IntentKey.ENTRIES.keyName, entries)
context.startActivity(intent) context.startActivity(intent)
} }
@ -41,16 +50,19 @@ class GraphActivity : PokerAnalyticsActivity() {
*/ */
private fun initUI() { private fun initUI() {
val stat = Stat.valueOf(intent.getStringExtra(IntentKey.STAT.keyName))
val entries = intent.getParcelableArrayExtra(IntentKey.ENTRIES.keyName)
val fragmentManager = supportFragmentManager val fragmentManager = supportFragmentManager
val fragmentTransaction = fragmentManager.beginTransaction() val fragmentTransaction = fragmentManager.beginTransaction()
val fragment = GraphFragment() val fragment = GraphFragment()
fragmentTransaction.add(R.id.container, fragment) fragmentTransaction.add(R.id.container, fragment)
fragmentTransaction.commit() fragmentTransaction.commit()
fragment.setData(stat, entries)
GraphActivity.parameters?.let {
fragment.setData(it.stat, it.entries)
GraphActivity.parameters = null
} ?: run {
throw Exception("Missing graph parameters")
}
} }

@ -1,7 +1,6 @@
package net.pokeranalytics.android.ui.fragment package net.pokeranalytics.android.ui.fragment
import android.os.Bundle import android.os.Bundle
import android.os.Parcelable
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
@ -21,16 +20,16 @@ interface GraphDataSource {
class GraphFragment : PokerAnalyticsFragment() { class GraphFragment : PokerAnalyticsFragment() {
lateinit var dataSource: GraphDataSource lateinit var dataSource: GraphDataSource
lateinit var entries: Array<Parcelable>
lateinit var stat: Stat lateinit var stat: Stat
lateinit var entries: List<Entry>
companion object { companion object {
} }
fun setData(stat: Stat, entries: Array<Parcelable>) { fun setData(stat: Stat, entries: List<Entry>) {
this.stat = stat this.stat = stat
this.entries = entries this.entries = entries
} }
@ -46,14 +45,10 @@ class GraphFragment : PokerAnalyticsFragment() {
private fun initUI() { private fun initUI() {
(this.entries.toList() as MutableList<Entry>).let { entries -> val dataSet = LineDataSet(this.entries, this.stat.name)
val dataSet = LineDataSet(entries, stat.name)
val lineData = LineData(listOf(dataSet)) val lineData = LineData(listOf(dataSet))
this.chart.data = lineData this.chart.data = lineData
} }
}
} }

@ -11,9 +11,7 @@ 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.model.StatRepresentable
import net.pokeranalytics.android.model.realm.ComputableResult import net.pokeranalytics.android.model.filter.QueryCondition
import net.pokeranalytics.android.model.realm.Session
import net.pokeranalytics.android.model.realm.SessionSet
import net.pokeranalytics.android.ui.activity.GraphActivity import net.pokeranalytics.android.ui.activity.GraphActivity
import net.pokeranalytics.android.ui.adapter.DisplayDescriptor import net.pokeranalytics.android.ui.adapter.DisplayDescriptor
import net.pokeranalytics.android.ui.adapter.RowRepresentableAdapter import net.pokeranalytics.android.ui.adapter.RowRepresentableAdapter
@ -165,32 +163,16 @@ class StatsFragment : SessionObserverFragment(), StaticRowRepresentableDataSourc
private fun createSessionGroupsAndStartCompute(realm: Realm) : List<ComputedResults> { private fun createSessionGroupsAndStartCompute(realm: Realm) : List<ComputedResults> {
val s = Date()
val allSessions = realm.where(ComputableResult::class.java).findAll()
val allSessionSets = realm.where(SessionSet::class.java).findAll()
Timber.d(">>>>> number of computables to compute = ${allSessions.size}")
val cgSessions = allSessions.where().equalTo("session.type", Session.Type.CASH_GAME.ordinal).findAll()
val cgSessionSets = realm.where(SessionSet::class.java).equalTo("sessions.type", Session.Type.CASH_GAME.ordinal).findAll()
val tSessions = allSessions.where().equalTo("session.type", Session.Type.TOURNAMENT.ordinal).findAll()
val tSessionSets = realm.where(SessionSet::class.java).equalTo("sessions.type", Session.Type.TOURNAMENT.ordinal).findAll()
val e = Date()
val duration = (e.time - s.time) / 1000.0
Timber.d(">>> filtering in ${duration} seconds")
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, allSessions, allSessionSets, 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, cgSessions, cgSessionSets, 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, tSessions, tSessionSets, tStats) val tSessionGroup = ComputableGroup(stringTournament, listOf(QueryCondition.TOURNAMENT), tStats)
Timber.d(">>>>> Start computations...") Timber.d(">>>>> Start computations...")
return Calculator.computeGroups(listOf(allSessionGroup, cgSessionGroup, tSessionGroup), Calculator.Options()) return Calculator.computeGroups(realm, listOf(allSessionGroup, cgSessionGroup, tSessionGroup), Calculator.Options())
} }
@ -217,8 +199,6 @@ class StatsFragment : SessionObserverFragment(), StaticRowRepresentableDataSourc
override fun onRowSelected(position: Int, row: RowRepresentable, fromAction: Boolean) { override fun onRowSelected(position: Int, row: RowRepresentable, fromAction: Boolean) {
return
if (row is StatRepresentable) { if (row is StatRepresentable) {
// filter groups // filter groups
@ -245,7 +225,7 @@ class StatsFragment : SessionObserverFragment(), StaticRowRepresentableDataSourc
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
results = Calculator.computeGroups(listOf(computableGroup), options) results = Calculator.computeGroups(realm, listOf(computableGroup), options)
realm.close() realm.close()
val e = Date() val e = Date()

Loading…
Cancel
Save