Session/SessionSet date refactoring, TimeFrame removed

feature/top10
Laurent 7 years ago
parent 6dba82a895
commit 9c3134d866
  1. 518
      app/src/androidTest/java/net/pokeranalytics/android/ExampleInstrumentedUnitTest.kt
  2. 573
      app/src/androidTest/java/net/pokeranalytics/android/StatsInstrumentedUnitTest.kt
  3. 15
      app/src/main/java/net/pokeranalytics/android/PokerAnalyticsApplication.kt
  4. 19
      app/src/main/java/net/pokeranalytics/android/calculus/Calculator.kt
  5. 1
      app/src/main/java/net/pokeranalytics/android/calculus/Computable.kt
  6. 45
      app/src/main/java/net/pokeranalytics/android/model/extensions/SessionExtensions.kt
  7. 30
      app/src/main/java/net/pokeranalytics/android/model/interfaces/Timed.kt
  8. 199
      app/src/main/java/net/pokeranalytics/android/model/realm/Session.kt
  9. 63
      app/src/main/java/net/pokeranalytics/android/model/realm/SessionSet.kt
  10. 568
      app/src/main/java/net/pokeranalytics/android/model/realm/TimeFrame.kt
  11. 2
      app/src/main/java/net/pokeranalytics/android/model/utils/FavoriteSessionFinder.kt
  12. 140
      app/src/main/java/net/pokeranalytics/android/model/utils/SessionSetManager.kt
  13. 4
      app/src/main/java/net/pokeranalytics/android/ui/fragment/SessionFragment.kt
  14. 3
      app/src/main/java/net/pokeranalytics/android/ui/fragment/StatsFragment.kt
  15. 2
      app/src/main/java/net/pokeranalytics/android/ui/fragment/components/SessionObserverFragment.kt
  16. 14
      app/src/main/java/net/pokeranalytics/android/ui/view/SessionRowView.kt
  17. 2
      app/src/main/res/values/strings.xml

@ -1,518 +0,0 @@
package net.pokeranalytics.android
import androidx.test.ext.junit.runners.AndroidJUnit4
import io.realm.RealmResults
import net.pokeranalytics.android.calculus.Calculator
import net.pokeranalytics.android.calculus.ComputedResults
import net.pokeranalytics.android.calculus.SessionGroup
import net.pokeranalytics.android.calculus.Stat
import net.pokeranalytics.android.model.realm.Session
import net.pokeranalytics.android.model.realm.SessionSet
import net.pokeranalytics.android.model.realm.TimeFrame
import org.junit.Assert
import org.junit.Assert.assertEquals
import org.junit.Test
import org.junit.runner.RunWith
import java.text.SimpleDateFormat
import java.util.*
/**
* Instrumented test, which will execute on an Android device.
*
* See [testing documentation](http://d.android.com/tools/testing).
*/
@RunWith(AndroidJUnit4::class)
class ExampleInstrumentedUnitTest : RealmInstrumentedUnitTest() {
// convenience extension
fun Session.Companion.testInstance(netResult: Double, startDate: Date, endDate: Date?): Session {
val session: Session = Session.newInstance(super.mockRealm, false)
session.result?.netResult = netResult
session.timeFrame?.setDate(startDate, endDate)
return session
}
@Test
fun testSessionStats() {
val realm = this.mockRealm
realm.beginTransaction()
val s1 = realm.createObject(Session::class.java, "1")
val s2 = realm.createObject(Session::class.java, "2")
s1.timeFrame = realm.createObject(TimeFrame::class.java)
s2.timeFrame = realm.createObject(TimeFrame::class.java)
s1.result = realm.createObject(net.pokeranalytics.android.model.realm.Result::class.java)
s2.result = realm.createObject(net.pokeranalytics.android.model.realm.Result::class.java)
s1.result?.buyin = 100.0 // net result = -100
s2.result?.buyin = 200.0
s2.result?.cashout = 500.0 // net result = 300
s1.cgBigBlind = 0.5 // bb net result = -200bb
s2.cgBigBlind = 2.0 // bb net result = 150bb
realm.insert(s1)
realm.insert(s2)
realm.commitTransaction()
val sdf = SimpleDateFormat("dd/M/yyyy hh:mm")
val sd1 = sdf.parse("01/1/2019 10:00")
val ed1 = sdf.parse("01/1/2019 11:00")
val sd2 = sdf.parse("02/1/2019 08:00")
val ed2 = sdf.parse("02/1/2019 11:00")
realm.beginTransaction()
s1.timeFrame?.setDate(sd1, ed1) // netDuration = 1h, hourly = -100, bb100 = -200bb / 25hands * 100 = -800
s2.timeFrame?.setDate(sd2, ed2) // netDuration = 3h, hourly = 100, bb100 = 150 / 75 * 100 = +200
realm.copyToRealmOrUpdate(s1)
realm.copyToRealmOrUpdate(s2)
realm.commitTransaction()
val sessions = realm.where(Session::class.java).findAll()
val group = SessionGroup(name = "test", sessions = sessions)
val options = Calculator.Options()
options.displayedStats = listOf(Stat.STANDARD_DEVIATION_BB_PER_100_HANDS, Stat.STANDARD_DEVIATION)
val results: ComputedResults = Calculator.compute(group, options)
val delta = 0.01
val sum = results.computedStat(Stat.NETRESULT)
if (sum != null) {
assertEquals(200.0, sum.value, delta)
} else {
Assert.fail("No Net result stat")
}
val average = results.computedStat(Stat.AVERAGE)
if (average != null) {
assertEquals(100.0, average.value, delta)
} else {
Assert.fail("No AVERAGE stat")
}
val duration = results.computedStat(Stat.DURATION)
if (duration != null) {
assertEquals(4.0, duration.value, delta)
} else {
Assert.fail("No netDuration stat")
}
val hourlyRate = results.computedStat(Stat.HOURLY_RATE)
if (hourlyRate != null) {
assertEquals(50.0, hourlyRate.value, delta)
} else {
Assert.fail("No houry rate stat")
}
val handsPlayed = results.computedStat(Stat.HANDS_PLAYED)
if (handsPlayed != null) {
assertEquals(100.0, handsPlayed.value, delta)
} else {
Assert.fail("No hands played stat")
}
val numberOfGames = results.computedStat(Stat.NUMBER_OF_GAMES)
if (numberOfGames != null) {
assertEquals(2, numberOfGames.value.toInt())
} else {
Assert.fail("No numberOfGames stat")
}
val numberOfSets = results.computedStat(Stat.NUMBER_OF_SETS)
if (numberOfSets != null) {
assertEquals(2, numberOfSets.value.toInt())
} else {
Assert.fail("No numberOfSets stat")
}
val avgBuyin = results.computedStat(Stat.AVERAGE_BUYIN)
if (avgBuyin != null) {
assertEquals(150.0, avgBuyin.value, delta)
} else {
Assert.fail("No avgBuyin stat")
}
val avgDuration = results.computedStat(Stat.AVERAGE_DURATION)
if (avgDuration != null) {
assertEquals(2.0, avgDuration.value, delta)
} else {
Assert.fail("No avgDuration stat")
}
val roi = results.computedStat(Stat.ROI)
if (roi != null) {
assertEquals(200 / 300.0, roi.value, delta)
} else {
Assert.fail("No roi stat")
}
val avgBBNet = results.computedStat(Stat.AVERAGE_NET_BB)
if (avgBBNet != null) {
assertEquals(-25.0, avgBBNet.value, delta)
} else {
Assert.fail("No avgBBNet stat")
}
val bbHourlyRate = results.computedStat(Stat.HOURLY_RATE_BB)
if (bbHourlyRate != null) {
assertEquals(-12.5, bbHourlyRate.value, delta)
} else {
Assert.fail("No bbHourlyRate stat")
}
val netbbPer100Hands = results.computedStat(Stat.NET_BB_PER_100_HANDS)
if (netbbPer100Hands != null) {
assertEquals(-50.0, netbbPer100Hands.value, delta)
} else {
Assert.fail("No netbbPer100Hands stat")
}
val std = results.computedStat(Stat.STANDARD_DEVIATION)
if (std != null) {
assertEquals(200.0, std.value, delta)
} else {
Assert.fail("No std stat")
}
val stdHourly = results.computedStat(Stat.STANDARD_DEVIATION_HOURLY)
if (stdHourly != null) {
assertEquals(111.8, stdHourly.value, delta)
} else {
Assert.fail("No stdHourly stat")
}
val std100 = results.computedStat(Stat.STANDARD_DEVIATION_BB_PER_100_HANDS)
if (std100 != null) {
assertEquals(559.01, std100.value, delta)
} else {
Assert.fail("No std100 stat")
}
}
@Test
fun testOverlappingSessions1() {
val realm = this.mockRealm
realm.beginTransaction()
val s1 = realm.createObject(Session::class.java, "1")
val s2 = realm.createObject(Session::class.java, "2")
s1.timeFrame = realm.createObject(TimeFrame::class.java)
s2.timeFrame = realm.createObject(TimeFrame::class.java)
s1.result = realm.createObject(net.pokeranalytics.android.model.realm.Result::class.java)
s2.result = realm.createObject(net.pokeranalytics.android.model.realm.Result::class.java)
realm.insert(s1)
realm.insert(s2)
val sdf = SimpleDateFormat("dd/M/yyyy hh:mm")
val sd1 = sdf.parse("01/1/2019 09:00")
val ed1 = sdf.parse("01/1/2019 10:00")
val sd2 = sdf.parse("01/1/2019 08:00")
val ed2 = sdf.parse("01/1/2019 11:00")
s1.timeFrame?.setDate(sd1, ed1) // netDuration = 1h, hourly = -100, bb100 = -200bb / 25hands * 100 = -800
s2.timeFrame?.setDate(sd2, ed2) // netDuration = 4h, hourly = 100, bb100 = 150 / 75 * 100 = +200
realm.copyToRealmOrUpdate(s1)
realm.copyToRealmOrUpdate(s2)
realm.commitTransaction()
val sessions = realm.where(Session::class.java).findAll()
val group = SessionGroup(name = "test", sessions = sessions)
val options = Calculator.Options()
options.displayedStats = listOf(Stat.STANDARD_DEVIATION_BB_PER_100_HANDS, Stat.STANDARD_DEVIATION)
val results: ComputedResults = Calculator.compute(group, options)
val delta = 0.01
val duration = results.computedStat(Stat.DURATION)
if (duration != null) {
assertEquals(3.0, duration.value, delta)
} else {
Assert.fail("No Net result stat")
}
val numberOfSets = results.computedStat(Stat.NUMBER_OF_SETS)
if (numberOfSets != null) {
assertEquals(1, numberOfSets.value.toInt())
} else {
Assert.fail("No numberOfSets stat")
}
val numberOfGames = results.computedStat(Stat.NUMBER_OF_GAMES)
if (numberOfGames != null) {
assertEquals(2, numberOfGames.value.toInt())
} else {
Assert.fail("No numberOfSets stat")
}
}
@Test
fun testOverlappingSessions2() {
val realm = this.mockRealm
realm.beginTransaction()
val s1 = realm.createObject(Session::class.java, "1")
val s2 = realm.createObject(Session::class.java, "2")
val s3 = realm.createObject(Session::class.java, "3")
s1.timeFrame = realm.createObject(TimeFrame::class.java)
s2.timeFrame = realm.createObject(TimeFrame::class.java)
s3.timeFrame = realm.createObject(TimeFrame::class.java)
realm.insert(s1)
realm.insert(s2)
realm.insert(s3)
val sdf = SimpleDateFormat("dd/M/yyyy hh:mm")
val sd1 = sdf.parse("01/1/2019 05:00")
val ed1 = sdf.parse("01/1/2019 09:00")
val sd2 = sdf.parse("01/1/2019 07:00")
val ed2 = sdf.parse("01/1/2019 11:00")
val sd3 = sdf.parse("01/1/2019 03:00")
val ed3 = sdf.parse("01/1/2019 06:00")
s1.timeFrame?.setDate(sd1, ed1) // netDuration = 4h
s2.timeFrame?.setDate(sd2, ed2) // netDuration = 4h
s3.timeFrame?.setDate(sd3, ed3) // netDuration = 3h
realm.copyToRealmOrUpdate(s1)
realm.copyToRealmOrUpdate(s2)
realm.copyToRealmOrUpdate(s3)
realm.commitTransaction()
val sessions = realm.where(Session::class.java).findAll()
val group = SessionGroup(name = "test", sessions = sessions)
val options = Calculator.Options()
options.displayedStats = listOf(Stat.STANDARD_DEVIATION_BB_PER_100_HANDS, Stat.STANDARD_DEVIATION)
val results: ComputedResults = Calculator.compute(group, options)
val delta = 0.01
val duration = results.computedStat(Stat.DURATION)
if (duration != null) {
assertEquals(8.0, duration.value, delta)
} else {
Assert.fail("No Net result stat")
}
val numberOfSets = results.computedStat(Stat.NUMBER_OF_SETS)
if (numberOfSets != null) {
assertEquals(1, numberOfSets.value.toInt())
} else {
Assert.fail("No numberOfSets stat")
}
val numberOfGames = results.computedStat(Stat.NUMBER_OF_GAMES)
if (numberOfGames != null) {
assertEquals(3, numberOfGames.value.toInt())
} else {
Assert.fail("No numberOfSets stat")
}
}
var sessions: RealmResults<Session>? = null
// @Test
fun testOverlappingSessionDeletion() {
val realm = this.mockRealm
this.sessions = realm.where(Session::class.java).findAll() // monitor session deletions
this.sessions?.addChangeListener { t, changeSet ->
val deletedSessions = realm.where(Session::class.java).`in`("id", changeSet.deletions.toTypedArray()).findAll()
deletedSessions.forEach { it.cleanup() }
}
realm.beginTransaction()
val s1 = realm.createObject(Session::class.java, "1")
val s2 = realm.createObject(Session::class.java, "2")
val s3 = realm.createObject(Session::class.java, "3")
s1.timeFrame = realm.createObject(TimeFrame::class.java)
s2.timeFrame = realm.createObject(TimeFrame::class.java)
s3.timeFrame = realm.createObject(TimeFrame::class.java)
realm.insert(s1)
realm.insert(s2)
realm.insert(s3)
realm.commitTransaction()
val sdf = SimpleDateFormat("dd/M/yyyy hh:mm")
val sd1 = sdf.parse("01/1/2019 05:00")
val ed1 = sdf.parse("01/1/2019 09:00")
val sd2 = sdf.parse("01/1/2019 07:00")
val ed2 = sdf.parse("01/1/2019 11:00")
val sd3 = sdf.parse("01/1/2019 03:00")
val ed3 = sdf.parse("01/1/2019 06:00")
realm.beginTransaction()
s1.timeFrame?.setDate(sd1, ed1) // netDuration = 4h
s2.timeFrame?.setDate(sd2, ed2) // netDuration = 4h
s3.timeFrame?.setDate(sd3, ed3) // netDuration = 3h
realm.copyToRealmOrUpdate(s1)
realm.copyToRealmOrUpdate(s2)
realm.copyToRealmOrUpdate(s3)
realm.commitTransaction()
val sessions = realm.where(Session::class.java).findAll()
val group = SessionGroup(name = "test", sessions = sessions)
val options = Calculator.Options()
options.displayedStats = listOf(Stat.STANDARD_DEVIATION_BB_PER_100_HANDS, Stat.STANDARD_DEVIATION)
val results: ComputedResults = Calculator.compute(group, options)
val delta = 0.01
val duration = results.computedStat(Stat.DURATION)
if (duration != null) {
assertEquals(8.0, duration.value, delta)
} else {
Assert.fail("No netDuration stat")
}
realm.executeTransaction {
s1.deleteFromRealm()
}
val group2 = SessionGroup(name = "test", sessions = sessions)
val results2: ComputedResults = Calculator.compute(group2, options)
val duration2 = results2.computedStat(Stat.DURATION)
if (duration2 != null) {
assertEquals(7.0, duration2.value, delta)
} else {
Assert.fail("No duration2 stat")
}
}
@Test
fun testSessionSetCount() {
val realm = this.mockRealm
realm.beginTransaction()
val s1 = realm.createObject(Session::class.java, "1")
s1.timeFrame = realm.createObject(TimeFrame::class.java)
s1.result = realm.createObject(net.pokeranalytics.android.model.realm.Result::class.java)
realm.insert(s1)
val sdf = SimpleDateFormat("dd/M/yyyy hh:mm")
val sd1 = sdf.parse("01/1/2019 09:00")
val ed1 = sdf.parse("01/1/2019 10:00")
s1.timeFrame?.setDate(sd1, ed1) // netDuration = 1h, hourly = -100, bb100 = -200bb / 25hands * 100 = -800
realm.copyToRealmOrUpdate(s1)
realm.commitTransaction()
val sets = realm.where(SessionSet::class.java).findAll()
Assert.assertEquals(1, sets.size)
val set = sets.first()
if (set != null) {
Assert.assertEquals(sd1.time, set.timeFrame?.startDate?.time)
Assert.assertEquals(ed1.time, set.timeFrame?.endDate?.time)
} else {
Assert.fail("No set")
}
}
@Test
fun testSessionSetCount2() {
val realm = this.mockRealm
realm.beginTransaction()
val s1 = realm.createObject(Session::class.java, "1")
val s2 = realm.createObject(Session::class.java, "2")
s1.timeFrame = realm.createObject(TimeFrame::class.java)
s2.timeFrame = realm.createObject(TimeFrame::class.java)
s1.result = realm.createObject(net.pokeranalytics.android.model.realm.Result::class.java)
s2.result = realm.createObject(net.pokeranalytics.android.model.realm.Result::class.java)
realm.insert(s1)
realm.insert(s2)
val sdf = SimpleDateFormat("dd/M/yyyy hh:mm")
val sd1 = sdf.parse("01/1/2019 09:00")
val ed1 = sdf.parse("01/1/2019 10:00")
val sd2 = sdf.parse("01/2/2018 09:00")
val ed2 = sdf.parse("01/2/2018 10:00")
s1.timeFrame?.let {
it.setStart(sd1)
it.setEnd(ed1)
}
s2.timeFrame?.let {
it.setStart(sd2)
it.setEnd(ed2)
}
// s1.timeFrame?.setDate(sd1, ed1) // netDuration = 1h, hourly = -100, bb100 = -200bb / 25hands * 100 = -800
// s2.timeFrame?.setDate(sd2, ed2) // netDuration = 1h, hourly = -100, bb100 = -200bb / 25hands * 100 = -800
realm.copyToRealmOrUpdate(s1)
realm.copyToRealmOrUpdate(s2)
realm.commitTransaction()
val sets = realm.where(SessionSet::class.java).findAll()
Assert.assertEquals(2, sets.size)
// val set = sets.first()
// if (set != null) {
// Assert.assertEquals(sd1.time, set.timeFrame?.startDate?.time)
// Assert.assertEquals(ed1.time, set.timeFrame?.endDate?.time)
// } else {
// Assert.fail("No set")
// }
}
//
// @Test
// fun testDurationConversion() {
//
// val duration = 6.7555561274509826
// val longDuration = duration.toLong()
// val formatted = longDuration.toMinutes()
//
// assert(formatted == "11:00")
// }
}

