Put async transaction everywhere

perftest
Laurent 3 years ago
parent 4ab1f561d8
commit 621357610b
  1. 3
      app/src/androidTest/java/net/pokeranalytics/android/performanceTests/PerfsInstrumentedUnitTest.kt
  2. 9
      app/src/main/java/net/pokeranalytics/android/PokerAnalyticsApplication.kt
  3. 14
      app/src/main/java/net/pokeranalytics/android/calculus/bankroll/BankrollReportManager.kt
  4. 1
      app/src/main/java/net/pokeranalytics/android/exceptions/Exceptions.kt
  5. 8
      app/src/main/java/net/pokeranalytics/android/model/LiveData.kt
  6. 10
      app/src/main/java/net/pokeranalytics/android/model/migrations/Patcher.kt
  7. 4
      app/src/main/java/net/pokeranalytics/android/model/realm/Filter.kt
  8. 82
      app/src/main/java/net/pokeranalytics/android/model/realm/Result.kt
  9. 19
      app/src/main/java/net/pokeranalytics/android/model/realm/Session.kt
  10. 8
      app/src/main/java/net/pokeranalytics/android/model/realm/SessionSet.kt
  11. 49
      app/src/main/java/net/pokeranalytics/android/model/utils/SessionSetManager.kt
  12. 5
      app/src/main/java/net/pokeranalytics/android/ui/fragment/ReportCreationFragment.kt
  13. 19
      app/src/main/java/net/pokeranalytics/android/ui/fragment/ReportsFragment.kt
  14. 10
      app/src/main/java/net/pokeranalytics/android/ui/fragment/StatisticsFragment.kt
  15. 24
      app/src/main/java/net/pokeranalytics/android/ui/fragment/components/DeletableItemFragment.kt
  16. 15
      app/src/main/java/net/pokeranalytics/android/ui/fragment/report/AbstractReportFragment.kt
  17. 16
      app/src/main/java/net/pokeranalytics/android/ui/fragment/report/ComposableTableReportFragment.kt
  18. 2
      app/src/main/java/net/pokeranalytics/android/ui/modules/data/DataManagerFragment.kt
  19. 20
      app/src/main/java/net/pokeranalytics/android/ui/modules/data/EditableDataFragment.kt
  20. 6
      app/src/main/java/net/pokeranalytics/android/ui/modules/datalist/DataListFragment.kt
  21. 12
      app/src/main/java/net/pokeranalytics/android/ui/modules/feed/FeedFragment.kt
  22. 36
      app/src/main/java/net/pokeranalytics/android/ui/modules/filter/FilterDetailsFragment.kt
  23. 3
      app/src/main/java/net/pokeranalytics/android/ui/modules/filter/FilterViewModel.kt
  24. 11
      app/src/main/java/net/pokeranalytics/android/ui/modules/filter/FiltersFragment.kt
  25. 6
      app/src/main/java/net/pokeranalytics/android/ui/modules/filter/FiltersListFragment.kt
  26. 7
      app/src/main/java/net/pokeranalytics/android/ui/modules/handhistory/editor/EditorFragment.kt
  27. 65
      app/src/main/java/net/pokeranalytics/android/ui/modules/handhistory/model/EditorViewModel.kt
  28. 39
      app/src/main/java/net/pokeranalytics/android/ui/modules/session/SessionFragment.kt
  29. 2
      app/src/main/java/net/pokeranalytics/android/ui/modules/settings/DealtHandsPerHourFragment.kt
  30. 6
      app/src/main/java/net/pokeranalytics/android/ui/modules/settings/TransactionFilterFragment.kt
  31. 4
      app/src/main/java/net/pokeranalytics/android/util/FakeDataManager.kt
  32. 2
      app/src/main/java/net/pokeranalytics/android/util/csv/PACSVDescriptor.kt
  33. 13
      app/src/main/java/net/pokeranalytics/android/util/extensions/RealmExtensions.kt

