Fixes calculation refresh problem

bs
Laurent 5 years ago
parent 50ff357afa
commit b125e94dda
  1. 7
      app/src/main/java/net/pokeranalytics/android/calculus/Calculator.kt
  2. 4
      app/src/main/java/net/pokeranalytics/android/ui/fragment/ImportFragment.kt
  3. 1
      app/src/main/java/net/pokeranalytics/android/ui/fragment/ReportsFragment.kt
  4. 43
      app/src/main/java/net/pokeranalytics/android/ui/fragment/StatisticsFragment.kt
  5. 50
      app/src/main/java/net/pokeranalytics/android/ui/fragment/components/RealmFragment.kt
  6. 4
      app/src/main/java/net/pokeranalytics/android/ui/fragment/report/ComposableTableReportFragment.kt
  7. 5
      app/src/main/java/net/pokeranalytics/android/ui/modules/bankroll/BankrollFragment.kt
  8. 72
      app/src/main/java/net/pokeranalytics/android/ui/modules/calendar/CalendarFragment.kt
  9. 4
      app/src/main/java/net/pokeranalytics/android/ui/modules/session/SessionFragment.kt

@ -18,6 +18,7 @@ import net.pokeranalytics.android.ui.activity.ProgressReportActivity
import net.pokeranalytics.android.ui.activity.TableReportActivity import net.pokeranalytics.android.ui.activity.TableReportActivity
import net.pokeranalytics.android.ui.view.RowRepresentable import net.pokeranalytics.android.ui.view.RowRepresentable
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
@ -281,8 +282,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)
// Timber.d(">>>> Start computing group ${computableGroup.name}, ${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 {
// Timber.d("$$$ buyin = ${it.ratedBuyin} $$$ net result = ${it.ratedNet}")
// }
val sum = computables.sum(ComputableResult.Field.RATED_NET.identifier).toDouble() val sum = computables.sum(ComputableResult.Field.RATED_NET.identifier).toDouble()
results.addStat(NET_RESULT, sum) results.addStat(NET_RESULT, sum)
@ -301,6 +305,7 @@ class Calculator {
val totalBuyin = computables.sum(ComputableResult.Field.RATED_BUYIN.identifier).toDouble() val totalBuyin = computables.sum(ComputableResult.Field.RATED_BUYIN.identifier).toDouble()
results.addStat(TOTAL_BUYIN, totalBuyin) results.addStat(TOTAL_BUYIN, totalBuyin)
Timber.d("########## totalBuyin = ${totalBuyin} ### sum = ${sum}")
val maxNetResult = computables.max(ComputableResult.Field.RATED_NET.identifier)?.toDouble() val maxNetResult = computables.max(ComputableResult.Field.RATED_NET.identifier)?.toDouble()
maxNetResult?.let { maxNetResult?.let {

@ -23,8 +23,8 @@ import kotlin.coroutines.CoroutineContext
class ImportFragment : RealmFragment(), ImportDelegate { class ImportFragment : RealmFragment(), ImportDelegate {
val coroutineContext: CoroutineContext // val coroutineContext: CoroutineContext
get() = Dispatchers.Main // get() = Dispatchers.Main
private lateinit var filePath: String private lateinit var filePath: String
private lateinit var inputStream: InputStream private lateinit var inputStream: InputStream

@ -190,6 +190,7 @@ class ReportsFragment : DeletableItemFragment(), StaticRowRepresentableDataSourc
val startDate = Date() val startDate = Date()
val realm = Realm.getDefaultInstance() val realm = Realm.getDefaultInstance()
realm.refresh()
val report = Calculator.computeStats(realm, options = options) val report = Calculator.computeStats(realm, options = options)

@ -7,8 +7,6 @@ import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import io.realm.Realm import io.realm.Realm
import io.realm.RealmModel
import io.realm.RealmResults
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.async import kotlinx.coroutines.async
@ -23,19 +21,16 @@ import net.pokeranalytics.android.model.filter.Query
import net.pokeranalytics.android.model.filter.QueryCondition 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.Filter
import net.pokeranalytics.android.ui.modules.filter.FiltersActivity
import net.pokeranalytics.android.ui.fragment.components.FilterableFragment import net.pokeranalytics.android.ui.fragment.components.FilterableFragment
import net.pokeranalytics.android.ui.fragment.components.RealmAsyncListener
import net.pokeranalytics.android.ui.fragment.report.ComposableTableReportFragment import net.pokeranalytics.android.ui.fragment.report.ComposableTableReportFragment
import net.pokeranalytics.android.ui.modules.filter.FilterActivityRequestCode import net.pokeranalytics.android.ui.modules.filter.FilterActivityRequestCode
import net.pokeranalytics.android.ui.modules.filter.FilterableType import net.pokeranalytics.android.ui.modules.filter.FilterableType
import net.pokeranalytics.android.ui.modules.filter.FiltersActivity
import timber.log.Timber import timber.log.Timber
import java.util.* import java.util.*
import kotlin.coroutines.CoroutineContext
class StatisticsFragment : FilterableFragment() { class StatisticsFragment : FilterableFragment(), RealmAsyncListener {
private val coroutineContext: CoroutineContext
get() = Dispatchers.Main
private lateinit var tableReportFragment: ComposableTableReportFragment private lateinit var tableReportFragment: ComposableTableReportFragment
@ -64,21 +59,27 @@ class StatisticsFragment : FilterableFragment() {
initUI() initUI()
this.currentFilterable = FilterableType.SESSION this.currentFilterable = FilterableType.SESSION
applyFilter() applyFilter()
listenAsynchronously(this, ComputableResult::class.java)
} }
private fun initUI() { private fun initUI() {
val fragmentTransaction = requireFragmentManager().beginTransaction() val fragmentTransaction = parentFragmentManager.beginTransaction()
val fragment = ComposableTableReportFragment.newInstance(null) val fragment = ComposableTableReportFragment.newInstance(null)
fragmentTransaction.add(R.id.tableContainer, fragment) fragmentTransaction.add(R.id.tableContainer, fragment)
fragmentTransaction.commitAllowingStateLoss() fragmentTransaction.commitAllowingStateLoss()
this.tableReportFragment = fragment this.tableReportFragment = fragment
} }
override val observedEntities: List<Class<out RealmModel>> = listOf(ComputableResult::class.java) // override val observedEntities: List<Class<out RealmModel>> = listOf(ComputableResult::class.java)
override fun entitiesChanged(clazz: Class<out RealmModel>, results: RealmResults<out RealmModel>) { // override fun entitiesChanged(clazz: Class<out RealmModel>, results: RealmResults<out RealmModel>) {
this.launchStatComputation() // Timber.d("Entities changes, launch stats computation, size = ${results.size}")
} // val cr = results as RealmResults<ComputableResult>
// cr.forEach {
// Timber.d("### buyin = ${it.ratedBuyin} ### net result = ${it.ratedNet}")
// }
// this.launchStatComputation()
// }
// override fun convertReportIntoRepresentables(report: Report): ArrayList<RowRepresentable> { // override fun convertReportIntoRepresentables(report: Report): ArrayList<RowRepresentable> {
// val rows: ArrayList<RowRepresentable> = ArrayList() // val rows: ArrayList<RowRepresentable> = ArrayList()
@ -115,6 +116,17 @@ class StatisticsFragment : FilterableFragment() {
// Business // Business
override fun asyncListenedEntityChange(realm: Realm) {
val report = createSessionGroupsAndStartCompute(realm)
tableReportFragment.report = report
GlobalScope.launch(Dispatchers.Main) {
tableReportFragment.showResults()
}
}
/** /**
* Launch stat computation * Launch stat computation
*/ */
@ -122,11 +134,12 @@ class StatisticsFragment : FilterableFragment() {
GlobalScope.launch(coroutineContext) { GlobalScope.launch(coroutineContext) {
val test = GlobalScope.async { val async = GlobalScope.async {
val s = Date() val s = Date()
Timber.d(">>> start...") Timber.d(">>> start...")
val realm = Realm.getDefaultInstance() val realm = Realm.getDefaultInstance()
realm.refresh()
val report = createSessionGroupsAndStartCompute(realm) val report = createSessionGroupsAndStartCompute(realm)
tableReportFragment.report = report tableReportFragment.report = report
@ -138,7 +151,7 @@ class StatisticsFragment : FilterableFragment() {
Timber.d(">>> ended in $duration seconds") Timber.d(">>> ended in $duration seconds")
} }
test.await() async.await()
if (!isDetached) { if (!isDetached) {
tableReportFragment.showResults() tableReportFragment.showResults()

@ -1,20 +1,46 @@
package net.pokeranalytics.android.ui.fragment.components package net.pokeranalytics.android.ui.fragment.components
import android.os.Bundle import android.os.Bundle
import android.os.Looper
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import io.realm.Realm import io.realm.Realm
import io.realm.RealmModel import io.realm.RealmModel
import io.realm.RealmResults import io.realm.RealmResults
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.async
import kotlinx.coroutines.launch
import timber.log.Timber
import kotlin.coroutines.CoroutineContext
interface RealmAsyncListener {
fun asyncListenedEntityChange(realm: Realm)
}
open class RealmFragment : BaseFragment() { open class RealmFragment : BaseFragment() {
val coroutineContext: CoroutineContext
get() = Dispatchers.Main
/** /**
* A realm instance * A realm instance
*/ */
private lateinit var realm: Realm private lateinit var realm: Realm
/***
* A background realm instance
*/
private var asyncRealm: Realm? = null
/***
* A listener to async updates
*/
private var asyncListener: RealmAsyncListener? = null
private var asyncResults: RealmResults<out RealmModel>? = null
/** /**
* A List of observed RealmResults * A List of observed RealmResults
*/ */
@ -36,6 +62,28 @@ open class RealmFragment : BaseFragment() {
return super.onCreateView(inflater, container, savedInstanceState) return super.onCreateView(inflater, container, savedInstanceState)
} }
fun listenAsynchronously(listener: RealmAsyncListener, clazz: Class<out RealmModel>) {
this.asyncListener = listener
GlobalScope.launch(coroutineContext) {
val async = GlobalScope.async {
Looper.prepare() // a looper is required on the thread to listen to change
val realm = Realm.getDefaultInstance()
asyncResults = realm.where(clazz).findAll()
asyncResults?.addChangeListener { t, _ ->
Timber.d("Realm changes: ${asyncResults?.size}, ${this@RealmFragment}")
asyncListener?.asyncListenedEntityChange(t.realm)
}
Looper.loop()
asyncRealm = realm
}
async.await()
}
}
override fun onDestroyView() { override fun onDestroyView() {
super.onDestroyView() super.onDestroyView()
@ -44,6 +92,8 @@ open class RealmFragment : BaseFragment() {
} }
this.realm.close() this.realm.close()
this.asyncResults?.removeAllChangeListeners()
this.asyncRealm?.close()
} }
/** /**

@ -34,8 +34,8 @@ import kotlin.coroutines.CoroutineContext
open class ComposableTableReportFragment : RealmFragment(), StaticRowRepresentableDataSource, CoroutineScope, open class ComposableTableReportFragment : RealmFragment(), StaticRowRepresentableDataSource, CoroutineScope,
RowRepresentableDelegate { RowRepresentableDelegate {
override val coroutineContext: CoroutineContext // override val coroutineContext: CoroutineContext
get() = Dispatchers.Main // get() = Dispatchers.Main
private var rowRepresentables: ArrayList<RowRepresentable> = ArrayList() private var rowRepresentables: ArrayList<RowRepresentable> = ArrayList()

@ -50,8 +50,7 @@ class BankrollFragment : DeletableItemFragment(), StaticRowRepresentableDataSour
* Create new instance * Create new instance
*/ */
fun newInstance(): BankrollFragment { fun newInstance(): BankrollFragment {
val fragment = val fragment = BankrollFragment()
BankrollFragment()
val bundle = Bundle() val bundle = Bundle()
fragment.arguments = bundle fragment.arguments = bundle
return fragment return fragment
@ -135,7 +134,7 @@ class BankrollFragment : DeletableItemFragment(), StaticRowRepresentableDataSour
rows.add(CustomizableRowRepresentable(RowViewType.HEADER_TITLE, resId = R.string.bankrolls)) rows.add(CustomizableRowRepresentable(RowViewType.HEADER_TITLE, resId = R.string.bankrolls))
bankrolls.forEach { bankroll -> bankrolls.forEach { bankroll ->
Timber.d("Creating row for br : ${bankroll.id}, name= ${bankroll.name}, isManaged = ${bankroll.isManaged()}, isValid = ${bankroll.isValid}") Timber.d("Creating row for br : ${bankroll.id}, name= ${bankroll.name}, isManaged = ${bankroll.isManaged}, isValid = ${bankroll.isValid}")
val row = BankrollTotalRow(bankroll.id, bankroll.name) val row = BankrollTotalRow(bankroll.id, bankroll.name)
rows.add(row) rows.add(row)
bankrollRowRepresentables[bankroll.id] = listOf(row) bankrollRowRepresentables[bankroll.id] = listOf(row)

@ -7,8 +7,6 @@ import android.view.ViewGroup
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import com.google.android.material.tabs.TabLayout import com.google.android.material.tabs.TabLayout
import io.realm.Realm import io.realm.Realm
import io.realm.RealmModel
import io.realm.RealmResults
import kotlinx.android.synthetic.main.fragment_calendar.* import kotlinx.android.synthetic.main.fragment_calendar.*
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
@ -27,6 +25,7 @@ import net.pokeranalytics.android.ui.adapter.RowRepresentableDelegate
import net.pokeranalytics.android.ui.adapter.StaticRowRepresentableDataSource import net.pokeranalytics.android.ui.adapter.StaticRowRepresentableDataSource
import net.pokeranalytics.android.ui.extensions.hideWithAnimation import net.pokeranalytics.android.ui.extensions.hideWithAnimation
import net.pokeranalytics.android.ui.extensions.showWithAnimation import net.pokeranalytics.android.ui.extensions.showWithAnimation
import net.pokeranalytics.android.ui.fragment.components.RealmAsyncListener
import net.pokeranalytics.android.ui.fragment.components.RealmFragment import net.pokeranalytics.android.ui.fragment.components.RealmFragment
import net.pokeranalytics.android.ui.view.CalendarTabs import net.pokeranalytics.android.ui.view.CalendarTabs
import net.pokeranalytics.android.ui.view.RowRepresentable import net.pokeranalytics.android.ui.view.RowRepresentable
@ -35,11 +34,10 @@ import net.pokeranalytics.android.ui.view.rowrepresentable.CustomizableRowRepres
import net.pokeranalytics.android.util.extensions.* import net.pokeranalytics.android.util.extensions.*
import timber.log.Timber import timber.log.Timber
import java.util.* import java.util.*
import kotlin.coroutines.CoroutineContext
class CalendarFragment : RealmFragment(), CoroutineScope, StaticRowRepresentableDataSource, class CalendarFragment : RealmFragment(), CoroutineScope, StaticRowRepresentableDataSource,
RowRepresentableDelegate { RowRepresentableDelegate, RealmAsyncListener {
enum class TimeFilter { enum class TimeFilter {
MONTH, YEAR MONTH, YEAR
@ -51,8 +49,7 @@ class CalendarFragment : RealmFragment(), CoroutineScope, StaticRowRepresentable
* Create new instance * Create new instance
*/ */
fun newInstance(): CalendarFragment { fun newInstance(): CalendarFragment {
val fragment = val fragment = CalendarFragment()
CalendarFragment()
val bundle = Bundle() val bundle = Bundle()
fragment.arguments = bundle fragment.arguments = bundle
return fragment return fragment
@ -61,8 +58,8 @@ class CalendarFragment : RealmFragment(), CoroutineScope, StaticRowRepresentable
private lateinit var calendarAdapter: RowRepresentableAdapter private lateinit var calendarAdapter: RowRepresentableAdapter
override val coroutineContext: CoroutineContext // override val coroutineContext: CoroutineContext
get() = Dispatchers.Main // get() = Dispatchers.Main
private var rows: ArrayList<CustomizableRowRepresentable> = ArrayList() private var rows: ArrayList<CustomizableRowRepresentable> = ArrayList()
@ -86,11 +83,7 @@ class CalendarFragment : RealmFragment(), CoroutineScope, StaticRowRepresentable
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
initData() initData()
initUI() initUI()
} listenAsynchronously(this, ComputableResult::class.java)
override fun onResume() {
super.onResume()
launchStatComputation()
} }
override fun adapterRows(): List<RowRepresentable>? { override fun adapterRows(): List<RowRepresentable>? {
@ -120,11 +113,11 @@ class CalendarFragment : RealmFragment(), CoroutineScope, StaticRowRepresentable
} }
} }
override val observedEntities: List<Class<out RealmModel>> = listOf(ComputableResult::class.java) // override val observedEntities: List<Class<out RealmModel>> = listOf(ComputableResult::class.java)
override fun entitiesChanged(clazz: Class<out RealmModel>, results: RealmResults<out RealmModel>) { // override fun entitiesChanged(clazz: Class<out RealmModel>, results: RealmResults<out RealmModel>) {
launchStatComputation() // launchAsyncStatComputation()
} // }
// Business // Business
@ -132,6 +125,7 @@ class CalendarFragment : RealmFragment(), CoroutineScope, StaticRowRepresentable
* Init data * Init data
*/ */
private fun initData() { private fun initData() {
launchAsyncStatComputation()
} }
/** /**
@ -173,7 +167,7 @@ class CalendarFragment : RealmFragment(), CoroutineScope, StaticRowRepresentable
sessionTypeCondition = null sessionTypeCondition = null
filterSessionCash.isChecked = false filterSessionCash.isChecked = false
filterSessionTournament.isChecked = false filterSessionTournament.isChecked = false
launchStatComputation() launchAsyncStatComputation()
} else if (sessionTypeCondition == null) { } else if (sessionTypeCondition == null) {
filterSessionAll.isChecked = true filterSessionAll.isChecked = true
} }
@ -183,7 +177,7 @@ class CalendarFragment : RealmFragment(), CoroutineScope, StaticRowRepresentable
sessionTypeCondition = QueryCondition.IsCash sessionTypeCondition = QueryCondition.IsCash
filterSessionAll.isChecked = false filterSessionAll.isChecked = false
filterSessionTournament.isChecked = false filterSessionTournament.isChecked = false
launchStatComputation() launchAsyncStatComputation()
} else if (sessionTypeCondition == QueryCondition.IsCash) { } else if (sessionTypeCondition == QueryCondition.IsCash) {
filterSessionCash.isChecked = true filterSessionCash.isChecked = true
} }
@ -193,7 +187,7 @@ class CalendarFragment : RealmFragment(), CoroutineScope, StaticRowRepresentable
sessionTypeCondition = QueryCondition.IsTournament sessionTypeCondition = QueryCondition.IsTournament
filterSessionAll.isChecked = false filterSessionAll.isChecked = false
filterSessionCash.isChecked = false filterSessionCash.isChecked = false
launchStatComputation() launchAsyncStatComputation()
} else if (sessionTypeCondition == QueryCondition.IsTournament) { } else if (sessionTypeCondition == QueryCondition.IsTournament) {
filterSessionTournament.isChecked = true filterSessionTournament.isChecked = true
} }
@ -233,22 +227,35 @@ class CalendarFragment : RealmFragment(), CoroutineScope, StaticRowRepresentable
} }
} }
/** /**
* Launch stat computation * Asynchronously Launch stat computation
*/ */
private fun launchStatComputation() { private fun launchAsyncStatComputation() {
progressBar?.showWithAnimation() progressBar?.showWithAnimation()
recyclerView?.hideWithAnimation() recyclerView?.hideWithAnimation()
GlobalScope.launch { GlobalScope.launch {
val realm = Realm.getDefaultInstance()
realm.refresh()
launchStatComputation(realm)
realm.close()
GlobalScope.launch(Dispatchers.Main) {
displayData()
}
}
}
private fun launchStatComputation(realm: Realm) {
val calendar = Calendar.getInstance() val calendar = Calendar.getInstance()
calendar.time = Date().startOfMonth() calendar.time = Date().startOfMonth()
val startDate = Date() val startDate = Date()
val realm = Realm.getDefaultInstance()
val monthlyReports: HashMap<Date, ComputedResults> = HashMap() val monthlyReports: HashMap<Date, ComputedResults> = HashMap()
val yearlyReports: HashMap<Date, ComputedResults> = HashMap() val yearlyReports: HashMap<Date, ComputedResults> = HashMap()
@ -337,19 +344,13 @@ class CalendarFragment : RealmFragment(), CoroutineScope, StaticRowRepresentable
Timber.d("$it => ${sortedYearlyReports[it]?.computedStat(Stat.NET_RESULT)?.value}") Timber.d("$it => ${sortedYearlyReports[it]?.computedStat(Stat.NET_RESULT)?.value}")
} }
*/ */
realm.close()
GlobalScope.launch(Dispatchers.Main) {
displayData()
}
}
} }
/** /**
* Display data * Display data
*/ */
private fun displayData() { private fun displayData() {
Timber.d("displayData")
val startDate = Date() val startDate = Date()
@ -415,4 +416,13 @@ class CalendarFragment : RealmFragment(), CoroutineScope, StaticRowRepresentable
} }
override fun asyncListenedEntityChange(realm: Realm) {
Timber.d("asyncListenedEntityChange")
launchStatComputation(realm)
activity?.runOnUiThread {
displayData()
}
}
} }

@ -74,8 +74,8 @@ class SessionFragment : RealmFragment(), RowRepresentableDelegate {
} }
} }
private val coroutineContext: CoroutineContext // private val coroutineContext: CoroutineContext
get() = Dispatchers.Main // get() = Dispatchers.Main
override fun onResume() { override fun onResume() {
super.onResume() super.onResume()

Loading…
Cancel
Save