Merge branch 'dev' of gitlab.com:stax-river/poker-analytics into dev

# Conflicts:
#	app/src/main/java/net/pokeranalytics/android/ui/fragment/SettingsFragment.kt
feature/top10
Aurelien Hubert 7 years ago
commit ae519a700a
  1. 46
      app/src/androidTest/java/net/pokeranalytics/android/unitTests/BankrollInstrumentedUnitTest.kt
  2. 39
      app/src/androidTest/java/net/pokeranalytics/android/unitTests/filter/BlindFilterInstrumentedTest.kt
  3. 40
      app/src/androidTest/java/net/pokeranalytics/android/unitTests/filter/DateFilterInstrumentedUnitTest.kt
  4. 20
      app/src/androidTest/java/net/pokeranalytics/android/unitTests/filter/SessionFilterInstrumentedUnitTest.kt
  5. 3
      app/src/main/java/net/pokeranalytics/android/PokerAnalyticsApplication.kt
  6. 16
      app/src/main/java/net/pokeranalytics/android/calculus/Calculator.kt
  7. 13
      app/src/main/java/net/pokeranalytics/android/calculus/Report.kt
  8. 18
      app/src/main/java/net/pokeranalytics/android/calculus/Stat.kt
  9. 83
      app/src/main/java/net/pokeranalytics/android/model/filter/QueryCondition.kt
  10. 5
      app/src/main/java/net/pokeranalytics/android/model/interfaces/Timed.kt
  11. 4
      app/src/main/java/net/pokeranalytics/android/model/migrations/PokerAnalyticsMigration.kt
  12. 12
      app/src/main/java/net/pokeranalytics/android/model/realm/Bankroll.kt
  13. 12
      app/src/main/java/net/pokeranalytics/android/model/realm/Currency.kt
  14. 10
      app/src/main/java/net/pokeranalytics/android/model/realm/Filter.kt
  15. 37
      app/src/main/java/net/pokeranalytics/android/model/realm/FilterCondition.kt
  16. 8
      app/src/main/java/net/pokeranalytics/android/model/realm/FilterElementBlind.kt
  17. 82
      app/src/main/java/net/pokeranalytics/android/model/realm/Session.kt
  18. 6
      app/src/main/java/net/pokeranalytics/android/model/realm/SessionSet.kt
  19. 7
      app/src/main/java/net/pokeranalytics/android/model/utils/Seed.kt
  20. 8
      app/src/main/java/net/pokeranalytics/android/ui/fragment/BankrollDataFragment.kt
  21. 25
      app/src/main/java/net/pokeranalytics/android/ui/fragment/GraphFragment.kt
  22. 5
      app/src/main/java/net/pokeranalytics/android/ui/fragment/SessionFragment.kt
  23. 10
      app/src/main/java/net/pokeranalytics/android/ui/fragment/SettingsFragment.kt
  24. 19
      app/src/main/java/net/pokeranalytics/android/ui/view/LegendView.kt
  25. 11
      app/src/main/java/net/pokeranalytics/android/ui/view/RowViewType.kt
  26. 13
      app/src/main/java/net/pokeranalytics/android/ui/view/SessionRowView.kt
  27. 6
      app/src/main/java/net/pokeranalytics/android/ui/view/TransactionRowView.kt
  28. 10
      app/src/main/java/net/pokeranalytics/android/ui/view/fields/FieldsExtension.kt
  29. 2
      app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/FilterCategoryRow.kt
  30. 19
      app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/FilterElementRow.kt
  31. 33
      app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/FilterSectionRow.kt
  32. 64
      app/src/main/java/net/pokeranalytics/android/util/CurrencyUtils.kt
  33. 92
      app/src/main/java/net/pokeranalytics/android/util/Preferences.kt
  34. 11
      app/src/main/java/net/pokeranalytics/android/util/extensions/NumbersExtension.kt

@ -28,53 +28,7 @@ class BankrollInstrumentedUnitTest : RealmInstrumentedUnitTest() {
@Test @Test
fun testSessionStats() { fun testSessionStats() {
val realm = this.mockRealm
realm.beginTransaction()
val s1 = newSessionInstance(realm)
val s2 = newSessionInstance(realm)
val br1 = realm.createObject(Bankroll::class.java, "1")
val br2 = realm.createObject(Bankroll::class.java, "2")
val c1 = realm.createObject(Currency::class.java, "1")
val c2 = realm.createObject(Currency::class.java, "2")
c1.rate = 0.1
c2.rate = 2.0
br1.currency = c1
br2.currency = c2
s1.bankroll = br1
s2.bankroll = br2
s1.result?.netResult = 100.0
s2.result?.netResult = 200.0
realm.commitTransaction()
val computableResults = realm.where(ComputableResult::class.java).findAll()
val sets = realm.where(SessionSet::class.java).findAll()
val stats: List<Stat> = listOf(Stat.NETRESULT, Stat.AVERAGE)
val group = ComputableGroup("test", computableResults, sets, stats)
val options = Calculator.Options()
val results: ComputedResults = Calculator.compute(group, options)
val delta = 0.01
val sum = results.computedStat(Stat.NETRESULT)
if (sum != null) {
Assert.assertEquals(410.0, sum.value, delta)
} else {
Assert.fail("No Net result stat")
}
val average = results.computedStat(Stat.AVERAGE)
if (average != null) {
Assert.assertEquals(205.0, average.value, delta)
} else {
Assert.fail("No AVERAGE stat")
}
} }

@ -21,7 +21,7 @@ class BlindFilterInstrumentedTest : BaseFilterInstrumentedUnitTest() {
realm.beginTransaction() realm.beginTransaction()
val currency = realm.createObject(net.pokeranalytics.android.model.realm.Currency::class.java, "1") val currency = realm.createObject(net.pokeranalytics.android.model.realm.Currency::class.java, "1")
currency.code = "AUD" currency.code = "USD"
val b1 = realm.createObject(Bankroll::class.java, "1") val b1 = realm.createObject(Bankroll::class.java, "1")
val b2 = realm.createObject(Bankroll::class.java, "2") val b2 = realm.createObject(Bankroll::class.java, "2")
@ -42,9 +42,9 @@ class BlindFilterInstrumentedTest : BaseFilterInstrumentedUnitTest() {
realm.commitTransaction() realm.commitTransaction()
val filter = QueryCondition.BLINDS val filter = QueryCondition.BLIND
val blind = FilterElementRow.Blind(0.5, 1.0, null) val blind = FilterElementRow.Blind(s1.blinds!!, true)
blind.filterSectionRow = FilterSectionRow.BLINDS blind.filterSectionRow = FilterSectionRow.BLIND
val filterElement = FilterCondition(filterElementRows = arrayListOf(blind)) val filterElement = FilterCondition(filterElementRows = arrayListOf(blind))
filter.updateValueMap(filterElement) filter.updateValueMap(filterElement)
@ -86,12 +86,14 @@ class BlindFilterInstrumentedTest : BaseFilterInstrumentedUnitTest() {
realm.commitTransaction() realm.commitTransaction()
val filter = QueryCondition.BLINDS val filter = QueryCondition.BLIND
val blind = FilterElementRow.Blind(null, 1.0, null) val blind1 = FilterElementRow.Blind(s1.blinds!!, true)
blind.filterSectionRow = FilterSectionRow.BLINDS val blind2 = FilterElementRow.Blind(s2.blinds!!, true)
blind1.filterSectionRow = FilterSectionRow.BLIND
blind2.filterSectionRow = FilterSectionRow.BLIND
val filterElement = FilterCondition(filterElementRows = arrayListOf(blind)) val filterElements = FilterCondition(filterElementRows = arrayListOf(blind1, blind2))
filter.updateValueMap(filterElement) filter.updateValueMap(filterElements)
val sessions = Filter.queryOn<Session>(realm, arrayListOf(filter)) val sessions = Filter.queryOn<Session>(realm, arrayListOf(filter))
@ -108,13 +110,14 @@ class BlindFilterInstrumentedTest : BaseFilterInstrumentedUnitTest() {
realm.beginTransaction() realm.beginTransaction()
val currency = realm.createObject(net.pokeranalytics.android.model.realm.Currency::class.java, "1") val currency = realm.createObject(net.pokeranalytics.android.model.realm.Currency::class.java, "1")
currency.code = "AUD" currency.code = "USD"
val b1 = realm.createObject(Bankroll::class.java, "1") val b1 = realm.createObject(Bankroll::class.java, "1")
val b2 = realm.createObject(Bankroll::class.java, "2") val b2 = realm.createObject(Bankroll::class.java, "2")
b2.currency = currency b2.currency = currency
val s1 = Session.testInstance(100.0, false, Date(), 1, b1) val s1 = Session.testInstance(100.0, false, Date(), 1, b1)
s1.cgBigBlind = 1.0 s1.cgBigBlind = 1.0
s1.cgSmallBlind = 0.5 s1.cgSmallBlind = 0.5
@ -129,9 +132,9 @@ class BlindFilterInstrumentedTest : BaseFilterInstrumentedUnitTest() {
realm.commitTransaction() realm.commitTransaction()
val filter = QueryCondition.BLINDS val filter = QueryCondition.BLIND
val blind = FilterElementRow.Blind(1.0, 2.0, "AUD") val blind = FilterElementRow.Blind(s3.blinds!!, false)
blind.filterSectionRow = FilterSectionRow.BLINDS blind.filterSectionRow = FilterSectionRow.BLIND
val filterElement = FilterCondition(filterElementRows = arrayListOf(blind)) val filterElement = FilterCondition(filterElementRows = arrayListOf(blind))
filter.updateValueMap(filterElement) filter.updateValueMap(filterElement)
@ -172,12 +175,12 @@ class BlindFilterInstrumentedTest : BaseFilterInstrumentedUnitTest() {
realm.commitTransaction() realm.commitTransaction()
val filter = QueryCondition.BLINDS val filter = QueryCondition.BLIND
val blind1 = FilterElementRow.Blind(1.0, 2.0, null) val blind1 = FilterElementRow.Blind(s1.blinds!!, false)
blind1.filterSectionRow = FilterSectionRow.BLINDS blind1.filterSectionRow = FilterSectionRow.BLIND
val blind2 = FilterElementRow.Blind(0.5, 1.0, null) val blind2 = FilterElementRow.Blind(s2.blinds!!, false)
blind2.filterSectionRow = FilterSectionRow.BLINDS blind2.filterSectionRow = FilterSectionRow.BLIND
val filterElement = FilterCondition(filterElementRows = arrayListOf(blind1, blind2)) val filterElement = FilterCondition(filterElementRows = arrayListOf(blind1, blind2))
filter.updateValueMap(filterElement) filter.updateValueMap(filterElement)

@ -35,14 +35,14 @@ class DateFilterInstrumentedUnitTest : BaseFilterInstrumentedUnitTest() {
val filterElementRow = FilterElementRow.Day(cal.get(Calendar.DAY_OF_WEEK)) val filterElementRow = FilterElementRow.Day(cal.get(Calendar.DAY_OF_WEEK))
filterElementRow.filterSectionRow = FilterSectionRow.DYNAMIC_DATE filterElementRow.filterSectionRow = FilterSectionRow.DYNAMIC_DATE
val filterElement = FilterCondition(filterElementRow) val filterElement = FilterCondition(arrayListOf(filterElementRow))
filter.updateValueMap(filterElement) filter.updateValueMap(filterElement)
val sessions = Filter.queryOn<Session>(realm, arrayListOf(filter)) val sessions = Filter.queryOn<Session>(realm, arrayListOf(filter))
Assert.assertEquals(1, sessions.size) Assert.assertEquals(1, sessions.size)
sessions[0]?.run { sessions[0]?.run {
Assert.assertEquals(s1.id, (this as Session).id) Assert.assertEquals(s1.id, (this).id)
} }
} }
@ -64,14 +64,14 @@ class DateFilterInstrumentedUnitTest : BaseFilterInstrumentedUnitTest() {
val filterElementRow = FilterElementRow.Month(cal.get(Calendar.MONTH)) val filterElementRow = FilterElementRow.Month(cal.get(Calendar.MONTH))
filterElementRow.filterSectionRow = FilterSectionRow.DYNAMIC_DATE filterElementRow.filterSectionRow = FilterSectionRow.DYNAMIC_DATE
val filterElement = FilterCondition(filterElementRow) val filterElement = FilterCondition(arrayListOf(filterElementRow))
filter.updateValueMap(filterElement) filter.updateValueMap(filterElement)
val sessions = Filter.queryOn<Session>(realm, arrayListOf(filter)) val sessions = Filter.queryOn<Session>(realm, arrayListOf(filter))
Assert.assertEquals(1, sessions.size) Assert.assertEquals(1, sessions.size)
sessions[0]?.run { sessions[0]?.run {
Assert.assertEquals(s1.id, (this as Session).id) Assert.assertEquals(s1.id, (this).id)
} }
} }
@ -92,14 +92,14 @@ class DateFilterInstrumentedUnitTest : BaseFilterInstrumentedUnitTest() {
cal.time = s1.startDate cal.time = s1.startDate
val filterElementRow = FilterElementRow.Year(cal.get(Calendar.YEAR)) val filterElementRow = FilterElementRow.Year(cal.get(Calendar.YEAR))
filterElementRow.filterSectionRow = FilterSectionRow.DYNAMIC_DATE filterElementRow.filterSectionRow = FilterSectionRow.DYNAMIC_DATE
val filterElement = FilterCondition(filterElementRow) val filterElement = FilterCondition(arrayListOf(filterElementRow))
filter.updateValueMap(filterElement) filter.updateValueMap(filterElement)
val sessions = Filter.queryOn<Session>(realm, arrayListOf(filter)) val sessions = Filter.queryOn<Session>(realm, arrayListOf(filter))
Assert.assertEquals(1, sessions.size) Assert.assertEquals(1, sessions.size)
sessions[0]?.run { sessions[0]?.run {
Assert.assertEquals(s1.id, (this as Session).id) Assert.assertEquals(s1.id, (this).id)
} }
} }
@ -122,7 +122,7 @@ class DateFilterInstrumentedUnitTest : BaseFilterInstrumentedUnitTest() {
Assert.assertEquals(1, sessions.size) Assert.assertEquals(1, sessions.size)
sessions[0]?.run { sessions[0]?.run {
Assert.assertEquals(s1.id, (this as Session).id) Assert.assertEquals(s1.id, (this).id)
} }
} }
@ -147,7 +147,7 @@ class DateFilterInstrumentedUnitTest : BaseFilterInstrumentedUnitTest() {
Assert.assertEquals(1, sessions.size) Assert.assertEquals(1, sessions.size)
sessions[0]?.run { sessions[0]?.run {
Assert.assertEquals(s1.id, (this as Session).id) Assert.assertEquals(s1.id, (this).id)
} }
} }
@ -384,15 +384,15 @@ class DateFilterInstrumentedUnitTest : BaseFilterInstrumentedUnitTest() {
realm.commitTransaction() realm.commitTransaction()
val filter = QueryCondition.STARTED_FROM_DATE val filter = QueryCondition.STARTED_FROM_DATE
val filterElementRow = FilterElementRow.From(s2.startDate!!) val filterElementRow = FilterElementRow.From.apply { dateValue = s2.startDate!!}
filterElementRow.filterSectionRow = FilterSectionRow.FIXED_DATE filterElementRow.filterSectionRow = FilterSectionRow.FIXED_DATE
filter.updateValueMap(FilterCondition(filterElementRow)) filter.updateValueMap(FilterCondition(arrayListOf(filterElementRow)))
val sessions = Filter.queryOn<Session>(realm, arrayListOf(filter)) val sessions = Filter.queryOn<Session>(realm, arrayListOf(filter))
Assert.assertEquals(1, sessions.size) Assert.assertEquals(1, sessions.size)
sessions[0]?.run { sessions[0]?.run {
Assert.assertEquals(s2.id, (this as Session).id) Assert.assertEquals(s2.id, (this).id)
} }
} }
@ -412,15 +412,15 @@ class DateFilterInstrumentedUnitTest : BaseFilterInstrumentedUnitTest() {
realm.commitTransaction() realm.commitTransaction()
val filter = QueryCondition.STARTED_TO_DATE val filter = QueryCondition.STARTED_TO_DATE
val filterElementRow = FilterElementRow.From(s1.startDate!!) val filterElementRow = FilterElementRow.From.apply { dateValue = s1.startDate!! }
filterElementRow.filterSectionRow = FilterSectionRow.FIXED_DATE filterElementRow.filterSectionRow = FilterSectionRow.FIXED_DATE
filter.updateValueMap(FilterCondition(filterElementRow)) filter.updateValueMap(FilterCondition(arrayListOf(filterElementRow)))
val sessions = Filter.queryOn<Session>(realm, arrayListOf(filter)) val sessions = Filter.queryOn<Session>(realm, arrayListOf(filter))
Assert.assertEquals(1, sessions.size) Assert.assertEquals(1, sessions.size)
sessions[0]?.run { sessions[0]?.run {
Assert.assertEquals(s1.id, (this as Session).id) Assert.assertEquals(s1.id, (this).id)
} }
} }
@ -441,15 +441,15 @@ class DateFilterInstrumentedUnitTest : BaseFilterInstrumentedUnitTest() {
realm.commitTransaction() realm.commitTransaction()
val filter = QueryCondition.ENDED_FROM_DATE val filter = QueryCondition.ENDED_FROM_DATE
val filterElementRow = FilterElementRow.From(s2.endDate()) val filterElementRow = FilterElementRow.From.apply { dateValue = s2.endDate() }
filterElementRow.filterSectionRow = FilterSectionRow.FIXED_DATE filterElementRow.filterSectionRow = FilterSectionRow.FIXED_DATE
filter.updateValueMap(FilterCondition(filterElementRow)) filter.updateValueMap(FilterCondition(arrayListOf(filterElementRow)))
val sessions = Filter.queryOn<Session>(realm, arrayListOf(filter)) val sessions = Filter.queryOn<Session>(realm, arrayListOf(filter))
Assert.assertEquals(1, sessions.size) Assert.assertEquals(1, sessions.size)
sessions[0]?.run { sessions[0]?.run {
Assert.assertEquals(s2.id, (this as Session).id) Assert.assertEquals(s2.id, (this).id)
} }
} }
@ -470,15 +470,15 @@ class DateFilterInstrumentedUnitTest : BaseFilterInstrumentedUnitTest() {
val filter = QueryCondition.ENDED_TO_DATE val filter = QueryCondition.ENDED_TO_DATE
val filterElementRow = FilterElementRow.From(s1.endDate()) val filterElementRow = FilterElementRow.From.apply { dateValue = s1.endDate() }
filterElementRow.filterSectionRow = FilterSectionRow.FIXED_DATE filterElementRow.filterSectionRow = FilterSectionRow.FIXED_DATE
filter.updateValueMap(FilterCondition(filterElementRow)) filter.updateValueMap(FilterCondition(arrayListOf(filterElementRow)))
val sessions = Filter.queryOn<Session>(realm, arrayListOf(filter)) val sessions = Filter.queryOn<Session>(realm, arrayListOf(filter))
Assert.assertEquals(1, sessions.size) Assert.assertEquals(1, sessions.size)
sessions[0]?.run { sessions[0]?.run {
Assert.assertEquals(s1.id, (this as Session).id) Assert.assertEquals(s1.id, (this).id)
} }
} }
} }