@ -39,8 +39,7 @@ class PerfsInstrumentedUnitTest : RealmInstrumentedUnitTest() {
Seed(app).execute(realm)
realm.commitTransaction()
FakeDataManager.createFakeSessions(5000) {success ->
FakeDataManager.createFakeSessions(5000) { success ->
if (success) {

@ -7,13 +7,15 @@ import com.google.firebase.FirebaseApp
import io.realm.Realm
import io.realm.RealmConfiguration
import io.realm.kotlin.where
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import net.pokeranalytics.android.calculus.ReportWhistleBlower
import net.pokeranalytics.android.model.migrations.Patcher
import net.pokeranalytics.android.model.migrations.PokerAnalyticsMigration
import net.pokeranalytics.android.model.realm.Session
import net.pokeranalytics.android.model.utils.Seed
import net.pokeranalytics.android.model.utils.SessionSetManager
import net.pokeranalytics.android.util.CrashLogging
import net.pokeranalytics.android.util.FakeDataManager
import net.pokeranalytics.android.util.PokerAnalyticsLogs
@ -53,7 +55,7 @@ class PokerAnalyticsApplication : Application() {
val realmConfiguration = RealmConfiguration.Builder()
.name(Realm.DEFAULT_REALM_NAME)
.schemaVersion(14)
.allowWritesOnUiThread(true)
// .allowWritesOnUiThread(true)
.migration(PokerAnalyticsMigration())
.initialData(Seed(this))
.build()
@ -82,6 +84,7 @@ class PokerAnalyticsApplication : Application() {
// Report
this.reportWhistleBlower = ReportWhistleBlower(this.applicationContext)
// SessionSetManager.configure()
// Infos
val locale = Locale.getDefault()
@ -103,7 +106,7 @@ class PokerAnalyticsApplication : Application() {
realm.close()
if (sessionsCount < 10) {
GlobalScope.launch {
CoroutineScope(Dispatchers.Default).launch {
FakeDataManager.createFakeSessions(500)
}
}

@ -62,12 +62,12 @@ object BankrollReportManager {
}
// otherwise compute it
CoroutineScope(Dispatchers.Default).launch {
CoroutineScope(Dispatchers.Main).launch {
var report: BankrollReport? = null
val coroutine = async {
val s = Date()
Timber.d(">>>>> start computing bankroll...")
val coroutine = CoroutineScope(Dispatchers.Default).async {
// val s = Date()
// Timber.d(">>>>> start computing bankroll...")
val realm = Realm.getDefaultInstance()
@ -76,9 +76,9 @@ object BankrollReportManager {
realm.close()
val e = Date()
val duration = (e.time - s.time) / 1000.0
Timber.d(">>>>> ended in $duration seconds")
// val e = Date()
// val duration = (e.time - s.time) / 1000.0
// Timber.d(">>>>> ended in $duration seconds")
}
coroutine.await()

@ -11,6 +11,7 @@ class ConfigurationException(message: String) : Exception(message)
class EnumIdentifierNotFoundException(message: String) : Exception(message)
class MisconfiguredSavableEnumException(message: String) : Exception(message)
class PAIllegalStateException(message: String) : Exception(message)
class PADataModelException(message: String) : Exception(message)
sealed class PokerAnalyticsException(message: String) : Exception(message) {
object FilterElementUnknownName : PokerAnalyticsException(message = "No filterElement name was found to identify the queryCondition")

@ -30,7 +30,7 @@ enum class LiveData : Localizable {
PLAYER,
HAND_HISTORY;
var subType:Int? = null
var subType: Int? = null
val relatedEntity: Class<out Deletable>
get() {
@ -52,10 +52,10 @@ enum class LiveData : Localizable {
fun updateOrCreate(realm: Realm, primaryKey: String?): Deletable {
val proxyItem: Deletable? = this.getData(realm, primaryKey)
proxyItem?.let {
return realm.copyFromRealm(it)
return proxyItem?.let {
realm.copyFromRealm(it)
} ?: run {
return this.newEntity()
this.newEntity()
}
}

@ -170,9 +170,9 @@ class Patcher {
private fun patchSessionSet() {
val realm = Realm.getDefaultInstance()
realm.executeTransactionAsync {
realm.where(SessionSet::class.java).findAll().deleteAllFromRealm()
val sessions = realm.where(Session::class.java).isNotNull("startDate").isNotNull("endDate").findAll()
realm.executeTransactionAsync { asyncRealm ->
asyncRealm.where(SessionSet::class.java).findAll().deleteAllFromRealm()
val sessions = asyncRealm.where(Session::class.java).isNotNull("startDate").isNotNull("endDate").findAll()
sessions.forEach { session ->
SessionSetManager.updateTimeline(session)
}
@ -187,8 +187,8 @@ class Patcher {
*/
private fun patchComputableResults() {
val realm = Realm.getDefaultInstance()
realm.executeTransactionAsync {
val crs = realm.where(ComputableResult::class.java).findAll()
realm.executeTransactionAsync { asyncRealm ->
val crs = asyncRealm.where(ComputableResult::class.java).findAll()
crs.forEach { cr ->
cr.session?.let { cr.updateWith(it) }
}

@ -109,7 +109,7 @@ open class Filter : RealmObject(), RowRepresentable, RowUpdatable, Deletable, Us
val previousCondition = filterConditions.filter {
it.filterName == newFilterCondition.filterName && it.operator == newFilterCondition.operator
}
filterConditions.removeAll(previousCondition)
filterConditions.removeAll(previousCondition.toSet())
filterConditions.add(newFilterCondition)
}
}
@ -118,7 +118,7 @@ open class Filter : RealmObject(), RowRepresentable, RowUpdatable, Deletable, Us
fun remove(filterCategoryRow: FilterCategoryRow) {
val sections = filterCategoryRow.filterSectionRows.map { it.name }
val savedSections = filterConditions.filter { sections.contains(it.sectionName) }
this.filterConditions.removeAll(savedSections)
this.filterConditions.removeAll(savedSections.toSet())
}
fun countBy(filterCategoryRow: FilterCategoryRow): Int {

@ -6,8 +6,10 @@ import io.realm.RealmResults
import io.realm.annotations.Ignore
import io.realm.annotations.LinkingObjects
import io.realm.annotations.RealmClass
import net.pokeranalytics.android.exceptions.PADataModelException
import net.pokeranalytics.android.model.filter.Filterable
import net.pokeranalytics.android.model.filter.QueryCondition
import java.lang.ref.WeakReference
@RealmClass
open class Result : RealmObject(), Filterable {
@ -40,7 +42,7 @@ open class Result : RealmObject(), Filterable {
field = value
this.computeNet(true)
if (value != null) {
this.session?.end()
this.session().end()
}
}
@ -49,19 +51,10 @@ open class Result : RealmObject(), Filterable {
*/
var netResult: Double? = null
set(value) {
// this.session?.bankroll?.let { bankroll ->
// if (bankroll.live) {
// throw PAIllegalStateException("Can't set net result on a live bankroll")
// }
// } ?: run {
// throw PAIllegalStateException("Session doesn't have any bankroll")
// }
field = value
this.computeNet(false)
if (value != null) {
this.session?.end()
this.session().end()
}
}
@ -77,7 +70,7 @@ open class Result : RealmObject(), Filterable {
var tips: Double? = null
set(value) {
field = value
this.session?.computeStats()
this.session().computeStats()
}
// The transactions associated with the Result, impacting the result
@ -96,16 +89,27 @@ open class Result : RealmObject(), Filterable {
@LinkingObjects("result")
private val sessions: RealmResults<Session>? = null
// @Ignore
// private fun managedSession(): Session {
// return this.sessions?.firstOrNull() ?: throw PAIllegalStateException("Unmanaged Result")
// }
// Manually set session
@Ignore
val session: Session? = this.sessions?.firstOrNull()
var inverseSession: WeakReference<Session>? = null
// @Ignore
fun session() : Session {
return this.inverseSession?.get() ?: throw PADataModelException("Inverse session not set")
}
/**
* Returns 1 if the session is positive
*/
val isPositive: Int
get() {
return if (session?.isTournament() == true) {
if (this.cashout ?: -1.0 >= 0.0) 1 else 0 // if cashout is null we want to count a negative session
return if (session().isTournament()) {
if ((this.cashout ?: -1.0) >= 0.0) 1 else 0 // if cashout is null we want to count a negative session
} else {
if (this.net >= 0.0) 1 else 0
}
@ -124,11 +128,9 @@ open class Result : RealmObject(), Filterable {
} else if (buyin != null || cashout != null) {
useBuyin = true
} else {
this.session?.let { session ->
if (session.isCashGame() && !session.isLive) {
useBuyin = false
}
}
if (this.session().isCashGame() && !this.session().isLive) {
useBuyin = false
}
}
}
@ -142,31 +144,29 @@ open class Result : RealmObject(), Filterable {
}
// Precompute results
this.session?.computeStats()
this.session?.sessionSet?.computeStats()
this.session().computeStats()
this.session().sessionSet?.computeStats()
}
// Computes the number of rebuy
fun computeNumberOfRebuy() {
this.session?.let {
if (it.isCashGame()) {
it.cgBiggestBet?.let { bb ->
if (bb > 0.0) {
this.numberOfRebuy = (this.buyin ?: 0.0) / (bb * 100.0)
} else {
this.numberOfRebuy = null
}
}
} else {
it.tournamentEntryFee?.let { entryFee ->
if (entryFee > 0.0) {
this.numberOfRebuy = (this.buyin ?: 0.0) / entryFee
} else {
this.numberOfRebuy = null
}
}
}
}
if (this.session().isCashGame()) {
this.session().cgBiggestBet?.let { bb ->
if (bb > 0.0) {
this.numberOfRebuy = (this.buyin ?: 0.0) / (bb * 100.0)
} else {
this.numberOfRebuy = null
}
}
} else {
this.session().tournamentEntryFee?.let { entryFee ->
if (entryFee > 0.0) {
this.numberOfRebuy = (this.buyin ?: 0.0) / entryFee
} else {
this.numberOfRebuy = null
}
}
}
}
// @todo tips?

@ -37,6 +37,7 @@ import net.pokeranalytics.android.util.extensions.hourMinute
import net.pokeranalytics.android.util.extensions.shortDateTime
import net.pokeranalytics.android.util.extensions.toCurrency
import net.pokeranalytics.android.util.extensions.toMinutes
import java.lang.ref.WeakReference
import java.text.DateFormat
import java.text.NumberFormat
import java.text.ParseException
@ -67,18 +68,27 @@ open class Session : RealmObject(), Savable, RowUpdatable, RowRepresentable, Tim
companion object {
fun newInstance(realm: Realm, isTournament: Boolean, bankroll: Bankroll? = null, managed: Boolean = true): Session {
fun newInstance(realm: Realm, isTournament: Boolean, bankroll: Bankroll? = null): Session {
val session = Session()
session.result = Result()
val result = Result()
result.inverseSession = WeakReference(session)
session.result = result
if (bankroll != null) {
session.bankroll = bankroll
} else {
session.bankroll = realm.where<Bankroll>().findFirst()
realm.where<Bankroll>().findFirst()?.let { br ->
session.bankroll = realm.copyFromRealm(br)
}
}
session.type = if (isTournament) Type.TOURNAMENT.ordinal else Type.CASH_GAME.ordinal
session.limit = Limit.NO.ordinal
session.game = realm.where(Game::class.java).equalTo("shortName", "HE").findFirst()
realm.where(Game::class.java)
.equalTo("shortName", "HE").findFirst()?.let {
session.game = it
}
return session
// return if (managed) {
@ -923,6 +933,7 @@ open class Session : RealmObject(), Savable, RowUpdatable, RowRepresentable, Tim
return this.result
?: run {
val result = realm.createObject(Result::class.java)
result.inverseSession = WeakReference(this)
this.result = result
result
}

@ -100,10 +100,10 @@ open class SessionSet() : RealmObject(), Timed, Filterable {
companion object {
// fun newInstance(realm: Realm) : SessionSet {
// val sessionSet = SessionSet()
// return realm.copyToRealm(sessionSet)
// }
fun newInstance(realm: Realm) : SessionSet {
val sessionSet = SessionSet()
return realm.copyToRealm(sessionSet)
}
fun fieldNameForQueryType(queryCondition: Class < out QueryCondition >): String? {
Session.fieldNameForQueryType(queryCondition)?.let {

@ -6,6 +6,8 @@ import io.realm.RealmResults
import net.pokeranalytics.android.exceptions.ModelException
import net.pokeranalytics.android.model.realm.Session
import net.pokeranalytics.android.model.realm.SessionSet
import net.pokeranalytics.android.util.extensions.findById
import timber.log.Timber
import kotlin.math.max
class CorruptSessionSetException(message: String) : Exception(message)
@ -24,7 +26,7 @@ object SessionSetManager {
val realm = Realm.getDefaultInstance()
this.sessions = realm.where(Session::class.java).findAll()
this.sessions = realm.where(Session::class.java).findAllAsync()
this.sessions.addChangeListener { sessions, changeSet ->
changeSet.insertions.forEach { index ->
sessions[index]?.let { this.sessionsToProcess.add(it) }
@ -33,7 +35,11 @@ object SessionSetManager {
sessions[index]?.let { this.sessionsToProcess.add(it) }
}
processSessions()
val sessionIds = this.sessionsToProcess.map { it.id }
realm.executeTransactionAsync { asyncRealm ->
processSessions(asyncRealm, sessionIds)
}
}
realm.close()
@ -43,14 +49,25 @@ object SessionSetManager {
// this.sessionsToProcess.add(session)
// }
private fun processSessions() {
for (session in this.sessionsToProcess) {
if (session.startDate != null && session.endDate != null) {
this.updateTimeline(session)
} else if (session.sessionSet != null) {
removeFromTimeline(session)
private fun processSessions(realm: Realm, sessionIds: List<String>) {
for (sessionId in sessionIds) {
realm.findById<Session>(sessionId)?.let { session ->
if (session.startDate != null && session.endDate != null) {
updateTimeline(session)
} else if (session.sessionSet != null) {
removeFromTimeline(session)
}
}
}
// for (session in this.sessionsToProcess) {
// if (session.startDate != null && session.endDate != null) {
// this.updateTimeline(realm, session)
// } else if (session.sessionSet != null) {
// removeFromTimeline(realm, session)
// }
// }
this.sessionsToProcess.clear()
}
@ -59,6 +76,8 @@ object SessionSetManager {
*/
fun updateTimeline(session: Session) {
Timber.d("updateTimeline")
// if (!session.realm.isInTransaction) {
// throw PAIllegalStateException("realm should be in transaction at this point")
// }
@ -73,6 +92,14 @@ object SessionSetManager {
val sessionSets = this.matchingSets(session)
cleanupSessionSets(session, sessionSets)
// val sessionId = session.id
// realm.executeTransactionAsync { asyncRealm ->
// asyncRealm.findById<Session>(sessionId)?.let { s ->
// val sessionSets = this.matchingSets(session)
// cleanupSessionSets(session, sessionSets)
// }
// }
}
private fun matchingSets(session: Session): RealmResults<SessionSet> {
@ -125,12 +152,10 @@ object SessionSetManager {
* Update the global timeline using the impacted [sessionSets] and the updated [session]
*/
private fun updateTimeFrames(sessionSets: RealmResults<SessionSet>, session: Session) {
when (sessionSets.size) {
0 -> this.createOrUpdateSessionSet(session)
else -> this.mergeSessionGroups(session, sessionSets)
}
}
/**
@ -152,7 +177,7 @@ object SessionSetManager {
* Create a set and affect it to the [session]
*/
private fun createSessionSet(session: Session) {
val set = SessionSet() //.newInstance(session.realm)
val set = SessionSet.newInstance(session.realm)
set.startDate = session.startDate!!
set.endDate = session.endDate!!
set.breakDuration = session.breakDuration
@ -196,7 +221,7 @@ object SessionSetManager {
sessionSets.deleteAllFromRealm()
// Create a new set
val set = SessionSet() //.newInstance(session.realm)
val set = SessionSet.newInstance(session.realm)
set.startDate = startDate
set.endDate = endDate

@ -118,11 +118,6 @@ class ReportCreationFragment : RealmFragment(), RowRepresentableDataSource, RowR
if (this.assistant.step == Assistant.Step.FINALIZE) {
// getRealm().executeTransaction {
// val rs = this.assistant.options.reportSetup("test")
// it.insert(rs)
// }
// launch report
this.finishActivityWithOptions(this.assistant.options, this.assistant.reportDisplay)

@ -11,13 +11,11 @@ import android.widget.Toast
import androidx.recyclerview.widget.LinearLayoutManager
import io.realm.Realm
import io.realm.RealmResults
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.*
import net.pokeranalytics.android.R
import net.pokeranalytics.android.calculus.Calculator
import net.pokeranalytics.android.calculus.NewPerformanceListener
import net.pokeranalytics.android.calculus.Report
import net.pokeranalytics.android.calculus.Stat
import net.pokeranalytics.android.calculus.calcul.ReportDisplay
import net.pokeranalytics.android.databinding.FragmentReportsBinding
@ -60,10 +58,7 @@ data class ReportSection(val report: StaticReport, var performances: MutableList
}
data class PerformanceRow(val performance: Performance, val report: StaticReport): RowRepresentable {
override val resId: Int? = this.performance.resId
override val viewType: Int = RowViewType.TITLE_BADGE_VALUE.identifier
}
@ -71,6 +66,7 @@ class ReportsFragment : DeletableItemFragment(), StaticRowRepresentableDataSourc
private lateinit var reportSetups: RealmResults<ReportSetup>
private lateinit var performances: RealmResults<Performance>
private var adapterRows = mutableListOf<RowRepresentable>()
override fun deletableItems(): List<Deletable> {
@ -152,12 +148,12 @@ class ReportsFragment : DeletableItemFragment(), StaticRowRepresentableDataSourc
* Init data
*/
private fun initData() {
this.reportSetups = getRealm().where(ReportSetup::class.java).findAll().sort("name")
this.reportSetups = getRealm().where(ReportSetup::class.java).findAllAsync().sort("name")
this.reportSetups.addChangeListener { _, _ ->
this.updateRows()
}
this.performances = getRealm().where(Performance::class.java).findAll()
this.performances = getRealm().where(Performance::class.java).findAllAsync()
this.performances.addChangeListener { _, _ ->
this.updateRows()
}
@ -315,15 +311,12 @@ class ReportsFragment : DeletableItemFragment(), StaticRowRepresentableDataSourc
CoroutineScope(Dispatchers.Default).launch {
val startDate = Date()
val realm = Realm.getDefaultInstance()
realm.refresh()
val report = Calculator.computeStats(realm, options = options)
// Timber.d("launchComputation: ${System.currentTimeMillis() - startDate.time}ms")
launch(Dispatchers.Main) {
CoroutineScope(Dispatchers.Main).launch {
if (!isDetached) {
hideLoader()
ReportActivity.newInstanceForResult(this@ReportsFragment, report, reportDisplay, reportName)

@ -159,8 +159,8 @@ class StatisticsFragment : FilterableFragment(), RealmAsyncListener {
CoroutineScope(Dispatchers.Default).launch {
val async = async {
val s = Date()
Timber.d(">>> start...")
// val s = Date()
// Timber.d(">>> start...")
val realm = Realm.getDefaultInstance()
realm.refresh()
@ -170,9 +170,9 @@ class StatisticsFragment : FilterableFragment(), RealmAsyncListener {
realm.close()
val e = Date()
val duration = (e.time - s.time) / 1000.0
Timber.d(">>> ended in $duration seconds")
// val e = Date()
// val duration = (e.time - s.time) / 1000.0
// Timber.d(">>> ended in $duration seconds")
}
async.await()

@ -8,15 +8,13 @@ import android.view.ViewGroup
import androidx.appcompat.app.AlertDialog
import com.google.android.material.snackbar.Snackbar
import io.realm.RealmObject
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.*
import net.pokeranalytics.android.R
import net.pokeranalytics.android.exceptions.PAIllegalStateException
import net.pokeranalytics.android.model.interfaces.Deletable
import net.pokeranalytics.android.ui.modules.datalist.DataListActivity
import net.pokeranalytics.android.ui.adapter.RowRepresentableAdapter
import net.pokeranalytics.android.util.extensions.findById
/**
* Deletable Item Fragment
@ -56,7 +54,7 @@ abstract class DeletableItemFragment : RealmFragment() {
val itemToDeleteId = data?.getStringExtra(DataListActivity.IntentKey.ITEM_DELETED.keyName)
itemToDeleteId?.let { id ->
GlobalScope.launch(Dispatchers.Main) {
CoroutineScope(Dispatchers.Main).launch {
delay(300)
deleteItem(dataListAdapter, deletableItems(), id)
}
@ -84,14 +82,21 @@ abstract class DeletableItemFragment : RealmFragment() {
if (itemToDelete is RealmObject && itemPosition != -1) {
val itemClass = itemToDelete.realmObjectClass
// Check if the object is valid for the deletion
if (itemToDelete.isValidForDelete(this.getRealm())) {
deletedItem = getRealm().copyFromRealm(itemToDelete)
lastDeletedItemPosition = itemPosition
getRealm().executeTransaction {
itemToDelete.deleteDependencies(it)
itemToDelete.deleteFromRealm()
getRealm().executeTransactionAsync { asyncRealm ->
val item = asyncRealm.findById(itemClass, itemId) as? Deletable
item?.let {
item.deleteDependencies(asyncRealm)
(item as RealmObject).deleteFromRealm()
}
}
itemHasBeenReInserted = false
updateUIAfterDeletion(itemId, itemPosition)
showUndoSnackBar()
@ -117,7 +122,8 @@ abstract class DeletableItemFragment : RealmFragment() {
snackBar?.setAction(R.string.cancel) {
if (!itemHasBeenReInserted) {
itemHasBeenReInserted = true
getRealm().executeTransaction { realm ->
getRealm().executeTransactionAsync { realm ->
deletedItem?.let {
val item = realm.copyToRealmOrUpdate(it)
updateUIAfterUndoDeletion(item)

@ -121,9 +121,12 @@ abstract class AbstractReportFragment : DataManagerFragment() {
this.reportViewModel.title = name
val rs = this.model.item as ReportSetup
getRealm().executeTransaction { realm ->
val setupId = rs.id
val firstSave = (this.model.primaryKey == null)
getRealm().executeTransactionAsync { realm ->
val firstSave = (this.model.primaryKey == null)
if (firstSave) {
val options = this.selectedReport.options
rs.name = name
@ -143,13 +146,15 @@ abstract class AbstractReportFragment : DataManagerFragment() {
}
realm.copyToRealmOrUpdate(rs)
} else {
rs.name = name
realm.insertOrUpdate(rs)
realm.findById<ReportSetup>(setupId)?.let { reportSetup ->
reportSetup.name = name
realm.insertOrUpdate(reportSetup)
}
}
}
this.model.primaryKey = rs.id
this.model.primaryKey = setupId
this.deleteButtonShouldAppear = true
setToolbarTitle(this.reportViewModel.title)
}

@ -9,11 +9,11 @@ import androidx.recyclerview.widget.LinearLayoutManager
import io.realm.Realm
import kotlinx.coroutines.*
import net.pokeranalytics.android.R
import net.pokeranalytics.android.calculus.calcul.ReportDisplay
import net.pokeranalytics.android.calculus.Calculator
import net.pokeranalytics.android.calculus.ComputableGroup
import net.pokeranalytics.android.calculus.Report
import net.pokeranalytics.android.calculus.Stat
import net.pokeranalytics.android.calculus.calcul.ReportDisplay
import net.pokeranalytics.android.databinding.FragmentComposableTableReportBinding
import net.pokeranalytics.android.exceptions.PAIllegalStateException
import net.pokeranalytics.android.ui.activity.components.ReportActivity
@ -27,8 +27,6 @@ import net.pokeranalytics.android.ui.view.rows.CustomizableRowRepresentable
import net.pokeranalytics.android.ui.view.rows.StatRow
import net.pokeranalytics.android.util.NULL_TEXT
import net.pokeranalytics.android.util.TextFormat
import timber.log.Timber
import java.util.*
open class ComposableTableReportFragment : RealmFragment(), StaticRowRepresentableDataSource,
RowRepresentableDelegate {
@ -208,9 +206,9 @@ open class ComposableTableReportFragment : RealmFragment(), StaticRowRepresentab
CoroutineScope(Dispatchers.Default).launch {
var report: Report? = null
val test = GlobalScope.async {
val s = Date()
Timber.d(">>> start...")
val test = async {
// val s = Date()
// Timber.d(">>> start...")
val realm = Realm.getDefaultInstance()
realm.refresh()
@ -221,9 +219,9 @@ open class ComposableTableReportFragment : RealmFragment(), StaticRowRepresentab
realm.close()
val e = Date()
val duration = (e.time - s.time) / 1000.0
Timber.d(">>> ended in $duration seconds")
// val e = Date()
// val duration = (e.time - s.time) / 1000.0
// Timber.d(">>> ended in $duration seconds")
}
test.await()

@ -96,7 +96,7 @@ open class DataManagerFragment : RealmFragment() {
val status = savable.getSaveValidityStatus(realm = this.getRealm())
when (status) {
SaveValidityStatus.VALID -> {
this.getRealm().executeTransaction {
this.getRealm().executeTransactionAsync {
val managedItem = it.copyToRealmOrUpdate(this.model.item)
if (managedItem is Savable) {
val uniqueIdentifier = managedItem.id

@ -18,7 +18,6 @@ import net.pokeranalytics.android.ui.adapter.RowRepresentableDelegate
import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.RowUpdatable
open class EditableDataFragment : DataManagerFragment(), RowRepresentableDelegate {
lateinit var rowRepresentableAdapter: RowRepresentableAdapter
@ -67,15 +66,20 @@ open class EditableDataFragment : DataManagerFragment(), RowRepresentableDelegat
}
override fun onRowValueChanged(value: Any?, row: RowRepresentable) {
getRealm().executeTransaction {
try {
(this.model.item as RowUpdatable).updateValue(value, row)
} catch (e: Exception) {
CrashLogging.log("Exception caught: row = $row, value=$value, class=${this.javaClass}")
throw e
}
(this.model.item as RowUpdatable).updateValue(value, row)
if (this.model.primaryKey != null) {
getRealm().executeTransactionAsync { asyncRealm ->
try {
asyncRealm.copyToRealmOrUpdate(this.model.item)
} catch (e: Exception) {
CrashLogging.log("Exception caught: row = $row, value=$value, class=${this.javaClass}")
throw e
}
}
}
rowRepresentableAdapter.refreshRow(row)
}

@ -81,10 +81,14 @@ open class DataListFragment : DeletableItemFragment(), RowRepresentableDelegate
getRealm().where(this.model.identifiableClass)
.`in`("id", itemIds)
.sort(this.model.dataType.sortFields, this.model.dataType.sortOrders)
.findAll()
.findAllAsync()
} else {
this.retrieveItems(getRealm())
}
items.addChangeListener { _, _ ->
this.dataListAdapter.notifyDataSetChanged()
}
this.model.setItemsList(items)
}

@ -44,6 +44,7 @@ import net.pokeranalytics.android.util.URL
import net.pokeranalytics.android.util.billing.AppGuard
import net.pokeranalytics.android.util.billing.PurchaseListener
import net.pokeranalytics.android.util.extensions.count
import net.pokeranalytics.android.util.extensions.findById
import java.util.*
class FeedFragment : FilterableFragment(), RowRepresentableDelegate, PurchaseListener {
@ -493,9 +494,16 @@ class FeedFragment : FilterableFragment(), RowRepresentableDelegate, PurchaseLis
* Delete selected transaction
*/
private fun deleteSelectedTransaction() {
getRealm().executeTransaction {
selectedTransaction?.deleteFromRealm()
selectedTransaction?.id?.let { id ->
getRealm().executeTransactionAsync { asyncRealm ->
asyncRealm.findById<Transaction>(id)?.deleteFromRealm()
}
}
// getRealm().executeTransaction {
// selectedTransaction?.deleteFromRealm()
// }
selectedTransactionPosition = -1
}

@ -10,6 +10,7 @@ import net.pokeranalytics.android.R
import net.pokeranalytics.android.databinding.FragmentFilterDetailsBinding
import net.pokeranalytics.android.exceptions.PAIllegalStateException
import net.pokeranalytics.android.model.filter.QueryCondition
import net.pokeranalytics.android.model.realm.Filter
import net.pokeranalytics.android.ui.adapter.RowRepresentableAdapter
import net.pokeranalytics.android.ui.adapter.RowRepresentableDelegate
import net.pokeranalytics.android.ui.fragment.components.RealmFragment
@ -17,6 +18,7 @@ import net.pokeranalytics.android.ui.helpers.DateTimePickerManager
import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.RowViewType
import net.pokeranalytics.android.ui.view.rows.*
import net.pokeranalytics.android.util.extensions.findById
import timber.log.Timber
import java.util.*
@ -230,27 +232,33 @@ open class FilterDetailsFragment : RealmFragment(), RowRepresentableDelegate {
*/
private fun saveData() {
val currentFilter = this.activityModel.currentFilter
// val currentFilter = this.activityModel.currentFilter
//TODO: Save currentFilter details data
Timber.d("Save data for queryWith: ${currentFilter?.id}")
this.model.selectedRows.forEach {
Timber.d("Selected rows: $it")
}
this.activityModel.currentFilter?.id?.let { filterId ->
this.activityModel.selectedCategoryRow?.let { category ->
this.activityModel.selectedCategoryRow?.let { category ->
getRealm().executeTransaction {
currentFilter?.remove(category)
val validConditions = this.model.selectedRows.filter { it.queryCondition != null }
currentFilter?.createOrUpdateFilterConditions(validConditions)
getRealm().executeTransactionAsync { asyncRealm ->
asyncRealm.findById<Filter>(filterId)?.let { filter ->
filter.remove(category)
val validConditions = this.model.selectedRows.filter { it.queryCondition != null }
filter.createOrUpdateFilterConditions(validConditions)
}
}
}
}
currentFilter?.filterConditions?.forEach {
Timber.d("Condition: $it")
}
// //TODO: Save currentFilter details data
// Timber.d("Save data for queryWith: ${currentFilter?.id}")
// this.model.selectedRows.forEach {
// Timber.d("Selected rows: $it")
// }
// currentFilter?.filterConditions?.forEach {
// Timber.d("Condition: $it")
// }
// finishActivityWithResult(currentFilter?.id)
}

@ -32,7 +32,6 @@ class FilterViewModel : ViewModel(), StaticRowRepresentableDataSource {
}
this.primaryKey?.let {
val filter = realm.findById<Filter>(it) ?: throw PAIllegalStateException("Can't find filter with id=$it")
this.currentFilter = realm.copyFromRealm(filter)
this.isUpdating = true
@ -59,7 +58,7 @@ class FilterViewModel : ViewModel(), StaticRowRepresentableDataSource {
// Data source
override fun adapterRows(): List<RowRepresentable>? {
override fun adapterRows(): List<RowRepresentable> {
return this.categoryRows
}

@ -15,7 +15,6 @@ import net.pokeranalytics.android.model.LiveData
import net.pokeranalytics.android.model.realm.Filter
import net.pokeranalytics.android.ui.adapter.RowRepresentableAdapter
import net.pokeranalytics.android.ui.adapter.RowRepresentableDelegate
import net.pokeranalytics.android.ui.extensions.px
import net.pokeranalytics.android.ui.fragment.components.RealmFragment
import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.rows.FilterCategoryRow
@ -220,10 +219,10 @@ open class FiltersFragment : RealmFragment(), RowRepresentableDelegate {
private fun validateUpdates() {
val currentFilter = this.model.currentFilter
getRealm().executeTransaction { realm ->
currentFilter?.let {
it.name = it.query.getName(requireContext())
realm.copyToRealmOrUpdate(it)
getRealm().executeTransactionAsync { realm ->
currentFilter?.let { filter ->
filter.name = filter.query.getName(requireContext())
realm.copyToRealmOrUpdate(filter)
}
}
@ -239,7 +238,7 @@ open class FiltersFragment : RealmFragment(), RowRepresentableDelegate {
val filterCopy = this.model.filterCopy
val filterId = filterCopy?.id ?: ""
getRealm().executeTransaction { realm ->
getRealm().executeTransactionAsync { realm ->
filterCopy?.let {
realm.copyToRealmOrUpdate(it)
}

@ -15,8 +15,10 @@ open class FiltersListFragment : DataListFragment() {
override fun onRowValueChanged(value: Any?, row: RowRepresentable) {
when (row) {
is Filter -> {
getRealm().executeTransaction {
row.updateValue(value, row)
row.updateValue(value, row)
getRealm().executeTransactionAsync { asyncRealm ->
asyncRealm.copyToRealmOrUpdate(row)
}
val index = this.model.items.indexOf(row)
this.dataListAdapter.notifyItemChanged(index)

@ -687,10 +687,9 @@ class EditorFragment : RealmFragment(), RowRepresentableDelegate, KeyboardListen
*/
private fun deleteHand() {
getRealm().findById<HandHistory>(this.model.handHistory.id)?.let { hh ->
getRealm().executeTransaction {
hh.deleteFromRealm()
}
val hhId = this.model.handHistory.id
getRealm().executeTransactionAsync { asyncRealm ->
asyncRealm.findById<HandHistory>(hhId)?.deleteFromRealm()
}
this.activity?.finish()

@ -24,12 +24,10 @@ import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.RowRepresentableEditDescriptor
import net.pokeranalytics.android.ui.view.rows.CustomizableRowRepresentable
import net.pokeranalytics.android.util.CrashLogging
import net.pokeranalytics.android.util.extensions.findById
import net.pokeranalytics.android.util.extensions.formatted
import timber.log.Timber
import java.text.DecimalFormat
import java.text.ParseException
import kotlin.coroutines.CoroutineContext
import kotlin.reflect.KClass
enum class HHKeyboard {
@ -640,25 +638,26 @@ class EditorViewModel : ViewModel(), RowRepresentableDataSource, CardCentralizer
this.handHistory.actions.addAll(actions)
realm.executeTransactionAsync { execRealm ->
this.handHistory.defineWinnerPositions()
execRealm.copyToRealmOrUpdate(this.handHistory)
}
this.defineWinnerPositions()
}
private fun defineWinnerPositions() {
val hhId = this.handHistory.id
CoroutineScope(Dispatchers.Default).launch {
val realm = Realm.getDefaultInstance()
realm.findById<HandHistory>(hhId)?.defineWinnerPositions()
realm.executeTransactionAsync { execRealm ->
execRealm.copyToRealmOrUpdate(handHistory)
}
realm.close()
}
}
// this.defineWinnerPositions()
}
// private fun defineWinnerPositions() {
//
// val hhId = this.handHistory.id
// CoroutineScope(Dispatchers.Default).launch {
// val realm = Realm.getDefaultInstance()
//
// realm.findById<HandHistory>(hhId)?.defineWinnerPositions()
// realm.executeTransactionAsync { execRealm ->
// execRealm.copyToRealmOrUpdate(handHistory)
// }
// realm.close()
// }
//
// }
// Card Centralizer
@ -1027,20 +1026,20 @@ class EditorViewModel : ViewModel(), RowRepresentableDataSource, CardCentralizer
/***
* Tries to deletes the row at the given [position]
*/
fun deleteIfPossible(position: Int) {
when (val row = this.rowRepresentables[position]) {
is PlayerSetupRow -> {
val playerSetup = this.handHistory.playerSetupForPosition(row.positionIndex) ?: throw PAIllegalStateException("Attempt to delete an null object")
this.handHistory.playerSetups.remove(playerSetup)
this.handHistory.realm?.let {
it.executeTransaction {
playerSetup.deleteFromRealm()
}
}
}
}
}
// fun deleteIfPossible(position: Int) {
// when (val row = this.rowRepresentables[position]) {
// is PlayerSetupRow -> {
// val playerSetup = this.handHistory.playerSetupForPosition(row.positionIndex) ?: throw PAIllegalStateException("Attempt to delete an null object")
// this.handHistory.playerSetups.remove(playerSetup)
//
// this.handHistory.realm?.let {
// it.executeTransaction {
// playerSetup.deleteFromRealm()
// }
// }
// }
// }
// }
fun removePlayerSetup(positionIndex: Int) {
val ps = this.handHistory.playerSetupForPosition(positionIndex)

@ -177,7 +177,7 @@ class SessionFragment : RealmFragment(), RowRepresentableDelegate, StaticRowRepr
val sessionRealm = realm.findById<Session>(sessionId)
sessionRealm?.let {
val copy = realm.copyFromRealm(it)
val copy = realm.copySessionFromRealm(it)
if (this.model.duplicate) { // duplicate session
// realm.executeTransaction {
@ -192,21 +192,6 @@ class SessionFragment : RealmFragment(), RowRepresentableDelegate, StaticRowRepr
} ?: throw PAIllegalStateException("Session cannot be null here, session id = $sessionId")
// if (sessionRealm != null) {
//
// if (this.model.duplicate) { // duplicate session
// realm.executeTransaction {
// val session = sessionRealm.duplicate()
// currentSession = session
// }
// sessionHasBeenUserCustomized = false
// } else { // show existing session
// currentSession = sessionRealm
// sessionHasBeenUserCustomized = true
// }
// } else {
// throw PAIllegalStateException("Session cannot be null here, session id = $sessionId")
// }
} else { // create new session
currentSession = Session.newInstance(realm, this.model.isTournament)
@ -530,8 +515,8 @@ class SessionFragment : RealmFragment(), RowRepresentableDelegate, StaticRowRepr
val bankrollId = this.currentSession.bankroll?.id
val sessionId = this.currentSession.id
getRealm().executeTransactionAsync { realm ->
realm.findById<Session>(sessionId)?.let { session ->
getRealm().executeTransactionAsync { asyncRealm ->
asyncRealm.findById<Session>(sessionId)?.let { session ->
session.delete()
}
}
@ -717,17 +702,19 @@ class SessionFragment : RealmFragment(), RowRepresentableDelegate, StaticRowRepr
override fun resultCaptureTypeSelected(resultCaptureType: ResultCaptureType, applyBankroll: Boolean) {
getRealm().executeTransaction { // cleanup existing results
when (resultCaptureType) {
ResultCaptureType.NET_RESULT -> {
this.currentSession.clearBuyinCashedOut()
}
ResultCaptureType.BUYIN_CASHED_OUT -> {
this.currentSession.clearNetResult()
}
when (resultCaptureType) {
ResultCaptureType.NET_RESULT -> {
this.currentSession.clearBuyinCashedOut()
}
ResultCaptureType.BUYIN_CASHED_OUT -> {
this.currentSession.clearNetResult()
}
}
getRealm().executeTransactionAsync { asyncRealm -> // cleanup existing results
asyncRealm.copyToRealmOrUpdate(this.currentSession)
}
this.model.resultCaptureType = resultCaptureType
if (applyBankroll) {
this.currentSession.bankroll?.let { bankroll ->

@ -58,7 +58,7 @@ class DealtHandsPerHourFragment : RealmFragment() {
private fun save() {
getRealm().executeTransaction { realm ->
getRealm().executeTransactionAsync { realm ->
UserConfig.getConfiguration(realm) { userConfig ->
this.liveValue.text.toString().toIntOrNull()?.let { liveDealtHandsPerHour ->

@ -97,10 +97,10 @@ class TransactionFilterFragment : RealmFragment(), StaticRowRepresentableDataSou
}
private fun save() {
getRealm().executeTransaction { realm ->
UserConfig.getConfiguration(this.getRealm()) { userConfig ->
getRealm().executeTransactionAsync { asyncRealm ->
UserConfig.getConfiguration(asyncRealm) { userConfig ->
userConfig.setTransactionTypeIds(this.model.selectedTransactionTypes)
realm.copyToRealmOrUpdate(userConfig)
asyncRealm.copyToRealmOrUpdate(userConfig)
}
}
this.activity?.finish()

@ -35,9 +35,9 @@ class FakeDataManager {
val locations = realm.where<Location>().findAll()
if (locations.size == 0) {
realm.executeTransaction {
realm.executeTransactionAsync { asyncRealm ->
listOf("Bellagio", "Aria", "Borgata").map {
realm.getOrCreate<Location>(it)
asyncRealm.getOrCreate<Location>(it)
}
}
}

@ -45,7 +45,7 @@ abstract class PACSVDescriptor<T : Identifiable>(source: DataSource,
protected fun parseSession(realm: Realm, record: CSVRecord): Session? {
val isTournament = isTournament ?: false
val session = Session.newInstance(realm, isTournament, managed = false)
val session = Session.newInstance(realm, isTournament)
var startDate: Date? = null
var endDate: Date? = null

@ -7,6 +7,7 @@ import net.pokeranalytics.android.model.interfaces.Identifiable
import net.pokeranalytics.android.model.interfaces.NameManageable
import net.pokeranalytics.android.model.interfaces.UsageCountable
import net.pokeranalytics.android.model.realm.*
import java.lang.ref.WeakReference
fun <T : RealmModel>Realm.count(clazz: Class<T>) : Long {
return this.where(clazz).count()
@ -62,7 +63,7 @@ fun <T : RealmModel> Realm.sorted(clazz: Class<T>, editableOnly: Boolean = false
query.notEqualTo("id", it)
}
val items = query.findAll()
val items = query.findAllAsync()
var sortField = arrayOf("name")
var resultSort = arrayOf(Sort.ASCENDING)
@ -96,8 +97,8 @@ inline fun <reified C : RealmModel> Realm.sorted(editableOnly: Boolean = false,
*/
fun <T : RealmModel>Realm.updateUsageCount(clazz: Class<T>) {
val results = this.where(clazz).findAll()
this.executeTransaction {
this.executeTransactionAsync {
val results = it.where(clazz).findAll()
results.forEach { countableUsage ->
val countable = (countableUsage as UsageCountable)
@ -146,4 +147,10 @@ fun Realm.lookupForNameInAllTablesById(id: String): String? {
}
}
return null
}
fun Realm.copySessionFromRealm(session: Session): Session {
val copy = this.copyFromRealm(session)
copy.result?.inverseSession = WeakReference(copy)
return copy
}
Loading…
Cancel
Save