Change the frequency of backups to 10 hours after the last change

kmmtest
Laurent 2 years ago
parent b5769173b7
commit 4583b5e12a
  1. 10
      app/src/main/java/net/pokeranalytics/android/calculus/ReportWhistleBlower.kt
  2. 10
      app/src/main/java/net/pokeranalytics/android/calculus/optimalduration/CashGameOptimalDurationCalculator.kt
  3. 1
      app/src/main/java/net/pokeranalytics/android/model/extensions/SessionExtensions.kt
  4. 6
      app/src/main/java/net/pokeranalytics/android/ui/fragment/StatisticsFragment.kt
  5. 2
      app/src/main/java/net/pokeranalytics/android/ui/fragment/report/ComposableTableReportFragment.kt
  6. 2
      app/src/main/java/net/pokeranalytics/android/ui/fragment/report/ProgressReportFragment.kt
  7. 8
      app/src/main/java/net/pokeranalytics/android/ui/modules/data/EditableDataActivity.kt
  8. 8
      app/src/main/java/net/pokeranalytics/android/ui/modules/session/SessionActivity.kt
  9. 78
      app/src/main/java/net/pokeranalytics/android/util/BackupOperator.kt
  10. 75
      app/src/main/java/net/pokeranalytics/android/util/BackupTask.kt
  11. 23
      app/src/main/java/net/pokeranalytics/android/util/csv/SessionTransactionCSVDescriptor.kt

