powerreport
Laurent 3 years ago
parent 80a617b5ce
commit 991cb6bf6e
  1. 7
      app/src/main/java/net/pokeranalytics/android/calculus/Calculator.kt
  2. 83
      app/src/main/java/net/pokeranalytics/android/calculus/ReportWhistleBlower.kt
  3. 1
      app/src/main/java/net/pokeranalytics/android/model/filter/QueryCondition.kt
  4. 5
      app/src/main/java/net/pokeranalytics/android/ui/activity/HomeActivity.kt
  5. 16
      app/src/main/java/net/pokeranalytics/android/ui/fragment/ImportFragment.kt
  6. 13
      app/src/main/java/net/pokeranalytics/android/ui/fragment/ReportsFragment.kt
  7. 12
      app/src/main/java/net/pokeranalytics/android/ui/view/rows/StaticReport.kt

@ -13,6 +13,7 @@ import net.pokeranalytics.android.model.realm.ComputableResult
import net.pokeranalytics.android.model.realm.Filter import net.pokeranalytics.android.model.realm.Filter
import net.pokeranalytics.android.model.realm.SessionSet import net.pokeranalytics.android.model.realm.SessionSet
import net.pokeranalytics.android.util.extensions.startOfDay import net.pokeranalytics.android.util.extensions.startOfDay
import timber.log.Timber
import java.util.* import java.util.*
import kotlin.math.max import kotlin.math.max
import kotlin.math.min import kotlin.math.min
@ -178,13 +179,13 @@ class Calculator {
val computableGroups: MutableList<ComputableGroup> = mutableListOf() val computableGroups: MutableList<ComputableGroup> = mutableListOf()
options.criterias.combined().forEach { comparatorQuery -> val combinations = options.criterias.combined()
Timber.d("Combinations: ${ combinations.map { it.defaultName }}")
for (comparatorQuery in combinations) {
comparatorQuery.merge(options.query) comparatorQuery.merge(options.query)
val group = ComputableGroup(comparatorQuery) val group = ComputableGroup(comparatorQuery)
computableGroups.add(group) computableGroups.add(group)
} }
if (computableGroups.size == 0) { if (computableGroups.size == 0) {

@ -2,6 +2,7 @@ package net.pokeranalytics.android.calculus
import android.content.Context import android.content.Context
import io.realm.Realm import io.realm.Realm
import io.realm.RealmQuery
import io.realm.RealmResults import io.realm.RealmResults
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
@ -30,6 +31,8 @@ class ReportWhistleBlower(var context: Context) {
private val listeners: MutableList<NewPerformanceListener> = mutableListOf() private val listeners: MutableList<NewPerformanceListener> = mutableListOf()
private var paused: Boolean = false
init { init {
val realm = Realm.getDefaultInstance() val realm = Realm.getDefaultInstance()
@ -43,15 +46,25 @@ class ReportWhistleBlower(var context: Context) {
this.results?.addChangeListener { _ -> this.results?.addChangeListener { _ ->
launchReportTask() launchReportTask()
} }
realm.close()
} }
fun addListener(newPerformanceListener: NewPerformanceListener) { fun addListener(newPerformanceListener: NewPerformanceListener) {
this.listeners.add(newPerformanceListener) this.listeners.add(newPerformanceListener)
} }
fun removeListener(listener: NewPerformanceListener) {
this.listeners.remove(listener)
}
fun launchReportTask() { fun launchReportTask() {
Timber.d(">>> Launch report") Timber.d(">>> Launch report")
if (paused) {
return
}
synchronized(this) { synchronized(this) {
this.currentTask?.cancel() this.currentTask?.cancel()
val reportTask = ReportTask(this, this.context) val reportTask = ReportTask(this, this.context)
@ -61,6 +74,15 @@ class ReportWhistleBlower(var context: Context) {
} }
fun pause() {
this.paused = true
}
fun resume() {
this.paused = false
this.launchReportTask()
}
fun has(performanceId: String): Boolean { fun has(performanceId: String): Boolean {
return this.currentNotifications.contains(performanceId) return this.currentNotifications.contains(performanceId)
} }
@ -144,43 +166,46 @@ class ReportTask(private var whistleBlower: ReportWhistleBlower, var context: Co
private fun launchOptimalDuration(realm: Realm, report: StaticReport) { private fun launchOptimalDuration(realm: Realm, report: StaticReport) {
LiveOnline.values().forEach { key -> LiveOnline.values().forEach { key ->
val duration = CashGameOptimalDurationCalculator.start(key.isLive) val duration = CashGameOptimalDurationCalculator.start(key.isLive)
duration?.let { analyseOptimalDuration(realm, report, key, duration)
analyseOptimalDuration(realm, report, key, it)
}
} }
} }
private fun analyseDefaultReport(realm: Realm, staticReport: StaticReport, result: Report) { private fun analyseDefaultReport(realm: Realm, staticReport: StaticReport, result: Report) {
val nameSeparator = " "
for (stat in result.options.stats) { for (stat in result.options.stats) {
Timber.d("analyse stat: $stat for report: $staticReport") Timber.d("analyse stat: $stat for report: $staticReport")
result.max(stat)?.let { computedResults -> // Get current performance
var query = performancesQuery(realm, staticReport, stat)
val customField: CustomField? = val customField: CustomField? =
(staticReport as? StaticReport.CustomFieldList)?.customField (staticReport as? StaticReport.CustomFieldList)?.customField
var query = realm.where(Performance::class.java)
.equalTo("key", stat.uniqueIdentifier)
.equalTo("reportId", staticReport.uniqueIdentifier)
customField?.let { customField?.let {
query = query.equalTo("customFieldId", it.id) query = query.equalTo("customFieldId", it.id)
} }
val currentPerf = query.findFirst() val currentPerf = query.findFirst()
// Store if necessary, delete if necessary
val bestComputedResults = result.max(stat)
bestComputedResults?.let { computedResults ->
val performanceQuery = computedResults.group.query val performanceQuery = computedResults.group.query
val performanceName = performanceQuery.getName(this.context, " ") val performanceName = performanceQuery.getName(this.context, nameSeparator)
Timber.d("Best computed = $performanceName, ${computedResults.computedStat(Stat.NET_RESULT)?.value}")
var storePerf = true var storePerf = true
currentPerf?.let { currentPerf?.let {
currentPerf.name?.let { currentPerf.name?.let { name ->
if (computedResults.group.query.defaultName == it) { if (computedResults.group.query.getName(this.context, nameSeparator) == name) {
storePerf = false storePerf = false
} }
} }
currentPerf.objectId?.let { currentPerf.objectId?.let { objectId ->
if (computedResults.group.query.objectId == it) { if (computedResults.group.query.objectId == objectId) {
storePerf = false storePerf = false
} }
} }
@ -209,20 +234,26 @@ class ReportTask(private var whistleBlower: ReportWhistleBlower, var context: Co
this.whistleBlower.notify(performance) this.whistleBlower.notify(performance)
} }
} ?: run { // if there is no max but a now irrelevant Performance, we delete it
Timber.d("NO best computed value, current perf = $currentPerf ")
currentPerf?.let { perf ->
realm.executeTransaction {
Timber.d("Delete perf: stat = ${perf.stat}, report = ${perf.reportId}")
perf.deleteFromRealm()
}
}
} }
} }
} }
private fun analyseOptimalDuration(realm: Realm, staticReport: StaticReport, key: PerformanceKey, duration: Double) { private fun analyseOptimalDuration(realm: Realm, staticReport: StaticReport, key: PerformanceKey, duration: Double?) {
var storePerf = true val performance = performancesQuery(realm, staticReport, key).findFirst()
val performance = realm.where(Performance::class.java) duration?.let {
.equalTo("reportId", staticReport.uniqueIdentifier) var storePerf = true
.equalTo("key", key.value)
.findFirst()
val formattedDuration = (duration / 3600 / 1000).formattedHourlyDuration() val formattedDuration = (duration / 3600 / 1000).formattedHourlyDuration()
performance?.let { perf -> performance?.let { perf ->
@ -244,6 +275,20 @@ class ReportTask(private var whistleBlower: ReportWhistleBlower, var context: Co
this.whistleBlower.notify(perf) this.whistleBlower.notify(perf)
} }
} ?: run { // no duration
performance?.let { perf ->
realm.executeTransaction {
perf.deleteFromRealm() // delete if the perf exists
}
}
}
}
private fun performancesQuery(realm: Realm, staticReport: StaticReport, key: PerformanceKey): RealmQuery<Performance> {
return realm.where(Performance::class.java)
.equalTo("reportId", staticReport.uniqueIdentifier)
.equalTo("key", key.value)
} }
} }

@ -95,6 +95,7 @@ sealed class QueryCondition : RowRepresentable {
inline fun <reified T : Filterable, reified S : QueryCondition, reified U : Comparable<U>> distinct(): RealmResults<T>? { inline fun <reified T : Filterable, reified S : QueryCondition, reified U : Comparable<U>> distinct(): RealmResults<T>? {
FilterHelper.fieldNameForQueryType<T>(S::class.java)?.let { FilterHelper.fieldNameForQueryType<T>(S::class.java)?.let {
val realm = Realm.getDefaultInstance() val realm = Realm.getDefaultInstance()
realm.refresh()
val distincts = when (T::class) { val distincts = when (T::class) {
String::class, Int::class -> realm.where<T>().distinct(it).findAll().sort(it, Sort.ASCENDING) String::class, Int::class -> realm.where<T>().distinct(it).findAll().sort(it, Sort.ASCENDING)

@ -103,6 +103,11 @@ class HomeActivity : BaseActivity(), NewPerformanceListener {
} }
override fun onDestroy() {
super.onDestroy()
this.paApplication.reportWhistleBlower?.removeListener(this)
}
private fun observeRealmObjects() { private fun observeRealmObjects() {
val realm = getRealm() val realm = getRealm()

@ -6,6 +6,7 @@ import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.TextView import android.widget.TextView
import com.google.android.material.snackbar.Snackbar import com.google.android.material.snackbar.Snackbar
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
@ -21,9 +22,6 @@ import java.util.*
class ImportFragment : RealmFragment(), ImportDelegate { class ImportFragment : RealmFragment(), ImportDelegate {
// val coroutineContext: CoroutineContext
// get() = Dispatchers.Main
private lateinit var filePath: String private lateinit var filePath: String
private lateinit var inputStream: InputStream private lateinit var inputStream: InputStream
private lateinit var importer: CSVImporter private lateinit var importer: CSVImporter
@ -86,15 +84,14 @@ class ImportFragment : RealmFragment(), ImportDelegate {
private fun startImport() { private fun startImport() {
// var shouldDismissActivity = false this.parentActivity?.paApplication?.reportWhistleBlower?.pause()
this.importer = CSVImporter(inputStream) this.importer = CSVImporter(inputStream)
this.importer.delegate = this this.importer.delegate = this
CoroutineScope(coroutineContext).launch {
GlobalScope.launch(coroutineContext) { val coroutine = GlobalScope.async {
val test = GlobalScope.async {
val s = Date() val s = Date()
Timber.d(">>> Start Import...") Timber.d(">>> Start Import...")
@ -105,7 +102,7 @@ class ImportFragment : RealmFragment(), ImportDelegate {
Timber.d(">>> Import ended in $duration seconds") Timber.d(">>> Import ended in $duration seconds")
} }
test.await() coroutine.await()
val exceptionMessage = exceptions.firstOrNull()?.message val exceptionMessage = exceptions.firstOrNull()?.message
if (exceptionMessage != null && view != null) { if (exceptionMessage != null && view != null) {
@ -139,12 +136,11 @@ class ImportFragment : RealmFragment(), ImportDelegate {
} }
private fun importDidFinish() { private fun importDidFinish() {
binding.save.isEnabled = true binding.save.isEnabled = true
} }
private fun end() { private fun end() {
this.parentActivity?.paApplication?.reportWhistleBlower?.resume()
activity?.finish() activity?.finish()
} }

@ -190,6 +190,11 @@ class ReportsFragment : DeletableItemFragment(), StaticRowRepresentableDataSourc
} }
override fun onDestroy() {
super.onDestroy()
this.paApplication?.reportWhistleBlower?.removeListener(this)
}
// Rows // Rows
private fun updateRows() { private fun updateRows() {
@ -207,15 +212,16 @@ class ReportsFragment : DeletableItemFragment(), StaticRowRepresentableDataSourc
private fun addStaticReportRows() { private fun addStaticReportRows() {
context?.let { context ->
val sections = buildReportSections() val sections = buildReportSections()
for (section in sections) { for (section in sections) {
adapterRows.add(CustomizableRowRepresentable(customViewType = RowViewType.HEADER_TITLE, title = section.getDisplayName(requireContext()))) adapterRows.add(CustomizableRowRepresentable(customViewType = RowViewType.HEADER_TITLE, title = section.getDisplayName(context)))
for (performance in section.performances) { for (performance in section.performances) {
adapterRows.add(performance) adapterRows.add(performance)
} }
} }
}
} }
private fun buildReportSections(): List<ReportSection> { private fun buildReportSections(): List<ReportSection> {
@ -330,8 +336,7 @@ class ReportsFragment : DeletableItemFragment(), StaticRowRepresentableDataSourc
override fun newBestPerformanceHandler() { override fun newBestPerformanceHandler() {
Timber.d("newBestPerformanceHandler called") Timber.d("newBestPerformanceHandler called")
requireActivity().runOnUiThread { activity?.runOnUiThread {
// this.updateRows()
this.dataListAdapter.notifyDataSetChanged() this.dataListAdapter.notifyDataSetChanged()
} }

@ -17,7 +17,7 @@ import net.pokeranalytics.android.util.enumerations.IntIdentifiable
*/ */
sealed class StaticReport(override var uniqueIdentifier: Int) : RowRepresentable, IntIdentifiable { sealed class StaticReport(override var uniqueIdentifier: Int) : RowRepresentable, IntIdentifiable {
object General : StaticReport(1) object General : StaticReport(1)
object Blinds : StaticReport(2) object Stakes : StaticReport(2)
object TournamentBuyin : StaticReport(3) object TournamentBuyin : StaticReport(3)
object DayOfWeek : StaticReport(4) object DayOfWeek : StaticReport(4)
object Location : StaticReport(5) object Location : StaticReport(5)
@ -35,7 +35,7 @@ sealed class StaticReport(override var uniqueIdentifier: Int) : RowRepresentable
return when (reportIdentifier) { return when (reportIdentifier) {
1 -> General 1 -> General
2 -> Blinds 2 -> Stakes
3 -> TournamentBuyin 3 -> TournamentBuyin
4 -> DayOfWeek 4 -> DayOfWeek
5 -> Location 5 -> Location
@ -56,8 +56,8 @@ sealed class StaticReport(override var uniqueIdentifier: Int) : RowRepresentable
} }
// val basicReports: Set<StaticReport> = setOf(Duration) // val basicReports: Set<StaticReport> = setOf(Stakes, TableSize)
val basicReports: Set<StaticReport> = setOf(General, Blinds, TournamentBuyin, val basicReports: Set<StaticReport> = setOf(General, Stakes, TournamentBuyin,
DayOfWeek, Location, TournamentType, Game, TableSize, Duration, OptimalDuration) DayOfWeek, Location, TournamentType, Game, TableSize, Duration, OptimalDuration)
} }
@ -71,7 +71,7 @@ sealed class StaticReport(override var uniqueIdentifier: Int) : RowRepresentable
override val resId: Int? override val resId: Int?
get() { get() {
return when (this) { return when (this) {
Blinds -> R.string.blinds Stakes -> R.string.stakes
TournamentBuyin -> R.string.buyin TournamentBuyin -> R.string.buyin
DayOfWeek -> R.string.day_of_the_week DayOfWeek -> R.string.day_of_the_week
General -> R.string.general General -> R.string.general
@ -91,7 +91,7 @@ sealed class StaticReport(override var uniqueIdentifier: Int) : RowRepresentable
val criteria: List<Criteria> val criteria: List<Criteria>
get() { get() {
return when (this) { return when (this) {
Blinds -> listOf(Criteria.Stakes) Stakes -> listOf(Criteria.Stakes)
TournamentBuyin -> listOf(Criteria.TournamentFees) TournamentBuyin -> listOf(Criteria.TournamentFees)
DayOfWeek -> listOf(Criteria.DaysOfWeek) DayOfWeek -> listOf(Criteria.DaysOfWeek)
General -> listOf(Criteria.BankrollTypes, Criteria.SessionTypes) General -> listOf(Criteria.BankrollTypes, Criteria.SessionTypes)

Loading…
Cancel
Save