@ -30,7 +30,7 @@ class SessionFilterInstrumentedUnitTest : BaseFilterInstrumentedUnitTest() {
Assert.assertEquals(1, sessions.size) Assert.assertEquals(1, sessions.size)
sessions[0]?.run { sessions[0]?.run {
Assert.assertEquals(Session.Type.CASH_GAME.ordinal, (this as Session).type) Assert.assertEquals(Session.Type.CASH_GAME.ordinal, (this).type)
} }
} }
@ -48,7 +48,7 @@ class SessionFilterInstrumentedUnitTest : BaseFilterInstrumentedUnitTest() {
Assert.assertEquals(1, sessions.size) Assert.assertEquals(1, sessions.size)
sessions[0]?.run { sessions[0]?.run {
Assert.assertEquals(Session.Type.TOURNAMENT.ordinal, (this as Session).type) Assert.assertEquals(Session.Type.TOURNAMENT.ordinal, (this).type)
} }
} }
@ -480,9 +480,9 @@ class SessionFilterInstrumentedUnitTest : BaseFilterInstrumentedUnitTest() {
realm.commitTransaction() realm.commitTransaction()
val filter = QueryCondition.MORE_THAN_NET_RESULT val filter = QueryCondition.MORE_THAN_NET_RESULT
val filterElementRow = FilterElementRow.ResultMoreThan(204.0) val filterElementRow = FilterElementRow.ResultMoreThan.apply { this.amount = 204.0 }
filterElementRow.filterSectionRow = FilterSectionRow.VALUE filterElementRow.filterSectionRow = FilterSectionRow.VALUE
filter.updateValueMap(FilterCondition(filterElementRow)) filter.updateValueMap(FilterCondition(arrayListOf(filterElementRow)))
val sessions = Filter.queryOn<Session>(realm, arrayListOf(filter)) val sessions = Filter.queryOn<Session>(realm, arrayListOf(filter))
@ -505,9 +505,9 @@ class SessionFilterInstrumentedUnitTest : BaseFilterInstrumentedUnitTest() {
realm.commitTransaction() realm.commitTransaction()
val filter = QueryCondition.LESS_THAN_NET_RESULT val filter = QueryCondition.LESS_THAN_NET_RESULT
val filterElementRow = FilterElementRow.ResultLessThan(540.0) val filterElementRow = FilterElementRow.ResultMoreThan.apply { this.amount = 540.0 }
filterElementRow.filterSectionRow = FilterSectionRow.VALUE filterElementRow.filterSectionRow = FilterSectionRow.VALUE
filter.updateValueMap(FilterCondition(filterElementRow)) filter.updateValueMap(FilterCondition(arrayListOf(filterElementRow)))
val sessions = Filter.queryOn<Session>(realm, arrayListOf(filter)) val sessions = Filter.queryOn<Session>(realm, arrayListOf(filter))
@ -530,14 +530,14 @@ class SessionFilterInstrumentedUnitTest : BaseFilterInstrumentedUnitTest() {
realm.commitTransaction() realm.commitTransaction()
val filterMore = QueryCondition.MORE_THAN_NET_RESULT val filterMore = QueryCondition.MORE_THAN_NET_RESULT
val filterElementRow = FilterElementRow.ResultMoreThan(200.0) val filterElementRow = FilterElementRow.ResultMoreThan.apply { this.amount = 200.0 }
filterElementRow.filterSectionRow = FilterSectionRow.VALUE filterElementRow.filterSectionRow = FilterSectionRow.VALUE
filterMore.updateValueMap(FilterCondition(filterElementRow)) filterMore.updateValueMap(FilterCondition(arrayListOf(filterElementRow)))
val filterLess = QueryCondition.LESS_THAN_NET_RESULT val filterLess = QueryCondition.LESS_THAN_NET_RESULT
val filterElementRow2 = FilterElementRow.ResultLessThan(400.0) val filterElementRow2 = FilterElementRow.ResultMoreThan.apply { this.amount = 400.0 }
filterElementRow2.filterSectionRow = FilterSectionRow.VALUE filterElementRow2.filterSectionRow = FilterSectionRow.VALUE
filterLess.updateValueMap(FilterCondition(filterElementRow2)) filterLess.updateValueMap(FilterCondition(arrayListOf(filterElementRow2)))
val sessions = Filter.queryOn<Session>(realm, arrayListOf(filterMore, filterLess)) val sessions = Filter.queryOn<Session>(realm, arrayListOf(filterMore, filterLess))

@ -14,6 +14,7 @@ import net.pokeranalytics.android.model.realm.Session
import net.pokeranalytics.android.model.utils.Seed import net.pokeranalytics.android.model.utils.Seed
import net.pokeranalytics.android.util.FakeDataManager import net.pokeranalytics.android.util.FakeDataManager
import net.pokeranalytics.android.util.PokerAnalyticsLogs import net.pokeranalytics.android.util.PokerAnalyticsLogs
import net.pokeranalytics.android.util.UserDefaults
import timber.log.Timber import timber.log.Timber
@ -22,6 +23,8 @@ class PokerAnalyticsApplication : Application() {
override fun onCreate() { override fun onCreate() {
super.onCreate() super.onCreate()
UserDefaults.init(this)
println("UserPreferences.defaultCurrency: ${UserDefaults.currency.symbol}")
// Realm // Realm
Realm.init(this) Realm.init(this)

@ -147,19 +147,19 @@ class Calculator {
tHands += computable.estimatedHands tHands += computable.estimatedHands
val session = computable.session ?: throw IllegalStateException("Computing lone ComputableResult") val session = computable.session ?: throw IllegalStateException("Computing lone ComputableResult")
results.addEvolutionValue(tSum, NETRESULT, session) results.addEvolutionValue(tSum, stat = NETRESULT, data = session)
results.addEvolutionValue(tSum / index, AVERAGE, session) results.addEvolutionValue(tSum / index, stat = AVERAGE, data = session)
results.addEvolutionValue(index.toDouble(), NUMBER_OF_GAMES, session) results.addEvolutionValue(index.toDouble(), stat = NUMBER_OF_GAMES, data = session)
results.addEvolutionValue(tBBSum / tBBSessionCount, AVERAGE_NET_BB, session) results.addEvolutionValue(tBBSum / tBBSessionCount, stat = AVERAGE_NET_BB, data = session)
results.addEvolutionValue((tWinningSessionCount / index).toDouble(), WIN_RATIO, session) results.addEvolutionValue((tWinningSessionCount / index).toDouble(), stat = WIN_RATIO, data = session)
results.addEvolutionValue(tBuyinSum / index, AVERAGE_BUYIN, session) results.addEvolutionValue(tBuyinSum / index, stat = AVERAGE_BUYIN, data = session)
Stat.netBBPer100Hands(tBBSum, tHands)?.let { netBB100 -> Stat.netBBPer100Hands(tBBSum, tHands)?.let { netBB100 ->
results.addEvolutionValue(netBB100, NET_BB_PER_100_HANDS, session) results.addEvolutionValue(netBB100, stat = NET_BB_PER_100_HANDS, data = session)
} }
Stat.returnOnInvestment(tSum, tBuyinSum)?.let { roi -> Stat.returnOnInvestment(tSum, tBuyinSum)?.let { roi ->
results.addEvolutionValue(roi, ROI, session) results.addEvolutionValue(roi, stat = ROI, data = session)
} }
} }

@ -158,13 +158,14 @@ class ComputedResults(group: ComputableGroup) {
/** /**
* Adds a value to the evolution values * Adds a value to the evolution values
*/ */
fun addEvolutionValue(value: Double, stat: Stat, data: Any) { fun addEvolutionValue(value: Double, duration: Double? = null, stat: Stat, data: Timed) {
this._addEvolutionValue(Point(value, data), stat = stat)
}
fun addEvolutionValue(value: Double, duration: Double, stat: Stat, data: Timed) { val point = if (duration != null) {
stat.underlyingClass = data::class.java Point(duration, y = value, data = data.objectIdentifier)
this._addEvolutionValue(Point(value, y = duration, data = data.id), stat = stat) } else {
Point(value, data = data.objectIdentifier)
}
this._addEvolutionValue(point, stat = stat)
} }
private fun _addEvolutionValue(point: Point, stat: Stat) { private fun _addEvolutionValue(point: Point, stat: Stat) {

@ -1,23 +1,27 @@
package net.pokeranalytics.android.calculus package net.pokeranalytics.android.calculus
import android.content.Context import android.content.Context
import io.realm.RealmModel
import net.pokeranalytics.android.R import net.pokeranalytics.android.R
import net.pokeranalytics.android.exceptions.FormattingException import net.pokeranalytics.android.exceptions.FormattingException
import net.pokeranalytics.android.model.interfaces.Identifiable
import net.pokeranalytics.android.model.interfaces.Timed import net.pokeranalytics.android.model.interfaces.Timed
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.RowViewType
import net.pokeranalytics.android.util.CurrencyUtils
import net.pokeranalytics.android.util.NULL_TEXT import net.pokeranalytics.android.util.NULL_TEXT
import net.pokeranalytics.android.util.extensions.formatted import net.pokeranalytics.android.util.extensions.formatted
import net.pokeranalytics.android.util.extensions.formattedHourlyDuration import net.pokeranalytics.android.util.extensions.formattedHourlyDuration
import net.pokeranalytics.android.util.extensions.toCurrency
import java.util.* import java.util.*
class StatFormattingException(message: String) : Exception(message) { class StatFormattingException(message: String) : Exception(message) {
} }
interface StatBase : RealmModel { class ObjectIdentifier(var id: String, var clazz: Class<out Timed>) {
}
interface StatBase : Identifiable {
fun formattedValue(stat: Stat, context: Context): TextFormat fun formattedValue(stat: Stat, context: Context): TextFormat
@ -48,7 +52,7 @@ enum class AggregationType {
/** /**
* An enum representing all the types of Session statistics * An enum representing all the types of Session statistics
*/ */
enum class Stat(var underlyingClass: Class<out Timed>? = null) : RowRepresentable { enum class Stat : RowRepresentable {
NETRESULT, NETRESULT,
HOURLY_RATE, HOURLY_RATE,
@ -132,9 +136,8 @@ enum class Stat(var underlyingClass: Class<out Timed>? = null) : RowRepresentabl
when (this) { when (this) {
// Amounts + red/green // Amounts + red/green
Stat.NETRESULT, Stat.HOURLY_RATE, Stat.AVERAGE -> { Stat.NETRESULT, Stat.HOURLY_RATE, Stat.AVERAGE -> {
val numberFormat = CurrencyUtils.getCurrencyFormatter(context, currency)
val color = if (value >= this.threshold) R.color.green else R.color.red val color = if (value >= this.threshold) R.color.green else R.color.red
return TextFormat(numberFormat.format(value), color) return TextFormat(value.toCurrency(currency), color)
} }
// Red/green numericValues // Red/green numericValues
Stat.HOURLY_RATE_BB, Stat.AVERAGE_NET_BB, Stat.NET_BB_PER_100_HANDS -> { Stat.HOURLY_RATE_BB, Stat.AVERAGE_NET_BB, Stat.NET_BB_PER_100_HANDS -> {
@ -154,8 +157,7 @@ enum class Stat(var underlyingClass: Class<out Timed>? = null) : RowRepresentabl
} // white amountsr } // white amountsr
Stat.AVERAGE_BUYIN, Stat.STANDARD_DEVIATION, Stat.STANDARD_DEVIATION_HOURLY, Stat.AVERAGE_BUYIN, Stat.STANDARD_DEVIATION, Stat.STANDARD_DEVIATION_HOURLY,
Stat.STANDARD_DEVIATION_BB_PER_100_HANDS -> { Stat.STANDARD_DEVIATION_BB_PER_100_HANDS -> {
val numberFormat = CurrencyUtils.getCurrencyFormatter(context, currency) return TextFormat(value.toCurrency(currency))
return TextFormat(numberFormat.format(value))
} }
else -> throw FormattingException("Stat formatting of ${this.name} not handled") else -> throw FormattingException("Stat formatting of ${this.name} not handled")
} }

@ -1,12 +1,9 @@
package net.pokeranalytics.android.model.filter package net.pokeranalytics.android.model.filter
import io.realm.RealmList
import io.realm.RealmQuery import io.realm.RealmQuery
import net.pokeranalytics.android.exceptions.PokerAnalyticsException import net.pokeranalytics.android.exceptions.PokerAnalyticsException
import net.pokeranalytics.android.model.realm.FilterCondition import net.pokeranalytics.android.model.realm.FilterCondition
import net.pokeranalytics.android.model.realm.FilterElementBlind
import net.pokeranalytics.android.model.realm.Session import net.pokeranalytics.android.model.realm.Session
import net.pokeranalytics.android.util.Preferences
import net.pokeranalytics.android.util.extensions.endOfDay import net.pokeranalytics.android.util.extensions.endOfDay
import net.pokeranalytics.android.util.extensions.startOfDay import net.pokeranalytics.android.util.extensions.startOfDay
import java.util.* import java.util.*
@ -32,7 +29,7 @@ enum class QueryCondition(var operator: Operator? = null) {
LIMIT, LIMIT,
TABLE_SIZE, TABLE_SIZE,
TOURNAMENT_TYPE, TOURNAMENT_TYPE,
BLINDS, BLIND,
LAST_GAMES, LAST_GAMES,
LAST_SESSIONS, LAST_SESSIONS,
MORE_NUMBER_OF_TABLE(Operator.MORE), MORE_NUMBER_OF_TABLE(Operator.MORE),
@ -77,10 +74,6 @@ enum class QueryCondition(var operator: Operator? = null) {
STARTED_FROM_TIME, STARTED_FROM_TIME,
ENDED_TO_TIME, ENDED_TO_TIME,
CURRENCY,
CURRENCY_CODE,
BIG_BLIND,
SMALL_BLIND,
COMMENT, COMMENT,
; ;
@ -118,7 +111,7 @@ enum class QueryCondition(var operator: Operator? = null) {
return when (this) { return when (this) {
BANKROLL, GAME, LOCATION, ANY_TOURNAMENT_FEATURES, ALL_TOURNAMENT_FEATURES, TOURNAMENT_NAME -> arrayOf("ids") BANKROLL, GAME, LOCATION, ANY_TOURNAMENT_FEATURES, ALL_TOURNAMENT_FEATURES, TOURNAMENT_NAME -> arrayOf("ids")
LIMIT, TOURNAMENT_TYPE, TABLE_SIZE -> arrayOf("values") LIMIT, TOURNAMENT_TYPE, TABLE_SIZE -> arrayOf("values")
BLINDS -> arrayOf("blinds") BLIND -> arrayOf("blinds", "hasDefaultCurrency")
STARTED_FROM_DATE, STARTED_TO_DATE, ENDED_FROM_DATE, ENDED_TO_DATE -> arrayOf("date") STARTED_FROM_DATE, STARTED_TO_DATE, ENDED_FROM_DATE, ENDED_TO_DATE -> arrayOf("date")
DAY_OF_WEEK -> arrayOf("dayOfWeek") DAY_OF_WEEK -> arrayOf("dayOfWeek")
MONTH -> arrayOf("month") MONTH -> arrayOf("month")
@ -132,50 +125,8 @@ enum class QueryCondition(var operator: Operator? = null) {
* providing a base RealmQuery [realmQuery], the method is able to attached the corresponding query and returns the newly formed [RealmQuery] * providing a base RealmQuery [realmQuery], the method is able to attached the corresponding query and returns the newly formed [RealmQuery]
*/ */
inline fun <reified T : Filterable> filter(realmQuery: RealmQuery<T>): RealmQuery<T> { inline fun <reified T : Filterable> filter(realmQuery: RealmQuery<T>): RealmQuery<T> {
when {
this == BLINDS -> {
val smallBlindFieldName = FilterHelper.fieldNameForQueryType<T>(SMALL_BLIND)
val bigBlindFieldName = FilterHelper.fieldNameForQueryType<T>(BIG_BLIND)
val currencyCodeFieldName = FilterHelper.fieldNameForQueryType<T>(CURRENCY_CODE)
smallBlindFieldName ?: throw PokerAnalyticsException.QueryValueMapUnknown
bigBlindFieldName ?: throw PokerAnalyticsException.QueryValueMapUnknown
currencyCodeFieldName ?: throw PokerAnalyticsException.QueryValueMapUnknown
val blinds: RealmList<FilterElementBlind> by valueMap
blinds.forEachIndexed { index, blind ->
realmQuery
.beginGroup()
blind.sb?.let {
realmQuery
.equalTo(smallBlindFieldName, it)
.and()
}
realmQuery
.equalTo(bigBlindFieldName, blind.bb)
.and()
blind.currencyCode?.let {
realmQuery.equalTo(currencyCodeFieldName, it)
} ?: run {
realmQuery.isNull(currencyCodeFieldName)
}
realmQuery.endGroup()
if (index < blinds.size - 1) {
realmQuery.or()
}
}
return realmQuery
}
else -> {
val fieldName = FilterHelper.fieldNameForQueryType<T>(this) val fieldName = FilterHelper.fieldNameForQueryType<T>(this)
fieldName ?: throw PokerAnalyticsException.QueryValueMapUnknown fieldName ?: throw PokerAnalyticsException.QueryValueMapUnknown
when (operator) { when (operator) {
Operator.LESS -> { Operator.LESS -> {
val value: Double by valueMap val value: Double by valueMap
@ -207,6 +158,27 @@ enum class QueryCondition(var operator: Operator? = null) {
val ids: Array<String> by valueMap val ids: Array<String> by valueMap
realmQuery.`in`(fieldName, ids) realmQuery.`in`(fieldName, ids)
} }
BLIND -> {
val blinds: Array<String> by valueMap
val hasDefaultCurrency: Array<Boolean> by valueMap
//realmQuery.`in`(fieldName, blinds)
blinds.forEachIndexed { index, s ->
val isUsingDefaultCurrency = hasDefaultCurrency[index]
realmQuery.beginGroup()
if (isUsingDefaultCurrency) {
realmQuery.endsWith(fieldName, s)
.and()
.isNull("bankroll.currency.code")
} else {
realmQuery.equalTo(fieldName, s)
}
.endGroup()
if (index < blinds.size - 1) {
realmQuery.or()
}
}
realmQuery
}
BANKROLL, GAME, LOCATION, TOURNAMENT_NAME -> { BANKROLL, GAME, LOCATION, TOURNAMENT_NAME -> {
val ids: Array<String> by valueMap val ids: Array<String> by valueMap
realmQuery.`in`(fieldName, ids) realmQuery.`in`(fieldName, ids)
@ -293,9 +265,6 @@ enum class QueryCondition(var operator: Operator? = null) {
} }
} }
} }
}
}
fun updateValueMap(filterCondition: FilterCondition) { fun updateValueMap(filterCondition: FilterCondition) {
if (filterValuesExpectedKeys == null) { if (filterValuesExpectedKeys == null) {
@ -314,8 +283,10 @@ enum class QueryCondition(var operator: Operator? = null) {
LIMIT, TOURNAMENT_TYPE, TABLE_SIZE -> { LIMIT, TOURNAMENT_TYPE, TABLE_SIZE -> {
valueMap = mapOf("values" to filterCondition.values) valueMap = mapOf("values" to filterCondition.values)
} }
BLINDS -> { BLIND -> {
valueMap = mapOf("blinds" to filterCondition.blinds) valueMap = mapOf(
"blinds" to filterCondition.blinds,
"hasDefaultCurrency" to filterCondition.hasDefaultCurrency)
} }
STARTED_FROM_DATE, STARTED_TO_DATE, ENDED_FROM_DATE, ENDED_TO_DATE -> { STARTED_FROM_DATE, STARTED_TO_DATE, ENDED_FROM_DATE, ENDED_TO_DATE -> {
valueMap = mapOf("date" to filterCondition.date) valueMap = mapOf("date" to filterCondition.date)

@ -1,9 +1,10 @@
package net.pokeranalytics.android.model.interfaces package net.pokeranalytics.android.model.interfaces
import net.pokeranalytics.android.calculus.ObjectIdentifier
import net.pokeranalytics.android.calculus.StatBase import net.pokeranalytics.android.calculus.StatBase
import java.util.* import java.util.*
interface Timed : StatBase, Identifiable { interface Timed : StatBase {
fun startDate() : Date? fun startDate() : Date?
@ -29,4 +30,6 @@ interface Timed : StatBase, Identifiable {
val hourlyDuration: Double val hourlyDuration: Double
get() = this.netDuration / 3600000.0 get() = this.netDuration / 3600000.0
val objectIdentifier : ObjectIdentifier
} }

@ -35,7 +35,9 @@ class PokerAnalyticsMigration : RealmMigration {
// Migrate to version 2 // Migrate to version 2
if (currentVersion == 1) { if (currentVersion == 1) {
Timber.d("*** Running migration ${currentVersion + 1}") Timber.d("*** Running migration ${currentVersion + 1}")
schema.get("Session")?.let {
it.addField("blinds", String::class.java).setNullable("blinds", true)
}
schema.rename("FilterElement", "FilterCondition") schema.rename("FilterElement", "FilterCondition")
schema.get("Filter")?.let { schema.get("Filter")?.let {
it.renameField("filterElements", "filterConditions") it.renameField("filterElements", "filterConditions")

@ -3,6 +3,8 @@ package net.pokeranalytics.android.model.realm
import io.realm.Realm import io.realm.Realm
import io.realm.RealmList import io.realm.RealmList
import io.realm.RealmObject import io.realm.RealmObject
import io.realm.RealmResults
import io.realm.annotations.LinkingObjects
import io.realm.annotations.PrimaryKey import io.realm.annotations.PrimaryKey
import io.realm.kotlin.where import io.realm.kotlin.where
import net.pokeranalytics.android.R import net.pokeranalytics.android.R
@ -32,6 +34,9 @@ open class Bankroll() : RealmObject(), NameManageable, StaticRowRepresentableDat
} }
} }
@LinkingObjects("bankroll")
private val sessions: RealmResults<Session>? = null
@PrimaryKey @PrimaryKey
override var id = UUID.randomUUID().toString() override var id = UUID.randomUUID().toString()
@ -46,6 +51,12 @@ open class Bankroll() : RealmObject(), NameManageable, StaticRowRepresentableDat
// The currency of the bankroll // The currency of the bankroll
var currency: Currency? = null var currency: Currency? = null
fun currencyCodeHasBeenUpdated() {
sessions?.forEach {
it.bankrollHasBeenUpdated()
}
}
override fun getDisplayName(): String { override fun getDisplayName(): String {
return this.name return this.name
} }
@ -86,6 +97,7 @@ open class Bankroll() : RealmObject(), NameManageable, StaticRowRepresentableDat
this.live = if (value is Boolean) !value else false this.live = if (value is Boolean) !value else false
} }
BankrollRow.CURRENCY -> { BankrollRow.CURRENCY -> {
//TODO handle a use default currency option
this.currency?.code = value as String? this.currency?.code = value as String?
} }
BankrollRow.RATE -> { BankrollRow.RATE -> {

@ -1,8 +1,11 @@
package net.pokeranalytics.android.model.realm package net.pokeranalytics.android.model.realm
import io.realm.RealmObject import io.realm.RealmObject
import io.realm.RealmResults
import io.realm.annotations.Ignore import io.realm.annotations.Ignore
import io.realm.annotations.LinkingObjects
import io.realm.annotations.PrimaryKey import io.realm.annotations.PrimaryKey
import net.pokeranalytics.android.util.Preferences
import java.util.* import java.util.*
open class Currency : RealmObject() { open class Currency : RealmObject() {
@ -13,10 +16,19 @@ open class Currency : RealmObject() {
@PrimaryKey @PrimaryKey
var id = UUID.randomUUID().toString() var id = UUID.randomUUID().toString()
@LinkingObjects("currency")
private val bankrolls: RealmResults<Bankroll>? = null
/** /**
* The currency code of the currency, i.e. USD, EUR... * The currency code of the currency, i.e. USD, EUR...
*/ */
var code: String? = null var code: String? = null
set(value) {
field = value
bankrolls?.forEach {
it.currencyCodeHasBeenUpdated()
}
}
/** /**
* The rate of the currency with the main currency * The rate of the currency with the main currency

@ -65,7 +65,7 @@ open class Filter : RealmObject() {
private set private set
fun createOrUpdateFilterConditions(filterConditionRows: ArrayList<FilterElementRow>) { fun createOrUpdateFilterConditions(filterConditionRows: ArrayList<FilterElementRow>) {
filterConditions.clear() val casted = arrayListOf<FilterElementRow>()
filterConditionRows filterConditionRows
.map { .map {
it.filterName it.filterName
@ -77,9 +77,13 @@ open class Filter : RealmObject() {
it.filterName == filterName it.filterName == filterName
} }
.apply { .apply {
val casted = arrayListOf<FilterElementRow>()
casted.addAll(this) casted.addAll(this)
filterConditions.add(FilterCondition(casted)) val newFilterCondition = FilterCondition(casted)
val previousCondition = filterConditions.filter {
it.sectionName == newFilterCondition.filterName
}
filterConditions.removeAll(previousCondition)
filterConditions.add(newFilterCondition)
} }
} }
} }

@ -23,6 +23,19 @@ open class FilterCondition() : RealmObject() {
is DateFilterElementRow -> { is DateFilterElementRow -> {
this.dateValue = row.dateValue this.dateValue = row.dateValue
} }
is Blind -> {
//TODO refactor raz
this.stringValues = RealmList<String>().apply {
this.addAll(filterElementRows.map {
(it as Blind).blind
})
}
this.booleanValues = RealmList<Boolean>().apply {
this.addAll(filterElementRows.map {
(it as Blind).hasDefaultCurrency
})
}
}
is StringFilterElementRow -> { is StringFilterElementRow -> {
this.stringValues = RealmList<String>().apply { this.stringValues = RealmList<String>().apply {
this.addAll(filterElementRows.map { this.addAll(filterElementRows.map {
@ -37,13 +50,6 @@ open class FilterCondition() : RealmObject() {
}) })
} }
} }
is FilterElementBlind -> {
this.blindValues = RealmList<FilterElementBlind>().apply {
this.addAll(filterElementRows.map {
FilterElementBlind((it as FilterElementRow.Blind).sb, it.bb, it.code)
})
}
}
} }
} }
@ -59,23 +65,16 @@ open class FilterCondition() : RealmObject() {
private var numericValues: RealmList<Double>? = null private var numericValues: RealmList<Double>? = null
private var dateValue: Date? = null private var dateValue: Date? = null
private var stringValues: RealmList<String>? = null private var stringValues: RealmList<String>? = null
private var blindValues: RealmList<FilterElementBlind>? = null private var booleanValues: RealmList<Boolean>? = null
val ids: Array<String> val ids: Array<String>
get() = stringValues?.toTypedArray() ?: throw PokerAnalyticsException.FilterElementExpectedValueMissing get() = stringValues?.toTypedArray() ?: throw PokerAnalyticsException.FilterElementExpectedValueMissing
val blinds: RealmList<FilterElementBlind> val blinds: Array<String>
get() { get() = stringValues?.toTypedArray() ?: throw PokerAnalyticsException.FilterElementExpectedValueMissing
blindValues?.let {
if (it.isNotEmpty()) {
return it
} else {
throw PokerAnalyticsException.FilterElementExpectedValueMissing
}
}
throw PokerAnalyticsException.FilterElementExpectedValueMissing
}
val hasDefaultCurrency: Array<Boolean>
get() = booleanValues?.toTypedArray() ?: throw PokerAnalyticsException.FilterElementExpectedValueMissing
val date: Date val date: Date
get() = dateValue ?: throw PokerAnalyticsException.FilterElementExpectedValueMissing get() = dateValue ?: throw PokerAnalyticsException.FilterElementExpectedValueMissing

@ -1,8 +0,0 @@
package net.pokeranalytics.android.model.realm
import io.realm.RealmObject
open class FilterElementBlind(var sb : Double? = null,
var bb : Double? = null,
var currencyCode : String? = null
) : RealmObject()

@ -11,10 +11,7 @@ import io.realm.annotations.LinkingObjects
import io.realm.annotations.PrimaryKey import io.realm.annotations.PrimaryKey
import io.realm.kotlin.where import io.realm.kotlin.where
import net.pokeranalytics.android.R import net.pokeranalytics.android.R
import net.pokeranalytics.android.calculus.ComputedStat import net.pokeranalytics.android.calculus.*
import net.pokeranalytics.android.calculus.Stat
import net.pokeranalytics.android.calculus.StatFormattingException
import net.pokeranalytics.android.calculus.TextFormat
import net.pokeranalytics.android.exceptions.ModelException import net.pokeranalytics.android.exceptions.ModelException
import net.pokeranalytics.android.model.Limit import net.pokeranalytics.android.model.Limit
import net.pokeranalytics.android.model.LiveData import net.pokeranalytics.android.model.LiveData
@ -35,8 +32,8 @@ import net.pokeranalytics.android.ui.view.RowViewType
import net.pokeranalytics.android.ui.view.rowrepresentable.CustomizableRowRepresentable import net.pokeranalytics.android.ui.view.rowrepresentable.CustomizableRowRepresentable
import net.pokeranalytics.android.ui.view.rowrepresentable.SeparatorRowRepresentable import net.pokeranalytics.android.ui.view.rowrepresentable.SeparatorRowRepresentable
import net.pokeranalytics.android.ui.view.rowrepresentable.SessionRow import net.pokeranalytics.android.ui.view.rowrepresentable.SessionRow
import net.pokeranalytics.android.util.CurrencyUtils
import net.pokeranalytics.android.util.NULL_TEXT import net.pokeranalytics.android.util.NULL_TEXT
import net.pokeranalytics.android.util.UserDefaults
import net.pokeranalytics.android.util.extensions.* import net.pokeranalytics.android.util.extensions.*
import java.util.* import java.util.*
import java.util.Currency import java.util.Currency
@ -47,7 +44,6 @@ typealias BB = Double
open class Session : RealmObject(), Savable, Editable, StaticRowRepresentableDataSource, RowRepresentable, Timed, open class Session : RealmObject(), Savable, Editable, StaticRowRepresentableDataSource, RowRepresentable, Timed,
TimeFilterable, Filterable { TimeFilterable, Filterable {
enum class Type { enum class Type {
CASH_GAME, CASH_GAME,
TOURNAMENT TOURNAMENT
@ -78,10 +74,7 @@ open class Session : RealmObject(), Savable, Editable, StaticRowRepresentableDat
LIMIT -> "limit" LIMIT -> "limit"
TABLE_SIZE -> "tableSize" TABLE_SIZE -> "tableSize"
TOURNAMENT_TYPE -> "tournamentType" TOURNAMENT_TYPE -> "tournamentType"
CURRENCY -> "bankroll.currency" BLIND -> "blind"
CURRENCY_CODE -> "bankroll.currency.code"
BIG_BLIND -> "cgBigBlind"
SMALL_BLIND -> "cgSmallBlind"
COMMENT -> "comment" COMMENT -> "comment"
BETWEEN_NUMBER_OF_TABLE, MORE_NUMBER_OF_TABLE, LESS_NUMBER_OF_TABLE -> "numberOfTable" BETWEEN_NUMBER_OF_TABLE, MORE_NUMBER_OF_TABLE, LESS_NUMBER_OF_TABLE -> "numberOfTable"
MORE_THAN_NET_RESULT, LESS_THAN_NET_RESULT -> "computableResults.ratedNet" MORE_THAN_NET_RESULT, LESS_THAN_NET_RESULT -> "computableResults.ratedNet"
@ -220,14 +213,22 @@ open class Session : RealmObject(), Savable, Editable, StaticRowRepresentableDat
// The small blind value // The small blind value
var cgSmallBlind: Double? = null var cgSmallBlind: Double? = null
set(value) {
field = value
formatBlinds()
}
// The big blind value // The big blind value
var cgBigBlind: Double? = null var cgBigBlind: Double? = null
set(value) { set(value) {
field = value field = value
this.computeStats() this.computeStats()
formatBlinds()
} }
var blinds: String? = null
private set
// Tournament // Tournament
// The entry fee of the tournament // The entry fee of the tournament
@ -245,6 +246,10 @@ open class Session : RealmObject(), Savable, Editable, StaticRowRepresentableDat
// The features of the tournament, like Knockout, Shootout, Turbo... // The features of the tournament, like Knockout, Shootout, Turbo...
var tournamentFeatures: RealmList<TournamentFeature> = RealmList() var tournamentFeatures: RealmList<TournamentFeature> = RealmList()
fun bankrollHasBeenUpdated() {
formatBlinds()
}
/** /**
* 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
@ -482,13 +487,18 @@ open class Session : RealmObject(), Savable, Editable, StaticRowRepresentableDat
return NULL_TEXT return NULL_TEXT
} }
/** val hasDefaultCurrency: Boolean
* Return the formatted blinds get() {
*/ return bankroll?.currency?.code == null
fun getBlinds(): String { }
val currencyCode = bankroll?.currency?.code ?: CurrencyUtils.getLocaleCurrency().currencyCode
val currencySymbol = Currency.getInstance(currencyCode).symbol val currency : Currency
return if (cgSmallBlind == null) NULL_TEXT else "$currencySymbol ${cgSmallBlind?.formatted()}/${cgBigBlind?.round()}" get() {
return bankroll?.currency?.code?.let {
Currency.getInstance(it)
} ?: run {
UserDefaults.currency
}
} }
/** /**
@ -508,6 +518,19 @@ open class Session : RealmObject(), Savable, Editable, StaticRowRepresentableDat
return if (gameTitle.isNotBlank()) gameTitle else NULL_TEXT return if (gameTitle.isNotBlank()) gameTitle else NULL_TEXT
} }
fun getFormattedBlinds(): String {
return blinds ?: NULL_TEXT
}
private fun formatBlinds() {
blinds = null
if (cgBigBlind == null) return
cgBigBlind?.let { bb ->
val sb = cgSmallBlind ?: bb / 2.0
blinds = "${currency.symbol} ${sb.formatted()}/${bb.round()}"
}
}
// LifeCycle // LifeCycle
/** /**
@ -558,7 +581,7 @@ open class Session : RealmObject(), Savable, Editable, StaticRowRepresentableDat
CustomizableRowRepresentable( CustomizableRowRepresentable(
RowViewType.HEADER_TITLE_AMOUNT_BIG, RowViewType.HEADER_TITLE_AMOUNT_BIG,
title = getFormattedDuration(), title = getFormattedDuration(),
computedStat = ComputedStat(Stat.NETRESULT, result?.net ?: 0.0, CurrencyUtils.getCurrency(bankroll)) computedStat = ComputedStat(Stat.NETRESULT, result?.net ?: 0.0, currency)
) )
) )
rows.add(SeparatorRowRepresentable()) rows.add(SeparatorRowRepresentable())
@ -568,7 +591,7 @@ open class Session : RealmObject(), Savable, Editable, StaticRowRepresentableDat
CustomizableRowRepresentable( CustomizableRowRepresentable(
RowViewType.HEADER_TITLE_AMOUNT_BIG, RowViewType.HEADER_TITLE_AMOUNT_BIG,
resId = R.string.pause, resId = R.string.pause,
computedStat = ComputedStat(Stat.NETRESULT, result?.net ?: 0.0, CurrencyUtils.getCurrency(bankroll)) computedStat = ComputedStat(Stat.NETRESULT, result?.net ?: 0.0, currency)
) )
) )
rows.add(SeparatorRowRepresentable()) rows.add(SeparatorRowRepresentable())
@ -578,14 +601,14 @@ open class Session : RealmObject(), Savable, Editable, StaticRowRepresentableDat
CustomizableRowRepresentable( CustomizableRowRepresentable(
RowViewType.HEADER_TITLE_AMOUNT_BIG, RowViewType.HEADER_TITLE_AMOUNT_BIG,
title = getFormattedDuration(), title = getFormattedDuration(),
computedStat = ComputedStat(Stat.NETRESULT, result?.net ?: 0.0, CurrencyUtils.getCurrency(bankroll)) computedStat = ComputedStat(Stat.NETRESULT, result?.net ?: 0.0, currency)
) )
) )
rows.add( rows.add(
CustomizableRowRepresentable( CustomizableRowRepresentable(
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, CurrencyUtils.getCurrency(bankroll)) computedStat = ComputedStat(Stat.HOURLY_RATE, this.hourlyRate, currency)
) )
) )
@ -624,20 +647,20 @@ open class Session : RealmObject(), Savable, Editable, StaticRowRepresentableDat
override fun stringForRow(row: RowRepresentable, context: Context): String { override fun stringForRow(row: RowRepresentable, context: Context): String {
return when (row) { return when (row) {
SessionRow.BANKROLL -> bankroll?.name ?: NULL_TEXT SessionRow.BANKROLL -> bankroll?.name ?: NULL_TEXT
SessionRow.BLINDS -> getBlinds() SessionRow.BLINDS -> getFormattedBlinds()
SessionRow.BREAK_TIME -> if (this.breakDuration > 0.0) this.breakDuration.toMinutes() else NULL_TEXT SessionRow.BREAK_TIME -> if (this.breakDuration > 0.0) this.breakDuration.toMinutes() else NULL_TEXT
SessionRow.BUY_IN -> this.result?.buyin?.toCurrency(CurrencyUtils.getCurrency(bankroll)) ?: NULL_TEXT SessionRow.BUY_IN -> this.result?.buyin?.toCurrency(currency) ?: NULL_TEXT
SessionRow.CASHED_OUT, SessionRow.PRIZE, SessionRow.NET_RESULT -> this.result?.cashout?.toCurrency(CurrencyUtils.getCurrency(bankroll)) ?: NULL_TEXT SessionRow.CASHED_OUT, SessionRow.PRIZE, SessionRow.NET_RESULT -> this.result?.cashout?.toCurrency(currency) ?: NULL_TEXT
SessionRow.COMMENT -> if (this.comment.isNotEmpty()) this.comment else NULL_TEXT SessionRow.COMMENT -> if (this.comment.isNotEmpty()) this.comment else NULL_TEXT
SessionRow.END_DATE -> this.endDate?.shortDateTime() ?: NULL_TEXT SessionRow.END_DATE -> this.endDate?.shortDateTime() ?: NULL_TEXT
SessionRow.GAME -> getFormattedGame() SessionRow.GAME -> getFormattedGame()
SessionRow.INITIAL_BUY_IN -> tournamentEntryFee?.toCurrency(CurrencyUtils.getCurrency(bankroll)) ?: NULL_TEXT SessionRow.INITIAL_BUY_IN -> tournamentEntryFee?.toCurrency(currency) ?: 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 -> this.startDate?.shortDateTime() ?: NULL_TEXT SessionRow.START_DATE -> this.startDate?.shortDateTime() ?: 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(CurrencyUtils.getCurrency(bankroll)) ?: NULL_TEXT SessionRow.TIPS -> result?.tips?.toCurrency(currency) ?: NULL_TEXT
SessionRow.TOURNAMENT_TYPE -> this.tournamentType?.let { SessionRow.TOURNAMENT_TYPE -> this.tournamentType?.let {
TournamentType.values()[it].localizedTitle(context) TournamentType.values()[it].localizedTitle(context)
} ?: run { } ?: run {
@ -860,7 +883,7 @@ open class Session : RealmObject(), Savable, Editable, StaticRowRepresentableDat
} }
value?.let { value?.let {
return stat.format(it, CurrencyUtils.getCurrency(this.bankroll), context) return stat.format(it, currency, context)
} ?: run { } ?: run {
return TextFormat(NULL_TEXT) return TextFormat(NULL_TEXT)
} }
@ -871,6 +894,11 @@ open class Session : RealmObject(), Savable, Editable, StaticRowRepresentableDat
} }
// Timed
override val objectIdentifier: ObjectIdentifier
get() = ObjectIdentifier(this.id, Session::class.java)
} }

@ -7,6 +7,7 @@ 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 io.realm.annotations.PrimaryKey import io.realm.annotations.PrimaryKey
import net.pokeranalytics.android.calculus.ObjectIdentifier
import net.pokeranalytics.android.calculus.Stat import net.pokeranalytics.android.calculus.Stat
import net.pokeranalytics.android.calculus.StatFormattingException import net.pokeranalytics.android.calculus.StatFormattingException
import net.pokeranalytics.android.calculus.TextFormat import net.pokeranalytics.android.calculus.TextFormat
@ -109,5 +110,10 @@ open class SessionSet() : RealmObject(), Timed, Filterable {
} }
// Timed
override val objectIdentifier: ObjectIdentifier
get() = ObjectIdentifier(this.id, SessionSet::class.java)
} }

@ -5,11 +5,10 @@ import io.realm.Realm
import io.realm.kotlin.where import io.realm.kotlin.where
import net.pokeranalytics.android.model.realm.Bankroll import net.pokeranalytics.android.model.realm.Bankroll
import net.pokeranalytics.android.model.realm.Currency import net.pokeranalytics.android.model.realm.Currency
import net.pokeranalytics.android.model.realm.Game
import net.pokeranalytics.android.model.realm.TournamentFeature import net.pokeranalytics.android.model.realm.TournamentFeature
import net.pokeranalytics.android.util.CurrencyUtils
import java.util.* import java.util.*
import net.pokeranalytics.android.model.realm.Game
import net.pokeranalytics.android.util.UserDefaults
class Seed(var context:Context) : Realm.Transaction { class Seed(var context:Context) : Realm.Transaction {
@ -32,7 +31,7 @@ class Seed(var context:Context) : Realm.Transaction {
private fun createDefaultCurrencyAndBankroll(realm: Realm) { private fun createDefaultCurrencyAndBankroll(realm: Realm) {
// Currency // Currency
val localeCurrency = CurrencyUtils.getLocaleCurrency() val localeCurrency = UserDefaults.getLocaleCurrency()
val defaultCurrency = Currency() val defaultCurrency = Currency()
defaultCurrency.code = localeCurrency.currencyCode defaultCurrency.code = localeCurrency.currencyCode
realm.insertOrUpdate(defaultCurrency) realm.insertOrUpdate(defaultCurrency)

@ -17,9 +17,9 @@ import net.pokeranalytics.android.ui.view.RowViewType
import net.pokeranalytics.android.ui.view.rowrepresentable.BankrollRow import net.pokeranalytics.android.ui.view.rowrepresentable.BankrollRow
import net.pokeranalytics.android.ui.view.rowrepresentable.CustomizableRowRepresentable import net.pokeranalytics.android.ui.view.rowrepresentable.CustomizableRowRepresentable
import net.pokeranalytics.android.ui.view.rowrepresentable.SimpleRow import net.pokeranalytics.android.ui.view.rowrepresentable.SimpleRow
import net.pokeranalytics.android.util.CurrencyUtils
import net.pokeranalytics.android.util.NULL_TEXT import net.pokeranalytics.android.util.NULL_TEXT
import net.pokeranalytics.android.util.Preferences import net.pokeranalytics.android.util.Preferences
import net.pokeranalytics.android.util.extensions.toRate
import retrofit2.Call import retrofit2.Call
import retrofit2.Response import retrofit2.Response
import java.util.* import java.util.*
@ -96,9 +96,9 @@ class BankrollDataFragment : EditableDataFragment(), StaticRowRepresentableDataS
} }
BankrollRow.RATE -> { BankrollRow.RATE -> {
this.bankroll.currency?.rate?.let { rate -> this.bankroll.currency?.rate?.let { rate ->
CurrencyUtils.getCurrencyRateFormatter().format(rate) rate.toRate()
} ?: run { } ?: run {
CurrencyUtils.getCurrencyRateFormatter().format(1.0) 1.0.toRate()
} }
} }
else -> super.stringForRow(row) else -> super.stringForRow(row)
@ -119,7 +119,7 @@ class BankrollDataFragment : EditableDataFragment(), StaticRowRepresentableDataS
BankrollRow.RATE -> { BankrollRow.RATE -> {
this.bankroll.currency?.rate?.let { rate -> this.bankroll.currency?.rate?.let { rate ->
row.editingDescriptors(mapOf("defaultValue" to CurrencyUtils.getCurrencyRateFormatter().format(rate))) row.editingDescriptors(mapOf("defaultValue" to rate.toRate()))
} ?: run { } ?: run {
row.editingDescriptors(mapOf()) row.editingDescriptors(mapOf())
} }

@ -17,6 +17,7 @@ import com.google.android.material.chip.ChipGroup
import kotlinx.android.synthetic.main.fragment_evograph.* import kotlinx.android.synthetic.main.fragment_evograph.*
import net.pokeranalytics.android.R import net.pokeranalytics.android.R
import net.pokeranalytics.android.calculus.GraphType import net.pokeranalytics.android.calculus.GraphType
import net.pokeranalytics.android.calculus.ObjectIdentifier
import net.pokeranalytics.android.calculus.Stat import net.pokeranalytics.android.calculus.Stat
import net.pokeranalytics.android.ui.activity.components.PokerAnalyticsActivity import net.pokeranalytics.android.ui.activity.components.PokerAnalyticsActivity
import net.pokeranalytics.android.ui.fragment.components.PokerAnalyticsFragment import net.pokeranalytics.android.ui.fragment.components.PokerAnalyticsFragment
@ -25,16 +26,11 @@ import net.pokeranalytics.android.ui.view.LegendView
import net.pokeranalytics.android.util.extensions.ChipGroupExtension import net.pokeranalytics.android.util.extensions.ChipGroupExtension
import net.pokeranalytics.android.util.extensions.px import net.pokeranalytics.android.util.extensions.px
import net.pokeranalytics.android.util.extensions.toast import net.pokeranalytics.android.util.extensions.toast
import java.text.DateFormat
interface GraphDataSource {
}
class GraphFragment : PokerAnalyticsFragment(), OnChartValueSelectedListener { class GraphFragment : PokerAnalyticsFragment(), OnChartValueSelectedListener {
private lateinit var parentActivity: PokerAnalyticsActivity private lateinit var parentActivity: PokerAnalyticsActivity
lateinit var dataSource: GraphDataSource
private var stat: Stat = Stat.NETRESULT private var stat: Stat = Stat.NETRESULT
private var entries: List<Entry> = ArrayList() private var entries: List<Entry> = ArrayList()
@ -70,7 +66,7 @@ class GraphFragment : PokerAnalyticsFragment(), OnChartValueSelectedListener {
this.legendView = LegendView(requireContext()) this.legendView = LegendView(requireContext())
this.legendContainer.addView(this.legendView) this.legendContainer.addView(this.legendView)
this.legendView.prepareWithStat(this.stat) this.legendView.prepareWithStat(this.stat, this.entries.size)
val dataSet = LineDataSet(this.entries, this.stat.name) val dataSet = LineDataSet(this.entries, this.stat.name)
val colors = arrayOf(R.color.green_light).toIntArray() val colors = arrayOf(R.color.green_light).toIntArray()
@ -125,23 +121,16 @@ class GraphFragment : PokerAnalyticsFragment(), OnChartValueSelectedListener {
e?.let { entry -> e?.let { entry ->
h?.let { highlight -> h?.let { highlight ->
val id = entry.data as String val identifier = entry.data as ObjectIdentifier
val item = getRealm().where(this.stat.underlyingClass).equalTo("id", id).findAll().firstOrNull() val item = getRealm().where(identifier.clazz).equalTo("id", identifier.id).findAll().firstOrNull()
item?.let { item?.let {
val date = it.startDate() val formattedDate = DateFormat.getDateInstance(DateFormat.SHORT).format(it.startDate())
val entryStatName = this.stat.localizedTitle(requireContext())
val entryValue = it.formattedValue(this.stat, requireContext()) val entryValue = it.formattedValue(this.stat, requireContext())
val totalStatName = this.stat.cumulativeLabelResId(requireContext())
val totalStatValue = this.stat.format(e.y.toDouble(), null, requireContext()) val totalStatValue = this.stat.format(e.y.toDouble(), null, requireContext())
this.legendView.setItemData(this.stat, formattedDate, entryValue, totalStatValue)
} }
// this.text.text = ""
} }
} }

@ -27,7 +27,6 @@ import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.RowRepresentableDiffCallback import net.pokeranalytics.android.ui.view.RowRepresentableDiffCallback
import net.pokeranalytics.android.ui.view.SmoothScrollLinearLayoutManager import net.pokeranalytics.android.ui.view.SmoothScrollLinearLayoutManager
import net.pokeranalytics.android.ui.view.rowrepresentable.SessionRow import net.pokeranalytics.android.ui.view.rowrepresentable.SessionRow
import net.pokeranalytics.android.util.CurrencyUtils
import java.util.* import java.util.*
@ -104,9 +103,9 @@ class SessionFragment : PokerAnalyticsFragment(), RowRepresentableDelegate {
} }
SessionRow.BANKROLL -> { SessionRow.BANKROLL -> {
BottomSheetFragment.create(fragmentManager, row, this, data, false, CurrencyUtils.getCurrency(currentSession.bankroll)) BottomSheetFragment.create(fragmentManager, row, this, data, false, currentSession.currency)
} }
else -> BottomSheetFragment.create(fragmentManager, row, this, data, currentCurrency = CurrencyUtils.getCurrency(currentSession.bankroll)) else -> BottomSheetFragment.create(fragmentManager, row, this, data, currentCurrency = currentSession.currency)
} }
} }

@ -7,9 +7,11 @@ import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import io.realm.Realm
import kotlinx.android.synthetic.main.fragment_settings.* import kotlinx.android.synthetic.main.fragment_settings.*
import net.pokeranalytics.android.BuildConfig import net.pokeranalytics.android.BuildConfig
import net.pokeranalytics.android.R import net.pokeranalytics.android.R
import net.pokeranalytics.android.model.realm.Bankroll
import net.pokeranalytics.android.ui.activity.CurrenciesActivity import net.pokeranalytics.android.ui.activity.CurrenciesActivity
import net.pokeranalytics.android.ui.activity.DataListActivity import net.pokeranalytics.android.ui.activity.DataListActivity
import net.pokeranalytics.android.ui.activity.GDPRActivity import net.pokeranalytics.android.ui.activity.GDPRActivity
@ -22,6 +24,7 @@ import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.rowrepresentable.SettingRow import net.pokeranalytics.android.ui.view.rowrepresentable.SettingRow
import net.pokeranalytics.android.util.Preferences import net.pokeranalytics.android.util.Preferences
import net.pokeranalytics.android.util.URL import net.pokeranalytics.android.util.URL
import net.pokeranalytics.android.util.UserDefaults
import net.pokeranalytics.android.util.extensions.openContactMail import net.pokeranalytics.android.util.extensions.openContactMail
import net.pokeranalytics.android.util.extensions.openPlayStorePage import net.pokeranalytics.android.util.extensions.openPlayStorePage
import net.pokeranalytics.android.util.extensions.openUrl import net.pokeranalytics.android.util.extensions.openUrl
@ -70,6 +73,13 @@ class SettingsFragment : PokerAnalyticsFragment(), RowRepresentableDelegate, Sta
if (requestCode == REQUEST_CODE_CURRENCY && resultCode == Activity.RESULT_OK) { if (requestCode == REQUEST_CODE_CURRENCY && resultCode == Activity.RESULT_OK) {
data?.let { data?.let {
Preferences.setCurrencyCode(data.getStringExtra(CurrenciesFragment.INTENT_CURRENCY_CODE), requireContext()) Preferences.setCurrencyCode(data.getStringExtra(CurrenciesFragment.INTENT_CURRENCY_CODE), requireContext())
val realm = Realm.getDefaultInstance()
realm.executeTransaction {
it.where(Bankroll::class.java).isNull("currency.code").findAll().forEach { bankroll ->
bankroll.currencyCodeHasBeenUpdated()
}
}
realm.close()
settingsAdapterRow.refreshRow(SettingRow.CURRENCY) settingsAdapterRow.refreshRow(SettingRow.CURRENCY)
} }
} }

@ -8,8 +8,8 @@ import androidx.constraintlayout.widget.ConstraintLayout
import kotlinx.android.synthetic.main.layout_legend_default.view.* import kotlinx.android.synthetic.main.layout_legend_default.view.*
import net.pokeranalytics.android.R import net.pokeranalytics.android.R
import net.pokeranalytics.android.calculus.Stat import net.pokeranalytics.android.calculus.Stat
import net.pokeranalytics.android.model.realm.Session import net.pokeranalytics.android.calculus.TextFormat
import net.pokeranalytics.android.ui.view.fields.setTextFormat
/** /**
* Display a row session * Display a row session
@ -46,23 +46,22 @@ class LegendView : FrameLayout {
/** /**
* Set the stat data to the view * Set the stat data to the view
*/ */
fun prepareWithStat(stat: Stat) { fun prepareWithStat(stat: Stat, counter: Int) {
this.stat1Name.text = stat.localizedTitle(context) this.stat1Name.text = stat.localizedTitle(context)
this.stat2Name.text = stat.cumulativeLabelResId(context) this.stat2Name.text = stat.cumulativeLabelResId(context)
this.counter.text = "$counter ${context.getString(R.string.sessions)}"
//TODO: Set real data
this.title.text = "11/04/2019"
this.stat1Value.text = "$521"
this.stat2Value.text = "$15,051"
this.counter.text = "21 Sessions"
} }
/** /**
* *
*/ */
fun setData(session: Session) { fun setItemData(stat: Stat, title: String, statFormat1: TextFormat, statFormat2: TextFormat) {
this.title.text = title
this.stat1Value.setTextFormat(statFormat1, context)
this.stat2Value.setTextFormat(statFormat2, context)
} }

@ -16,6 +16,7 @@ import net.pokeranalytics.android.R
import net.pokeranalytics.android.model.realm.Session import net.pokeranalytics.android.model.realm.Session
import net.pokeranalytics.android.model.realm.Transaction import net.pokeranalytics.android.model.realm.Transaction
import net.pokeranalytics.android.ui.adapter.RowRepresentableAdapter import net.pokeranalytics.android.ui.adapter.RowRepresentableAdapter
import net.pokeranalytics.android.ui.view.fields.setTextFormat
import net.pokeranalytics.android.ui.view.rowrepresentable.CustomizableRowRepresentable import net.pokeranalytics.android.ui.view.rowrepresentable.CustomizableRowRepresentable
/** /**
@ -121,8 +122,9 @@ enum class RowViewType(private var layoutRes: Int) {
itemView.findViewById<AppCompatTextView?>(R.id.value)?.let { itemView.findViewById<AppCompatTextView?>(R.id.value)?.let {
if (row.computedStat != null) { if (row.computedStat != null) {
val format = row.computedStat!!.format(itemView.context) val format = row.computedStat!!.format(itemView.context)
it.setTextColor(format.getColor(itemView.context)) it.setTextFormat(format, itemView.context)
it.text = format.text // it.setTextColor(format.getColor(itemView.context))
// it.text = format.text
} else if (row.value != null) { } else if (row.value != null) {
it.text = row.value it.text = row.value
} }
@ -229,8 +231,9 @@ enum class RowViewType(private var layoutRes: Int) {
// Value // Value
itemView.findViewById<AppCompatTextView?>(R.id.value)?.let { view -> itemView.findViewById<AppCompatTextView?>(R.id.value)?.let { view ->
adapter.dataSource.contentDescriptorForRow(row)?.textFormat?.let { adapter.dataSource.contentDescriptorForRow(row)?.textFormat?.let {
view.text = it.text view.setTextFormat(it, itemView.context)
view.setTextColor(it.getColor(itemView.context)) // view.text = it.text
// view.setTextColor(it.getColor(itemView.context))
} }
} }

@ -15,7 +15,7 @@ import net.pokeranalytics.android.model.TournamentType
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.realm.Session import net.pokeranalytics.android.model.realm.Session
import net.pokeranalytics.android.util.CurrencyUtils import net.pokeranalytics.android.ui.view.fields.setTextFormat
import net.pokeranalytics.android.util.extensions.getDayNumber import net.pokeranalytics.android.util.extensions.getDayNumber
import net.pokeranalytics.android.util.extensions.getShortDayName import net.pokeranalytics.android.util.extensions.getShortDayName
import net.pokeranalytics.android.util.extensions.shortTime import net.pokeranalytics.android.util.extensions.shortTime
@ -68,7 +68,7 @@ class SessionRowView : FrameLayout {
if (session.isTournament()) { if (session.isTournament()) {
session.tournamentEntryFee?.let { session.tournamentEntryFee?.let {
parameters.add(it.toCurrency(CurrencyUtils.getCurrency(session.bankroll))) parameters.add(it.toCurrency(session.currency))
} }
session.tournamentName?.let { session.tournamentName?.let {
@ -85,7 +85,7 @@ class SessionRowView : FrameLayout {
} }
} else { } else {
if (session.cgSmallBlind != null && session.cgBigBlind != null) { if (session.cgSmallBlind != null && session.cgBigBlind != null) {
parameters.add(session.getBlinds()) parameters.add(session.getFormattedBlinds())
} }
session.game?.let { session.game?.let {
parameters.add(session.getFormattedGame()) parameters.add(session.getFormattedGame())
@ -149,9 +149,10 @@ class SessionRowView : FrameLayout {
rowHistorySession.infoTitle.isVisible = false rowHistorySession.infoTitle.isVisible = false
val result = session.result?.net ?: 0.0 val result = session.result?.net ?: 0.0
val formattedStat = ComputedStat(Stat.NETRESULT, result, currency = CurrencyUtils.getCurrency(session.bankroll)).format(context) val formattedStat = ComputedStat(Stat.NETRESULT, result, currency = session.currency).format(context)
rowHistorySession.gameResult.setTextColor(formattedStat.getColor(context)) rowHistorySession.gameResult.setTextFormat(formattedStat, context)
rowHistorySession.gameResult.text = formattedStat.text // rowHistorySession.gameResult.setTextColor(formattedStat.getColor(context))
// rowHistorySession.gameResult.text = formattedStat.text
} }
} }

@ -10,6 +10,7 @@ import net.pokeranalytics.android.R
import net.pokeranalytics.android.calculus.ComputedStat import net.pokeranalytics.android.calculus.ComputedStat
import net.pokeranalytics.android.calculus.Stat import net.pokeranalytics.android.calculus.Stat
import net.pokeranalytics.android.model.realm.Transaction import net.pokeranalytics.android.model.realm.Transaction
import net.pokeranalytics.android.ui.view.fields.setTextFormat
import net.pokeranalytics.android.util.extensions.getDayNumber import net.pokeranalytics.android.util.extensions.getDayNumber
import net.pokeranalytics.android.util.extensions.getShortDayName import net.pokeranalytics.android.util.extensions.getShortDayName
@ -63,8 +64,9 @@ class TransactionRowView : FrameLayout {
// Amount // Amount
val formattedStat = ComputedStat(Stat.NETRESULT, transaction.amount).format(context) val formattedStat = ComputedStat(Stat.NETRESULT, transaction.amount).format(context)
rowTransaction.transactionAmount.setTextColor(formattedStat.getColor(context)) rowTransaction.transactionAmount.setTextFormat(formattedStat, context)
rowTransaction.transactionAmount.text = formattedStat.text // rowTransaction.transactionAmount.setTextColor(formattedStat.getColor(context))
// rowTransaction.transactionAmount.text = formattedStat.text
} }

@ -0,0 +1,10 @@
package net.pokeranalytics.android.ui.view.fields
import android.content.Context
import androidx.appcompat.widget.AppCompatTextView
import net.pokeranalytics.android.calculus.TextFormat
fun AppCompatTextView.setTextFormat(textFormat: TextFormat, context: Context) {
this.setTextColor(textFormat.getColor(context))
this.text = textFormat.text
}

@ -54,7 +54,7 @@ enum class FilterCategoryRow(override val resId: Int?, override val viewType: In
BANKROLL BANKROLL
) )
CASH -> arrayListOf( CASH -> arrayListOf(
BLINDS, BLIND,
CASH_RE_BUY_COUNT CASH_RE_BUY_COUNT
) )
TOURNAMENT -> arrayListOf( TOURNAMENT -> arrayListOf(

@ -11,10 +11,8 @@ import net.pokeranalytics.android.ui.fragment.components.bottomsheet.BottomSheet
import net.pokeranalytics.android.ui.view.RowRepresentable import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.RowRepresentableEditDescriptor import net.pokeranalytics.android.ui.view.RowRepresentableEditDescriptor
import net.pokeranalytics.android.ui.view.RowViewType import net.pokeranalytics.android.ui.view.RowViewType
import net.pokeranalytics.android.util.CurrencyUtils import net.pokeranalytics.android.util.Preferences
import net.pokeranalytics.android.util.NULL_TEXT import net.pokeranalytics.android.util.UserDefaults
import net.pokeranalytics.android.util.extensions.formatted
import net.pokeranalytics.android.util.extensions.round
import java.text.DateFormatSymbols import java.text.DateFormatSymbols
import java.util.* import java.util.*
@ -105,14 +103,7 @@ sealed class FilterElementRow : RowRepresentable {
data class Month(val month: Int) : SingleValueFilterElementRow(month) data class Month(val month: Int) : SingleValueFilterElementRow(month)
data class Day(val day: Int) : SingleValueFilterElementRow(day) data class Day(val day: Int) : SingleValueFilterElementRow(day)
data class Blind(var sb: Double? = null, var bb: Double? = null, var code: String? = null) : FilterElementRow() { data class Blind(val blind: String, val hasDefaultCurrency: Boolean) : StringFilterElementRow(blind)
val name: String
get() {
val currencyCode = code ?: CurrencyUtils.getLocaleCurrency().currencyCode
val currencySymbol = Currency.getInstance(currencyCode).symbol
return if (sb == null) NULL_TEXT else "$currencySymbol ${sb?.formatted()}/${bb?.round()}"
}
}
//TODO: Refactor? //TODO: Refactor?
data class PastDays(var lastDays: Int = 0) : SingleValueFilterElementRow(lastDays) { data class PastDays(var lastDays: Int = 0) : SingleValueFilterElementRow(lastDays) {
@ -155,7 +146,7 @@ sealed class FilterElementRow : RowRepresentable {
return when (this) { return when (this) {
is Cash -> QueryCondition.CASH is Cash -> QueryCondition.CASH
is Tournament -> QueryCondition.TOURNAMENT is Tournament -> QueryCondition.TOURNAMENT
is Blind -> QueryCondition.BLINDS is Blind -> QueryCondition.BLIND
is From -> QueryCondition.STARTED_FROM_DATE is From -> QueryCondition.STARTED_FROM_DATE
is To -> QueryCondition.ENDED_TO_DATE is To -> QueryCondition.ENDED_TO_DATE
is FromTime -> QueryCondition.STARTED_FROM_TIME is FromTime -> QueryCondition.STARTED_FROM_TIME
@ -308,7 +299,7 @@ sealed class FilterElementRow : RowRepresentable {
} }
is DataFilterElementRow -> this.name is DataFilterElementRow -> this.name
is StaticDataFilterElementRow -> this.name is StaticDataFilterElementRow -> this.name
is Blind -> this.name is Blind -> this.blind
else -> super.getDisplayName() else -> super.getDisplayName()
} }
} }

@ -30,7 +30,7 @@ enum class FilterSectionRow(override val resId: Int?) : RowRepresentable {
SESSION_DURATION(net.pokeranalytics.android.R.string.session_duration), SESSION_DURATION(net.pokeranalytics.android.R.string.session_duration),
RANGE(net.pokeranalytics.android.R.string.hour_slot), RANGE(net.pokeranalytics.android.R.string.hour_slot),
SESSIONS(R.string.sessions), SESSIONS(R.string.sessions),
BLINDS(net.pokeranalytics.android.R.string.blinds), BLIND(net.pokeranalytics.android.R.string.blinds),
CASH_RE_BUY_COUNT(net.pokeranalytics.android.R.string.rebuy_count), CASH_RE_BUY_COUNT(net.pokeranalytics.android.R.string.rebuy_count),
TOURNAMENT_TYPE(net.pokeranalytics.android.R.string.tournament_types), TOURNAMENT_TYPE(net.pokeranalytics.android.R.string.tournament_types),
TOURNAMENT_NAME(net.pokeranalytics.android.R.string.tournament_name), TOURNAMENT_NAME(net.pokeranalytics.android.R.string.tournament_name),
@ -160,36 +160,15 @@ enum class FilterSectionRow(override val resId: Int?) : RowRepresentable {
SESSIONS -> arrayListOf(LastGames(0), LastSessions(0)) SESSIONS -> arrayListOf(LastGames(0), LastSessions(0))
// Cash // Cash
BLINDS -> { BLIND -> {
val blinds = arrayListOf<Blind>()
// TODO: Improve the way we get the blinds distinctly
val blinds = arrayListOf<FilterElementRow.Blind>()
val realm = Realm.getDefaultInstance() val realm = Realm.getDefaultInstance()
val sessions = realm.where<Session>().distinct("blind", "bankroll.currency.code").findAll().sort("cgSmallBlind", Sort.ASCENDING).map {
realm.where<Session>().isNotNull("cgSmallBlind").isNotNull("cgBigBlind").findAll() it.blinds?.let { stake ->
.sort("cgSmallBlind", Sort.ASCENDING) blinds.add(Blind(stake, it.hasDefaultCurrency))
val distinctBlinds: ArrayList<Session> = ArrayList()
val blindsHashMap: ArrayList<String> = ArrayList()
sessions.forEach {
if (!blindsHashMap.contains(it.getBlinds())) {
blindsHashMap.add(it.getBlinds())
distinctBlinds.add(it)
} }
} }
distinctBlinds.forEach { session ->
blinds.add(
Blind(
session.cgSmallBlind,
session.cgBigBlind,
session.bankroll?.currency?.code
)
)
session.getBlinds()
}
realm.close() realm.close()
blinds blinds
} }
CASH_RE_BUY_COUNT -> arrayListOf( CASH_RE_BUY_COUNT -> arrayListOf(

@ -1,64 +0,0 @@
package net.pokeranalytics.android.util
import android.content.Context
import net.pokeranalytics.android.model.realm.Bankroll
import java.text.NumberFormat
import java.util.*
class CurrencyUtils {
companion object {
/**
* return the currency associated with this bankroll
*/
fun getCurrency(bankroll: Bankroll? = null) : Currency {
val currencyCode = bankroll?.currency?.code ?: CurrencyUtils.getLocaleCurrency().currencyCode
return Currency.getInstance(currencyCode)
}
/**
* Get a currency formatter
*/
fun getCurrencyFormatter(context: Context, currency: Currency? = null) : NumberFormat {
val currencyFormatter = NumberFormat.getCurrencyInstance(Preferences.getCurrencyLocale(context))
currency?.let {
currencyFormatter.currency = it
}
currencyFormatter.minimumFractionDigits = 0
currencyFormatter.maximumFractionDigits = 2
return currencyFormatter
}
/**
* Get a currency rate formatter
*/
fun getCurrencyRateFormatter() : NumberFormat {
val currencyFormatter = NumberFormat.getInstance()
currencyFormatter.minimumFractionDigits = 0
currencyFormatter.maximumFractionDigits = 6
return currencyFormatter
}
/**
* Return the locale currency, or en_US if there
*/
fun getLocaleCurrency() : Currency {
return try {
Currency.getInstance(Locale.getDefault())
} catch (ex: Exception) {
when (Locale.getDefault().language) {
"en" -> Currency.getInstance(Locale("en", "US"))
"fr" -> Currency.getInstance(Locale("fr", "FR"))
"es" -> Currency.getInstance(Locale("es", "ES"))
"de" -> Currency.getInstance(Locale("de", "DE"))
"ja" -> Currency.getInstance(Locale("ja", "JP"))
"zh" -> Currency.getInstance(Locale("zh", "CN"))
else -> Currency.getInstance(Locale("en", "US"))
}
}
}
}
}

@ -16,8 +16,6 @@ class Preferences {
companion object { companion object {
var currencyLocale : Locale? = null
fun setString(key: Keys, value: String, context: Context) { fun setString(key: Keys, value: String, context: Context) {
val preferences = PreferenceManager.getDefaultSharedPreferences(context) val preferences = PreferenceManager.getDefaultSharedPreferences(context)
val editor = preferences.edit() val editor = preferences.edit()
@ -43,21 +41,16 @@ class Preferences {
} }
fun setCurrencyCode(currencyCode: String, context: Context) { fun setCurrencyCode(currencyCode: String, context: Context) {
Preferences.setString(Keys.CURRENCY_CODE, currencyCode, context) setString(Keys.CURRENCY_CODE, currencyCode, context)
currencyLocale = null UserDefaults.setCurrencyValues(context)
} }
private fun getCurrencyCode(context: Context) : String? { private fun getCurrencyCode(context: Context) : String? {
return Preferences.getString(Keys.CURRENCY_CODE, context) return getString(Keys.CURRENCY_CODE, context)
} }
fun getCurrencyLocale(context : Context) : Locale { fun getCurrencyLocale(context : Context) : Locale? {
getCurrencyCode(context)?.let { currencyCode ->
currencyLocale?. let {
return it
}
Preferences.getCurrencyCode(context)?.let { currencyCode ->
Locale.getAvailableLocales().filter{ Locale.getAvailableLocales().filter{
try { try {
Currency.getInstance(it).currencyCode == currencyCode Currency.getInstance(it).currencyCode == currencyCode
@ -65,22 +58,87 @@ class Preferences {
false false
} }
}.first().let { }.first().let {
currencyLocale = it
return it return it
} }
} }
currencyLocale = Locale.getDefault() return null
return currencyLocale!! }
fun getDefaultCurrency(context: Context) : Currency? {
getCurrencyLocale(context)?.let {
return Currency.getInstance(it)
}
return null
} }
fun setStopShowingDisclaimer(context: Context) { fun setStopShowingDisclaimer(context: Context) {
Preferences.setBoolean(Keys.STOP_SHOWING_DISCLAIMER, true, context) setBoolean(Keys.STOP_SHOWING_DISCLAIMER, true, context)
} }
fun shouldShowDisclaimer(context: Context) : Boolean { fun shouldShowDisclaimer(context: Context) : Boolean {
return !Preferences.getBoolean(Keys.STOP_SHOWING_DISCLAIMER, context) return !getBoolean(Keys.STOP_SHOWING_DISCLAIMER, context)
}
}
}
class UserDefaults private constructor(context: Context) {
init {
setCurrencyValues(context)
} }
companion object : SingletonHolder<UserDefaults, Context>(::UserDefaults) {
lateinit var currency : Currency
lateinit var currencyLocale : Locale
fun setCurrencyValues(context: Context) {
currency = Preferences.getDefaultCurrency(context) ?: getLocaleCurrency()
currencyLocale = Preferences.getCurrencyLocale(context) ?: Locale.getDefault()
}
/**
* Return the locale currency, or en_US if there
*/
fun getLocaleCurrency() : Currency {
return try {
Currency.getInstance(Locale.getDefault())
} catch (ex: Exception) {
when (Locale.getDefault().language) {
"en" -> Currency.getInstance(Locale("en", "US"))
"fr" -> Currency.getInstance(Locale("fr", "FR"))
"es" -> Currency.getInstance(Locale("es", "ES"))
"de" -> Currency.getInstance(Locale("de", "DE"))
"ja" -> Currency.getInstance(Locale("ja", "JP"))
"zh" -> Currency.getInstance(Locale("zh", "CN"))
else -> Currency.getInstance(Locale("en", "US"))
}
}
}
}
}
open class SingletonHolder<out T, in A>(creator: (A) -> T) {
private var creator: ((A) -> T)? = creator
@Volatile private var instance: T? = null
fun init(context: A): T {
val i = instance
if (i != null) {
return i
} }
return synchronized(this) {
val i2 = instance
if (i2 != null) {
i2
} else {
val created = creator!!(context)
instance = created
creator = null
created
}
}
}
} }

@ -2,6 +2,7 @@ package net.pokeranalytics.android.util.extensions
import android.content.Context import android.content.Context
import net.pokeranalytics.android.R import net.pokeranalytics.android.R
import net.pokeranalytics.android.util.UserDefaults
import java.text.DecimalFormat import java.text.DecimalFormat
import java.text.NumberFormat import java.text.NumberFormat
import java.util.* import java.util.*
@ -23,7 +24,7 @@ fun Double.formatted(): String {
fun Double.toCurrency(currency: Currency? = null): String { fun Double.toCurrency(currency: Currency? = null): String {
val currencyFormatter = NumberFormat.getCurrencyInstance() val currencyFormatter = NumberFormat.getCurrencyInstance(UserDefaults.currencyLocale)
currency?.let { currency?.let {
currencyFormatter.currency = currency currencyFormatter.currency = currency
} }
@ -33,6 +34,14 @@ fun Double.toCurrency(currency: Currency? = null): String {
return currencyFormatter.format(this) return currencyFormatter.format(this)
} }
fun Double.toRate(): String {
val currencyFormatter = NumberFormat.getInstance()
currencyFormatter.minimumFractionDigits = 0
currencyFormatter.maximumFractionDigits = 6
return currencyFormatter.format(this)
}
fun Double.formattedHourlyDuration() : String { fun Double.formattedHourlyDuration() : String {
return (this * 1000 * 3600).toLong().toMinutes() return (this * 1000 * 3600).toLong().toMinutes()
} }

Loading…
Cancel
Save