diff --git a/app/build.gradle b/app/build.gradle index 44fc9963..88ceffcf 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -12,7 +12,7 @@ apply plugin: "kotlinx-serialization" repositories { maven { url 'https://jitpack.io' } // required for MPAndroidChart - jcenter() // for kotlin serialization + mavenCentral() // for kotlin serialization } android { @@ -98,8 +98,8 @@ dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) // Kotlin - implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.6' - implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.6" + implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.0-native-mt' + implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.0-native-mt" implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version" // implementation("org.jetbrains.kotlinx:kotlinx-serialization-runtime:0.20.0") // JVM dependency implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.4.1" @@ -141,6 +141,9 @@ dependencies { // ffmpeg for encoding video (HH export) implementation 'com.arthenica:ffmpeg-kit-min-gpl:4.4.LTS' + // https://mvnrepository.com/artifact/com.android.volley/volley + implementation 'com.android.volley:volley:1.2.1' + // Instrumented Tests androidTestImplementation 'androidx.test:core:1.3.0' androidTestImplementation 'androidx.test:runner:1.3.0' diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 714f4e26..79892d86 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -188,6 +188,7 @@ android:launchMode="singleTop"/> + = Build.VERSION_CODES.N) { val locales = resources.configuration.locales CrashLogging.log("App onCreate. Locales = $locales") @@ -81,7 +93,7 @@ class PokerAnalyticsApplication : Application() { // Patch Patcher.patchAll(this) - // Report + // Reports this.reportWhistleBlower = ReportWhistleBlower(this.applicationContext) SessionSetManager.configure() @@ -91,6 +103,34 @@ class PokerAnalyticsApplication : Application() { } + /** Defines callbacks for service binding, passed to bindService() */ + private val connection = object : ServiceConnection { + + override fun onServiceDisconnected(name: ComponentName?) { + realmWriteService = null + } + + override fun onServiceConnected(name: ComponentName?, service: IBinder?) { + val binder = service as RealmWriteService.LocalBinder + realmWriteService = binder.getService() + } + + } + + private fun initRealmWriteService() { + val intent = Intent(this, RealmWriteService::class.java) + bindService(intent, connection, Context.BIND_AUTO_CREATE) + } + + override fun onTerminate() { + super.onTerminate() + unbindService(connection) + } + + fun executeRealmAsyncTransaction(handler: (Realm) -> (Unit)) { + this.realmWriteService?.executeRealmAsyncTransaction(handler) ?: throw PAIllegalStateException("no realmWriteService") + } + /** * Create fake sessions if we have less than 10 sessions */ diff --git a/app/src/main/java/net/pokeranalytics/android/RealmWriteService.kt b/app/src/main/java/net/pokeranalytics/android/RealmWriteService.kt new file mode 100644 index 00000000..874fdbba --- /dev/null +++ b/app/src/main/java/net/pokeranalytics/android/RealmWriteService.kt @@ -0,0 +1,56 @@ +package net.pokeranalytics.android + +import android.app.Service +import android.content.Intent +import android.os.Binder +import android.os.IBinder +import io.realm.Realm +import timber.log.Timber + +class RealmWriteService : Service() { + + private lateinit var realm: Realm + + private val binder = LocalBinder() + + override fun onBind(intent: Intent?): IBinder { + return binder + } + + inner class LocalBinder : Binder() { + fun getService(): RealmWriteService = this@RealmWriteService + } + + override fun onCreate() { + super.onCreate() + this.realm = Realm.getDefaultInstance() + } + + override fun onDestroy() { + super.onDestroy() + + Timber.d(">>>> Service destroyed : realm close") + this.realm.close() + } + + override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { + return super.onStartCommand(intent, flags, startId) + } + + fun executeRealmAsyncTransaction(handler: (Realm) -> (Unit)) { + + Timber.d(">>>> Launch async transaction...") + + this.realm.executeTransactionAsync({ asyncRealm -> + handler(asyncRealm) + Timber.d(">> handler done") + }, { + Timber.d(">> YEAAAAAAAAAAAH !!!") + this.realm.refresh() + }, { + Timber.d(">> NOOOOO error = $it") + }) + + } + +} \ No newline at end of file diff --git a/app/src/main/java/net/pokeranalytics/android/calculus/Calculator.kt b/app/src/main/java/net/pokeranalytics/android/calculus/Calculator.kt index ec880fbb..98d83abb 100644 --- a/app/src/main/java/net/pokeranalytics/android/calculus/Calculator.kt +++ b/app/src/main/java/net/pokeranalytics/android/calculus/Calculator.kt @@ -177,7 +177,7 @@ class Calculator { val computableGroups: MutableList = mutableListOf() - val combinations = options.criterias.combined() + val combinations = options.criterias.combined(realm) // Timber.d("Combinations: ${ combinations.map { it.defaultName }}") for (comparatorQuery in combinations) { diff --git a/app/src/main/java/net/pokeranalytics/android/calculus/ComputableGroup.kt b/app/src/main/java/net/pokeranalytics/android/calculus/ComputableGroup.kt index d0ce49c6..2531b4a3 100644 --- a/app/src/main/java/net/pokeranalytics/android/calculus/ComputableGroup.kt +++ b/app/src/main/java/net/pokeranalytics/android/calculus/ComputableGroup.kt @@ -53,6 +53,8 @@ class ComputableGroup(val query: Query, var displayedStats: List? = null) } } +// Timber.d("QUERY = ${query.defaultName}") + val sortedField = if (sorted) "session.startDate" else null val computables = Filter.queryOn(realm, this.query, sortedField) diff --git a/app/src/main/java/net/pokeranalytics/android/calculus/ReportWhistleBlower.kt b/app/src/main/java/net/pokeranalytics/android/calculus/ReportWhistleBlower.kt index ef24f01d..bc126f9e 100644 --- a/app/src/main/java/net/pokeranalytics/android/calculus/ReportWhistleBlower.kt +++ b/app/src/main/java/net/pokeranalytics/android/calculus/ReportWhistleBlower.kt @@ -1,19 +1,24 @@ package net.pokeranalytics.android.calculus +import android.content.BroadcastReceiver import android.content.Context +import android.content.Intent +import android.content.IntentFilter import android.os.CountDownTimer +import androidx.localbroadcastmanager.content.LocalBroadcastManager import io.realm.Realm import io.realm.RealmQuery import io.realm.RealmResults import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch +import net.pokeranalytics.android.AppState import net.pokeranalytics.android.calculus.optimalduration.CashGameOptimalDurationCalculator import net.pokeranalytics.android.exceptions.PAIllegalStateException import net.pokeranalytics.android.model.LiveOnline import net.pokeranalytics.android.model.realm.* +import net.pokeranalytics.android.ui.fragment.ImportBroadcast import net.pokeranalytics.android.ui.view.rows.StaticReport -import net.pokeranalytics.android.util.Global import net.pokeranalytics.android.util.extensions.formattedHourlyDuration import timber.log.Timber @@ -33,10 +38,19 @@ class ReportWhistleBlower(var context: Context) { private val listeners: MutableList = mutableListOf() - private var paused: Boolean = !Global.LAUNCH_ASYNC_LISTENERS - private var timer: CountDownTimer? = null + private val startImportReceiver = object : BroadcastReceiver() { + override fun onReceive(context: Context?, intent: Intent?) { + pause() + } + } + private val endImportReceiver = object : BroadcastReceiver() { + override fun onReceive(context: Context?, intent: Intent?) { + resume() + } + } + init { val realm = Realm.getDefaultInstance() @@ -57,6 +71,9 @@ class ReportWhistleBlower(var context: Context) { } realm.close() + + LocalBroadcastManager.getInstance(context).registerReceiver(startImportReceiver, IntentFilter(ImportBroadcast.START.identifier)) + LocalBroadcastManager.getInstance(context).registerReceiver(endImportReceiver, IntentFilter(ImportBroadcast.END.identifier)) } fun addListener(newPerformanceListener: NewPerformanceListener) { @@ -69,7 +86,7 @@ class ReportWhistleBlower(var context: Context) { fun requestReportLaunch() { - if (paused) { + if (AppState.isImporting) { return } @@ -103,14 +120,12 @@ class ReportWhistleBlower(var context: Context) { /** * Pauses the whistleblower, for example when importing data */ - fun pause() { - this.paused = true + private fun pause() { this.currentTask?.cancel() this.currentTask = null } - fun resume() { - this.paused = false + private fun resume() { this.requestReportLaunch() } diff --git a/app/src/main/java/net/pokeranalytics/android/calculus/bankroll/BankrollReportManager.kt b/app/src/main/java/net/pokeranalytics/android/calculus/bankroll/BankrollReportManager.kt index 895cf731..7c9182e0 100644 --- a/app/src/main/java/net/pokeranalytics/android/calculus/bankroll/BankrollReportManager.kt +++ b/app/src/main/java/net/pokeranalytics/android/calculus/bankroll/BankrollReportManager.kt @@ -2,14 +2,14 @@ package net.pokeranalytics.android.calculus.bankroll import io.realm.Realm import io.realm.RealmResults -import kotlinx.coroutines.* +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.async +import kotlinx.coroutines.launch import net.pokeranalytics.android.model.realm.Bankroll import net.pokeranalytics.android.model.realm.ComputableResult import net.pokeranalytics.android.model.realm.Transaction -import net.pokeranalytics.android.util.Global import timber.log.Timber -import java.util.* -import kotlin.coroutines.CoroutineContext object BankrollReportManager { @@ -26,9 +26,7 @@ object BankrollReportManager { bankrolls = realm.where(Bankroll::class.java).findAll() transactions = realm.where(Transaction::class.java).findAll() - if (Global.LAUNCH_ASYNC_LISTENERS) { - initializeListeners() - } + initializeListeners() realm.close() } diff --git a/app/src/main/java/net/pokeranalytics/android/model/Criteria.kt b/app/src/main/java/net/pokeranalytics/android/model/Criteria.kt index 608489c5..58d8883a 100644 --- a/app/src/main/java/net/pokeranalytics/android/model/Criteria.kt +++ b/app/src/main/java/net/pokeranalytics/android/model/Criteria.kt @@ -25,11 +25,12 @@ import net.pokeranalytics.android.ui.view.RowRepresentable import net.pokeranalytics.android.util.enumerations.IntIdentifiable import net.pokeranalytics.android.util.enumerations.IntSearchable import net.pokeranalytics.android.util.extensions.findById +import timber.log.Timber -fun List.combined(): List { +fun List.combined(realm: Realm): List { val comparatorList = ArrayList>() this.forEach { criteria -> - comparatorList.add(criteria.queries) + comparatorList.add(criteria.queries(realm)) } return getCombinations(comparatorList) } @@ -64,7 +65,7 @@ sealed class Criteria(override var uniqueIdentifier: Int) : IntIdentifiable, Row inline fun comparison(): List { if (this is ListCustomFields) { val objects = mutableListOf() - val realm = Realm.getDefaultInstance() + val realm = Realm.getDefaultInstance() realm.findById(CustomField::class.java, this.customFieldId)?.entries?.forEach { objects.add(QueryCondition.CustomFieldListQuery(it)) } @@ -165,14 +166,11 @@ sealed class Criteria(override var uniqueIdentifier: Int) : IntIdentifiable, Row data class ValueCustomFields(override var customFieldId: String) : ListCriteria(22), CustomFieldCriteria object Duration : ListCriteria(23) - val queries: List - get() { + fun queries(realm: Realm): List { return when (this) { is AllMonthsUpToNow -> { - val realm = Realm.getDefaultInstance() val firstSession = realm.where().isNotNull("startDate").sort("startDate", Sort.ASCENDING).findFirst() val lastSession = realm.where().isNotNull("startDate").sort("startDate", Sort.DESCENDING).findFirst() - realm.close() val years: ArrayList = arrayListOf() @@ -200,13 +198,12 @@ sealed class Criteria(override var uniqueIdentifier: Int) : IntIdentifiable, Row years } else -> { - return this.queryConditions + return this.queryConditions(realm) } } } - val queryConditions: List - get() { + fun queryConditions(realm: Realm): List { return when (this) { is Bankrolls -> comparison() is Games -> comparison() @@ -221,7 +218,6 @@ sealed class Criteria(override var uniqueIdentifier: Int) : IntIdentifiable, Row is TournamentFees -> comparison() is Years -> { val years = arrayListOf() - val realm = Realm.getDefaultInstance() val lastSession = realm.where().isNotNull("startDate").sort("startDate", Sort.DESCENDING).findFirst() val yearNow = lastSession?.year ?: return years @@ -233,19 +229,16 @@ sealed class Criteria(override var uniqueIdentifier: Int) : IntIdentifiable, Row years.add(Query(yearCondition)) } } - realm.close() years } is Stakes -> comparison() is ListCustomFields -> comparison() is ValueCustomFields -> { - val realm = Realm.getDefaultInstance() val queries = when (this.customFieldType(realm)) { CustomField.Type.AMOUNT.uniqueIdentifier -> comparison() CustomField.Type.NUMBER.uniqueIdentifier -> comparison() else -> throw PokerAnalyticsException.ComparisonCriteriaUnhandled(this) } - realm.close() queries } is Duration -> { diff --git a/app/src/main/java/net/pokeranalytics/android/model/filter/Query.kt b/app/src/main/java/net/pokeranalytics/android/model/filter/Query.kt index 7c7c89bc..79a4b52d 100644 --- a/app/src/main/java/net/pokeranalytics/android/model/filter/Query.kt +++ b/app/src/main/java/net/pokeranalytics/android/model/filter/Query.kt @@ -73,16 +73,16 @@ class Query { it is QueryCondition.EndedToTime } - this.conditions.forEach { - realmQuery = when (it) { + for (condition in this.conditions) { + realmQuery = when (condition) { is QueryCondition.StartedFromTime -> { - it.queryWith(realmQuery, queryToTime) + condition.queryWith(realmQuery, queryToTime) } is QueryCondition.EndedToTime -> { - it.queryWith(realmQuery, queryFromTime) + condition.queryWith(realmQuery, queryFromTime) } else -> { - it.queryWith(realmQuery) + condition.queryWith(realmQuery) } } } diff --git a/app/src/main/java/net/pokeranalytics/android/model/realm/UserConfig.kt b/app/src/main/java/net/pokeranalytics/android/model/realm/UserConfig.kt index f72ab107..356ec36e 100644 --- a/app/src/main/java/net/pokeranalytics/android/model/realm/UserConfig.kt +++ b/app/src/main/java/net/pokeranalytics/android/model/realm/UserConfig.kt @@ -5,6 +5,7 @@ import io.realm.RealmObject import io.realm.annotations.PrimaryKey import net.pokeranalytics.android.util.UUID_SEPARATOR import net.pokeranalytics.android.util.extensions.findById +import timber.log.Timber import java.util.* open class UserConfig : RealmObject() { diff --git a/app/src/main/java/net/pokeranalytics/android/model/utils/SessionSetManager.kt b/app/src/main/java/net/pokeranalytics/android/model/utils/SessionSetManager.kt index ae9edb23..99e21550 100644 --- a/app/src/main/java/net/pokeranalytics/android/model/utils/SessionSetManager.kt +++ b/app/src/main/java/net/pokeranalytics/android/model/utils/SessionSetManager.kt @@ -6,7 +6,6 @@ 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.Global import net.pokeranalytics.android.util.extensions.findById import timber.log.Timber @@ -33,12 +32,10 @@ object SessionSetManager { val realm = Realm.getDefaultInstance() this.sessions = realm.where(Session::class.java).findAllAsync() - if (Global.LAUNCH_ASYNC_LISTENERS) { - this.sessions.addChangeListener { _, _ -> - if (this.sessionIdsToProcess.isNotEmpty()) { - realm.executeTransactionAsync { asyncRealm -> - processSessions(asyncRealm) - } + this.sessions.addChangeListener { _, _ -> + if (this.sessionIdsToProcess.isNotEmpty()) { + realm.executeTransactionAsync { asyncRealm -> + processSessions(asyncRealm) } } } diff --git a/app/src/main/java/net/pokeranalytics/android/ui/activity/HomeActivity.kt b/app/src/main/java/net/pokeranalytics/android/ui/activity/HomeActivity.kt index aee03553..e44125fe 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/activity/HomeActivity.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/activity/HomeActivity.kt @@ -17,7 +17,6 @@ import net.pokeranalytics.android.model.realm.Currency import net.pokeranalytics.android.model.realm.Session import net.pokeranalytics.android.ui.activity.components.BaseActivity import net.pokeranalytics.android.ui.adapter.HomePagerAdapter -import net.pokeranalytics.android.util.Global import net.pokeranalytics.android.util.Preferences import net.pokeranalytics.android.util.billing.AppGuard import net.pokeranalytics.android.util.extensions.findAll @@ -115,13 +114,10 @@ class HomeActivity : BaseActivity(), NewPerformanceListener { // observe currency changes this.currencies = realm.where(Currency::class.java).findAllAsync() - - if (Global.LAUNCH_ASYNC_LISTENERS) { - this.currencies.addChangeListener { _, _ -> - realm.executeTransactionAsync { asyncRealm -> - asyncRealm.where(Currency::class.java).findAll().forEach { currency -> - currency.refreshRelatedRatedValues() - } + this.currencies.addChangeListener { _, _ -> + getRealm().executeTransactionAsync { asyncRealm -> + asyncRealm.where(Currency::class.java).findAll().forEach { currency -> + currency.refreshRelatedRatedValues() } } } diff --git a/app/src/main/java/net/pokeranalytics/android/ui/activity/components/BaseActivity.kt b/app/src/main/java/net/pokeranalytics/android/ui/activity/components/BaseActivity.kt index d23270f0..59ef2b9a 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/activity/components/BaseActivity.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/activity/components/BaseActivity.kt @@ -34,6 +34,7 @@ abstract class BaseActivity : AppCompatActivity() { } private var realm: Realm? = null + private var permissionCallback: ((granted: Boolean) -> Unit)? = null private var permissionRequest: PermissionRequest? = null @@ -86,7 +87,7 @@ abstract class BaseActivity : AppCompatActivity() { override fun onBackPressed() { super.onBackPressed() - AppReviewManager.showReviewManager(this) + AppReviewManager.showReviewManagerIfNecessary(this) } override fun onRequestPermissionsResult(requestCode: Int, permissions: Array, grantResults: IntArray) { @@ -136,10 +137,12 @@ abstract class BaseActivity : AppCompatActivity() { fragmentTransaction.commit() } + /** * Return the realm instance */ fun getRealm(): Realm { +// return this.realm this.realm?.let { return it } ?: run { @@ -149,6 +152,23 @@ abstract class BaseActivity : AppCompatActivity() { } } + fun executeRealmAsyncTransaction(handler: (Realm) -> (Unit)) { + + this.paApplication.executeRealmAsyncTransaction(handler) + +// Timber.d(">>>> Launch async transaction") +// +// this.realm.executeTransactionAsync({ asyncRealm -> +// handler(asyncRealm) +// }, { +// Timber.d("YEAAAAAAAAAAAH !!!") +// this.realm.refresh() +// }, { +// Timber.d("NOOOOO error = $it") +// }) + + } + /** * Return if the location permission has been granted by the user */ diff --git a/app/src/main/java/net/pokeranalytics/android/ui/fragment/ImportFragment.kt b/app/src/main/java/net/pokeranalytics/android/ui/fragment/ImportFragment.kt index a1f19a8c..f1209805 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/fragment/ImportFragment.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/fragment/ImportFragment.kt @@ -1,12 +1,15 @@ package net.pokeranalytics.android.ui.fragment +import android.content.Intent import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.TextView +import androidx.localbroadcastmanager.content.LocalBroadcastManager import com.google.android.material.snackbar.Snackbar import kotlinx.coroutines.* +import net.pokeranalytics.android.AppState import net.pokeranalytics.android.R import net.pokeranalytics.android.databinding.FragmentImportBinding import net.pokeranalytics.android.ui.fragment.components.RealmFragment @@ -17,6 +20,11 @@ import java.io.InputStream import java.text.NumberFormat import java.util.* +enum class ImportBroadcast(var identifier: String) { + START("start-import"), + END("end-import") +} + class ImportFragment : RealmFragment(), ImportDelegate { private lateinit var filePath: String @@ -81,7 +89,10 @@ class ImportFragment : RealmFragment(), ImportDelegate { private fun startImport() { - this.parentActivity?.paApplication?.reportWhistleBlower?.pause() + AppState.isImporting = true + LocalBroadcastManager.getInstance(requireContext()).sendBroadcast(Intent(ImportBroadcast.START.identifier)) + +// this.parentActivity?.paApplication?.reportWhistleBlower?.pause() this.importer = CSVImporter(inputStream) this.importer.delegate = this @@ -113,15 +124,6 @@ class ImportFragment : RealmFragment(), ImportDelegate { snackBar.show() } -// if (shouldDismissActivity) { -// -// activity?.let { -// it.setResult(ResultCode.IMPORT_UNRECOGNIZED_FORMAT.value) -// it.finish() -// } -// -// } else { -// } importDidFinish() } @@ -137,7 +139,10 @@ class ImportFragment : RealmFragment(), ImportDelegate { } private fun end() { - this.parentActivity?.paApplication?.reportWhistleBlower?.resume() + + AppState.isImporting = false + LocalBroadcastManager.getInstance(requireContext()).sendBroadcast(Intent(ImportBroadcast.END.identifier)) +// this.parentActivity?.paApplication?.reportWhistleBlower?.resume() activity?.finish() } diff --git a/app/src/main/java/net/pokeranalytics/android/ui/fragment/ReportsFragment.kt b/app/src/main/java/net/pokeranalytics/android/ui/fragment/ReportsFragment.kt index 61df4581..691a1884 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/fragment/ReportsFragment.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/fragment/ReportsFragment.kt @@ -38,7 +38,6 @@ import net.pokeranalytics.android.ui.view.RowRepresentable import net.pokeranalytics.android.ui.view.RowViewType import net.pokeranalytics.android.ui.view.rows.CustomizableRowRepresentable import net.pokeranalytics.android.ui.view.rows.StaticReport -import net.pokeranalytics.android.util.Global import net.pokeranalytics.android.util.NULL_TEXT import net.pokeranalytics.android.util.Preferences import timber.log.Timber @@ -154,13 +153,11 @@ class ReportsFragment : DeletableItemFragment(), StaticRowRepresentableDataSourc this.reportSetups = getRealm().where(ReportSetup::class.java).sort("name").findAllAsync() this.performances = getRealm().where(Performance::class.java).findAllAsync() - if (Global.LAUNCH_ASYNC_LISTENERS) { - this.reportSetups.addChangeListener { _, _ -> - this.updateRows() - } - this.performances.addChangeListener { _, _ -> - this.updateRows() - } + this.reportSetups.addChangeListener { _, _ -> + this.updateRows() + } + this.performances.addChangeListener { _, _ -> + this.updateRows() } } @@ -293,7 +290,7 @@ class ReportsFragment : DeletableItemFragment(), StaticRowRepresentableDataSourc */ private fun launchComputation(criteriaList: List, reportName: String, stat: Stat) { - if (criteriaList.combined().size < 2) { + if (criteriaList.combined(getRealm()).size < 2) { Toast.makeText(context, R.string.less_then_2_values_for_display, Toast.LENGTH_LONG).show() return } diff --git a/app/src/main/java/net/pokeranalytics/android/ui/fragment/SettingsFragment.kt b/app/src/main/java/net/pokeranalytics/android/ui/fragment/SettingsFragment.kt index fa0a4c9e..52f4abe5 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/fragment/SettingsFragment.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/fragment/SettingsFragment.kt @@ -185,7 +185,7 @@ class SettingsFragment : RealmFragment(), RowRepresentableDelegate, StaticRowRep Preferences.setCurrencyCode(currencyCode, requireContext()) val realm = Realm.getDefaultInstance() - realm.executeTransactionAsync { execRealm-> + executeRealmAsyncTransaction { execRealm-> execRealm.where(Currency::class.java).findAll().forEach { currency -> currency.rate = (currency.rate ?: 1.0) * rate } diff --git a/app/src/main/java/net/pokeranalytics/android/ui/fragment/StatisticsFragment.kt b/app/src/main/java/net/pokeranalytics/android/ui/fragment/StatisticsFragment.kt index ccb9c3d5..366adec3 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/fragment/StatisticsFragment.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/fragment/StatisticsFragment.kt @@ -30,7 +30,6 @@ import net.pokeranalytics.android.ui.modules.filter.FilterActivityRequestCode import net.pokeranalytics.android.ui.modules.filter.FilterableType import net.pokeranalytics.android.ui.modules.filter.FiltersActivity import net.pokeranalytics.android.ui.modules.settings.TransactionFilterActivity -import net.pokeranalytics.android.util.Global import timber.log.Timber import java.util.* @@ -75,12 +74,10 @@ class StatisticsFragment : FilterableFragment(), RealmAsyncListener { this.currentFilterable = FilterableType.SESSION applyFilter() - if (Global.LAUNCH_ASYNC_LISTENERS) { - addRealmChangeListener(this, UserConfig::class.java) - addRealmChangeListener(this, ComputableResult::class.java) - addRealmChangeListener(this, Transaction::class.java) - addRealmChangeListener(this, SessionSet::class.java) - } + addRealmChangeListener(this, UserConfig::class.java) + addRealmChangeListener(this, ComputableResult::class.java) + addRealmChangeListener(this, Transaction::class.java) + addRealmChangeListener(this, SessionSet::class.java) } private fun initUI() { diff --git a/app/src/main/java/net/pokeranalytics/android/ui/fragment/components/DeletableItemFragment.kt b/app/src/main/java/net/pokeranalytics/android/ui/fragment/components/DeletableItemFragment.kt index a9b206ab..5675009e 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/fragment/components/DeletableItemFragment.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/fragment/components/DeletableItemFragment.kt @@ -89,7 +89,7 @@ abstract class DeletableItemFragment : RealmFragment() { deletedItem = getRealm().copyFromRealm(itemToDelete) lastDeletedItemPosition = itemPosition - getRealm().executeTransactionAsync { asyncRealm -> + executeRealmAsyncTransaction { asyncRealm -> val item = asyncRealm.findById(itemClass, itemId) as? Deletable item?.let { item.deleteDependencies(asyncRealm) @@ -123,7 +123,7 @@ abstract class DeletableItemFragment : RealmFragment() { if (!itemHasBeenReInserted) { itemHasBeenReInserted = true - getRealm().executeTransactionAsync { realm -> + executeRealmAsyncTransaction { realm -> deletedItem?.let { val item = realm.copyToRealmOrUpdate(it) updateUIAfterUndoDeletion(item) diff --git a/app/src/main/java/net/pokeranalytics/android/ui/fragment/components/RealmFragment.kt b/app/src/main/java/net/pokeranalytics/android/ui/fragment/components/RealmFragment.kt index 5d6d48e3..a0cdab81 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/fragment/components/RealmFragment.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/fragment/components/RealmFragment.kt @@ -1,14 +1,20 @@ package net.pokeranalytics.android.ui.fragment.components +import android.content.BroadcastReceiver +import android.content.Context +import android.content.Intent +import android.content.IntentFilter import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import androidx.localbroadcastmanager.content.LocalBroadcastManager import io.realm.Realm import io.realm.RealmModel import io.realm.RealmResults +import net.pokeranalytics.android.AppState import net.pokeranalytics.android.exceptions.PAIllegalStateException -import net.pokeranalytics.android.util.Global +import net.pokeranalytics.android.ui.fragment.ImportBroadcast interface RealmAsyncListener { fun asyncListenedEntityChange(realm: Realm, clazz: Class) @@ -19,14 +25,21 @@ open class RealmFragment : BaseFragment() { /** * A realm instance */ - private lateinit var realm: Realm +// private lateinit var realm: Realm /*** * A listener to async updates */ private var changeListener: RealmAsyncListener? = null - private var realmResults: RealmResults? = null + private val endImportReceiver = object : BroadcastReceiver() { + override fun onReceive(context: Context?, intent: Intent?) { + sendRealmChange() + } + } + + +// private var realmResults: RealmResults? = null /** * A List of observed RealmResults @@ -34,7 +47,8 @@ open class RealmFragment : BaseFragment() { private var observedRealmResults: MutableList> = mutableListOf() override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { - realm = Realm.getDefaultInstance() +// realm = Realm.getDefaultInstance() + LocalBroadcastManager.getInstance(requireContext()).registerReceiver(endImportReceiver, IntentFilter(ImportBroadcast.END.identifier)) return super.onCreateView(inflater, container, savedInstanceState) } @@ -42,7 +56,11 @@ open class RealmFragment : BaseFragment() { * Get the realm instance */ fun getRealm(): Realm { - return this.realm + return this.parentActivity?.getRealm() ?: throw PAIllegalStateException("parent activity missing") + } + + fun executeRealmAsyncTransaction(handler: (Realm) -> (Unit)) { + this.parentActivity?.executeRealmAsyncTransaction(handler) ?: throw PAIllegalStateException("parent activity missing") } fun addRealmChangeListener(listener: RealmAsyncListener, clazz: Class) { @@ -52,23 +70,38 @@ open class RealmFragment : BaseFragment() { } this.changeListener = listener - val results = this.realm.where(clazz).findAllAsync() + val results = getRealm().where(clazz).findAllAsync() results.addChangeListener { res, _ -> // Timber.d("Realm changes: ${realmResults?.size}, $this") - this.changeListener?.asyncListenedEntityChange(res.realm, clazz) + if (!AppState.isImporting) { + this.changeListener?.asyncListenedEntityChange(res.realm, clazz) + } else { + this.changedClasses.add(clazz) + } } this.observedRealmResults.add(results) } + private var changedClasses: MutableSet> = mutableSetOf() + + fun sendRealmChange() { + if (!AppState.isImporting) { + for (clazz in this.changedClasses) { + this.changeListener?.asyncListenedEntityChange(getRealm(), clazz) + } + this.changedClasses.clear() + } + } + override fun onDestroyView() { super.onDestroyView() + LocalBroadcastManager.getInstance(requireContext()).unregisterReceiver(endImportReceiver) + this.observedRealmResults.forEach { it.removeAllChangeListeners() } - this.realm.close() - this.realmResults?.removeAllChangeListeners() } /** diff --git a/app/src/main/java/net/pokeranalytics/android/ui/fragment/report/AbstractReportFragment.kt b/app/src/main/java/net/pokeranalytics/android/ui/fragment/report/AbstractReportFragment.kt index bb30b148..a45c168b 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/fragment/report/AbstractReportFragment.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/fragment/report/AbstractReportFragment.kt @@ -125,7 +125,7 @@ abstract class AbstractReportFragment : DataManagerFragment() { val firstSave = (this.model.primaryKey == null) - getRealm().executeTransactionAsync { realm -> + executeRealmAsyncTransaction { realm -> if (firstSave) { val options = this.selectedReport.options diff --git a/app/src/main/java/net/pokeranalytics/android/ui/fragment/report/ProgressReportFragment.kt b/app/src/main/java/net/pokeranalytics/android/ui/fragment/report/ProgressReportFragment.kt index b617ce24..ce7cf056 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/fragment/report/ProgressReportFragment.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/fragment/report/ProgressReportFragment.kt @@ -141,7 +141,7 @@ class ProgressReportFragment : AbstractReportFragment() { when (aggregationType) { AggregationType.MONTH, AggregationType.YEAR -> { - if (aggregationType.criterias.combined().size < 2) { + if (aggregationType.criterias.combined(getRealm()).size < 2) { Toast.makeText(context, R.string.less_then_2_values_for_display, Toast.LENGTH_LONG).show() return } diff --git a/app/src/main/java/net/pokeranalytics/android/ui/helpers/AppReviewManager.kt b/app/src/main/java/net/pokeranalytics/android/ui/helpers/AppReviewManager.kt index 285d3d14..c4e3396d 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/helpers/AppReviewManager.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/helpers/AppReviewManager.kt @@ -14,7 +14,7 @@ object AppReviewManager { this.reviewRequested = true } - fun showReviewManager(activity: Activity) { + fun showReviewManagerIfNecessary(activity: Activity) { if (this.reviewRequested && this.shouldAskForReview(activity.baseContext)) { this.reviewRequested = false diff --git a/app/src/main/java/net/pokeranalytics/android/ui/modules/bankroll/BankrollFragment.kt b/app/src/main/java/net/pokeranalytics/android/ui/modules/bankroll/BankrollFragment.kt index 9f982a96..b0306d9c 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/modules/bankroll/BankrollFragment.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/modules/bankroll/BankrollFragment.kt @@ -33,11 +33,8 @@ import net.pokeranalytics.android.ui.view.rows.BankrollGraphRow import net.pokeranalytics.android.ui.view.rows.BankrollMainRow import net.pokeranalytics.android.ui.view.rows.BankrollTotalRow import net.pokeranalytics.android.ui.view.rows.CustomizableRowRepresentable -import net.pokeranalytics.android.util.Global import net.pokeranalytics.android.util.extensions.sorted import timber.log.Timber -import java.util.* -import kotlin.collections.ArrayList interface BankrollRowRepresentable : RowRepresentable { var bankrollId: String? @@ -119,10 +116,8 @@ class BankrollFragment : DeletableItemFragment(), StaticRowRepresentableDataSour private fun initData() { this.bankrolls = getRealm().sorted() - if (Global.LAUNCH_ASYNC_LISTENERS) { - this.bankrolls.addChangeListener { _, _ -> - this.createRowRepresentables() - } + this.bankrolls.addChangeListener { _, _ -> + this.createRowRepresentables() } this.createRowRepresentables() diff --git a/app/src/main/java/net/pokeranalytics/android/ui/modules/calendar/CalendarFragment.kt b/app/src/main/java/net/pokeranalytics/android/ui/modules/calendar/CalendarFragment.kt index b8db032d..61d23e32 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/modules/calendar/CalendarFragment.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/modules/calendar/CalendarFragment.kt @@ -11,10 +11,13 @@ import io.realm.Realm import io.realm.RealmModel import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.async import kotlinx.coroutines.launch +import net.pokeranalytics.android.AppState import net.pokeranalytics.android.R import net.pokeranalytics.android.calculus.Calculator import net.pokeranalytics.android.calculus.ComputedResults +import net.pokeranalytics.android.calculus.Report import net.pokeranalytics.android.calculus.Stat import net.pokeranalytics.android.databinding.FragmentCalendarBinding import net.pokeranalytics.android.exceptions.PAIllegalStateException @@ -35,13 +38,11 @@ import net.pokeranalytics.android.ui.view.CalendarTabs import net.pokeranalytics.android.ui.view.RowRepresentable import net.pokeranalytics.android.ui.view.RowViewType import net.pokeranalytics.android.ui.view.rows.CustomizableRowRepresentable -import net.pokeranalytics.android.util.Global import net.pokeranalytics.android.util.extensions.* import timber.log.Timber import java.util.* import kotlin.collections.set - class CalendarFragment : RealmFragment(), StaticRowRepresentableDataSource, RowRepresentableDelegate, RealmAsyncListener { @@ -85,6 +86,13 @@ class CalendarFragment : RealmFragment(), StaticRowRepresentableDataSource, private var _binding: FragmentCalendarBinding? = null private val binding get() = _binding!! + private val requiredStats: List = listOf( + Stat.LOCATIONS_PLAYED, + Stat.LONGEST_STREAKS, + Stat.DAYS_PLAYED, + Stat.STANDARD_DEVIATION_HOURLY + ) + // Life Cycle override fun onCreateView( @@ -99,15 +107,13 @@ class CalendarFragment : RealmFragment(), StaticRowRepresentableDataSource, override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - initData() initUI() + initData() - if (Global.LAUNCH_ASYNC_LISTENERS) { - addRealmChangeListener(this, UserConfig::class.java) - addRealmChangeListener(this, ComputableResult::class.java) - addRealmChangeListener(this, Transaction::class.java) - addRealmChangeListener(this, SessionSet::class.java) - } + addRealmChangeListener(this, UserConfig::class.java) + addRealmChangeListener(this, ComputableResult::class.java) + addRealmChangeListener(this, Transaction::class.java) + addRealmChangeListener(this, SessionSet::class.java) } private var transactionFilterMenuItem: MenuItem? = null @@ -162,12 +168,44 @@ class CalendarFragment : RealmFragment(), StaticRowRepresentableDataSource, } private fun showDetails(computedResults: ComputedResults, title: String?) { - CalendarDetailsActivity.newInstance( - requireContext(), - computedResults, - sessionTypeCondition, - title - ) + + // start calculation with progress values + + CoroutineScope(Dispatchers.Default).launch { + + var report: Report? = null + + val coroutine = async { + + val realm = Realm.getDefaultInstance() + + val options = Calculator.Options( + progressValues = Calculator.Options.ProgressValues.STANDARD, + stats = requiredStats, + query = computedResults.group.query, + includedTransactions = transactionTypes(realm) + ) + report = Calculator.computeStats(realm, options = options) + + realm.close() + } + coroutine.await() + + launch(Dispatchers.Main) { + + report?.results?.firstOrNull()?.let { cr -> + CalendarDetailsActivity.newInstance( + requireContext(), + cr, + sessionTypeCondition, + title + ) + } + + } + + } + } override fun onRowSelected(position: Int, row: RowRepresentable, tag: Int) { @@ -348,17 +386,52 @@ class CalendarFragment : RealmFragment(), StaticRowRepresentableDataSource, CoroutineScope(Dispatchers.Default).launch { - val realm = Realm.getDefaultInstance() - realm.refresh() + val async = async { + val s = Date() + Timber.d(">>> start...") + + val realm = Realm.getDefaultInstance() + realm.refresh() - launchStatComputation(realm) + launchStatComputation(realm) - realm.close() + realm.close() + + val e = Date() + val duration = (e.time - s.time) / 1000.0 + Timber.d(">>> computations took $duration seconds") + + } + async.await() launch(Dispatchers.Main) { - displayData() + if (isAdded && !isDetached) { + displayData() + } } } + +// CoroutineScope(Dispatchers.Default).launch { +// +// val realm = Realm.getDefaultInstance() +// realm.refresh() +// +// launchStatComputation(realm) +// +// realm.close() +// +// launch(Dispatchers.Main) { +// displayData() +// } +// } + } + + private fun transactionTypes(realm: Realm): List { + var transactionTypes = listOf() + UserConfig.getConfiguration(realm) { userConfig -> + transactionTypes = userConfig.transactionTypes(realm) + } + return transactionTypes } private fun launchStatComputation(realm: Realm) { @@ -368,26 +441,12 @@ class CalendarFragment : RealmFragment(), StaticRowRepresentableDataSource, val calendar = Calendar.getInstance() calendar.time = Date().startOfMonth() -// val startDate = Date() - - val requiredStats: List = - listOf( - Stat.LOCATIONS_PLAYED, - Stat.LONGEST_STREAKS, - Stat.DAYS_PLAYED, - Stat.STANDARD_DEVIATION_HOURLY - ) - - var transactionTypes = listOf() - UserConfig.getConfiguration(realm) { userConfig -> - transactionTypes = userConfig.transactionTypes(realm) - } + val startDate = Date() -// val transactionTypes = UserConfig.getConfiguration(realm).transactionTypes(realm) + val transactionTypes = this.transactionTypes(realm) // All val allOptions = Calculator.Options( - progressValues = Calculator.Options.ProgressValues.STANDARD, stats = requiredStats, query = Query(this.sessionTypeCondition), includedTransactions = transactionTypes @@ -397,7 +456,6 @@ class CalendarFragment : RealmFragment(), StaticRowRepresentableDataSource, // Sliding Month [sm] val smOptions = Calculator.Options( - progressValues = Calculator.Options.ProgressValues.STANDARD, stats = requiredStats, query = Query(this.slidingMonthQueryCondition, this.sessionTypeCondition), includedTransactions = transactionTypes @@ -410,23 +468,24 @@ class CalendarFragment : RealmFragment(), StaticRowRepresentableDataSource, val monthlyReports: HashMap = HashMap() val monthlyQueries = when (sessionTypeCondition) { - QueryCondition.IsCash -> listOf(Criteria.AllMonthsUpToNow, Criteria.Cash).combined() - QueryCondition.IsTournament -> listOf(Criteria.AllMonthsUpToNow, Criteria.Tournament).combined() - else -> listOf(Criteria.Years, Criteria.MonthsOfYear).combined() + QueryCondition.IsCash -> listOf(Criteria.AllMonthsUpToNow, Criteria.Cash).combined(realm) + QueryCondition.IsTournament -> listOf(Criteria.AllMonthsUpToNow, Criteria.Tournament).combined(realm) + else -> listOf(Criteria.Years, Criteria.MonthsOfYear).combined(realm) } - monthlyQueries.forEach { query -> + for (monthlyQuery in monthlyQueries) { val options = Calculator.Options( - progressValues = Calculator.Options.ProgressValues.STANDARD, stats = requiredStats, - query = query, + query = monthlyQuery, includedTransactions = transactionTypes ) val report = Calculator.computeStats(realm, options = options) - report.results.forEach { computedResults -> + + for (computedResults in report.results) { if (!computedResults.isEmpty) { // Set date data - query.conditions.forEach { condition -> + + for (condition in monthlyQuery.conditions) { when (condition) { is QueryCondition.AnyYear -> calendar.set( Calendar.YEAR, @@ -443,11 +502,11 @@ class CalendarFragment : RealmFragment(), StaticRowRepresentableDataSource, monthlyReports[calendar.time] = computedResults } } + } // Sliding Year [sm] val syOptions = Calculator.Options( - progressValues = Calculator.Options.ProgressValues.STANDARD, stats = requiredStats, query = Query(this.slidingYearQueryCondition, this.sessionTypeCondition), includedTransactions = transactionTypes @@ -462,14 +521,13 @@ class CalendarFragment : RealmFragment(), StaticRowRepresentableDataSource, val yearlyReports: HashMap = HashMap() val yearConditions = when (sessionTypeCondition) { - QueryCondition.IsCash -> listOf(Criteria.Years, Criteria.Cash).combined() - QueryCondition.IsTournament -> listOf(Criteria.Years, Criteria.Tournament).combined() - else -> listOf(Criteria.Years).combined() + QueryCondition.IsCash -> listOf(Criteria.Years, Criteria.Cash).combined(realm) + QueryCondition.IsTournament -> listOf(Criteria.Years, Criteria.Tournament).combined(realm) + else -> listOf(Criteria.Years).combined(realm) } yearConditions.forEach { query -> val options = Calculator.Options( - progressValues = Calculator.Options.ProgressValues.STANDARD, stats = requiredStats, query = query, includedTransactions = transactionTypes @@ -495,7 +553,7 @@ class CalendarFragment : RealmFragment(), StaticRowRepresentableDataSource, sortedMonthlyReports = monthlyReports.toSortedMap(compareByDescending { it }) sortedYearlyReports = yearlyReports.toSortedMap(compareByDescending { it }) -// Timber.d("Computation: ${System.currentTimeMillis() - startDate.time}ms") + Timber.d("Computation: ${System.currentTimeMillis() - startDate.time}ms") } @@ -505,9 +563,12 @@ class CalendarFragment : RealmFragment(), StaticRowRepresentableDataSource, private fun displayData() { // Timber.d("displayData") + this.binding.progressBar.hideWithAnimation() + this.binding.recyclerView.showWithAnimation() + if (context == null) { return } // required because of launchAsyncStatComputation -// val startDate = Date() + val startDate = Date() datesForRows.clear() rows.clear() @@ -599,14 +660,11 @@ class CalendarFragment : RealmFragment(), StaticRowRepresentableDataSource, } } -// Timber.d("Display data: ${System.currentTimeMillis() - startDate.time}ms") -// Timber.d("Rows: ${rows.size}") + Timber.d("Display data: ${System.currentTimeMillis() - startDate.time}ms") + Timber.d("Rows: ${rows.size}") this.calendarAdapter.notifyDataSetChanged() - this.binding.progressBar.hideWithAnimation() - this.binding.recyclerView.showWithAnimation() - } override fun asyncListenedEntityChange(realm: Realm, clazz: Class) { diff --git a/app/src/main/java/net/pokeranalytics/android/ui/modules/data/DataManagerFragment.kt b/app/src/main/java/net/pokeranalytics/android/ui/modules/data/DataManagerFragment.kt index 34c2d64f..ac591daf 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/modules/data/DataManagerFragment.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/modules/data/DataManagerFragment.kt @@ -108,7 +108,7 @@ open class DataManagerFragment : RealmFragment() { when (status) { SaveValidityStatus.VALID -> { - this.getRealm().executeTransactionAsync { asyncRealm -> + executeRealmAsyncTransaction { asyncRealm -> asyncRealm.insertOrUpdate(savable) } diff --git a/app/src/main/java/net/pokeranalytics/android/ui/modules/data/EditableDataFragment.kt b/app/src/main/java/net/pokeranalytics/android/ui/modules/data/EditableDataFragment.kt index 784d5e93..8c5e2dcb 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/modules/data/EditableDataFragment.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/modules/data/EditableDataFragment.kt @@ -69,7 +69,8 @@ open class EditableDataFragment : DataManagerFragment(), RowRepresentableDelegat (this.model.item as RowUpdatable).updateValue(value, row) if (this.model.primaryKey != null) { - getRealm().executeTransactionAsync { asyncRealm -> + + executeRealmAsyncTransaction { asyncRealm -> try { asyncRealm.insertOrUpdate(this.model.item) } catch (e: Exception) { @@ -77,6 +78,7 @@ open class EditableDataFragment : DataManagerFragment(), RowRepresentableDelegat throw e } } + } rowRepresentableAdapter.refreshRow(row) diff --git a/app/src/main/java/net/pokeranalytics/android/ui/modules/feed/FeedFragment.kt b/app/src/main/java/net/pokeranalytics/android/ui/modules/feed/FeedFragment.kt index 8a2c5422..9776bde5 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/modules/feed/FeedFragment.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/modules/feed/FeedFragment.kt @@ -12,10 +12,7 @@ import com.android.billingclient.api.Purchase import com.google.android.material.badge.BadgeDrawable import com.google.android.material.badge.BadgeUtils import com.google.android.material.tabs.TabLayout -import io.realm.Realm -import io.realm.RealmModel -import io.realm.RealmResults -import io.realm.Sort +import io.realm.* import io.realm.kotlin.where import net.pokeranalytics.android.R import net.pokeranalytics.android.api.BlogPostApi @@ -47,6 +44,7 @@ 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 timber.log.Timber import java.util.* class FeedFragment : FilterableFragment(), RowRepresentableDelegate, PurchaseListener, RealmAsyncListener { @@ -78,6 +76,7 @@ class FeedFragment : FilterableFragment(), RowRepresentableDelegate, PurchaseLis private lateinit var realmTransactions: RealmResults private lateinit var realmHandHistories: RealmResults +// private lateinit var realmSessions: RealmResults private var newSessionCreated: Boolean = false private var adapterHasBeenSet: Boolean = false @@ -88,8 +87,10 @@ class FeedFragment : FilterableFragment(), RowRepresentableDelegate, PurchaseLis override fun asyncListenedEntityChange(realm: Realm, clazz: Class) { + Timber.d("asyncListenedEntityChange for $clazz") when (clazz.kotlin) { Session::class -> { + Timber.d("WOWOWOOWOOWOWOWOWOWOWOWOWO") this.sessionAdapter.refreshData() this.sessionAdapter.notifyDataSetChanged() } @@ -148,12 +149,30 @@ class FeedFragment : FilterableFragment(), RowRepresentableDelegate, PurchaseLis AppGuard.registerListener(this) +// this.realmSessions = getRealm().where().findAllAsync() + +// val listener = RealmChangeListener> { +// Timber.d("WOWOWOOWOOWOWOWOWOWOWOWOWO") +// sessionAdapter.refreshData() +// sessionAdapter.notifyDataSetChanged() +// } +// this.realmSessions.addChangeListener(listener) + +// this.realmSessions.addChangeListener { t, changeSet -> +// Timber.d("WOWOWOOWOOWOWOWOWOWOWOWOWO") +// this.sessionAdapter.refreshData() +// this.sessionAdapter.notifyDataSetChanged() +// } + initUI() initData() } override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { super.onActivityResult(requestCode, resultCode, data) + + getRealm().refresh() + if (requestCode == RequestCode.FEED_MENU.value && resultCode == RESULT_OK && data != null) { when (data.getIntExtra(NewDataMenuActivity.IntentKey.CHOICE.keyName, -1)) { 0 -> createNewSession(false) @@ -489,7 +508,7 @@ class FeedFragment : FilterableFragment(), RowRepresentableDelegate, PurchaseLis private fun deleteSelectedTransaction() { selectedTransaction?.id?.let { id -> - getRealm().executeTransactionAsync { asyncRealm -> + executeRealmAsyncTransaction { asyncRealm -> asyncRealm.findById(id)?.deleteFromRealm() } } diff --git a/app/src/main/java/net/pokeranalytics/android/ui/modules/filter/FilterDetailsFragment.kt b/app/src/main/java/net/pokeranalytics/android/ui/modules/filter/FilterDetailsFragment.kt index cfef89bd..4dde54af 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/modules/filter/FilterDetailsFragment.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/modules/filter/FilterDetailsFragment.kt @@ -95,7 +95,7 @@ open class FilterDetailsFragment : RealmFragment(), RowRepresentableDelegate { val categoryRow = FilterCategoryRow.values()[category] Timber.d("Category row = $categoryRow") - val factory = FilterDetailsViewModelFactory(filter, categoryRow) + val factory = FilterDetailsViewModelFactory(getRealm(), filter, categoryRow) this.model = ViewModelProvider(this, factory).get(FilterDetailsViewModel::class.java) } ?: throw PAIllegalStateException("Missing bundle") diff --git a/app/src/main/java/net/pokeranalytics/android/ui/modules/filter/FilterDetailsViewModel.kt b/app/src/main/java/net/pokeranalytics/android/ui/modules/filter/FilterDetailsViewModel.kt index fcca1b00..7b0da9bc 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/modules/filter/FilterDetailsViewModel.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/modules/filter/FilterDetailsViewModel.kt @@ -3,6 +3,7 @@ package net.pokeranalytics.android.ui.modules.filter import android.content.Context import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModelProvider +import io.realm.Realm import net.pokeranalytics.android.model.realm.Filter import net.pokeranalytics.android.ui.adapter.RowRepresentableAdapter import net.pokeranalytics.android.ui.adapter.StaticRowRepresentableDataSource @@ -13,21 +14,21 @@ import net.pokeranalytics.android.ui.view.rows.FilterItemRow import net.pokeranalytics.android.util.NULL_TEXT import timber.log.Timber -class FilterDetailsViewModelFactory(var filter: Filter, private var categoryRow: FilterCategoryRow): ViewModelProvider.Factory { +class FilterDetailsViewModelFactory(var realm: Realm, var filter: Filter, private var categoryRow: FilterCategoryRow): ViewModelProvider.Factory { override fun create(modelClass: Class): T { - return FilterDetailsViewModel(categoryRow, filter) as T + return FilterDetailsViewModel(realm, categoryRow, filter) as T } } -class FilterDetailsViewModel(categoryRow: FilterCategoryRow, var filter: Filter) : ViewModel(), StaticRowRepresentableDataSource { +class FilterDetailsViewModel(var realm: Realm, categoryRow: FilterCategoryRow, var filter: Filter) : ViewModel(), StaticRowRepresentableDataSource { private var rows: ArrayList = ArrayList() val selectedRows = ArrayList() init { - this.rows.addAll(categoryRow.filterElements) + this.rows.addAll(categoryRow.filterElements(realm)) this.defineSelectedItems() } diff --git a/app/src/main/java/net/pokeranalytics/android/ui/modules/filter/FilterHandler.kt b/app/src/main/java/net/pokeranalytics/android/ui/modules/filter/FilterHandler.kt index f8e5ad07..ea2a20c5 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/modules/filter/FilterHandler.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/modules/filter/FilterHandler.kt @@ -9,6 +9,7 @@ import net.pokeranalytics.android.model.realm.Filter import net.pokeranalytics.android.util.Preferences import net.pokeranalytics.android.util.enumerations.IntIdentifiable import net.pokeranalytics.android.util.enumerations.IntSearchable +import timber.log.Timber enum class FilterActivityRequestCode { SELECT_FILTER, diff --git a/app/src/main/java/net/pokeranalytics/android/ui/modules/filter/FiltersFragment.kt b/app/src/main/java/net/pokeranalytics/android/ui/modules/filter/FiltersFragment.kt index 3c5a696c..facab492 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/modules/filter/FiltersFragment.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/modules/filter/FiltersFragment.kt @@ -217,7 +217,7 @@ open class FiltersFragment : RealmFragment(), RowRepresentableDelegate { private fun save() { val filter = this.model.currentFilter - getRealm().executeTransactionAsync { asyncRealm -> + executeRealmAsyncTransaction { asyncRealm -> filter.name = filter.query.getName(requireContext()) asyncRealm.insertOrUpdate(filter) } @@ -233,7 +233,7 @@ open class FiltersFragment : RealmFragment(), RowRepresentableDelegate { val filterCopy = this.model.filterCopy val filterId = filterCopy?.id ?: "" - getRealm().executeTransactionAsync { realm -> + executeRealmAsyncTransaction { realm -> filterCopy?.let { realm.insertOrUpdate(it) } diff --git a/app/src/main/java/net/pokeranalytics/android/ui/modules/filter/FiltersListFragment.kt b/app/src/main/java/net/pokeranalytics/android/ui/modules/filter/FiltersListFragment.kt index 93c00b8f..0d913d24 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/modules/filter/FiltersListFragment.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/modules/filter/FiltersListFragment.kt @@ -17,7 +17,7 @@ open class FiltersListFragment : DataListFragment() { is Filter -> { row.updateValue(value, row) - getRealm().executeTransactionAsync { asyncRealm -> + executeRealmAsyncTransaction { asyncRealm -> asyncRealm.insertOrUpdate(row) } val index = this.model.items.indexOf(row) diff --git a/app/src/main/java/net/pokeranalytics/android/ui/modules/handhistory/editor/EditorFragment.kt b/app/src/main/java/net/pokeranalytics/android/ui/modules/handhistory/editor/EditorFragment.kt index a9858a50..167a4ed7 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/modules/handhistory/editor/EditorFragment.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/modules/handhistory/editor/EditorFragment.kt @@ -688,7 +688,7 @@ class EditorFragment : RealmFragment(), RowRepresentableDelegate, KeyboardListen private fun deleteHand() { val hhId = this.model.handHistory.id - getRealm().executeTransactionAsync { asyncRealm -> + executeRealmAsyncTransaction { asyncRealm -> asyncRealm.findById(hhId)?.deleteFromRealm() } diff --git a/app/src/main/java/net/pokeranalytics/android/ui/modules/session/SessionFragment.kt b/app/src/main/java/net/pokeranalytics/android/ui/modules/session/SessionFragment.kt index 24d3d31f..17396031 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/modules/session/SessionFragment.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/modules/session/SessionFragment.kt @@ -11,6 +11,7 @@ import androidx.appcompat.content.res.AppCompatResources import androidx.interpolator.view.animation.FastOutSlowInInterpolator import androidx.lifecycle.ViewModelProvider import androidx.recyclerview.widget.DiffUtil +import io.realm.Realm import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch @@ -62,7 +63,6 @@ class SessionFragment : RealmFragment(), RowRepresentableDelegate, StaticRowRepr private var sessionMenu: Menu? = null private val oldRows: ArrayList = ArrayList() - private var sessionHasBeenUserCustomized = false private val handler: Handler = Handler() private val timer: Runnable = object : Runnable { @@ -146,7 +146,6 @@ class SessionFragment : RealmFragment(), RowRepresentableDelegate, StaticRowRepr binding.floatingActionButton.setOnClickListener { if (this.currentSession.isValidForSave()) { - sessionHasBeenUserCustomized = true startPauseResumeSession() } else { val builder = AlertDialog.Builder(requireContext()) @@ -198,10 +197,8 @@ class SessionFragment : RealmFragment(), RowRepresentableDelegate, StaticRowRepr val session = copy.duplicate() currentSession = session // } - sessionHasBeenUserCustomized = false } else { // show existing session currentSession = copy - sessionHasBeenUserCustomized = true } } ?: throw PAIllegalStateException("Session cannot be null here, session id = $sessionId") @@ -227,7 +224,6 @@ class SessionFragment : RealmFragment(), RowRepresentableDelegate, StaticRowRepr } } - this.sessionHasBeenUserCustomized = false } } @@ -273,7 +269,6 @@ class SessionFragment : RealmFragment(), RowRepresentableDelegate, StaticRowRepr override fun onRowValueChanged(value: Any?, row: RowRepresentable) { Timber.d("value changed: $value, row: $row") - this.sessionHasBeenUserCustomized = true updateSessionThenSaveAsynchronously { session -> session.updateValue(value, row) @@ -311,7 +306,7 @@ class SessionFragment : RealmFragment(), RowRepresentableDelegate, StaticRowRepr return } - getRealm().executeTransactionAsync { realm -> + executeRealmAsyncTransaction { realm -> val session = realm.copyToRealmOrUpdate(this.currentSession) session.preCompute() @@ -319,6 +314,7 @@ class SessionFragment : RealmFragment(), RowRepresentableDelegate, StaticRowRepr realm.insertOrUpdate(customField) } } + } /** @@ -539,7 +535,7 @@ class SessionFragment : RealmFragment(), RowRepresentableDelegate, StaticRowRepr val bankrollId = this.currentSession.bankroll?.id val sessionId = this.currentSession.id - getRealm().executeTransactionAsync { asyncRealm -> + executeRealmAsyncTransaction { asyncRealm -> asyncRealm.findById(sessionId)?.delete() } diff --git a/app/src/main/java/net/pokeranalytics/android/ui/modules/settings/DealtHandsPerHourFragment.kt b/app/src/main/java/net/pokeranalytics/android/ui/modules/settings/DealtHandsPerHourFragment.kt index b61c0735..306e9dd4 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/modules/settings/DealtHandsPerHourFragment.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/modules/settings/DealtHandsPerHourFragment.kt @@ -58,7 +58,7 @@ class DealtHandsPerHourFragment : RealmFragment() { private fun save() { - getRealm().executeTransactionAsync { realm -> + executeRealmAsyncTransaction { realm -> UserConfig.getConfiguration(realm) { userConfig -> this.liveValue.text.toString().toIntOrNull()?.let { liveDealtHandsPerHour -> diff --git a/app/src/main/java/net/pokeranalytics/android/ui/modules/settings/TransactionFilterFragment.kt b/app/src/main/java/net/pokeranalytics/android/ui/modules/settings/TransactionFilterFragment.kt index 7a322ef9..a7838ff3 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/modules/settings/TransactionFilterFragment.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/modules/settings/TransactionFilterFragment.kt @@ -97,7 +97,7 @@ class TransactionFilterFragment : RealmFragment(), StaticRowRepresentableDataSou } private fun save() { - getRealm().executeTransactionAsync { asyncRealm -> + executeRealmAsyncTransaction { asyncRealm -> UserConfig.getConfiguration(asyncRealm) { userConfig -> userConfig.setTransactionTypeIds(this.model.selectedTransactionTypes) asyncRealm.insertOrUpdate(userConfig) diff --git a/app/src/main/java/net/pokeranalytics/android/ui/view/rows/FilterCategoryRow.kt b/app/src/main/java/net/pokeranalytics/android/ui/view/rows/FilterCategoryRow.kt index f1384967..8da2d797 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/view/rows/FilterCategoryRow.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/view/rows/FilterCategoryRow.kt @@ -60,14 +60,13 @@ enum class FilterCategoryRow(override val resId: Int?, override val viewType: In } } - val filterElements: List - get() { + fun filterElements(realm: Realm): List { return filterSectionRows.flatMap { - val items = it.filterItems + val items = it.filterItems(realm) val list = mutableListOf() if (items.isNotEmpty()) { list.add(it) - list.addAll(it.filterItems) + list.addAll(it.filterItems(realm)) } list } diff --git a/app/src/main/java/net/pokeranalytics/android/ui/view/rows/FilterSectionRow.kt b/app/src/main/java/net/pokeranalytics/android/ui/view/rows/FilterSectionRow.kt index 4d62f22d..209f121b 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/view/rows/FilterSectionRow.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/view/rows/FilterSectionRow.kt @@ -1,6 +1,7 @@ package net.pokeranalytics.android.ui.view.rows import android.content.Context +import io.realm.Realm import net.pokeranalytics.android.R import net.pokeranalytics.android.exceptions.PokerAnalyticsException import net.pokeranalytics.android.model.Criteria @@ -71,9 +72,8 @@ sealed class FilterSectionRow(override val resId: Int?) : RowRepresentable { val allowMultiSelection: Boolean get() = (this.selectionType == SelectionType.MULTIPLE) - val filterItems: List - get() { - return this.queryConditions.map { + fun filterItems(realm: Realm): List { + return this.queryConditions(realm).map { rowWrapper(it, this@FilterSectionRow) // it.toRowWrapper(this@FilterSectionRow) } @@ -101,15 +101,14 @@ sealed class FilterSectionRow(override val resId: Int?) : RowRepresentable { } } - private val queryConditions: List - get() { + private fun queryConditions(realm: Realm): List { return when (this@FilterSectionRow) { // General - CashOrTournament -> Criteria.SessionTypes.queryConditions.mapFirstCondition() - LiveOrOnline -> Criteria.BankrollTypes.queryConditions.mapFirstCondition() - Game -> Criteria.Games.queryConditions.mapFirstCondition() - LimitType -> Criteria.Limits.queryConditions.mapFirstCondition() - TableSize -> Criteria.TableSizes.queryConditions.mapFirstCondition() + CashOrTournament -> Criteria.SessionTypes.queryConditions(realm).mapFirstCondition() + LiveOrOnline -> Criteria.BankrollTypes.queryConditions(realm).mapFirstCondition() + Game -> Criteria.Games.queryConditions(realm).mapFirstCondition() + LimitType -> Criteria.Limits.queryConditions(realm).mapFirstCondition() + TableSize -> Criteria.TableSizes.queryConditions(realm).mapFirstCondition() // Date DynamicDate -> arrayListOf( QueryCondition.IsToday, @@ -120,9 +119,9 @@ sealed class FilterSectionRow(override val resId: Int?) : RowRepresentable { QueryCondition.DuringThisYear ) WeekdayOrWeekend -> arrayListOf(QueryCondition.IsWeekDay, QueryCondition.IsWeekEnd) - Year -> Criteria.Years.queryConditions.mapFirstCondition() - DayOfWeek -> Criteria.DaysOfWeek.queryConditions.mapFirstCondition() - MonthOfYear -> Criteria.MonthsOfYear.queryConditions.mapFirstCondition() + Year -> Criteria.Years.queryConditions(realm).mapFirstCondition() + DayOfWeek -> Criteria.DaysOfWeek.queryConditions(realm).mapFirstCondition() + MonthOfYear -> Criteria.MonthsOfYear.queryConditions(realm).mapFirstCondition() // Duration SessionDuration -> QueryCondition.moreEqualOrLessEqual() @@ -135,20 +134,20 @@ sealed class FilterSectionRow(override val resId: Int?) : RowRepresentable { //Sessions -> arrayListOf(QueryCondition.LastGame(), QueryCondition.LastSession()) // Cash - Stakes -> Criteria.Stakes.queryConditions.mapFirstCondition() + Stakes -> Criteria.Stakes.queryConditions(realm).mapFirstCondition() // CashRebuyCount -> QueryCondition.moreOrLess() // Tournament - TournamentType -> Criteria.TournamentTypes.queryConditions.mapFirstCondition() + TournamentType -> Criteria.TournamentTypes.queryConditions(realm).mapFirstCondition() // CompletionPercentage -> arrayListOf() TournamentFinalPosition -> QueryCondition.moreEqualOrLessEqual() TournamentNumberOfPlayer -> QueryCondition.moreEqualOrLessEqual() - TournamentEntryFee -> Criteria.TournamentFees.queryConditions.mapFirstCondition() - TournamentName -> Criteria.TournamentNames.queryConditions.mapFirstCondition() - TournamentFeature -> Criteria.TournamentFeatures.queryConditions.mapFirstCondition() - Location -> Criteria.Locations.queryConditions.mapFirstCondition() - Bankroll -> Criteria.Bankrolls.queryConditions.mapFirstCondition() + TournamentEntryFee -> Criteria.TournamentFees.queryConditions(realm).mapFirstCondition() + TournamentName -> Criteria.TournamentNames.queryConditions(realm).mapFirstCondition() + TournamentFeature -> Criteria.TournamentFeatures.queryConditions(realm).mapFirstCondition() + Location -> Criteria.Locations.queryConditions(realm).mapFirstCondition() + Bankroll -> Criteria.Bankrolls.queryConditions(realm).mapFirstCondition() MultiTabling -> QueryCondition.moreEqualOrLessEqual() //NumberOfPlayers -> QueryCondition.moreOrLess() NumberOfRebuy -> QueryCondition.moreEqualOrLessEqual() @@ -158,12 +157,12 @@ sealed class FilterSectionRow(override val resId: Int?) : RowRepresentable { addAll(QueryCondition.moreEqualOrLessEqual()) addAll(QueryCondition.moreEqualOrLessEqual()) } - TransactionType -> Criteria.TransactionTypes.queryConditions.mapFirstCondition() + TransactionType -> Criteria.TransactionTypes.queryConditions(realm).mapFirstCondition() is CustomField -> { val cf = this@FilterSectionRow.customField when { cf.isListType -> { - Criteria.ListCustomFields(cf.id).queryConditions.mapFirstCondition() + Criteria.ListCustomFields(cf.id).queryConditions(realm).mapFirstCondition() } cf.isAmountType -> { QueryCondition.moreEqualOrLessEqual().apply { diff --git a/app/src/main/java/net/pokeranalytics/android/util/Global.kt b/app/src/main/java/net/pokeranalytics/android/util/Global.kt index fd639abc..99ee1411 100644 --- a/app/src/main/java/net/pokeranalytics/android/util/Global.kt +++ b/app/src/main/java/net/pokeranalytics/android/util/Global.kt @@ -6,8 +6,8 @@ const val FFMPEG_DESCRIPTOR_FILE = "descriptor.txt" const val BLIND_SEPARATOR: String = "/" const val UUID_SEPARATOR: String = "," -class Global { - companion object { - const val LAUNCH_ASYNC_LISTENERS = false - } -} +//class Global { +// companion object { +// const val LAUNCH_ASYNC_LISTENERS = false +// } +//} diff --git a/build.gradle b/build.gradle index c357114f..54b7b1f4 100644 --- a/build.gradle +++ b/build.gradle @@ -4,12 +4,12 @@ buildscript { ext.kotlin_version = '1.7.21' repositories { google() - jcenter() + mavenCentral() } dependencies { classpath 'com.android.tools.build:gradle:4.2.2' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" - classpath 'io.realm:realm-gradle-plugin:10.3.1' + classpath 'io.realm:realm-gradle-plugin:10.13.0' // crashlytics classpath 'com.google.gms:google-services:4.3.4' @@ -24,7 +24,7 @@ buildscript { allprojects { repositories { google() - jcenter() + mavenCentral() } }