@ -0,0 +1,573 @@
package net.pokeranalytics.android
import androidx.test.ext.junit.runners.AndroidJUnit4
import io.realm.RealmResults
import net.pokeranalytics.android.calculus.Calculator
import net.pokeranalytics.android.calculus.ComputedResults
import net.pokeranalytics.android.calculus.SessionGroup
import net.pokeranalytics.android.calculus.Stat
import net.pokeranalytics.android.model.realm.Session
import net.pokeranalytics.android.model.realm.SessionSet
import org.junit.Assert
import org.junit.Assert.assertEquals
import org.junit.Test
import org.junit.runner.RunWith
import java.text.SimpleDateFormat
import java.util.*
/**
* Instrumented test, which will execute on an Android device.
*
* See [testing documentation](http://d.android.com/tools/testing).
*/
@RunWith(AndroidJUnit4::class)
class StatsInstrumentedUnitTest : RealmInstrumentedUnitTest() {
// convenience extension
fun Session.Companion.testInstance(netResult: Double, startDate: Date, endDate: Date?): Session {
val session: Session = Session.newInstance(super.mockRealm, false)
session.result?.netResult = netResult
session.startDate = startDate
session.endDate = endDate
return session
}
@Test
fun testSessionStats() {
val realm = this.mockRealm
realm.beginTransaction()
val s1 = realm.createObject(Session::class.java, "1")
val s2 = realm.createObject(Session::class.java, "2")
s1.result = realm.createObject(net.pokeranalytics.android.model.realm.Result::class.java)
s2.result = realm.createObject(net.pokeranalytics.android.model.realm.Result::class.java)
s1.result?.buyin = 100.0 // net result = -100
s2.result?.buyin = 200.0
s2.result?.cashout = 500.0 // net result = 300
s1.cgBigBlind = 0.5 // bb net result = -200bb
s2.cgBigBlind = 2.0 // bb net result = 150bb
realm.insert(s1)
realm.insert(s2)
realm.commitTransaction()
val sdf = SimpleDateFormat("dd/M/yyyy hh:mm")
val sd1 = sdf.parse("01/1/2019 10:00")
val ed1 = sdf.parse("01/1/2019 11:00")
val sd2 = sdf.parse("02/1/2019 08:00")
val ed2 = sdf.parse("02/1/2019 11:00")
realm.beginTransaction()
s1.startDate = sd1
s1.endDate = ed1
s2.startDate = sd2
s2.endDate = ed2
realm.copyToRealmOrUpdate(s1)
realm.copyToRealmOrUpdate(s2)
realm.commitTransaction()
val sessions = realm.where(Session::class.java).findAll()
val group = SessionGroup(name = "test", sessions = sessions)
val options = Calculator.Options()
options.displayedStats = listOf(Stat.STANDARD_DEVIATION_BB_PER_100_HANDS, Stat.STANDARD_DEVIATION)
val results: ComputedResults = Calculator.compute(group, options)
val delta = 0.01
val sum = results.computedStat(Stat.NETRESULT)
if (sum != null) {
assertEquals(200.0, sum.value, delta)
} else {
Assert.fail("No Net result stat")
}
val average = results.computedStat(Stat.AVERAGE)
if (average != null) {
assertEquals(100.0, average.value, delta)
} else {
Assert.fail("No AVERAGE stat")
}
val duration = results.computedStat(Stat.DURATION)
if (duration != null) {
assertEquals(4.0, duration.value, delta)
} else {
Assert.fail("No netDuration stat")
}
val hourlyRate = results.computedStat(Stat.HOURLY_RATE)
if (hourlyRate != null) {
assertEquals(50.0, hourlyRate.value, delta)
} else {
Assert.fail("No houry rate stat")
}
val handsPlayed = results.computedStat(Stat.HANDS_PLAYED)
if (handsPlayed != null) {
assertEquals(100.0, handsPlayed.value, delta)
} else {
Assert.fail("No hands played stat")
}
val numberOfGames = results.computedStat(Stat.NUMBER_OF_GAMES)
if (numberOfGames != null) {
assertEquals(2, numberOfGames.value.toInt())
} else {
Assert.fail("No numberOfGames stat")
}
val numberOfSets = results.computedStat(Stat.NUMBER_OF_SETS)
if (numberOfSets != null) {
assertEquals(2, numberOfSets.value.toInt())
} else {
Assert.fail("No numberOfSets stat")
}
val avgBuyin = results.computedStat(Stat.AVERAGE_BUYIN)
if (avgBuyin != null) {
assertEquals(150.0, avgBuyin.value, delta)
} else {
Assert.fail("No avgBuyin stat")
}
val avgDuration = results.computedStat(Stat.AVERAGE_DURATION)
if (avgDuration != null) {
assertEquals(2.0, avgDuration.value, delta)
} else {
Assert.fail("No avgDuration stat")
}
val roi = results.computedStat(Stat.ROI)
if (roi != null) {
assertEquals(200 / 300.0, roi.value, delta)
} else {
Assert.fail("No roi stat")
}
val avgBBNet = results.computedStat(Stat.AVERAGE_NET_BB)
if (avgBBNet != null) {
assertEquals(-25.0, avgBBNet.value, delta)
} else {
Assert.fail("No avgBBNet stat")
}
val bbHourlyRate = results.computedStat(Stat.HOURLY_RATE_BB)
if (bbHourlyRate != null) {
assertEquals(-12.5, bbHourlyRate.value, delta)
} else {
Assert.fail("No bbHourlyRate stat")
}
val netbbPer100Hands = results.computedStat(Stat.NET_BB_PER_100_HANDS)
if (netbbPer100Hands != null) {
assertEquals(-50.0, netbbPer100Hands.value, delta)
} else {
Assert.fail("No netbbPer100Hands stat")
}
val std = results.computedStat(Stat.STANDARD_DEVIATION)
if (std != null) {
assertEquals(200.0, std.value, delta)
} else {
Assert.fail("No std stat")
}
val stdHourly = results.computedStat(Stat.STANDARD_DEVIATION_HOURLY)
if (stdHourly != null) {
assertEquals(111.8, stdHourly.value, delta)
} else {
Assert.fail("No stdHourly stat")
}
val std100 = results.computedStat(Stat.STANDARD_DEVIATION_BB_PER_100_HANDS)
if (std100 != null) {
assertEquals(559.01, std100.value, delta)
} else {
Assert.fail("No std100 stat")
}
}
@Test
fun testOverlappingSessions1() {
val realm = this.mockRealm
realm.beginTransaction()
val s1 = realm.createObject(Session::class.java, "1")
val s2 = realm.createObject(Session::class.java, "2")
s1.result = realm.createObject(net.pokeranalytics.android.model.realm.Result::class.java)
s2.result = realm.createObject(net.pokeranalytics.android.model.realm.Result::class.java)
realm.insert(s1)
realm.insert(s2)
val sdf = SimpleDateFormat("dd/M/yyyy hh:mm")
val sd1 = sdf.parse("01/1/2019 09:00")
val ed1 = sdf.parse("01/1/2019 10:00")
val sd2 = sdf.parse("01/1/2019 08:00")
val ed2 = sdf.parse("01/1/2019 11:00")
s1.startDate = sd1
s1.endDate = ed1
s2.startDate = sd2
s2.endDate = ed2
// netDuration = 1h, hourly = -100, bb100 = -200bb / 25hands * 100 = -800
// netDuration = 4h, hourly = 100, bb100 = 150 / 75 * 100 = +200
realm.copyToRealmOrUpdate(s1)
realm.copyToRealmOrUpdate(s2)
realm.commitTransaction()
val sessions = realm.where(Session::class.java).findAll()
val group = SessionGroup(name = "test", sessions = sessions)
val options = Calculator.Options()
options.displayedStats = listOf(Stat.STANDARD_DEVIATION_BB_PER_100_HANDS, Stat.STANDARD_DEVIATION)
val results: ComputedResults = Calculator.compute(group, options)
val delta = 0.01
val duration = results.computedStat(Stat.DURATION)
if (duration != null) {
assertEquals(3.0, duration.value, delta)
} else {
Assert.fail("No Net result stat")
}
val numberOfSets = results.computedStat(Stat.NUMBER_OF_SETS)
if (numberOfSets != null) {
assertEquals(1, numberOfSets.value.toInt())
} else {
Assert.fail("No numberOfSets stat")
}
val numberOfGames = results.computedStat(Stat.NUMBER_OF_GAMES)
if (numberOfGames != null) {
assertEquals(2, numberOfGames.value.toInt())
} else {
Assert.fail("No numberOfSets stat")
}
}
@Test
fun testOverlappingSessions2() {
val realm = this.mockRealm
realm.beginTransaction()
val s1 = realm.createObject(Session::class.java, "1")
val s2 = realm.createObject(Session::class.java, "2")
val s3 = realm.createObject(Session::class.java, "3")
realm.insert(s1)
realm.insert(s2)
realm.insert(s3)
val sdf = SimpleDateFormat("dd/M/yyyy hh:mm")
val sd1 = sdf.parse("01/1/2019 05:00")
val ed1 = sdf.parse("01/1/2019 09:00") // 4h
val sd2 = sdf.parse("01/1/2019 07:00")
val ed2 = sdf.parse("01/1/2019 11:00") // 4h
val sd3 = sdf.parse("01/1/2019 03:00")
val ed3 = sdf.parse("01/1/2019 06:00") // 3h
s1.startDate = sd1
s1.endDate = ed1
s2.startDate = sd2
s2.endDate = ed2
s3.startDate = sd3
s3.endDate = ed3
realm.copyToRealmOrUpdate(s1)
realm.copyToRealmOrUpdate(s2)
realm.copyToRealmOrUpdate(s3)
realm.commitTransaction()
val sessions = realm.where(Session::class.java).findAll()
val group = SessionGroup(name = "test", sessions = sessions)
val options = Calculator.Options()
options.displayedStats = listOf(Stat.STANDARD_DEVIATION_BB_PER_100_HANDS, Stat.STANDARD_DEVIATION)
val results: ComputedResults = Calculator.compute(group, options)
val delta = 0.01
val duration = results.computedStat(Stat.DURATION)
if (duration != null) {
assertEquals(8.0, duration.value, delta)
} else {
Assert.fail("No Net result stat")
}
val numberOfSets = results.computedStat(Stat.NUMBER_OF_SETS)
if (numberOfSets != null) {
assertEquals(1, numberOfSets.value.toInt())
} else {
Assert.fail("No numberOfSets stat")
}
val numberOfGames = results.computedStat(Stat.NUMBER_OF_GAMES)
if (numberOfGames != null) {
assertEquals(3, numberOfGames.value.toInt())
} else {
Assert.fail("No numberOfSets stat")
}
}
private var sessions: RealmResults<Session>? = null
// @Test
fun testOverlappingSessionDeletion() {
val realm = this.mockRealm
this.sessions = realm.where(Session::class.java).findAll() // monitor session deletions
this.sessions?.addChangeListener { _, changeSet ->
val deletedSessions =
realm.where(Session::class.java).`in`("id", changeSet.deletions.toTypedArray()).findAll()
deletedSessions.forEach { it.cleanup() }
}
realm.beginTransaction()
val s1 = realm.createObject(Session::class.java, "1")
val s2 = realm.createObject(Session::class.java, "2")
val s3 = realm.createObject(Session::class.java, "3")
realm.insert(s1)
realm.insert(s2)
realm.insert(s3)
realm.commitTransaction()
val sdf = SimpleDateFormat("dd/M/yyyy hh:mm")
val sd1 = sdf.parse("01/1/2019 05:00")
val ed1 = sdf.parse("01/1/2019 09:00")
val sd2 = sdf.parse("01/1/2019 07:00")
val ed2 = sdf.parse("01/1/2019 11:00")
val sd3 = sdf.parse("01/1/2019 03:00")
val ed3 = sdf.parse("01/1/2019 06:00")
realm.beginTransaction()
s1.startDate = sd1
s1.endDate = ed1
s2.startDate = sd2
s2.endDate = ed2
s3.startDate = sd3
s3.endDate = ed3
realm.copyToRealmOrUpdate(s1)
realm.copyToRealmOrUpdate(s2)
realm.copyToRealmOrUpdate(s3)
realm.commitTransaction()
val sessions = realm.where(Session::class.java).findAll()
val group = SessionGroup(name = "test", sessions = sessions)
val options = Calculator.Options()
options.displayedStats = listOf(Stat.STANDARD_DEVIATION_BB_PER_100_HANDS, Stat.STANDARD_DEVIATION)
val results: ComputedResults = Calculator.compute(group, options)
val delta = 0.01
val duration = results.computedStat(Stat.DURATION)
if (duration != null) {
assertEquals(8.0, duration.value, delta)
} else {
Assert.fail("No netDuration stat")
}
realm.executeTransaction {
s1.deleteFromRealm()
}
val group2 = SessionGroup(name = "test", sessions = sessions)
val results2: ComputedResults = Calculator.compute(group2, options)
val duration2 = results2.computedStat(Stat.DURATION)
if (duration2 != null) {
assertEquals(7.0, duration2.value, delta)
} else {
Assert.fail("No duration2 stat")
}
}
@Test
fun testSessionSetCount() {
val realm = this.mockRealm
realm.beginTransaction()
val s1 = realm.createObject(Session::class.java, "1")
s1.result = realm.createObject(net.pokeranalytics.android.model.realm.Result::class.java)
realm.insert(s1)
val sdf = SimpleDateFormat("dd/M/yyyy hh:mm")
val sd1 = sdf.parse("01/1/2019 09:00")
val ed1 = sdf.parse("01/1/2019 10:00")
s1.startDate = sd1 // timeFrame?.setDate(sd1, ed1) // netDuration = 1h, hourly = -100, bb100 = -200bb / 25hands * 100 = -800
s1.endDate = ed1
realm.copyToRealmOrUpdate(s1)
realm.commitTransaction()
val sets = realm.where(SessionSet::class.java).findAll()
Assert.assertEquals(1, sets.size)
val set = sets.first()
if (set != null) {
Assert.assertEquals(sd1.time, set.startDate.time)
Assert.assertEquals(ed1.time, set.endDate.time)
} else {
Assert.fail("No set")
}
}
@Test
fun testSessionSetCount2() {
val realm = this.mockRealm
realm.beginTransaction()
val s1 = realm.createObject(Session::class.java, "1")
val s2 = realm.createObject(Session::class.java, "2")
s1.result = realm.createObject(net.pokeranalytics.android.model.realm.Result::class.java)
s2.result = realm.createObject(net.pokeranalytics.android.model.realm.Result::class.java)
realm.insert(s1)
realm.insert(s2)
val sdf = SimpleDateFormat("dd/M/yyyy hh:mm")
val sd1 = sdf.parse("01/1/2019 09:00")
val ed1 = sdf.parse("01/1/2019 10:00")
val sd2 = sdf.parse("01/2/2018 09:00")
val ed2 = sdf.parse("01/2/2018 10:00")
s1.startDate = sd1
s1.endDate = ed1
s2.startDate = sd2
s2.endDate = ed2
// s1.timeFrame?.setDate(sd1, ed1) // netDuration = 1h, hourly = -100, bb100 = -200bb / 25hands * 100 = -800
// s2.timeFrame?.setDate(sd2, ed2) // netDuration = 1h, hourly = -100, bb100 = -200bb / 25hands * 100 = -800
realm.copyToRealmOrUpdate(s1)
realm.copyToRealmOrUpdate(s2)
realm.commitTransaction()
val sets = realm.where(SessionSet::class.java).findAll()
Assert.assertEquals(2, sets.size)
// val set = sets.first()
// if (set != null) {
// Assert.assertEquals(sd1.time, set.timeFrame?.startDate?.time)
// Assert.assertEquals(ed1.time, set.timeFrame?.endDate?.time)
// } else {
// Assert.fail("No set")
// }
}
//
// @Test
// fun testDurationConversion() {
//
// val duration = 6.7555561274509826
// val longDuration = duration.toLong()
// val formatted = longDuration.toMinutes()
//
// assert(formatted == "11:00")
// }
@Test
fun testSessionRestartInOverlappingSessions() {
val realm = this.mockRealm
realm.beginTransaction()
val s1 = realm.createObject(Session::class.java, "1")
val s2 = realm.createObject(Session::class.java, "2")
val s3 = realm.createObject(Session::class.java, "3")
realm.insert(s1)
realm.insert(s2)
realm.insert(s3)
val sdf = SimpleDateFormat("dd/M/yyyy hh:mm")
val sd1 = sdf.parse("01/1/2019 05:00")
val ed1 = sdf.parse("01/1/2019 09:00") // 4h
val sd2 = sdf.parse("01/1/2019 07:00")
val ed2 = sdf.parse("01/1/2019 11:00") // 4h
val sd3 = sdf.parse("01/1/2019 03:00")
val ed3 = sdf.parse("01/1/2019 06:00") // 3h
s1.startDate = sd1
s1.endDate = ed1
s2.startDate = sd2
s2.endDate = ed2
s3.startDate = sd3
s3.endDate = ed3
realm.copyToRealmOrUpdate(s1)
realm.copyToRealmOrUpdate(s2)
realm.copyToRealmOrUpdate(s3)
realm.commitTransaction()
realm.executeTransaction {
s1.endDate = null
}
val sessions = realm.where(Session::class.java).findAll()
val group = SessionGroup(name = "test", sessions = sessions)
val options = Calculator.Options()
// options.displayedStats = listOf(Stat.STANDARD_DEVIATION_BB_PER_100_HANDS, Stat.STANDARD_DEVIATION)
val results: ComputedResults = Calculator.compute(group, options)
val delta = 0.01
val duration = results.computedStat(Stat.DURATION)
if (duration != null) {
assertEquals(7.0, duration.value, delta)
} else {
Assert.fail("No Net result stat")
}
val numberOfSets = results.computedStat(Stat.NUMBER_OF_SETS)
if (numberOfSets != null) {
assertEquals(2, numberOfSets.value.toInt())
} else {
Assert.fail("No numberOfSets stat")
}
}
}

