RealmWriteService + FlatTimeInterval for better performance

threading
Laurent 3 years ago
parent 526e50f8e4
commit 929365fc4c
  1. 4
      app/src/main/java/net/pokeranalytics/android/RealmWriteService.kt
  2. 1252
      app/src/main/java/net/pokeranalytics/android/calculus/Calculator.kt
  3. 5
      app/src/main/java/net/pokeranalytics/android/calculus/ComputableGroup.kt
  4. 16
      app/src/main/java/net/pokeranalytics/android/calculus/ReportWhistleBlower.kt
  5. 2
      app/src/main/java/net/pokeranalytics/android/model/extensions/SessionExtensions.kt
  6. 7
      app/src/main/java/net/pokeranalytics/android/model/filter/Filterable.kt
  7. 13
      app/src/main/java/net/pokeranalytics/android/model/migrations/PokerAnalyticsMigration.kt
  8. 61
      app/src/main/java/net/pokeranalytics/android/model/realm/FlatTimeInterval.kt
  9. 29
      app/src/main/java/net/pokeranalytics/android/model/realm/Session.kt
  10. 257
      app/src/main/java/net/pokeranalytics/android/model/utils/SessionSetManager.kt
  11. 3
      app/src/main/java/net/pokeranalytics/android/ui/fragment/StatisticsFragment.kt
  12. 1
      app/src/main/java/net/pokeranalytics/android/ui/fragment/report/ComposableTableReportFragment.kt
  13. 8
      app/src/main/java/net/pokeranalytics/android/ui/modules/calendar/CalendarFragment.kt
  14. 27
      app/src/main/java/net/pokeranalytics/android/ui/modules/feed/FeedFragment.kt
  15. 26
      app/src/main/java/net/pokeranalytics/android/util/extensions/DateExtension.kt

