powerreport
Laurent 3 years ago
parent 80a617b5ce
commit 991cb6bf6e
  1. 7
      app/src/main/java/net/pokeranalytics/android/calculus/Calculator.kt
  2. 115
      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. 21
      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.SessionSet
import net.pokeranalytics.android.util.extensions.startOfDay
import timber.log.Timber
import java.util.*
import kotlin.math.max
import kotlin.math.min
@ -178,13 +179,13 @@ class Calculator {
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)
val group = ComputableGroup(comparatorQuery)
computableGroups.add(group)
}
if (computableGroups.size == 0) {

@ -2,6 +2,7 @@ package net.pokeranalytics.android.calculus
import android.content.Context
import io.realm.Realm
import io.realm.RealmQuery
import io.realm.RealmResults
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
@ -30,6 +31,8 @@ class ReportWhistleBlower(var context: Context) {
private val listeners: MutableList<NewPerformanceListener> = mutableListOf()
private var paused: Boolean = false
init {
val realm = Realm.getDefaultInstance()
@ -43,15 +46,25 @@ class ReportWhistleBlower(var context: Context) {
this.results?.addChangeListener { _ ->
launchReportTask()
}
realm.close()
}
fun addListener(newPerformanceListener: NewPerformanceListener) {
this.listeners.add(newPerformanceListener)
}
fun removeListener(listener: NewPerformanceListener) {
this.listeners.remove(listener)
}
fun launchReportTask() {
Timber.d(">>> Launch report")
if (paused) {
return
}
synchronized(this) {
this.currentTask?.cancel()
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 {
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) {
LiveOnline.values().forEach { key ->
val duration = CashGameOptimalDurationCalculator.start(key.isLive)
duration?.let {
analyseOptimalDuration(realm, report, key, it)
}
analyseOptimalDuration(realm, report, key, duration)
}
}
private fun analyseDefaultReport(realm: Realm, staticReport: StaticReport, result: Report) {
val nameSeparator = " "
for (stat in result.options.stats) {
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? =
(staticReport as? StaticReport.CustomFieldList)?.customField
var query = realm.where(Performance::class.java)
.equalTo("key", stat.uniqueIdentifier)
.equalTo("reportId", staticReport.uniqueIdentifier)
val customField: CustomField? =
(staticReport as? StaticReport.CustomFieldList)?.customField
customField?.let {
query = query.equalTo("customFieldId", it.id)
}
val currentPerf = query.findFirst()
customField?.let {
query = query.equalTo("customFieldId", it.id)
}
val currentPerf = query.findFirst()
// Store if necessary, delete if necessary
val bestComputedResults = result.max(stat)
bestComputedResults?.let { computedResults ->
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
currentPerf?.let {
currentPerf.name?.let {
if (computedResults.group.query.defaultName == it) {
currentPerf.name?.let { name ->
if (computedResults.group.query.getName(this.context, nameSeparator) == name) {
storePerf = false
}
}
currentPerf.objectId?.let {
if (computedResults.group.query.objectId == it) {
currentPerf.objectId?.let { objectId ->
if (computedResults.group.query.objectId == objectId) {
storePerf = false
}
}
@ -209,41 +234,61 @@ class ReportTask(private var whistleBlower: ReportWhistleBlower, var context: Co
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)
.equalTo("reportId", staticReport.uniqueIdentifier)
.equalTo("key", key.value)
.findFirst()
duration?.let {
var storePerf = true
val formattedDuration = (duration / 3600 / 1000).formattedHourlyDuration()
performance?.let { perf ->
if (perf.value == duration) {
storePerf = false
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)
}
} ?: run { // no duration
performance?.let { perf ->
realm.executeTransaction {
perf.name = formattedDuration
perf.value = duration
perf.deleteFromRealm() // delete if the perf exists
}
}
}
if (storePerf) {
val perf = Performance(staticReport, key, name = formattedDuration, value = duration)
realm.executeTransaction { it.copyToRealm(perf) }
this.whistleBlower.notify(perf)
}
}
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>? {
FilterHelper.fieldNameForQueryType<T>(S::class.java)?.let {
val realm = Realm.getDefaultInstance()
realm.refresh()
val distincts = when (T::class) {
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() {
val realm = getRealm()

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

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

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

Loading…
Cancel
Save