@ -63,7 +63,7 @@ class PokerAnalyticsApplication : Application() {
this.createDefaultData() this.createDefaultData()
if (BuildConfig.DEBUG) { if (BuildConfig.DEBUG) {
this.createFakeSessions() // debug // this.createFakeSessions() // debug
} }
} }
@ -158,11 +158,14 @@ class PokerAnalyticsApplication : Application() {
// val timeFrame = TimeFrame() // val timeFrame = TimeFrame()
session.timeFrame?.let { session.startDate = startDate
// it.startDate = startDate session.endDate = endDate
// it.endDate = endDate
it.setDate(startDate, endDate) // session.timeFrame?.let {
} // // it.startDate = startDate
//// it.endDate = endDate
// it.setDate(startDate, endDate)
// }
// session.timeFrame = timeFrame // session.timeFrame = timeFrame
session.creationDate = startDate session.creationDate = startDate

@ -64,7 +64,7 @@ class Calculator {
*/ */
fun computeGroups(groups: List<SessionGroup>, options: Options): List<ComputedResults> { fun computeGroups(groups: List<SessionGroup>, options: Options): List<ComputedResults> {
var computedResults: MutableList<ComputedResults> = mutableListOf() val computedResults = mutableListOf<ComputedResults>()
groups.forEach { group -> groups.forEach { group ->
// Computes actual sessionGroup stats // Computes actual sessionGroup stats
val results: ComputedResults = Calculator.compute(group, options = options) val results: ComputedResults = Calculator.compute(group, options = options)
@ -90,9 +90,9 @@ class Calculator {
fun compute(sessionGroup: SessionGroup, options: Options) : ComputedResults { fun compute(sessionGroup: SessionGroup, options: Options) : ComputedResults {
val sessions: List<SessionInterface> = sessionGroup.sessions val sessions: List<SessionInterface> = sessionGroup.sessions
var sessionSets = sessionGroup.sessions.mapNotNull { it.sessionSet }.toHashSet() val sessionSets = sessionGroup.sessions.mapNotNull { it.sessionSet }.toHashSet()
var results: ComputedResults = ComputedResults(sessionGroup) val results: ComputedResults = ComputedResults(sessionGroup)
var sum: Double = 0.0 var sum: Double = 0.0
var totalHands: Double = 0.0 var totalHands: Double = 0.0
@ -159,7 +159,7 @@ class Calculator {
results.addEvolutionValue(gSum / duration, duration, HOURLY_RATE) results.addEvolutionValue(gSum / duration, duration, HOURLY_RATE)
results.addEvolutionValue(hourlyRate, duration, HOURLY_RATE) results.addEvolutionValue(hourlyRate, duration, HOURLY_RATE)
results.addEvolutionValue(gIndex.toDouble(), duration, NUMBER_OF_SETS) results.addEvolutionValue(gIndex.toDouble(), duration, NUMBER_OF_SETS)
results.addEvolutionValue(sessionSet.duration.toDouble(), duration, DURATION) results.addEvolutionValue(sessionSet.netDuration.toDouble(), duration, DURATION)
results.addEvolutionValue(duration / gIndex, duration, AVERAGE_DURATION) results.addEvolutionValue(duration / gIndex, duration, AVERAGE_DURATION)
results.addEvolutionValue(hourlyRateBB, duration, HOURLY_RATE_BB) results.addEvolutionValue(hourlyRateBB, duration, HOURLY_RATE_BB)
} }
@ -175,19 +175,24 @@ class Calculator {
var average = 0.0 var average = 0.0
if (sessions.size > 0) { if (sessions.size > 0) {
average = sum / sessions.size.toDouble() average = sum / sessions.size.toDouble()
val avgDuration = duration / sessions.size
val winRatio = (winningSessionCount / sessions.size).toDouble() val winRatio = (winningSessionCount / sessions.size).toDouble()
val avgBuyin = totalBuyin / sessions.size val avgBuyin = totalBuyin / sessions.size
results.addStats(setOf( results.addStats(setOf(
ComputedStat(AVERAGE, average), ComputedStat(AVERAGE, average),
ComputedStat(AVERAGE_DURATION, avgDuration),
ComputedStat(WIN_RATIO, winRatio), ComputedStat(WIN_RATIO, winRatio),
ComputedStat(AVERAGE_BUYIN, avgBuyin) ComputedStat(AVERAGE_BUYIN, avgBuyin)
)) ))
} }
// Create stats if (sessionSets.size > 0) {
val avgDuration = duration / sessionSets.size
results.addStats(setOf(
ComputedStat(AVERAGE_DURATION, avgDuration)
))
}
// Create stats
results.addStats(setOf( results.addStats(setOf(
ComputedStat(NETRESULT, sum), ComputedStat(NETRESULT, sum),
ComputedStat(HOURLY_RATE, hourlyRate), ComputedStat(HOURLY_RATE, hourlyRate),

@ -19,7 +19,6 @@ interface SessionInterface : Summable {
var bigBlindSessionCount: Int // 0 or 1 var bigBlindSessionCount: Int // 0 or 1
var buyin: Double var buyin: Double
var bbPer100Hands: Double var bbPer100Hands: Double
} }
/** /**

@ -18,24 +18,35 @@ enum class SessionState {
*/ */
fun Session.getState(): SessionState { fun Session.getState(): SessionState {
if (timeFrame == null) { // if (timeFrame == null) {
return SessionState.PENDING // return SessionState.PENDING
} // }
val endDate = timeFrame?.endDate if (startDate > Date()) {
timeFrame?.let {sessionTimeFrame -> return SessionState.PLANNED
timeFrame?.startDate?.let {startDate -> } else if (endDate != null) {
if (startDate > Date()) { return SessionState.FINISHED
return SessionState.PLANNED } else if (this.pauseDate != null) {
} else if (endDate != null) { return SessionState.PAUSED
return SessionState.FINISHED } else {
} else if (sessionTimeFrame.paused) { return SessionState.STARTED
return SessionState.PAUSED
} else {
return SessionState.STARTED
}
}
} }
return SessionState.INVALID
// val endDate = timeFrame?.endDate
// timeFrame?.let {sessionTimeFrame ->
// timeFrame?.startDate?.let {startDate ->
// if (startDate > Date()) {
// return SessionState.PLANNED
// } else if (endDate != null) {
// return SessionState.FINISHED
// } else if (sessionTimeFrame.paused) {
// return SessionState.PAUSED
// } else {
// return SessionState.STARTED
// }
// }
// }
// return SessionState.INVALID
} }

@ -0,0 +1,30 @@
package net.pokeranalytics.android.model.interfaces
import java.util.*
interface Timed {
var startDate: Date
fun endDate() : Date
var breakDuration: Long
var netDuration: Long
/**
* Computes the net netDuration of the session
*/
fun computeDuration() {
this.netDuration = this.endDate().time - this.startDate.time - this.breakDuration
}
// fun hourlyDuration() : Double {
// return this.netDuration / 3600000.0 // 3.6 millions of milliseconds
// }
var hourlyDuration: Double
get() = this.netDuration / 3600000.0
set(value) = TODO()
}

@ -19,6 +19,8 @@ import net.pokeranalytics.android.model.TableSize
import net.pokeranalytics.android.model.extensions.SessionState import net.pokeranalytics.android.model.extensions.SessionState
import net.pokeranalytics.android.model.extensions.getState import net.pokeranalytics.android.model.extensions.getState
import net.pokeranalytics.android.model.interfaces.Savable import net.pokeranalytics.android.model.interfaces.Savable
import net.pokeranalytics.android.model.interfaces.Timed
import net.pokeranalytics.android.model.utils.SessionSetManager
import net.pokeranalytics.android.ui.adapter.StaticRowRepresentableDataSource import net.pokeranalytics.android.ui.adapter.StaticRowRepresentableDataSource
import net.pokeranalytics.android.ui.adapter.UnmanagedRowRepresentableException import net.pokeranalytics.android.ui.adapter.UnmanagedRowRepresentableException
import net.pokeranalytics.android.ui.view.RowRepresentable import net.pokeranalytics.android.ui.view.RowRepresentable
@ -31,8 +33,8 @@ import net.pokeranalytics.android.util.*
import java.util.* import java.util.*
import kotlin.collections.ArrayList import kotlin.collections.ArrayList
open class Session : RealmObject(), SessionInterface, Savable, open class Session : RealmObject(), SessionInterface, Savable, StaticRowRepresentableDataSource, RowRepresentable,
StaticRowRepresentableDataSource, RowRepresentable { Timed {
enum class Type { enum class Type {
CASH_GAME, CASH_GAME,
@ -60,13 +62,54 @@ open class Session : RealmObject(), SessionInterface, Savable,
// The result of the main user // The result of the main user
var result: Result? = null var result: Result? = null
// The time frame of the Session, i.e. the start & end date // Timed interface
var timeFrame: TimeFrame? = null
override var startDate: Date = Date()
set(value) {
field = value
this.computeDuration()
if (this.endDate != null && this.startDate.after(this.endDate)) {
this.endDate = null
}
this.dateChanged()
}
var endDate: Date? = null
set(value) { set(value) {
field = value field = value
value?.let { it.notifySessionDateChange(this) } this.computeDuration()
this.dateChanged()
} }
private fun dateChanged() {
if (this.endDate != null) {
SessionSetManager.updateTimeline(this)
} else if (this.sessionSet != null) {
SessionSetManager.removeFromTimeline(this)
}
}
override fun endDate(): Date {
return this.endDate ?: Date()
}
override var breakDuration: Long = 0L
set(value) {
field = value
this.computeDuration()
}
override var netDuration: Long = 0L
var pauseDate: Date? = null
// The time frame of the Session, i.e. the start & end date
// var timeFrame: TimeFrame? = null
// set(value) {
// field = value
// value?.let { it.notifySessionDateChange(this) }
// }
// The time frame sessionGroup, which can contain multiple sessions // The time frame sessionGroup, which can contain multiple sessions
override var sessionSet: SessionSet? = null override var sessionSet: SessionSet? = null
@ -129,16 +172,19 @@ open class Session : RealmObject(), SessionInterface, Savable,
* Return if this session is a tournament * Return if this session is a tournament
*/ */
fun isTournament(): Boolean { fun isTournament(): Boolean {
return type == Type.TOURNAMENT.ordinal return this.type == Type.TOURNAMENT.ordinal
} }
/** /**
* Return if this session is a cash game * Return if this session is a cash game
*/ */
fun isCashGame(): Boolean { fun isCashGame(): Boolean {
return type == Type.CASH_GAME.ordinal return this.type == Type.CASH_GAME.ordinal
} }
// Stats
@Ignore // SessionInterface value @Ignore // SessionInterface value
override var value: Double = 0.0 override var value: Double = 0.0
get() { get() {
@ -146,7 +192,7 @@ open class Session : RealmObject(), SessionInterface, Savable,
} }
@Ignore @Ignore
override var estimatedHands: Double = 25.0 * (this.timeFrame?.hourlyDuration ?: 0.0) override var estimatedHands: Double = 25.0 * this.hourlyDuration
@Ignore @Ignore
override var bbNetResult: Double = 0.0 override var bbNetResult: Double = 0.0
@ -171,25 +217,15 @@ open class Session : RealmObject(), SessionInterface, Savable,
@Ignore @Ignore
override var buyin: Double = 0.0 override var buyin: Double = 0.0
get() { get() {
this.result?.let { this.result?.let { result ->
it.buyin?.let { result.buyin?.let {
return it return it
} }
} }
return 0.0 return 0.0
} }
@Ignore val hourlyRate: Double
var netDuration: Long = 0L
get() {
this.timeFrame?.let {
return it.netDuration
}
return 0L
}
@Ignore
var hourlyRate: Double = 0.0
get() { get() {
this.result?.let { result -> this.result?.let { result ->
return result.net / this.netDuration.toDouble() return result.net / this.netDuration.toDouble()
@ -206,16 +242,19 @@ open class Session : RealmObject(), SessionInterface, Savable,
realm.executeTransaction { realm.executeTransaction {
when (getState()) { when (getState()) {
SessionState.PENDING, SessionState.PLANNED -> { SessionState.PENDING, SessionState.PLANNED -> {
val sessionTimeFrame = this.timeFrame ?: realm.createObject(TimeFrame::class.java) this.startDate = Date()
sessionTimeFrame.setStart(Date())
// val sessionTimeFrame = this.timeFrame ?: realm.createObject(TimeFrame::class.java)
// sessionTimeFrame.setStart(Date())
// sessionTimeFrame.setDate(Date(), null) // sessionTimeFrame.setDate(Date(), null)
this.timeFrame = sessionTimeFrame // this.timeFrame = sessionTimeFrame
} }
SessionState.PAUSED -> { SessionState.PAUSED -> {
this.timeFrame?.paused = false // this.timeFrame?.paused = false
this.timeFrame?.pauseDate = null this.pauseDate = null
} }
else -> { else -> {
throw IllegalStateException("unmanaged session state")
} }
} }
} }
@ -228,9 +267,10 @@ open class Session : RealmObject(), SessionInterface, Savable,
realm.executeTransaction { realm.executeTransaction {
when (getState()) { when (getState()) {
SessionState.STARTED -> { SessionState.STARTED -> {
this.timeFrame?.paused = true // this.?.paused = true
this.timeFrame?.pauseDate = Date() this.pauseDate = Date()
} }
else -> throw IllegalStateException("unmanaged state")
} }
} }
} }
@ -242,9 +282,10 @@ open class Session : RealmObject(), SessionInterface, Savable,
realm.executeTransaction { realm.executeTransaction {
when (getState()) { when (getState()) {
SessionState.STARTED, SessionState.PAUSED -> { SessionState.STARTED, SessionState.PAUSED -> {
this.timeFrame?.paused = false this.end()
this.timeFrame?.pauseDate = null // this.timeFrame?.paused = false
this.timeFrame?.setEnd(Date()) // this.pauseDate = null
// this.endDate = Date()
// this.timeFrame?.setDate(null, Date()) // this.timeFrame?.setDate(null, Date())
} }
else -> throw Exception("Stopping session in unmanaged state") else -> throw Exception("Stopping session in unmanaged state")
@ -257,10 +298,17 @@ open class Session : RealmObject(), SessionInterface, Savable,
*/ */
fun restart() { fun restart() {
realm.executeTransaction { realm.executeTransaction {
this.timeFrame?.paused = false // this.timeFrame?.paused = false
this.timeFrame?.pauseDate = null this.pauseDate = null
this.timeFrame?.setDate(Date(), null) this.startDate = Date() // timeFrame?.setDate(Date(), null)
this.timeFrame?.breakDuration = 0L this.breakDuration = 0L
}
}
private fun end() {
this.pauseDate = null
if (this.endDate == null) {
this.endDate = Date()
} }
} }
@ -270,8 +318,7 @@ open class Session : RealmObject(), SessionInterface, Savable,
* Return the netDuration of the current session * Return the netDuration of the current session
*/ */
fun getDuration(): String { fun getDuration(): String {
val startDate = timeFrame?.startDate ?: Date() val enDate = this.endDate ?: Date()
val enDate = timeFrame?.endDate ?: Date()
return startDate.getDuration(enDate) return startDate.getDuration(enDate)
} }
@ -321,13 +368,14 @@ open class Session : RealmObject(), SessionInterface, Savable,
// cleanup unnecessary related objects // cleanup unnecessary related objects
set.deleteFromRealm() set.deleteFromRealm()
this.timeFrame?.deleteFromRealm() // this.timeFrame?.deleteFromRealm()
this.result?.deleteFromRealm() this.result?.deleteFromRealm()
// make sessions recreate/find their session set // make sessions recreate/find their session set
sessionsFromSet?.let { sessions -> sessionsFromSet?.let { sessions ->
sessions.forEach { session -> sessions.forEach { session ->
session.timeFrame?.notifySessionDateChange(session) // @todo
// session.timeFrame?.notifySessionDateChange(session)
} }
} }
} }
@ -381,7 +429,7 @@ open class Session : RealmObject(), SessionInterface, Savable,
HeaderRowRepresentable( HeaderRowRepresentable(
RowViewType.HEADER_TITLE_AMOUNT, RowViewType.HEADER_TITLE_AMOUNT,
resId = R.string.hour_rate_without_pauses, resId = R.string.hour_rate_without_pauses,
computedStat = ComputedStat(Stat.HOURLY_RATE, this.hourlyRate ?: 0.0) computedStat = ComputedStat(Stat.HOURLY_RATE, this.hourlyRate)
) )
) )
@ -417,19 +465,17 @@ open class Session : RealmObject(), SessionInterface, Savable,
return when (row) { return when (row) {
SessionRow.BANKROLL -> bankroll?.name ?: NULL_TEXT SessionRow.BANKROLL -> bankroll?.name ?: NULL_TEXT
SessionRow.BLINDS -> getBlinds() SessionRow.BLINDS -> getBlinds()
SessionRow.BREAK_TIME -> timeFrame?.breakDuration?.toMinutes() ?: NULL_TEXT SessionRow.BREAK_TIME -> this.breakDuration.toMinutes()
SessionRow.BUY_IN -> buyin.toCurrency() SessionRow.BUY_IN -> buyin.toCurrency()
SessionRow.CASHED_OUT, SessionRow.PRIZE, SessionRow.NET_RESULT -> result?.cashout?.toCurrency() ?: NULL_TEXT SessionRow.CASHED_OUT, SessionRow.PRIZE, SessionRow.NET_RESULT -> result?.cashout?.toCurrency() ?: NULL_TEXT
SessionRow.COMMENT -> if (comment.isNotEmpty()) comment else NULL_TEXT SessionRow.COMMENT -> if (comment.isNotEmpty()) comment else NULL_TEXT
SessionRow.END_DATE -> if (timeFrame != null) timeFrame?.endDate?.shortDateTime() SessionRow.END_DATE -> this.endDate?.shortDateTime() ?: NULL_TEXT
?: NULL_TEXT else NULL_TEXT
SessionRow.GAME -> getGameTitle() SessionRow.GAME -> getGameTitle()
SessionRow.INITIAL_BUY_IN -> tournamentEntryFee?.toCurrency() ?: NULL_TEXT SessionRow.INITIAL_BUY_IN -> tournamentEntryFee?.toCurrency() ?: NULL_TEXT
SessionRow.LOCATION -> location?.name ?: NULL_TEXT SessionRow.LOCATION -> location?.name ?: NULL_TEXT
SessionRow.PLAYERS -> tournamentNumberOfPlayers?.toString() ?: NULL_TEXT SessionRow.PLAYERS -> tournamentNumberOfPlayers?.toString() ?: NULL_TEXT
SessionRow.POSITION -> result?.tournamentFinalPosition?.toString() ?: NULL_TEXT SessionRow.POSITION -> result?.tournamentFinalPosition?.toString() ?: NULL_TEXT
SessionRow.START_DATE -> if (timeFrame != null) timeFrame?.startDate?.shortDateTime() SessionRow.START_DATE -> this.startDate.shortDateTime()
?: NULL_TEXT else NULL_TEXT
SessionRow.TABLE_SIZE -> this.tableSize?.let { TableSize(it).localizedTitle(context) } ?: NULL_TEXT SessionRow.TABLE_SIZE -> this.tableSize?.let { TableSize(it).localizedTitle(context) } ?: NULL_TEXT
SessionRow.TIPS -> result?.tips?.toCurrency() ?: NULL_TEXT SessionRow.TIPS -> result?.tips?.toCurrency() ?: NULL_TEXT
SessionRow.TOURNAMENT_TYPE -> tournamentType?.name ?: NULL_TEXT SessionRow.TOURNAMENT_TYPE -> tournamentType?.name ?: NULL_TEXT
@ -481,12 +527,12 @@ open class Session : RealmObject(), SessionInterface, Savable,
} }
SessionRow.BUY_IN -> { SessionRow.BUY_IN -> {
// Add first & second buttons values, current value & set the 2 edit texts // Add first & second buttons values, current value & set the 2 edit texts
if (cgBigBlind != null) { if (this.cgBigBlind != null) {
data.add(RowRepresentableEditDescriptor(100.0 * (cgBigBlind ?: 0.0))) data.add(RowRepresentableEditDescriptor(100.0 * (this.cgBigBlind ?: 0.0)))
data.add(RowRepresentableEditDescriptor(200.0 * (cgBigBlind ?: 0.0))) data.add(RowRepresentableEditDescriptor(200.0 * (this.cgBigBlind ?: 0.0)))
} else if (tournamentEntryFee != null) { } else if (this.tournamentEntryFee != null) {
data.add(RowRepresentableEditDescriptor((tournamentEntryFee ?: 0.0) * 1.0)) data.add(RowRepresentableEditDescriptor((this.tournamentEntryFee ?: 0.0) * 1.0))
data.add(RowRepresentableEditDescriptor((tournamentEntryFee ?: 0.0) * 2.0)) data.add(RowRepresentableEditDescriptor((this.tournamentEntryFee ?: 0.0) * 2.0))
} else { } else {
data.add(RowRepresentableEditDescriptor(0)) data.add(RowRepresentableEditDescriptor(0))
data.add(RowRepresentableEditDescriptor(0)) data.add(RowRepresentableEditDescriptor(0))
@ -596,10 +642,10 @@ open class Session : RealmObject(), SessionInterface, Savable,
cgBigBlind = null cgBigBlind = null
} }
SessionRow.BREAK_TIME -> { SessionRow.BREAK_TIME -> {
val timeFrameToUpdate = // val timeFrameToUpdate =
if (timeFrame != null) timeFrame as TimeFrame else realm.createObject(TimeFrame::class.java) // if (timeFrame != null) timeFrame as TimeFrame else realm.createObject(TimeFrame::class.java)
timeFrameToUpdate.breakDuration = if (value != null) (value as String).toLong() * 60 * 1000 else 0 this.breakDuration = if (value != null) (value as String).toLong() * 60 * 1000 else 0
timeFrame = timeFrameToUpdate // timeFrame = timeFrameToUpdate
} }
SessionRow.BUY_IN -> { SessionRow.BUY_IN -> {
val localResult = if (result != null) result as Result else realm.createObject(Result::class.java) val localResult = if (result != null) result as Result else realm.createObject(Result::class.java)
@ -613,10 +659,12 @@ open class Session : RealmObject(), SessionInterface, Savable,
localResult.cashout = null localResult.cashout = null
} else { } else {
localResult.cashout = (value as String).toDouble() localResult.cashout = (value as String).toDouble()
val timeFrameToUpdate = this.end()
if (timeFrame != null) timeFrame as TimeFrame else realm.createObject(TimeFrame::class.java)
timeFrameToUpdate.setEnd(Date()) // val timeFrameToUpdate =
timeFrame = timeFrameToUpdate // if (timeFrame != null) timeFrame as TimeFrame else realm.createObject(TimeFrame::class.java)
// timeFrameToUpdate.setEnd(Date())
// timeFrame = timeFrameToUpdate
} }
result = localResult result = localResult
@ -624,11 +672,13 @@ open class Session : RealmObject(), SessionInterface, Savable,
SessionRow.COMMENT -> comment = value as String? ?: "" SessionRow.COMMENT -> comment = value as String? ?: ""
SessionRow.END_DATE -> if (value is Date?) { SessionRow.END_DATE -> if (value is Date?) {
val timeFrameToUpdate = this.endDate = value
if (timeFrame != null) timeFrame as TimeFrame else realm.createObject(TimeFrame::class.java)
// timeFrameToUpdate.setDate(null, value) // val timeFrameToUpdate =
timeFrameToUpdate.setEnd(value) // if (timeFrame != null) timeFrame as TimeFrame else realm.createObject(TimeFrame::class.java)
timeFrame = timeFrameToUpdate //// timeFrameToUpdate.setDate(null, value)
// timeFrameToUpdate.setEnd(value)
// timeFrame = timeFrameToUpdate
} }
SessionRow.GAME -> { SessionRow.GAME -> {
if (value is ArrayList<*>) { if (value is ArrayList<*>) {
@ -655,16 +705,17 @@ open class Session : RealmObject(), SessionInterface, Savable,
localResult.tournamentFinalPosition = if (value == null) null else (value as String).toInt() localResult.tournamentFinalPosition = if (value == null) null else (value as String).toInt()
result = localResult result = localResult
} }
SessionRow.START_DATE -> if (value is Date?) { SessionRow.START_DATE -> if (value is Date) {
if (value == null) { this.startDate = value
timeFrame = null // if (value == null) {
} else { // timeFrame = null
val timeFrameToUpdate = // } else {
if (timeFrame != null) timeFrame as TimeFrame else realm.createObject(TimeFrame::class.java) // val timeFrameToUpdate =
timeFrameToUpdate.setStart(value) // if (timeFrame != null) timeFrame as TimeFrame else realm.createObject(TimeFrame::class.java)
// timeFrameToUpdate.setDate(value, null) // timeFrameToUpdate.setStart(value)
timeFrame = timeFrameToUpdate //// timeFrameToUpdate.setDate(value, null)
} // timeFrame = timeFrameToUpdate
// }
} }
SessionRow.TABLE_SIZE -> tableSize = value as Int? SessionRow.TABLE_SIZE -> tableSize = value as Int?
SessionRow.TIPS -> { SessionRow.TIPS -> {

@ -5,15 +5,41 @@ import io.realm.RealmObject
import io.realm.RealmResults import io.realm.RealmResults
import io.realm.annotations.Ignore import io.realm.annotations.Ignore
import io.realm.annotations.LinkingObjects import io.realm.annotations.LinkingObjects
import net.pokeranalytics.android.model.interfaces.Timed
import java.util.*
open class SessionSet() : RealmObject() { open class SessionSet : RealmObject(), Timed {
override var startDate: Date = Date()
set(value) {
field = value
this.computeDuration()
}
var endDate: Date = Date()
set(value) {
field = value
this.computeDuration()
}
override fun endDate(): Date {
return this.endDate
}
override var breakDuration: Long = 0L
set(value) {
field = value
this.computeDuration()
}
override var netDuration: Long = 0L
companion object { companion object {
fun newInstance(realm: Realm) : SessionSet { fun newInstance(realm: Realm) : SessionSet {
val sessionSet: SessionSet = realm.createObject(SessionSet::class.java) val sessionSet: SessionSet = realm.createObject(SessionSet::class.java)
sessionSet.timeFrame = realm.createObject(TimeFrame::class.java) // sessionSet.timeFrame = realm.createObject(TimeFrame::class.java)
return realm.copyToRealm(sessionSet) return realm.copyToRealm(sessionSet)
} }
@ -22,8 +48,7 @@ open class SessionSet() : RealmObject() {
/** /**
* The timeframe of the set, i.e. its start & end date * The timeframe of the set, i.e. its start & end date
*/ */
// var timeFrame: TimeFrame? = null
var timeFrame: TimeFrame? = null
/** /**
* The list of sessions associated with this set * The list of sessions associated with this set
@ -31,37 +56,17 @@ open class SessionSet() : RealmObject() {
@LinkingObjects("sessionSet") @LinkingObjects("sessionSet")
val sessions: RealmResults<Session>? = null val sessions: RealmResults<Session>? = null
@Ignore // a netDuration shortcut @Ignore
var duration: Long = 0L val netResult: Double = this.sessions?.sumByDouble { it.value } ?: 0.0
get() {
return this.timeFrame?.netDuration ?: 0L
}
@Ignore // a netDuration in hour
var hourlyDuration: Double = 0.0
get() {
return this.timeFrame?.hourlyDuration ?: 0.0
}
@Ignore // a netResult shortcut
var netResult: Double = 0.0
get () {
return this.sessions?.sumByDouble { it.value } ?: 0.0
}
@Ignore // a netDuration shortcut @Ignore
var hourlyRate: Double = 0.0 val hourlyRate: Double = this.netResult / this.hourlyDuration
get () {
return this.netResult / this.hourlyDuration
}
@Ignore @Ignore
var estimatedHands: Double = 25.0 * (this.timeFrame?.hourlyDuration?.toDouble() ?: 0.0) val estimatedHands: Double = 25.0 * this.hourlyDuration
@Ignore @Ignore
var bbNetResult: Double = 0.0 var bbNetResult: Double = 0.0
} }

@ -1,280 +1,288 @@
package net.pokeranalytics.android.model.realm //package net.pokeranalytics.android.model.realm
//
import io.realm.RealmObject //import io.realm.RealmObject
import io.realm.RealmQuery //import io.realm.RealmQuery
import io.realm.RealmResults //import io.realm.RealmResults
import io.realm.annotations.Ignore //import io.realm.annotations.Ignore
import io.realm.annotations.LinkingObjects //import io.realm.annotations.LinkingObjects
import net.pokeranalytics.android.exceptions.ModelException //import net.pokeranalytics.android.exceptions.ModelException
import timber.log.Timber //import timber.log.Timber
import java.util.* //import java.util.*
//
open class TimeFrame : RealmObject() { //open class TimeFrame : RealmObject() {
//
// A start date // // A start date
var startDate: Date = Date() // var startDate: Date = Date()
private set(value) { // private set(value) {
field = value // field = value
this.computeDuration() // this.computeDuration()
} // }
//
// An end date // // An end date
var endDate: Date? = null // var endDate: Date? = null
private set(value) { // private set(value) {
field = value // field = value
this.computeDuration() // this.computeDuration()
} // }
//
// The latest pause date // // The latest pause date
var pauseDate: Date? = null // var pauseDate: Date? = null
set(value) { // set(value) {
field?.let { // field?.let {
if (value == null && field != null) { // if (value == null && field != null) {
breakDuration += Date().time - it.time // breakDuration += Date().time - it.time
} // }
} // }
field = value // field = value
this.computeDuration() // this.computeDuration()
} // }
//
// The break netDuration // // The break netDuration
var breakDuration: Long = 0L // var breakDuration: Long = 0L
set(value) { // set(value) {
field = value // field = value
this.computeDuration() // this.computeDuration()
} // }
//
// the total netDuration // // the total netDuration
var netDuration: Long = 0L // var netDuration: Long = 0L
private set // private set
//
var hourlyDuration: Double = 0.0 // var hourlyDuration: Double = 0.0
get() { // get() {
return this.netDuration / 3600000.0 // 3.6 millions of milliseconds // return this.netDuration / 3600000.0 // 3.6 millions of milliseconds
} // }
//
// indicates a state of pause // // Session
var paused: Boolean = false // @LinkingObjects("timeFrame")
// private val sessions: RealmResults<Session>? = null // we should have only one session
// Session //
@LinkingObjects("timeFrame") // @Ignore
private val sessions: RealmResults<Session>? = null // we should have only one session // var session: Session? = null
// get() = if (this.sessions != null && this.sessions.isEmpty()) null else this.sessions?.first()
@Ignore //
var session: Session? = null // // Group
get() = if (this.sessions != null && this.sessions.isEmpty()) null else this.sessions?.first() // @LinkingObjects("timeFrame")
// private val sets: RealmResults<SessionSet>? = null // we should have only one sessionGroup
// Group //
@LinkingObjects("timeFrame") // @Ignore
private val sets: RealmResults<SessionSet>? = null // we should have only one sessionGroup // var set: SessionSet? = null
// get() = this.sets?.first()
@Ignore //
var set: SessionSet? = null // fun setStart(startDate: Date) {
get() = this.sets?.first() // this.startDate = startDate
// this.session?.let {
fun setStart(startDate: Date) { // this.notifySessionDateChange(it)
this.startDate = startDate // }
this.session?.let { // }
this.notifySessionDateChange(it) //
} // fun setEnd(endDate: Date?) {
} // this.endDate = endDate
// this.session?.let {
fun setEnd(endDate: Date?) { // this.notifySessionDateChange(it)
this.endDate = endDate // }
this.session?.let { // }
this.notifySessionDateChange(it) //
} // fun setDate(startDate: Date, endDate: Date?) {
} // this.startDate = startDate
// this.endDate = endDate
fun setDate(startDate: Date, endDate: Date?) { //
this.startDate = startDate // this.session?.let {
this.endDate = endDate // this.notifySessionDateChange(it)
// }
this.session?.let { // }
this.notifySessionDateChange(it) //
} // /**
} // * Computes the net netDuration of the session
// */
/** // private fun computeDuration() {
* Computes the net netDuration of the session // var endDate: Date = this.endDate ?: Date()
*/ // this.netDuration = endDate.time - this.startDate.time - this.breakDuration
private fun computeDuration() { // }
var endDate: Date = this.endDate ?: Date() //
this.netDuration = endDate.time - this.startDate.time - this.breakDuration // /**
} // * Queries all time frames that might be impacted by the date change
// * Makes all necessary changes to keep sequential time frames
/** // */
* Queries all time frames that might be impacted by the date change // fun notifySessionDateChange(owner: Session) {
* Makes all necessary changes to keep sequential time frames //
*/ // var query: RealmQuery<SessionSet> = this.realm.where(SessionSet::class.java)
fun notifySessionDateChange(owner: Session) { // query.isNotNull("timeFrame")
//
var query: RealmQuery<SessionSet> = this.realm.where(SessionSet::class.java) //// Timber.d("this> sd = : ${this.startDate}, ed = ${this.endDate}")
query.isNotNull("timeFrame") //
// val sets = realm.where(SessionSet::class.java).findAll()
// Timber.d("this> sd = : ${this.startDate}, ed = ${this.endDate}") //// Timber.d("set count = ${sets.size}")
//
val sets = realm.where(SessionSet::class.java).findAll() // if (this.endDate == null) {
// Timber.d("set count = ${sets.size}") // query.greaterThanOrEqualTo("timeFrame.startDate", this.startDate)
// .or()
if (this.endDate == null) { // .greaterThanOrEqualTo("timeFrame.endDate", this.startDate)
query.greaterThanOrEqualTo("timeFrame.startDate", this.startDate) // .or()
.or() // .isNull("timeFrame.endDate")
.greaterThanOrEqualTo("timeFrame.endDate", this.startDate) // } else {
.or() // val endDate = this.endDate!!
.isNull("timeFrame.endDate") // query
} else { // .lessThanOrEqualTo("timeFrame.startDate", this.startDate)
val endDate = this.endDate!! // .greaterThanOrEqualTo("timeFrame.endDate", this.startDate)
query // .or()
.lessThanOrEqualTo("timeFrame.startDate", this.startDate) // .lessThanOrEqualTo("timeFrame.startDate", endDate)
.greaterThanOrEqualTo("timeFrame.endDate", this.startDate) // .greaterThanOrEqualTo("timeFrame.endDate", endDate)
.or() // .or()
.lessThanOrEqualTo("timeFrame.startDate", endDate) // .greaterThanOrEqualTo("timeFrame.startDate", this.startDate)
.greaterThanOrEqualTo("timeFrame.endDate", endDate) // .lessThanOrEqualTo("timeFrame.endDate", endDate)
.or() // .or()
.greaterThanOrEqualTo("timeFrame.startDate", this.startDate) // .isNull("timeFrame.endDate")
.lessThanOrEqualTo("timeFrame.endDate", endDate) // .lessThanOrEqualTo("timeFrame.startDate", endDate)
.or() // }
.isNull("timeFrame.endDate") //
.lessThanOrEqualTo("timeFrame.startDate", endDate) // val sessionGroups = query.findAll()
} //
// this.updateTimeFrames(sessionGroups, owner)
val sessionGroups = query.findAll() //
// }
this.updateTimeFrames(sessionGroups, owner) //
// /**
} // * Update Time frames from sets
// */
/** // private fun updateTimeFrames(sessionSets: RealmResults<SessionSet>, owner: Session) {
* Update Time frames from sets //
*/ // when (sessionSets.size) {
private fun updateTimeFrames(sessionSets: RealmResults<SessionSet>, owner: Session) { // 0 -> this.createOrUpdateSessionSet(owner)
// 1 -> this.updateSessionGroup(owner, sessionSets.first()!!)
when (sessionSets.size) { // else -> this.mergeSessionGroups(owner, sessionSets)
0 -> this.createSessionGroup(owner) // }
1 -> this.updateSessionGroup(owner, sessionSets.first()!!) //
else -> this.mergeSessionGroups(owner, sessionSets) // }
} //
// /**
} // * Creates the session sessionGroup when the session has none
// */
/** // private fun createOrUpdateSessionSet(owner: Session) {
* Creates the session sessionGroup when the session has none //
*/ // val set = owner.sessionSet
private fun createSessionGroup(owner: Session) { // if (set != null) {
// set.timeFrame?.startDate = this.startDate
val set: SessionSet = SessionSet.newInstance(this.realm) // set.timeFrame?.endDate = this.endDate
set.timeFrame?.let { // } else {
it.startDate = this.startDate // this.createSessionSet(owner)
it.endDate = this.endDate // }
} ?: run { //
throw ModelException("TimeFrame should never be null here") //// Timber.d("sd = : ${set.timeFrame?.startDate}, ed = ${set.timeFrame?.endDate}")
} // Timber.d("netDuration 1 = : ${set?.timeFrame?.netDuration}")
//
owner.sessionSet = set // }
//
// Timber.d("sd = : ${set.timeFrame?.startDate}, ed = ${set.timeFrame?.endDate}") // fun createSessionSet(owner: Session) {
Timber.d("netDuration 1 = : ${set.timeFrame?.netDuration}") // val set: SessionSet = SessionSet.newInstance(this.realm)
// set.timeFrame?.let {
} // it.startDate = this.startDate
// it.endDate = this.endDate
/** // } ?: run {
* Single SessionSet update, the session might be the owner // throw ModelException("TimeFrame should never be null here")
* Changes the sessionGroup timeframe using the current timeframe dates // }
*/ //
private fun updateSessionGroup(owner: Session, sessionSet: SessionSet) { // owner.sessionSet = set
// }
var timeFrame: TimeFrame = sessionSet.timeFrame!! // tested in the query //
// timeFrame.setDate(this.startDate, this.endDate) //
// /**
val sisterSessions = sessionSet.sessions!! // shouldn't crash ever // * Single SessionSet update, the session might be the owner
// * Changes the sessionGroup timeframe using the current timeframe dates
// if we have only one session in the set and that it corresponds to the set // */
if (sessionSet.sessions?.size == 1 && sessionSet.sessions?.first() == owner) { // private fun updateSessionGroup(owner: Session, sessionSet: SessionSet) {
timeFrame.setDate(this.startDate, this.endDate) //
} else { // there are 2+ sessions to manage and possible splits // var timeFrame: TimeFrame = sessionSet.timeFrame!! // tested in the query
//// timeFrame.setDate(this.startDate, this.endDate)
val endDate = this.endDate //
// val sisterSessions = sessionSet.sessions!! // shouldn't crash ever
// case where all sessions are over but the set is not, we might have a split, so we delete the set and save everything again //
if (endDate != null && sisterSessions.all { it.timeFrame?.endDate != null } && timeFrame.endDate == null) { // // if we have only one session in the set and that it corresponds to the set
var sessions = mutableListOf<Session>(owner) // if (sessionSet.sessions?.size == 1 && sessionSet.sessions?.first() == owner) {
sessionSet.sessions?.forEach { sessions.add(it) } // timeFrame.setDate(this.startDate, this.endDate)
sessionSet.deleteFromRealm() // } else { // there are 2+ sessions to manage and possible splits
sessions.forEach { it.timeFrame?.notifySessionDateChange(it) } //
} else { // val endDate = this.endDate
//
if (this.startDate.before(timeFrame.startDate)) { // // case where all sessions are over but the set is not, we might have a split, so we delete the set and save everything again
timeFrame.startDate = this.startDate // if (endDate != null && sisterSessions.all { it.timeFrame?.endDate != null } && timeFrame.endDate == null) {
} // var sessions = mutableListOf<Session>(owner)
if (endDate != null && timeFrame.endDate != null && endDate.after(timeFrame.endDate)) { // sessionSet.sessions?.forEach { sessions.add(it) }
timeFrame.endDate = endDate // sessionSet.deleteFromRealm()
} else if (endDate == null) { // sessions.forEach { it.timeFrame?.notifySessionDateChange(it) }
timeFrame.endDate = null // } else {
} //
// if (this.startDate.before(timeFrame.startDate)) {
owner.sessionSet = sessionSet // timeFrame.startDate = this.startDate
// }
// Timber.d("sd = : ${sessionSet.timeFrame?.startDate}, ed = ${sessionSet.timeFrame?.endDate}") // if (endDate != null && timeFrame.endDate != null && endDate.after(timeFrame.endDate)) {
Timber.d("netDuration 2 = : ${sessionSet.timeFrame?.netDuration}") // timeFrame.endDate = endDate
} // } else if (endDate == null) {
// timeFrame.endDate = null
} // }
//
} // owner.sessionSet = sessionSet
//
/** //// Timber.d("sd = : ${sessionSet.timeFrame?.startDate}, ed = ${sessionSet.timeFrame?.endDate}")
* Multiple session sets update: // Timber.d("netDuration 2 = : ${sessionSet.timeFrame?.netDuration}")
* Merges all sets into one (delete all then create a new one) // }
*/ //
private fun mergeSessionGroups(owner: Session, sessionSets: RealmResults<SessionSet>) { // }
//
var startDate: Date = this.startDate // }
var endDate: Date? = this.endDate //
// /**
// find earlier and later dates from all sets // * Multiple session sets update:
val timeFrames = sessionSets.mapNotNull { it.timeFrame } // * Merges all sets into one (delete all then create a new one)
timeFrames.forEach { tf -> // */
if (tf.startDate.before(startDate)) { // private fun mergeSessionGroups(owner: Session, sessionSets: RealmResults<SessionSet>) {
startDate = tf.startDate //
} // var startDate: Date = this.startDate
// var endDate: Date? = this.endDate
endDate?.let { ed -> //
tf.endDate?.let { tfed -> // // find earlier and later dates from all sets
if (tfed.after(ed)) { // val timeFrames = sessionSets.mapNotNull { it.timeFrame }
endDate = tfed // timeFrames.forEach { tf ->
} // if (tf.startDate.before(startDate)) {
} // startDate = tf.startDate
} ?: run { // }
endDate = tf.endDate //
} // endDate?.let { ed ->
// tf.endDate?.let { tfed ->
} // if (tfed.after(ed)) {
// endDate = tfed
// get all sessions from sets // }
var sessions = mutableSetOf<Session>() // }
sessionSets.forEach { set -> // } ?: run {
set.sessions?.asIterable()?.let { sessions.addAll(it) } // endDate = tf.endDate
} // }
//
// delete all sets // }
sessionSets.deleteAllFromRealm() //
// // get all sessions from sets
// Create a new sets // var sessions = mutableSetOf<Session>()
val set: SessionSet = SessionSet.newInstance(this.realm) // sessionSets.forEach { set ->
set.timeFrame?.let { // set.sessions?.asIterable()?.let { sessions.addAll(it) }
it.setDate(startDate, endDate) // }
} ?: run { //
throw ModelException("TimeFrame should never be null here") // // delete all sets
} // sessionSets.deleteAllFromRealm()
//
// Add the session linked to this timeframe to the new sessionGroup // // Create a new sets
owner.sessionSet = set // val set: SessionSet = SessionSet.newInstance(this.realm)
// set.timeFrame?.let {
// Add all orphan sessions // it.setDate(startDate, endDate)
sessions.forEach { it.sessionSet = set } // } ?: run {
Timber.d("netDuration 3 = : ${set.timeFrame?.netDuration}") // throw ModelException("TimeFrame should never be null here")
// }
} //
// // Add the session linked to this timeframe to the new sessionGroup
} // owner.sessionSet = set
//
// // Add all orphan sessions
// sessions.forEach { it.sessionSet = set }
// Timber.d("netDuration 3 = : ${set.timeFrame?.netDuration}")
//
// }
//
//}

@ -106,7 +106,7 @@ class FavoriteSessionFinder {
lastSessionsQuery.equalTo("location.id", location.id) lastSessionsQuery.equalTo("location.id", location.id)
} }
val lastSessions = lastSessionsQuery val lastSessions = lastSessionsQuery
.sort("timeFrame.startDate", Sort.DESCENDING) .sort("startDate", Sort.DESCENDING)
.limit(FAVORITE_SIGNIFICANT_SESSIONS) .limit(FAVORITE_SIGNIFICANT_SESSIONS)
.findAll() .findAll()

@ -0,0 +1,140 @@
package net.pokeranalytics.android.model.utils
import io.realm.RealmQuery
import io.realm.RealmResults
import net.pokeranalytics.android.model.realm.Session
import net.pokeranalytics.android.model.realm.SessionSet
class SessionSetManager {
companion object {
fun updateTimeline(session: Session) {
if (!session.realm.isInTransaction) {
throw IllegalStateException("realm should be in transaction at this point")
}
if (session.endDate == null) {
throw IllegalStateException("End date should never be null here")
}
val endDate = session.endDate!! // tested above
val startDate = session.startDate
val realm = session.realm
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)
val sessionGroups = query.findAll()
this.updateTimeFrames(sessionGroups, session)
}
/**
* Update Time frames from sets
*/
private fun updateTimeFrames(sessionSets: RealmResults<SessionSet>, session: Session) {
when (sessionSets.size) {
0 -> this.createOrUpdateSessionSet(session)
else -> this.mergeSessionGroups(session, sessionSets)
}
}
private fun createOrUpdateSessionSet(session: Session) {
val set = session.sessionSet
if (set != null) {
set.startDate = session.startDate
set.endDate = session.endDate!!
} else {
this.createSessionSet(session)
}
}
private fun createSessionSet(session: Session) {
val set: SessionSet = SessionSet.newInstance(session.realm)
set.startDate = session.startDate
set.endDate = session.endDate!!
session.sessionSet = set
}
/**
* Multiple session sets update:
* Merges all sets into one (delete all then create a new one)
*/
private fun mergeSessionGroups(session: Session, sessionSets: RealmResults<SessionSet>) {
var startDate = session.startDate
var endDate = session.endDate!!
// find earlier and later dates from all sets
sessionSets.forEach { set ->
if (set.startDate.before(startDate)) {
startDate = set.startDate
}
if (set.endDate.after(endDate)) {
endDate = set.endDate
}
}
// get all sessions from sets
val sessions = mutableSetOf<Session>()
sessionSets.forEach { set ->
set.sessions?.asIterable()?.let { sessions.addAll(it) }
}
// delete all sets
sessionSets.deleteAllFromRealm()
// Create a new set
val set: SessionSet = SessionSet.newInstance(session.realm)
set.startDate = startDate
set.endDate = endDate
// Add the session linked to this timeframe to the new sessionGroup
session.sessionSet = set
// Add all orphan sessions
sessions.forEach { it.sessionSet = set }
// Timber.d("netDuration 3 = : ${set.timeFrame?.netDuration}")
}
fun removeFromTimeline(session: Session) {
if (!session.realm.isInTransaction) {
throw IllegalStateException("realm should be in transaction at this point")
}
val sessionSet = session.sessionSet
if (sessionSet != null) {
val sessions = mutableSetOf<Session>()
sessionSet.sessions?.asIterable()?.let { sessions.addAll(it) }
sessions.remove(session)
sessionSet.deleteFromRealm()
sessions.forEach {
SessionSetManager.updateTimeline(it)
}
}
}
}
}

@ -90,13 +90,13 @@ class SessionFragment : PokerAnalyticsFragment(), RowRepresentableDelegate, Bott
requireContext(), requireContext(),
row, row,
this, this,
currentSession.timeFrame?.startDate ?: Date() currentSession.startDate
) )
SessionRow.END_DATE -> DateTimePickerManager.create( SessionRow.END_DATE -> DateTimePickerManager.create(
requireContext(), requireContext(),
row, row,
this, this,
currentSession.timeFrame?.endDate ?: currentSession.timeFrame?.startDate ?: Date() currentSession.endDate ?: currentSession.startDate ?: Date()
) )
SessionRow.BANKROLL -> { SessionRow.BANKROLL -> {
BottomSheetFragment.create(fragmentManager, row, this, data, false) BottomSheetFragment.create(fragmentManager, row, this, data, false)

@ -16,7 +16,6 @@ import net.pokeranalytics.android.ui.adapter.RowRepresentableAdapter
import net.pokeranalytics.android.ui.adapter.StaticRowRepresentableDataSource import net.pokeranalytics.android.ui.adapter.StaticRowRepresentableDataSource
import net.pokeranalytics.android.ui.fragment.components.SessionObserverFragment import net.pokeranalytics.android.ui.fragment.components.SessionObserverFragment
import net.pokeranalytics.android.ui.view.RowRepresentable import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.RowViewType
import net.pokeranalytics.android.ui.view.rowrepresentable.HeaderRowRepresentable import net.pokeranalytics.android.ui.view.rowrepresentable.HeaderRowRepresentable
import net.pokeranalytics.android.util.NULL_TEXT import net.pokeranalytics.android.util.NULL_TEXT
@ -111,7 +110,7 @@ class StatsFragment : SessionObserverFragment(), StaticRowRepresentableDataSourc
} }
} }
val allStats: List<Stat> = listOf(Stat.NETRESULT, Stat.HOURLY_RATE, Stat.AVERAGE, Stat.NUMBER_OF_GAMES, Stat.AVERAGE_DURATION, Stat.DURATION) val allStats: List<Stat> = listOf(Stat.NETRESULT, Stat.HOURLY_RATE, Stat.AVERAGE, Stat.NUMBER_OF_SETS, Stat.AVERAGE_DURATION, Stat.DURATION)
val allSessionGroup = SessionGroup(getString(R.string.all), super.sessions, allStats) val allSessionGroup = SessionGroup(getString(R.string.all), super.sessions, allStats)
val cgStats: List<Stat> = listOf(Stat.NETRESULT, Stat.HOURLY_RATE, Stat.NET_BB_PER_100_HANDS, Stat.HOURLY_RATE_BB, Stat.AVERAGE, Stat.STANDARD_DEVIATION_HOURLY, Stat.WIN_RATIO, Stat.NUMBER_OF_GAMES, Stat.AVERAGE_BUYIN) val cgStats: List<Stat> = listOf(Stat.NETRESULT, Stat.HOURLY_RATE, Stat.NET_BB_PER_100_HANDS, Stat.HOURLY_RATE_BB, Stat.AVERAGE, Stat.STANDARD_DEVIATION_HOURLY, Stat.WIN_RATIO, Stat.NUMBER_OF_GAMES, Stat.AVERAGE_BUYIN)
val cgSessionGroup = SessionGroup(getString(R.string.cash_game), cgSessions, cgStats) val cgSessionGroup = SessionGroup(getString(R.string.cash_game), cgSessions, cgStats)

@ -10,7 +10,7 @@ open class SessionObserverFragment : PokerAnalyticsFragment() {
init { init {
val realm = Realm.getDefaultInstance() val realm = Realm.getDefaultInstance()
this.sessions = realm.where(Session::class.java).isNotNull("timeFrame.endDate").findAll() this.sessions = realm.where(Session::class.java).isNotNull("endDate").findAll()
this.sessions.addChangeListener { _, _ -> this.sessions.addChangeListener { _, _ ->
this.sessionsChanged() this.sessionsChanged()
} }

@ -95,11 +95,13 @@ class SessionRowView : FrameLayout {
rowHistorySession.sessionTitle.text = title rowHistorySession.sessionTitle.text = title
// Duration // Duration
rowHistorySession.sessionInfoDurationIcon.isVisible = session.timeFrame != null // rowHistorySession.sessionInfoDurationIcon.isVisible = session.timeFrame != null
rowHistorySession.sessionInfoDurationValue.isVisible = session.timeFrame != null // rowHistorySession.sessionInfoDurationValue.isVisible = session.timeFrame != null
session.timeFrame?.let { // session.timeFrame?.let {
rowHistorySession.sessionInfoDurationValue.text = session.getDuration() // rowHistorySession.sessionInfoDurationValue.text = session.getDuration()
} // }
rowHistorySession.sessionInfoDurationValue.text = session.getDuration()
// Location // Location
rowHistorySession.sessionInfoLocationIcon.isVisible = session.location != null rowHistorySession.sessionInfoLocationIcon.isVisible = session.location != null
@ -127,7 +129,7 @@ class SessionRowView : FrameLayout {
rowHistorySession.infoIcon.isVisible = true rowHistorySession.infoIcon.isVisible = true
rowHistorySession.infoIcon.setImageResource(R.drawable.ic_planned) rowHistorySession.infoIcon.setImageResource(R.drawable.ic_planned)
rowHistorySession.infoTitle.isVisible = true rowHistorySession.infoTitle.isVisible = true
rowHistorySession.infoTitle.text = session.timeFrame?.startDate?.shortTime() rowHistorySession.infoTitle.text = session.startDate.shortTime()
} else { } else {
rowHistorySession.gameResult.isVisible = true rowHistorySession.gameResult.isVisible = true
rowHistorySession.infoIcon.isVisible = false rowHistorySession.infoIcon.isVisible = false

@ -8,7 +8,7 @@
<!-- Stats --> <!-- Stats -->
<string name="hourly_rate">Hourly Rate</string> <string name="hourly_rate">Hourly Rate</string>
<string name="number_of_groups">Number of groups</string> <string name="number_of_groups">Number of sessions</string>
<string name="number_of_games">Number of games</string> <string name="number_of_games">Number of games</string>
<string name="average_duration">Average duration</string> <string name="average_duration">Average duration</string>
<string name="net_bb_per_100_hands">Net(BB) per 100 hands</string> <string name="net_bb_per_100_hands">Net(BB) per 100 hands</string>

Loading…
Cancel
Save