@ -43,9 +43,9 @@ class RealmWriteService : Service() {
this.realm.executeTransactionAsync({ asyncRealm -> this.realm.executeTransactionAsync({ asyncRealm ->
handler(asyncRealm) handler(asyncRealm)
Timber.d(">> handler done") // Timber.d(">> handler done")
}, { }, {
Timber.d(">> YEAAAAAAAAAAAH !!!") // Timber.d(">> YEAAAAAAAAAAAH !!!")
this.realm.refresh() this.realm.refresh()
}, { }, {
Timber.d(">> NOOOOO error = $it") Timber.d(">> NOOOOO error = $it")

@ -64,6 +64,11 @@ class ComputableGroup(val query: Query, var displayedStats: List<Stat>? = null)
return computables return computables
} }
fun timeIntervals(realm: Realm): RealmResults<FlatTimeInterval> {
return Filter.queryOn(realm, this.query)
}
/** /**
* The list of sets to compute * The list of sets to compute
*/ */

@ -55,18 +55,18 @@ class ReportWhistleBlower(var context: Context) {
val realm = Realm.getDefaultInstance() val realm = Realm.getDefaultInstance()
this.sessions = realm.where(Session::class.java).findAll() sessions = realm.where(Session::class.java).findAll()
this.sessions?.addChangeListener { _ -> sessions?.addChangeListener { _ ->
requestReportLaunch() requestReportLaunch()
} }
this.results = realm.where(Result::class.java).findAll() results = realm.where(Result::class.java).findAll()
this.results?.addChangeListener { _ -> results?.addChangeListener { _ ->
requestReportLaunch() requestReportLaunch()
} }
this.sessionSets = realm.where(SessionSet::class.java).findAll() sessionSets = realm.where(SessionSet::class.java).findAll()
this.sessionSets?.addChangeListener { _ -> sessionSets?.addChangeListener { _ ->
requestReportLaunch() requestReportLaunch()
} }
@ -156,13 +156,13 @@ class ReportTask(private var whistleBlower: ReportWhistleBlower, var context: Co
} }
fun cancel() { fun cancel() {
Timber.d("Reportwhistleblower task CANCEL") // Timber.d("Reportwhistleblower task CANCEL")
this.cancelled = true this.cancelled = true
} }
private fun launchReports() { private fun launchReports() {
Timber.d("====== Report whistleblower launch batch...") // Timber.d("====== Report whistleblower launch batch...")
CoroutineScope(Dispatchers.Default).launch { CoroutineScope(Dispatchers.Default).launch {

@ -133,7 +133,7 @@ val AbstractList<Session>.hourlyDuration: Double
return intervals.sumOf { it.hourlyDuration } return intervals.sumOf { it.hourlyDuration }
} }
class TimeInterval(var start: Date, var end: Date, var breakDuration: Long) { class TimeInterval(var start: Date, var end: Date, var breakDuration: Long = 0L) {
val hourlyDuration: Double val hourlyDuration: Double
get() { get() {

@ -32,9 +32,9 @@ import net.pokeranalytics.android.util.CrashLogging
* *
*/ */
class UnmanagedFilterField(message: String) : Exception(message) { //class UnmanagedFilterField(message: String) : Exception(message) {
//
} //}
/** /**
* Companion-level Interface to indicate an RealmObject class can be filtered and to provide all the fieldNames (eg: parameter's path) needed to be query on. * Companion-level Interface to indicate an RealmObject class can be filtered and to provide all the fieldNames (eg: parameter's path) needed to be query on.
@ -64,6 +64,7 @@ class FilterHelper {
SessionSet::class.java -> SessionSet.fieldNameForQueryType(queryCondition) SessionSet::class.java -> SessionSet.fieldNameForQueryType(queryCondition)
Transaction::class.java -> Transaction.fieldNameForQueryType(queryCondition) Transaction::class.java -> Transaction.fieldNameForQueryType(queryCondition)
Result::class.java -> Result.fieldNameForQueryType(queryCondition) Result::class.java -> Result.fieldNameForQueryType(queryCondition)
FlatTimeInterval::class.java -> FlatTimeInterval.fieldNameForQueryType(queryCondition)
else -> { else -> {
CrashLogging.logException(PAIllegalStateException("Filterable type fields are not defined for condition ${queryCondition::class}, class ${T::class}")) CrashLogging.logException(PAIllegalStateException("Filterable type fields are not defined for condition ${queryCondition::class}, class ${T::class}"))
null null

@ -3,6 +3,7 @@ package net.pokeranalytics.android.model.migrations
import io.realm.DynamicRealm import io.realm.DynamicRealm
import io.realm.RealmMigration import io.realm.RealmMigration
import net.pokeranalytics.android.exceptions.PAIllegalStateException import net.pokeranalytics.android.exceptions.PAIllegalStateException
import net.pokeranalytics.android.model.realm.FlatTimeInterval
import timber.log.Timber import timber.log.Timber
import java.util.* import java.util.*
@ -341,6 +342,18 @@ class PokerAnalyticsMigration : RealmMigration {
crs.addField("id", String::class.java).setRequired("id", true) crs.addField("id", String::class.java).setRequired("id", true)
crs.addPrimaryKey("id") crs.addPrimaryKey("id")
} }
schema.create("FlatTimeInterval")?.let { fs ->
fs.addField("id", String::class.java).setRequired("id", true)
fs.addPrimaryKey("id")
fs.addField("startDate", Date::class.java).setRequired("startDate", true)
fs.addField("endDate", Date::class.java).setRequired("endDate", true)
fs.addField("duration", Long::class.java)
schema.get("Session")?.let { ss ->
ss.addRealmSetField("flatTimeIntervals", fs)
}
}
currentVersion++ currentVersion++
} }

@ -0,0 +1,61 @@
package net.pokeranalytics.android.model.realm
import io.realm.RealmObject
import io.realm.RealmResults
import io.realm.annotations.LinkingObjects
import io.realm.annotations.PrimaryKey
import io.realm.annotations.RealmClass
import net.pokeranalytics.android.model.filter.Filterable
import net.pokeranalytics.android.model.filter.QueryCondition
import java.util.*
@RealmClass
open class FlatTimeInterval : RealmObject(), Filterable {
@PrimaryKey
var id = UUID.randomUUID().toString()
/**
* The start date of the session
*/
var startDate: Date = Date()
set(value) {
field = value
this.computeDuration()
}
/**
* The start date of the session
*/
var endDate: Date = Date()
set(value) {
field = value
this.computeDuration()
}
/**
* the net duration of the session, automatically calculated
*/
var duration: Long = 0L
@LinkingObjects("flatTimeIntervals")
val sessions: RealmResults<Session>? = null
private fun computeDuration() {
duration = endDate.time - startDate.time
}
companion object {
fun fieldNameForQueryType(queryCondition: Class <out QueryCondition>): String? {
Session.fieldNameForQueryType(queryCondition)?.let {
return "sessions.$it"
}
return null
}
}
}

@ -33,10 +33,7 @@ import net.pokeranalytics.android.ui.graph.Graph
import net.pokeranalytics.android.ui.view.* import net.pokeranalytics.android.ui.view.*
import net.pokeranalytics.android.ui.view.rows.SessionPropertiesRow import net.pokeranalytics.android.ui.view.rows.SessionPropertiesRow
import net.pokeranalytics.android.util.* import net.pokeranalytics.android.util.*
import net.pokeranalytics.android.util.extensions.hourMinute import net.pokeranalytics.android.util.extensions.*
import net.pokeranalytics.android.util.extensions.shortDateTime
import net.pokeranalytics.android.util.extensions.toCurrency
import net.pokeranalytics.android.util.extensions.toMinutes
import java.text.DateFormat import java.text.DateFormat
import java.text.NumberFormat import java.text.NumberFormat
import java.text.ParseException import java.text.ParseException
@ -202,6 +199,7 @@ open class Session : RealmObject(), Savable, RowUpdatable, RowRepresentable, Tim
*/ */
var startDate: Date? = null var startDate: Date? = null
set(value) { set(value) {
val previous = this.startDate
field = value field = value
if (value == null) { if (value == null) {
startDateHourMinuteComponent = null startDateHourMinuteComponent = null
@ -217,7 +215,9 @@ open class Session : RealmObject(), Savable, RowUpdatable, RowRepresentable, Tim
if (value != null && this.endDate != null && value.after(this.endDate)) { if (value != null && this.endDate != null && value.after(this.endDate)) {
this.endDate = null this.endDate = null
} }
this.dateChanged()
SessionSetManager.startChanged(this, min(previous, value))
// this.computeStats() // this.computeStats()
} }
@ -227,6 +227,7 @@ open class Session : RealmObject(), Savable, RowUpdatable, RowRepresentable, Tim
@Index @Index
var endDate: Date? = null var endDate: Date? = null
set(value) { set(value) {
val previous = this.endDate
field = value field = value
if (value == null) { if (value == null) {
endDateHourMinuteComponent = null endDateHourMinuteComponent = null
@ -237,7 +238,7 @@ open class Session : RealmObject(), Savable, RowUpdatable, RowRepresentable, Tim
} }
this.computeNetDuration() this.computeNetDuration()
this.dateChanged() SessionSetManager.endChanged(this, max(previous, value))
this.defineDefaultTournamentBuyinIfNecessary() this.defineDefaultTournamentBuyinIfNecessary()
// this.computeStats() // this.computeStats()
} }
@ -373,6 +374,9 @@ open class Session : RealmObject(), Savable, RowUpdatable, RowRepresentable, Tim
// The custom fields values // The custom fields values
var customFieldEntries: RealmList<CustomFieldEntry> = RealmList() var customFieldEntries: RealmList<CustomFieldEntry> = RealmList()
// The list of opponents who participated to the session
var flatTimeIntervals: RealmList<FlatTimeInterval> = RealmList()
// The number of hands played during the sessions // The number of hands played during the sessions
var handsCount: Int? = null var handsCount: Int? = null
@ -380,10 +384,6 @@ open class Session : RealmObject(), Savable, RowUpdatable, RowRepresentable, Tim
this.generateStakes() this.generateStakes()
} }
private fun dateChanged() {
SessionSetManager.sessionDateChanged(this)
}
// /** // /**
// * Manages impacts on SessionSets // * Manages impacts on SessionSets
// * Should be called when the start / end date are changed // * Should be called when the start / end date are changed
@ -697,10 +697,8 @@ open class Session : RealmObject(), Savable, RowUpdatable, RowRepresentable, Tim
CrashLogging.log("Deletes session. Id = ${this.id}") CrashLogging.log("Deletes session. Id = ${this.id}")
if (isValid) { if (isValid) {
// realm.executeTransaction { cleanup()
cleanup() deleteFromRealm()
deleteFromRealm()
// }
} else { } else {
CrashLogging.log("Attempt to delete an invalid session") CrashLogging.log("Attempt to delete an invalid session")
} }
@ -715,6 +713,9 @@ open class Session : RealmObject(), Savable, RowUpdatable, RowRepresentable, Tim
this.sessionSet?.let { this.sessionSet?.let {
SessionSetManager.removeFromTimeline(this) SessionSetManager.removeFromTimeline(this)
} }
SessionSetManager.sessionDateChanged(this)
// cleanup unnecessary related objects // cleanup unnecessary related objects
this.result?.deleteFromRealm() this.result?.deleteFromRealm()
this.computableResult?.deleteFromRealm() this.computableResult?.deleteFromRealm()

@ -1,13 +1,18 @@
package net.pokeranalytics.android.model.utils package net.pokeranalytics.android.model.utils
import io.realm.Realm import io.realm.Realm
import io.realm.RealmModel
import io.realm.RealmQuery import io.realm.RealmQuery
import io.realm.RealmResults import io.realm.RealmResults
import net.pokeranalytics.android.exceptions.ModelException import net.pokeranalytics.android.exceptions.ModelException
import net.pokeranalytics.android.model.realm.FlatTimeInterval
import net.pokeranalytics.android.model.realm.Session import net.pokeranalytics.android.model.realm.Session
import net.pokeranalytics.android.model.realm.SessionSet import net.pokeranalytics.android.model.realm.SessionSet
import net.pokeranalytics.android.util.extensions.findById import net.pokeranalytics.android.util.extensions.findById
import net.pokeranalytics.android.util.extensions.max
import net.pokeranalytics.android.util.extensions.min
import timber.log.Timber import timber.log.Timber
import java.util.*
class CorruptSessionSetException(message: String) : Exception(message) class CorruptSessionSetException(message: String) : Exception(message)
@ -17,12 +22,25 @@ class CorruptSessionSetException(message: String) : Exception(message)
*/ */
object SessionSetManager { object SessionSetManager {
var sessions: RealmResults<Session> var sessions: RealmResults<Session>? = null
private val sessionIdsToProcess = mutableSetOf<String>() private val sessionIdsToProcess = mutableSetOf<String>()
private var start: Date? = null
private var end: Date? = null
fun configure() {} // launch init fun configure() {} // launch init
fun startChanged(session: Session, date: Date?) {
this.start = min(this.start, date)
this.sessionIdsToProcess.add(session.id)
}
fun endChanged(session: Session, date: Date?) {
this.end = max(this.end, date)
this.sessionIdsToProcess.add(session.id)
}
fun sessionDateChanged(session: Session) { fun sessionDateChanged(session: Session) {
this.sessionIdsToProcess.add(session.id) this.sessionIdsToProcess.add(session.id)
} }
@ -31,11 +49,12 @@ object SessionSetManager {
val realm = Realm.getDefaultInstance() val realm = Realm.getDefaultInstance()
this.sessions = realm.where(Session::class.java).findAllAsync() sessions = realm.where(Session::class.java).findAllAsync()
this.sessions.addChangeListener { _, _ -> sessions?.addChangeListener { _, _ ->
if (this.sessionIdsToProcess.isNotEmpty()) { if (this.start != null && this.end != null) {
realm.executeTransactionAsync { asyncRealm -> realm.executeTransactionAsync { asyncRealm ->
processSessions(asyncRealm) processSessions(asyncRealm)
cleanUp()
} }
} }
} }
@ -43,21 +62,38 @@ object SessionSetManager {
realm.close() realm.close()
} }
private fun cleanUp() {
this.start = null
this.end = null
// this.sessionIdsToProcess.clear()
}
private fun processSessions(realm: Realm) { private fun processSessions(realm: Realm) {
Timber.d("***** processSessions, process count = ${sessionIdsToProcess.size}") // Timber.d("***** processSessions, process count = ${sessionIdsToProcess.size}")
for (sessionId in this.sessionIdsToProcess) { val start = this.start
realm.findById<Session>(sessionId)?.let { session -> val end = this.end
if (session.startDate != null && session.endDate != null) {
updateTimeline(session) val sessions = sessionIdsToProcess.mapNotNull { realm.findById<Session>(it) }
} else if (session.sessionSet != null) { for (session in sessions) {
removeFromTimeline(session)
} // Session Sets
val startDate = session.startDate
val endDate = session.endDate
if (startDate != null && endDate != null) {
updateTimeline(session)
} else if (session.sessionSet != null) {
removeFromTimeline(session)
} }
}
// FlatTimeIntervals
if (start != null && end != null) {
processFlatTimeInterval(realm, start, end)
} }
this.sessionIdsToProcess.clear()
} }
/** /**
@ -76,25 +112,37 @@ object SessionSetManager {
throw ModelException("End date should never be null here") throw ModelException("End date should never be null here")
} }
val sessionSets = this.matchingSets(session) val start = session.startDate!!
cleanupSessionSets(session, sessionSets) val end = session.endDate!!
// val sessionId = session.id val sessionSets = this.matchingData<SessionSet>(session.realm, start, end)
// realm.executeTransactionAsync { asyncRealm -> cleanupSessionSets(session, sessionSets)
// asyncRealm.findById<Session>(sessionId)?.let { s ->
// val sessionSets = this.matchingSets(session)
// cleanupSessionSets(session, sessionSets)
// }
// }
} }
private fun matchingSets(session: Session): RealmResults<SessionSet> { // private fun matchingSets(session: Session): RealmResults<SessionSet> {
val realm = session.realm // val realm = session.realm
val endDate = session.endDate!! // tested above // val endDate = session.endDate!! // tested above
val startDate = session.startDate!! // val startDate = session.startDate!!
//
val query: RealmQuery<SessionSet> = realm.where(SessionSet::class.java) // val query: RealmQuery<SessionSet> = realm.where(SessionSet::class.java)
//
// query
// .lessThanOrEqualTo("startDate", startDate)
// .greaterThanOrEqualTo("endDate", startDate)
// .or()
// .lessThanOrEqualTo("startDate", endDate)
// .greaterThanOrEqualTo("endDate", endDate)
// .or()
// .greaterThanOrEqualTo("startDate", startDate)
// .lessThanOrEqualTo("endDate", endDate)
//
// return query.findAll()
// }
private inline fun <reified T : RealmModel> matchingData(realm: Realm, startDate: Date, endDate: Date): RealmResults<T> {
val query: RealmQuery<T> = realm.where(T::class.java)
query query
.lessThanOrEqualTo("startDate", startDate) .lessThanOrEqualTo("startDate", startDate)
@ -127,7 +175,7 @@ object SessionSetManager {
sessionSets.deleteAllFromRealm() sessionSets.deleteAllFromRealm()
allImpactedSessions.forEach { impactedSession -> allImpactedSessions.forEach { impactedSession ->
val sets = matchingSets(impactedSession) val sets = matchingData<SessionSet>(impactedSession.realm, impactedSession.startDate!!, impactedSession.endDate!!)
this.updateTimeFrames(sets, impactedSession) this.updateTimeFrames(sets, impactedSession)
} }
@ -249,4 +297,155 @@ object SessionSetManager {
} }
} }
private fun processFlatTimeInterval(realm: Realm, start: Date, end: Date) {
val sessions = matchingData<Session>(realm, start, end)
val intervalsStore = IntervalsStore(sessions.toSet())
intervalsStore.intervals.forEach { it.deleteFromRealm() }
val intervals = SessionInterval.intervalMap(intervalsStore.sessions)
for (interval in intervals) {
val sortedDates = interval.dates.sorted()
for (i in (0 until sortedDates.size - 1)) {
val s = sortedDates[i]
val e = sortedDates[i + 1]
val matchingSessions = interval.sessions.filter {
val sd = it.startDate
val ed = it.endDate
(sd != null && ed != null && sd <= s && ed >= e)
}
if (matchingSessions.isNotEmpty()) {
Timber.d("**** Create FTI: $s - $e")
val fti = FlatTimeInterval()
fti.startDate = s
fti.endDate = e
matchingSessions.forEach { it.flatTimeIntervals.add(fti) }
realm.insertOrUpdate(fti)
} else {
Timber.w("The FTI has no sessions")
}
}
}
}
}
class IntervalsStore(sessions: Set<Session>) {
var start: Date = Date()
var end: Date = Date(0L)
val intervals = mutableSetOf<FlatTimeInterval>()
val sessions = mutableSetOf<Session>()
private val sessionIds: MutableSet<String> = mutableSetOf()
init {
processSessions(sessions)
}
private fun processSessions(sessions: Set<Session>) {
this.sessions.addAll(sessions)
for (session in sessions) {
loadIntervals(session)
}
}
private fun loadIntervals(session: Session) {
if (sessionIds.contains(session.id)) {
return
}
session.startDate?.let { this.start = min(this.start, it) }
session.endDate?.let { this.end = max(this.end, it) }
this.sessionIds.add(session.id)
for (fti in session.flatTimeIntervals) {
this.intervals.add(fti)
fti.sessions?.let { sessions ->
for (s in sessions) {
loadIntervals(s)
}
}
}
}
}
class SessionInterval(session: Session) {
var start: Date
var end: Date?
var sessions: MutableSet<Session> = mutableSetOf()
val dates: MutableSet<Date> = mutableSetOf()
val duration: Long
get() {
val endDate = end ?: Date()
return endDate.time - start.time
}
init {
this.start = session.startDate!!
this.end = session.endDate
this.addSession(session)
}
private fun addSession(session: Session) {
this.sessions.add(session)
session.startDate?.let { this.dates.add(it) }
session.endDate?.let { endDate ->
this.dates.add(endDate)
if (endDate > end) {
end = endDate
}
}
}
companion object {
fun intervalMap(sessions: Set<Session>): List<SessionInterval> {
val sorted = sessions.sortedBy { it.startDate }
val intervals = mutableListOf<SessionInterval>()
sorted.firstOrNull()?.let { firstSession ->
var currentInterval = SessionInterval(firstSession)
intervals.add(currentInterval)
for (session in sessions.drop(1)) {
val start = session.startDate!!
val currentEnd = currentInterval.end
if (currentEnd != null && start > currentEnd) {
val interval = SessionInterval(session)
currentInterval = interval
intervals.add(interval)
} else {
currentInterval.addSession(session)
}
}
}
intervals.forEach {
Timber.d("s = ${it.start}, e = ${it.end}")
}
return intervals
}
}
} }

@ -167,7 +167,7 @@ class StatisticsFragment : FilterableFragment(), RealmAsyncListener {
val async = async { val async = async {
val s = Date() val s = Date()
Timber.d(">>> start...") // Timber.d(">>> start...")
val realm = Realm.getDefaultInstance() val realm = Realm.getDefaultInstance()
realm.refresh() realm.refresh()
@ -199,7 +199,6 @@ class StatisticsFragment : FilterableFragment(), RealmAsyncListener {
Timber.d(">>> Launch statistics computations") Timber.d(">>> Launch statistics computations")
val filter: Filter? = this.currentFilter(this.requireContext(), realm)?.let { val filter: Filter? = this.currentFilter(this.requireContext(), realm)?.let {
if (it.filterableType == currentFilterable) { it } else { null } if (it.filterableType == currentFilterable) { it } else { null }
} }

@ -27,6 +27,7 @@ import net.pokeranalytics.android.ui.view.rows.CustomizableRowRepresentable
import net.pokeranalytics.android.ui.view.rows.StatRow import net.pokeranalytics.android.ui.view.rows.StatRow
import net.pokeranalytics.android.util.NULL_TEXT import net.pokeranalytics.android.util.NULL_TEXT
import net.pokeranalytics.android.util.TextFormat import net.pokeranalytics.android.util.TextFormat
import timber.log.Timber
open class ComposableTableReportFragment : RealmFragment(), StaticRowRepresentableDataSource, open class ComposableTableReportFragment : RealmFragment(), StaticRowRepresentableDataSource,
RowRepresentableDelegate { RowRepresentableDelegate {

@ -388,7 +388,7 @@ class CalendarFragment : RealmFragment(), StaticRowRepresentableDataSource,
val async = async { val async = async {
val s = Date() val s = Date()
Timber.d(">>> start...") // Timber.d(">>> start...")
val realm = Realm.getDefaultInstance() val realm = Realm.getDefaultInstance()
realm.refresh() realm.refresh()
@ -436,6 +436,8 @@ class CalendarFragment : RealmFragment(), StaticRowRepresentableDataSource,
private fun launchStatComputation(realm: Realm) { private fun launchStatComputation(realm: Realm) {
return
Timber.d(">>> Launch calendar computations") Timber.d(">>> Launch calendar computations")
val calendar = Calendar.getInstance() val calendar = Calendar.getInstance()
@ -660,8 +662,8 @@ class CalendarFragment : RealmFragment(), StaticRowRepresentableDataSource,
} }
} }
Timber.d("Display data: ${System.currentTimeMillis() - startDate.time}ms") // Timber.d("Display data: ${System.currentTimeMillis() - startDate.time}ms")
Timber.d("Rows: ${rows.size}") // Timber.d("Rows: ${rows.size}")
this.calendarAdapter.notifyDataSetChanged() this.calendarAdapter.notifyDataSetChanged()

@ -19,9 +19,7 @@ import net.pokeranalytics.android.api.BlogPostApi
import net.pokeranalytics.android.databinding.FragmentFeedBinding import net.pokeranalytics.android.databinding.FragmentFeedBinding
import net.pokeranalytics.android.exceptions.PAIllegalStateException import net.pokeranalytics.android.exceptions.PAIllegalStateException
import net.pokeranalytics.android.model.LiveData import net.pokeranalytics.android.model.LiveData
import net.pokeranalytics.android.model.realm.Filter import net.pokeranalytics.android.model.realm.*
import net.pokeranalytics.android.model.realm.Session
import net.pokeranalytics.android.model.realm.Transaction
import net.pokeranalytics.android.model.realm.handhistory.HandHistory import net.pokeranalytics.android.model.realm.handhistory.HandHistory
import net.pokeranalytics.android.ui.activity.BillingActivity import net.pokeranalytics.android.ui.activity.BillingActivity
import net.pokeranalytics.android.ui.activity.components.RequestCode import net.pokeranalytics.android.ui.activity.components.RequestCode
@ -87,10 +85,10 @@ class FeedFragment : FilterableFragment(), RowRepresentableDelegate, PurchaseLis
override fun asyncListenedEntityChange(realm: Realm, clazz: Class<out RealmModel>) { override fun asyncListenedEntityChange(realm: Realm, clazz: Class<out RealmModel>) {
Timber.d("asyncListenedEntityChange for $clazz") // Timber.d("asyncListenedEntityChange for $clazz")
when (clazz.kotlin) { when (clazz.kotlin) {
Session::class -> { Session::class -> {
Timber.d("WOWOWOOWOOWOWOWOWOWOWOWOWO") // Timber.d("WOWOWOOWOOWOWOWOWOWOWOWOWO")
this.sessionAdapter.refreshData() this.sessionAdapter.refreshData()
this.sessionAdapter.notifyDataSetChanged() this.sessionAdapter.notifyDataSetChanged()
} }
@ -286,9 +284,20 @@ class FeedFragment : FilterableFragment(), RowRepresentableDelegate, PurchaseLis
displayBlogPostButton() displayBlogPostButton()
binding.postButton.setOnClickListener { binding.postButton.setOnClickListener {
Preferences.setBlogTipsTapped(requireContext())
parentActivity?.openUrl(URL.BLOG_TIPS.value) getRealm().executeTransactionAsync { realm ->
displayBlogPostButton()
realm.where<Session>().findAll().deleteAllFromRealm()
realm.where<SessionSet>().findAll().deleteAllFromRealm()
realm.where<FlatTimeInterval>().findAll().deleteAllFromRealm()
realm.where<Result>().findAll().deleteAllFromRealm()
realm.where<ComputableResult>().findAll().deleteAllFromRealm()
}
// Preferences.setBlogTipsTapped(requireContext())
// parentActivity?.openUrl(URL.BLOG_TIPS.value)
// displayBlogPostButton()
} }
binding.postButton.viewTreeObserver.addOnGlobalLayoutListener { binding.postButton.viewTreeObserver.addOnGlobalLayoutListener {
@ -632,7 +641,7 @@ class FeedFragment : FilterableFragment(), RowRepresentableDelegate, PurchaseLis
show = true show = true
this.badgeDrawable?.number = newCount this.badgeDrawable?.number = newCount
} }
this.binding.postButton.isVisible = show this.binding.postButton.isVisible = true
this.badgeDrawable?.isVisible = show this.badgeDrawable?.isVisible = show
} }

@ -7,6 +7,32 @@ import java.util.*
// Calendar // Calendar
fun min(d1: Date, d2: Date): Date {
return if (d1 < d2) d1 else d2
}
fun max(d1: Date, d2: Date): Date {
return if (d1 > d2) d1 else d2
}
@JvmName("min1")
fun min(d1: Date?, d2: Date?): Date? {
return if (d1 != null) {
if (d2 != null) min(d1, d2) else d1
} else {
d2
}
}
@JvmName("max1")
fun max(d1: Date?, d2: Date?): Date? {
return if (d1 != null) {
if (d2 != null) max(d1, d2) else d1
} else {
d2
}
}
// Return a double representing the hour / minute of a date from a calendar // Return a double representing the hour / minute of a date from a calendar
fun Calendar.hourMinute(): Double { fun Calendar.hourMinute(): Double {
return (this.get(Calendar.HOUR_OF_DAY) + this.get(Calendar.MINUTE).toDouble() / 60.0).roundOffDecimal() return (this.get(Calendar.HOUR_OF_DAY) + this.get(Calendar.MINUTE).toDouble() / 60.0).roundOffDecimal()

Loading…
Cancel
Save