@ -62,7 +62,7 @@ class ReportWhistleBlower(var context: Context) {
}
fun requestReportLaunch() {
Timber.d(">>> Launch report")
// Timber.d(">>> Launch report")
if (paused) {
return
@ -171,7 +171,7 @@ class ReportTask(private var whistleBlower: ReportWhistleBlower, var context: Co
private fun launchReport(realm: Realm, report: StaticReport) {
Timber.d(">>> launch report = $report")
// Timber.d(">>> launch report = $report")
when (report) {
StaticReport.OptimalDuration -> launchOptimalDuration(realm, report)
@ -202,7 +202,7 @@ class ReportTask(private var whistleBlower: ReportWhistleBlower, var context: Co
for (stat in result.options.stats) {
Timber.d("analyse stat: $stat for report: $staticReport")
// Timber.d("analyse stat: $stat for report: $staticReport")
// Get current performance
var query = performancesQuery(realm, staticReport, stat)
@ -261,10 +261,10 @@ class ReportTask(private var whistleBlower: ReportWhistleBlower, var context: Co
}
} ?: run { // if there is no max but a now irrelevant Performance, we delete it
Timber.d("NO best computed value, current perf = $currentPerf ")
// Timber.d("NO best computed value, current perf = $currentPerf ")
currentPerf?.let { perf ->
realm.executeTransaction {
Timber.d("Delete perf: stat = ${perf.stat}, report = ${perf.reportId}")
// Timber.d("Delete perf: stat = ${perf.stat}, report = ${perf.reportId}")
perf.deleteFromRealm()
}
}

@ -65,7 +65,7 @@ class CashGameOptimalDurationCalculator {
var validBuckets = 0
val hkeys = sessionsByDuration.keys.map { it / 3600 / 1000.0 }.sorted()
Timber.d("Stop notif > keys: $hkeys ")
// Timber.d("Stop notif > keys: $hkeys ")
for (key in sessionsByDuration.keys.sorted()) {
val sessionCount = sessionsByDuration[key]?.size ?: 0
if (start == null && sessionCount >= minimumValidityCount) {
@ -76,15 +76,15 @@ class CashGameOptimalDurationCalculator {
validBuckets++
}
}
Timber.d("Stop notif > validBuckets: $validBuckets ")
// Timber.d("Stop notif > validBuckets: $validBuckets ")
if (!(start != null && end != null && (end - start) >= intervalValidity)) {
Timber.d("Stop notif > invalid setup: $start / $end ")
// Timber.d("Stop notif > invalid setup: $start / $end ")
return null
}
// define if we have enough sessions
if (sessions.size < 50) {
Timber.d("Stop notif > not enough sessions: ${sessions.size} ")
// Timber.d("Stop notif > not enough sessions: ${sessions.size} ")
return null
}
@ -134,7 +134,7 @@ class CashGameOptimalDurationCalculator {
return bestDuration
}
Timber.d("Stop notif > not found, best duration: $bestDuration")
// Timber.d("Stop notif > not found, best duration: $bestDuration")
realm.close()
return null
}

@ -120,7 +120,6 @@ fun Session.scheduleStopNotification(context: Context, optimalDuration: Long) {
.addTag(this.id)
.build()
// WorkManager.getInstance(context).enqueue(work)
WorkManager.getInstance(context).enqueueUniqueWork(this.id, ExistingWorkPolicy.REPLACE, work)
}

@ -162,7 +162,7 @@ class StatisticsFragment : FilterableFragment(), RealmAsyncListener {
val async = GlobalScope.async {
val s = Date()
Timber.d(">>> start...")
// Timber.d(">>> start...")
val realm = Realm.getDefaultInstance()
realm.refresh()
@ -174,7 +174,7 @@ class StatisticsFragment : FilterableFragment(), RealmAsyncListener {
val e = Date()
val duration = (e.time - s.time) / 1000.0
Timber.d(">>> ended in $duration seconds")
// Timber.d(">>> ended in $duration seconds")
}
async.await()
@ -241,7 +241,7 @@ class StatisticsFragment : FilterableFragment(), RealmAsyncListener {
val tSessionGroup = ComputableGroup(Query(QueryCondition.IsTournament).merge(query), tStats)
Timber.d(">>>>> Start computations...")
// Timber.d(">>>>> Start computations...")
val options = Calculator.Options()
val computedStats = mutableListOf<Stat>()

@ -208,7 +208,7 @@ open class ComposableTableReportFragment : RealmFragment(), StaticRowRepresentab
var report: Report? = null
val test = GlobalScope.async {
val s = Date()
Timber.d(">>> start...")
// Timber.d(">>> start...")
val realm = Realm.getDefaultInstance()
realm.refresh()

@ -166,7 +166,7 @@ class ProgressReportFragment : AbstractReportFragment() {
GlobalScope.launch {
val s = Date()
Timber.d(">>> start...")
// Timber.d(">>> start...")
val realm = Realm.getDefaultInstance()

@ -51,10 +51,10 @@ class EditableDataActivity : MediaActivity() {
initUI()
}
override fun onPause() {
super.onPause()
this.paApplication.backupOperator?.backupIfNecessary()
}
// override fun onPause() {
// super.onPause()
// this.paApplication.backupOperator?.backupIfNecessary()
// }
/**
* Init UI

@ -68,10 +68,10 @@ class SessionActivity: BaseActivity() {
initUI()
}
override fun onPause() {
super.onPause()
this.paApplication.backupOperator?.backupIfNecessary()
}
// override fun onPause() {
// super.onPause()
// this.paApplication.backupOperator?.backupIfNecessary()
// }
override fun onBackPressed() {
setResult(Activity.RESULT_OK)

@ -1,26 +1,25 @@
package net.pokeranalytics.android.util
import android.content.Context
import androidx.work.Data
import androidx.work.ExistingWorkPolicy
import androidx.work.OneTimeWorkRequestBuilder
import androidx.work.WorkManager
import io.realm.Realm
import io.realm.RealmResults
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import net.pokeranalytics.android.api.BackupApi
import net.pokeranalytics.android.model.realm.Session
import net.pokeranalytics.android.model.realm.Transaction
import net.pokeranalytics.android.util.csv.ProductCSVDescriptors
import net.pokeranalytics.android.util.extensions.dateTimeFileFormatted
import net.pokeranalytics.android.util.csv.DataType
import timber.log.Timber
import java.util.*
import java.util.concurrent.TimeUnit
class BackupOperator(var context: Context) {
private var sessions: RealmResults<Session>? = null
private var transactions: RealmResults<Transaction>? = null
private var sessionsChanged = false
private var transactionsChanged = false
private var sessionsInitialized = false
private var transactionsInitialized = false
private val realm = Realm.getDefaultInstance()
@ -28,59 +27,40 @@ class BackupOperator(var context: Context) {
this.sessions = this.realm.where(Session::class.java).findAllAsync()
this.sessions?.addChangeListener { _ ->
sessionsChanged = true
if (this.sessionsInitialized) {
Preferences.getBackupEmail(context)?.let {
backupDataType(DataType.SESSION)
}
this.transactions = this.realm.where(Transaction::class.java).findAllAsync()
this.transactions?.addChangeListener { _ ->
transactionsChanged = true
}
this.sessionsInitialized = true
}
fun backupIfNecessary() {
Timber.d(">>> backupIfNecessary")
Preferences.getBackupEmail(context)?.let { email ->
this.backupSessionsIfNecessary(email)
this.backupTransactionsIfNecessary(email)
}
}
private fun backupSessionsIfNecessary(email: String) {
if (this.sessionsChanged) {
Timber.d(">>>> backup sessions")
val sessions = this.realm.where(Session::class.java).findAll().sort("startDate")
val csv = ProductCSVDescriptors.pokerAnalyticsAndroid6Sessions.toCSV(sessions)
val fileName = "sessions_${Date().dateTimeFileFormatted}.csv"
CoroutineScope(context = Dispatchers.IO).launch {
if (BackupApi.backupFile(context, email, fileName, csv)) {
sessionsChanged = false
this.transactions = this.realm.where(Transaction::class.java).findAllAsync()
this.transactions?.addChangeListener { _ ->
if (this.transactionsInitialized) {
Preferences.getBackupEmail(context)?.let {
backupDataType(DataType.TRANSACTION)
}
}
this.transactionsInitialized = true
}
}
private fun backupTransactionsIfNecessary(email: String) {
private fun backupDataType(dataType: DataType) {
val data = Data.Builder()
.putInt(BackupTask.ParamKeys.DATA.value, dataType.ordinal)
if (this.transactionsChanged) {
Timber.d(">>>> backup transactions")
val transactions = this.realm.where(Transaction::class.java).findAll().sort("date")
val csv = ProductCSVDescriptors.pokerAnalyticsAndroidTransactions.toCSV(transactions)
val fileName = "transactions_${Date().dateTimeFileFormatted}.csv"
val backupTask = OneTimeWorkRequestBuilder<BackupTask>()
.setInitialDelay(10, TimeUnit.HOURS)
// .setInitialDelay(10, TimeUnit.SECONDS)
.setInputData(data.build())
.addTag(dataType.workId)
.build()
CoroutineScope(context = Dispatchers.IO).launch {
if (BackupApi.backupFile(context, email, fileName, csv)) {
transactionsChanged = false
}
}
}
Timber.d(">>> create backupTask")
WorkManager.getInstance(context).enqueueUniqueWork(dataType.workId, ExistingWorkPolicy.REPLACE, backupTask)
}
}

@ -0,0 +1,75 @@
package net.pokeranalytics.android.util
import android.content.Context
import androidx.work.Worker
import androidx.work.WorkerParameters
import io.realm.Realm
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import net.pokeranalytics.android.api.BackupApi
import net.pokeranalytics.android.model.realm.Session
import net.pokeranalytics.android.model.realm.Transaction
import net.pokeranalytics.android.util.csv.DataType
import net.pokeranalytics.android.util.csv.ProductCSVDescriptors
import net.pokeranalytics.android.util.extensions.dateTimeFileFormatted
import timber.log.Timber
import java.util.*
class BackupTask(var context: Context, var params: WorkerParameters) : Worker(context, params) {
enum class ParamKeys(val value: String) {
DATA("title"),
}
override fun doWork(): Result {
val data = params.inputData
val dataTypeInt = data.getInt(ParamKeys.DATA.value, 0)
val dataType = DataType.values()[dataTypeInt]
Preferences.getBackupEmail(context)?.let { email ->
when(dataType) {
DataType.SESSION -> {
backupSessions(email)
}
DataType.TRANSACTION -> {
backupTransactions(email)
}
}
}
return Result.success()
}
private fun backupSessions(email: String) {
Timber.d(">>>> backup sessions")
val realm = Realm.getDefaultInstance()
val sessions = realm.where(Session::class.java).findAll().sort("startDate")
val csv = ProductCSVDescriptors.pokerAnalyticsAndroid6Sessions.toCSV(sessions)
val fileName = "sessions_${Date().dateTimeFileFormatted}.csv"
CoroutineScope(context = Dispatchers.IO).launch {
BackupApi.backupFile(context, email, fileName, csv)
}
realm.close()
}
private fun backupTransactions(email: String) {
Timber.d(">>>> backup transactions")
val realm = Realm.getDefaultInstance()
val transactions = realm.where(Transaction::class.java).findAll().sort("date")
val csv = ProductCSVDescriptors.pokerAnalyticsAndroidTransactions.toCSV(transactions)
val fileName = "transactions_${Date().dateTimeFileFormatted}.csv"
CoroutineScope(context = Dispatchers.IO).launch {
BackupApi.backupFile(context, email, fileName, csv)
}
realm.close()
}
}

@ -11,13 +11,7 @@ import org.apache.commons.csv.CSVRecord
import timber.log.Timber
import java.util.*
/**
* A SessionCSVDescriptor is a CSVDescriptor specialized in parsing Session objects
*/
class SessionTransactionCSVDescriptor(source: DataSource, isTournament: Boolean?, vararg elements: CSVField) :
PACSVDescriptor<Identifiable>(source, isTournament, *elements) {
private enum class DataType {
enum class DataType {
TRANSACTION,
SESSION;
@ -32,8 +26,23 @@ class SessionTransactionCSVDescriptor(source: DataSource, isTournament: Boolean?
}
}
val workId: String
get() {
return when (this) {
TRANSACTION -> "transaction.work"
SESSION -> "session.work"
}
}
}
/**
* A SessionCSVDescriptor is a CSVDescriptor specialized in parsing Session objects
*/
class SessionTransactionCSVDescriptor(source: DataSource, isTournament: Boolean?, vararg elements: CSVField) :
PACSVDescriptor<Identifiable>(source, isTournament, *elements) {
/**
* Parses a [record] and return an optional Session
*/

Loading…
Cancel
Save