feature/top10
Laurent 7 years ago
commit f384e2c653
  1. 5
      app/build.gradle
  2. 440
      app/src/androidTest/java/net/pokeranalytics/android/FilterInstrumentedUnitTest.kt
  3. 41
      app/src/androidTest/java/net/pokeranalytics/android/filter/BaseFilterInstrumentedUnitTest.kt
  4. 205
      app/src/androidTest/java/net/pokeranalytics/android/filter/BlindFilterInstrumentedTest.kt
  5. 274
      app/src/androidTest/java/net/pokeranalytics/android/filter/DateFilterInstrumentedUnitTest.kt
  6. 55
      app/src/androidTest/java/net/pokeranalytics/android/filter/ExceptionFilterInstrumentedTest.kt
  7. 567
      app/src/androidTest/java/net/pokeranalytics/android/filter/SessionFilterInstrumentedUnitTest.kt
  8. 9
      app/src/main/AndroidManifest.xml
  9. 80
      app/src/main/java/net/pokeranalytics/android/api/CurrencyConverterApi.kt
  10. 21
      app/src/main/java/net/pokeranalytics/android/calculus/Stat.kt
  11. 4
      app/src/main/java/net/pokeranalytics/android/exceptions/Exceptions.kt
  12. 3
      app/src/main/java/net/pokeranalytics/android/model/LiveData.kt
  13. 77
      app/src/main/java/net/pokeranalytics/android/model/filter/DateFilterable.kt
  14. 113
      app/src/main/java/net/pokeranalytics/android/model/filter/FilterComponent.kt
  15. 16
      app/src/main/java/net/pokeranalytics/android/model/filter/Filterable.kt
  16. 147
      app/src/main/java/net/pokeranalytics/android/model/filter/SessionFilterable.kt
  17. 8
      app/src/main/java/net/pokeranalytics/android/model/filter/interfaces/Filterable.kt
  18. 20
      app/src/main/java/net/pokeranalytics/android/model/filter/interfaces/TimeFilterable.kt
  19. 28
      app/src/main/java/net/pokeranalytics/android/model/filter/interfaces/ValueFilterable.kt
  20. 1
      app/src/main/java/net/pokeranalytics/android/model/interfaces/Timed.kt
  21. 34
      app/src/main/java/net/pokeranalytics/android/model/realm/Session.kt
  22. 11
      app/src/main/java/net/pokeranalytics/android/model/retrofit/ConvertResult.kt
  23. 60
      app/src/main/java/net/pokeranalytics/android/ui/activity/FilterDetailsActivity.kt
  24. 59
      app/src/main/java/net/pokeranalytics/android/ui/activity/FiltersActivity.kt
  25. 80
      app/src/main/java/net/pokeranalytics/android/ui/activity/HomeActivity.kt
  26. 65
      app/src/main/java/net/pokeranalytics/android/ui/fragment/BankrollDataFragment.kt
  27. 2
      app/src/main/java/net/pokeranalytics/android/ui/fragment/EditableDataFragment.kt
  28. 245
      app/src/main/java/net/pokeranalytics/android/ui/fragment/FilterDetailsFragment.kt
  29. 191
      app/src/main/java/net/pokeranalytics/android/ui/fragment/FiltersFragment.kt
  30. 19
      app/src/main/java/net/pokeranalytics/android/ui/fragment/HistoryFragment.kt
  31. 5
      app/src/main/java/net/pokeranalytics/android/ui/fragment/SessionFragment.kt
  32. 40
      app/src/main/java/net/pokeranalytics/android/ui/fragment/StatsFragment.kt
  33. 7
      app/src/main/java/net/pokeranalytics/android/ui/fragment/components/bottomsheet/BottomSheetFragment.kt
  34. 15
      app/src/main/java/net/pokeranalytics/android/ui/fragment/components/bottomsheet/BottomSheetMultiSelectionFragment.kt
  35. 6
      app/src/main/java/net/pokeranalytics/android/ui/fragment/components/bottomsheet/BottomSheetSumFragment.kt
  36. 3
      app/src/main/java/net/pokeranalytics/android/ui/view/RowViewType.kt
  37. 5
      app/src/main/java/net/pokeranalytics/android/ui/view/SessionRowView.kt
  38. 91
      app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/FilterCategoryRow.kt
  39. 27
      app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/FilterRow.kt
  40. 146
      app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/FilterSubcategoryRow.kt
  41. 5
      app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/SessionRow.kt
  42. 4
      app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/SettingRow.kt
  43. 35
      app/src/main/java/net/pokeranalytics/android/util/CurrencyUtils.kt
  44. 20
      app/src/main/java/net/pokeranalytics/android/util/FormatUtils.kt
  45. 4
      app/src/main/java/net/pokeranalytics/android/util/URL.kt
  46. 16
      app/src/main/java/net/pokeranalytics/android/util/extensions/NumbersExtension.kt
  47. 7
      app/src/main/res/layout/activity_filter_details.xml
  48. 7
      app/src/main/res/layout/activity_filters.xml
  49. 61
      app/src/main/res/layout/fragment_filter_details.xml
  50. 61
      app/src/main/res/layout/fragment_filters.xml
  51. 11
      app/src/main/res/menu/home_menu.xml
  52. 1
      app/src/main/res/values/secrets.xml
  53. 2
      app/src/main/res/values/styles.xml

@ -57,6 +57,11 @@ dependencies {
implementation 'androidx.lifecycle:lifecycle-extensions:2.0.0' implementation 'androidx.lifecycle:lifecycle-extensions:2.0.0'
implementation 'androidx.browser:browser:1.0.0' implementation 'androidx.browser:browser:1.0.0'
// Retrofit
implementation 'com.squareup.retrofit2:retrofit:2.5.0'
implementation 'com.squareup.retrofit2:converter-gson:2.5.0'
implementation 'com.squareup.okhttp3:logging-interceptor:3.9.1'
implementation 'com.google.code.gson:gson:2.8.5'
// Places // Places
implementation 'com.google.android.libraries.places:places:1.0.0' implementation 'com.google.android.libraries.places:places:1.0.0'

@ -1,440 +0,0 @@
package net.pokeranalytics.android
import androidx.test.ext.junit.runners.AndroidJUnit4
import io.realm.RealmResults
import net.pokeranalytics.android.model.filter.FilterManager
import net.pokeranalytics.android.model.filter.SessionFilterable
import net.pokeranalytics.android.model.realm.Bankroll
import net.pokeranalytics.android.model.realm.Result
import net.pokeranalytics.android.model.realm.Session
import org.junit.Assert
import org.junit.Test
import org.junit.runner.RunWith
import java.util.*
import java.util.prefs.Preferences
@RunWith(AndroidJUnit4::class)
class FilterInstrumentedUnitTest : RealmInstrumentedUnitTest() {
// convenience extension
fun Session.Companion.testInstance(netResult: Double, isTournament: Boolean, startDate: Date, endDate: Int, bankroll:Bankroll? = null): Session {
val session: Session = Session.newInstance(super.mockRealm, isTournament, bankroll)
session.result?.netResult = netResult
session.startDate = startDate
val cal = Calendar.getInstance() // creates calendar
cal.time = startDate // sets calendar time/date
cal.add(Calendar.HOUR_OF_DAY, endDate) // adds one hour
session.endDate = cal.time // returns new date object, one hour in the future
return session
}
@Test
fun testCashFilter() {
val realm = this.mockRealm
realm.beginTransaction()
val s1 = Session.testInstance(100.0, false, Date(), 1)
val s2 = Session.testInstance(100.0, true, Date(), 1)
realm.commitTransaction()
val sessions = FilterManager().filter(
realm,
Session::class.java,
arrayListOf(SessionFilterable.CASH)
) as RealmResults<Session>
Assert.assertEquals(1, sessions.size)
sessions[0]?.run {
Assert.assertEquals(Session.Type.CASH_GAME.ordinal, this.type)
}
}
@Test
fun testTournamentFilter() {
val realm = this.mockRealm
realm.beginTransaction()
val s1 = Session.testInstance(100.0, false, Date(), 1)
val s2 = Session.testInstance(100.0, true, Date(), 1)
realm.commitTransaction()
val sessions = FilterManager().filter(
realm,
Session::class.java,
arrayListOf(SessionFilterable.TOURNAMENT)
) as RealmResults<Session>
Assert.assertEquals(1, sessions.size)
sessions[0]?.run {
Assert.assertEquals(Session.Type.TOURNAMENT.ordinal, this.type)
}
}
@Test
fun testLiveFilter() {
val realm = this.mockRealm
realm.beginTransaction()
val b1 = realm.createObject(Bankroll::class.java, "1")
val b2 = realm.createObject(Bankroll::class.java, "2")
b1.live = true
b2.live = false
val s1 = Session.testInstance(100.0, false, Date(), 1, b1)
val s2 = Session.testInstance(100.0, true, Date(), 1, b2)
realm.commitTransaction()
val sessions = FilterManager().filter(
realm,
Session::class.java,
arrayListOf(SessionFilterable.LIVE)
) as RealmResults<Session>
Assert.assertEquals(1, sessions.size)
sessions[0]?.bankroll?.run {
Assert.assertEquals(true, this.live)
}
}
@Test
fun testOnlineFilter() {
val realm = this.mockRealm
realm.beginTransaction()
val b1 = realm.createObject(Bankroll::class.java, "1")
val b2 = realm.createObject(Bankroll::class.java, "2")
b1.live = false
b2.live = true
val s1 = Session.testInstance(100.0, false, Date(), 1, b1)
val s2 = Session.testInstance(100.0, true, Date(), 1, b2)
realm.commitTransaction()
val sessions = FilterManager().filter(
realm,
Session::class.java,
arrayListOf(SessionFilterable.ONLINE)
) as RealmResults<Session>
Assert.assertEquals(1, sessions.size)
sessions[0]?.bankroll?.run {
Assert.assertEquals(false, this.live)
}
}
@Test
fun testStartedFomDateFilter() {
val realm = this.mockRealm
realm.beginTransaction()
val cal = Calendar.getInstance() // creates calendar
cal.time = Date() // sets calendar time/date
val s1 = Session.testInstance(100.0, false, cal.time, 1)
cal.add(Calendar.HOUR_OF_DAY, 2) // adds one hour
val s2 = Session.testInstance(100.0, true, cal.time, 1)
realm.commitTransaction()
var filter = SessionFilterable.STARTED_FROM_DATE
filter.valueMap = mapOf("date" to s2.startDate)
val sessions = FilterManager().filter(
realm,
Session::class.java,
arrayListOf(filter)
) as RealmResults<Session>
Assert.assertEquals(1, sessions.size)
sessions[0]?.run {
Assert.assertEquals(s2.id, this.id)
}
}
@Test
fun testStartedToDateFilter() {
val realm = this.mockRealm
realm.beginTransaction()
val cal = Calendar.getInstance() // creates calendar
cal.time = Date() // sets calendar time/date
val s1 = Session.testInstance(100.0, false, cal.time, 1)
cal.add(Calendar.HOUR_OF_DAY, 2) // adds one hour
val s2 = Session.testInstance(100.0, true, cal.time, 1)
realm.commitTransaction()
var filter = SessionFilterable.STARTED_TO_DATE
filter.valueMap = mapOf("date" to s1.startDate)
val sessions = FilterManager().filter(
realm,
Session::class.java,
arrayListOf(filter)
) as RealmResults<Session>
Assert.assertEquals(1, sessions.size)
sessions[0]?.run {
Assert.assertEquals(s1.id, this.id)
}
}
@Test
fun testEndedFomDateFilter() {
val realm = this.mockRealm
realm.beginTransaction()
val cal = Calendar.getInstance() // creates calendar
cal.time = Date() // sets calendar time/date
val s1 = Session.testInstance(100.0, false, cal.time, 1)
cal.add(Calendar.HOUR_OF_DAY, 2) // adds one hour
val s2 = Session.testInstance(100.0, true, cal.time, 1)
realm.commitTransaction()
var filter = SessionFilterable.ENDED_FROM_DATE
filter.valueMap = mapOf("date" to s2.endDate)
val sessions = FilterManager().filter(
realm,
Session::class.java,
arrayListOf(filter)
) as RealmResults<Session>
Assert.assertEquals(1, sessions.size)
sessions[0]?.run {
Assert.assertEquals(s2.id, this.id)
}
}
@Test
fun testEndedToDateFilter() {
val realm = this.mockRealm
realm.beginTransaction()
val cal = Calendar.getInstance() // creates calendar
cal.time = Date() // sets calendar time/date
val s1 = Session.testInstance(100.0, false, cal.time, 1)
cal.add(Calendar.HOUR_OF_DAY, 2) // adds one hour
val s2 = Session.testInstance(100.0, true, cal.time, 1)
realm.commitTransaction()
var filter = SessionFilterable.ENDED_TO_DATE
filter.valueMap = mapOf("date" to s1.endDate)
val sessions = FilterManager().filter(
realm,
Session::class.java,
arrayListOf(filter)
) as RealmResults<Session>
Assert.assertEquals(1, sessions.size)
sessions[0]?.run {
Assert.assertEquals(s1.id, this.id)
}
}
@Test
fun testSingleBlindNoCurrencyFilter() {
val realm = this.mockRealm
realm.beginTransaction()
val currency = realm.createObject(net.pokeranalytics.android.model.realm.Currency::class.java, "1")
currency.code = "AUD"
val b1 = realm.createObject(Bankroll::class.java, "1")
val b2 = realm.createObject(Bankroll::class.java, "2")
b2.currency = currency
val s1 = Session.testInstance(100.0, false, Date(), 1, b1)
s1.cgBigBlind = 1.0
s1.cgSmallBlind = 0.5
val s2 = Session.testInstance(100.0, false, Date(), 1, b1)
s2.cgBigBlind = 1.0
s2.cgSmallBlind = 0.5
val s3 = Session.testInstance(100.0, false, Date(), 1, b1)
s3.cgBigBlind = 2.0
s3.cgSmallBlind = 1.0
realm.commitTransaction()
var filter = SessionFilterable.BLINDS
filter.valueMap = mapOf("map" to arrayOf(mapOf(
"sb" to 0.5,
"bb" to 1.0,
"code" to null
)))
val sessions = FilterManager().filter(
realm,
Session::class.java,
arrayListOf(filter)
) as RealmResults<Session>
Assert.assertEquals(2, sessions.size)
sessions.map {
Assert.assertTrue(arrayListOf(s1.id, s2.id).contains(it.id))
}
}
@Test
fun testSingleBlindNoSmallBlindNoCurrencyFilter() {
val realm = this.mockRealm
realm.beginTransaction()
val currency = realm.createObject(net.pokeranalytics.android.model.realm.Currency::class.java, "1")
currency.code = "AUD"
val b1 = realm.createObject(Bankroll::class.java, "1")
val b2 = realm.createObject(Bankroll::class.java, "2")
b2.currency = currency
val s1 = Session.testInstance(100.0, false, Date(), 1, b1)
s1.cgBigBlind = 1.0
s1.cgSmallBlind = 0.5
val s2 = Session.testInstance(100.0, false, Date(), 1, b1)
s2.cgBigBlind = 1.0
s2.cgSmallBlind = 0.5
val s3 = Session.testInstance(100.0, false, Date(), 1, b1)
s3.cgBigBlind = 2.0
s3.cgSmallBlind = 1.0
realm.commitTransaction()
var filter = SessionFilterable.BLINDS
filter.valueMap = mapOf("map" to arrayOf(mapOf(
"sb" to null,
"bb" to 1.0,
"code" to null
)))
val sessions = FilterManager().filter(
realm,
Session::class.java,
arrayListOf(filter)
) as RealmResults<Session>
Assert.assertEquals(2, sessions.size)
sessions.map {
Assert.assertTrue(arrayListOf(s1.id, s2.id).contains(it.id))
}
}
@Test
fun testSingleBlindCurrencyFilter() {
val realm = this.mockRealm
realm.beginTransaction()
val currency = realm.createObject(net.pokeranalytics.android.model.realm.Currency::class.java, "1")
currency.code = "AUD"
val b1 = realm.createObject(Bankroll::class.java, "1")
val b2 = realm.createObject(Bankroll::class.java, "2")
b2.currency = currency
val s1 = Session.testInstance(100.0, false, Date(), 1, b1)
s1.cgBigBlind = 1.0
s1.cgSmallBlind = 0.5
val s2 = Session.testInstance(100.0, false, Date(), 1, b1)
s2.cgBigBlind = 1.0
s2.cgSmallBlind = 0.5
val s3 = Session.testInstance(100.0, false, Date(), 1, b2)
s3.cgBigBlind = 2.0
s3.cgSmallBlind = 1.0
realm.commitTransaction()
var filter = SessionFilterable.BLINDS
filter.valueMap = mapOf("map" to arrayOf(mapOf(
"sb" to 1.0,
"bb" to 2.0,
"code" to "AUD"
)))
val sessions = FilterManager().filter(
realm,
Session::class.java,
arrayListOf(filter)
) as RealmResults<Session>
Assert.assertEquals(1, sessions.size)
sessions.map {
Assert.assertEquals(s3.id, it.id)
}
}
@Test
fun testMultiBlindNoCurrencyFilter() {
val realm = this.mockRealm
realm.beginTransaction()
val currency = realm.createObject(net.pokeranalytics.android.model.realm.Currency::class.java, "1")
currency.code = "AUD"
val b1 = realm.createObject(Bankroll::class.java, "1")
val b2 = realm.createObject(Bankroll::class.java, "2")
b2.currency = currency
val s1 = Session.testInstance(100.0, false, Date(), 1, b1)
s1.cgBigBlind = 1.0
s1.cgSmallBlind = 0.5
val s2 = Session.testInstance(100.0, false, Date(), 1, b1)
s2.cgBigBlind = 2.0
s2.cgSmallBlind = 1.0
val s3 = Session.testInstance(100.0, false, Date(), 1, b2)
s3.cgBigBlind = 2.0
s3.cgSmallBlind = 1.0
realm.commitTransaction()
var filter = SessionFilterable.BLINDS
filter.valueMap = mapOf("map" to arrayOf(
mapOf(
"sb" to 1.0,
"bb" to 2.0,
"code" to null
),
mapOf(
"sb" to 0.5,
"bb" to 1.0,
"code" to null
)))
val sessions = FilterManager().filter(
realm,
Session::class.java,
arrayListOf(filter)
) as RealmResults<Session>
Assert.assertEquals(2, sessions.size)
sessions.map {
Assert.assertTrue(arrayListOf(s1.id, s2.id).contains(it.id))
}
}
}

@ -0,0 +1,41 @@
package net.pokeranalytics.android.filter
import io.realm.RealmList
import net.pokeranalytics.android.RealmInstrumentedUnitTest
import net.pokeranalytics.android.model.realm.*
import java.util.*
open class BaseFilterInstrumentedUnitTest : RealmInstrumentedUnitTest() {
// convenience extension
fun Session.Companion.testInstance(
netResult: Double = 0.0,
isTournament: Boolean = false,
startDate: Date = Date(),
endDate: Int = 1,
bankroll: Bankroll? = null,
game: Game? = null,
location : Location? = null,
tournamentName: TournamentName? = null,
tournamentFeatures: RealmList<TournamentFeature> = RealmList(),
numberOfTable: Int = 1,
limit: Int? = null,
tableSize: Int? = null
): Session {
val session: Session = Session.newInstance(super.mockRealm, isTournament, bankroll)
session.game = game
session.location = location
session.tournamentFeatures = tournamentFeatures
session.tournamentName = tournamentName
session.limit = limit
session.numberOfTables = numberOfTable
session.tableSize = tableSize
session.result?.netResult = netResult
session.startDate = startDate
val cal = Calendar.getInstance() // creates calendar
cal.time = startDate // sets calendar time/date
cal.add(Calendar.HOUR_OF_DAY, endDate) // adds one hour
session.endDate = cal.time // returns new date object, one hour in the future
return session
}
}

@ -0,0 +1,205 @@
package net.pokeranalytics.android.filter
import net.pokeranalytics.android.model.filter.FilterManager
import net.pokeranalytics.android.model.filter.SessionFilterable
import net.pokeranalytics.android.model.realm.Bankroll
import net.pokeranalytics.android.model.realm.Session
import org.junit.Assert
import org.junit.Test
import java.util.*
class BlindFilterInstrumentedTest : BaseFilterInstrumentedUnitTest() {
@Test
fun testSingleBlindNoCurrencyFilter() {
val realm = this.mockRealm
realm.beginTransaction()
val currency = realm.createObject(net.pokeranalytics.android.model.realm.Currency::class.java, "1")
currency.code = "AUD"
val b1 = realm.createObject(Bankroll::class.java, "1")
val b2 = realm.createObject(Bankroll::class.java, "2")
b2.currency = currency
val s1 = Session.testInstance(100.0, false, Date(), 1, b1)
s1.cgBigBlind = 1.0
s1.cgSmallBlind = 0.5
val s2 = Session.testInstance(100.0, false, Date(), 1, b1)
s2.cgBigBlind = 1.0
s2.cgSmallBlind = 0.5
val s3 = Session.testInstance(100.0, false, Date(), 1, b1)
s3.cgBigBlind = 2.0
s3.cgSmallBlind = 1.0
realm.commitTransaction()
val filter = SessionFilterable.BLINDS
filter.valueMap = mapOf("map" to arrayOf(mapOf(
"sb" to 0.5,
"bb" to 1.0,
"code" to null
)))
val sessions = FilterManager().filter(
realm,
Session::class.java,
arrayListOf(filter)
)
Assert.assertEquals(2, sessions.size)
sessions.map {
Assert.assertTrue(arrayListOf(s1.id, s2.id).contains((it as Session).id))
}
}
@Test
fun testSingleBlindNoSmallBlindNoCurrencyFilter() {
val realm = this.mockRealm
realm.beginTransaction()
val currency = realm.createObject(net.pokeranalytics.android.model.realm.Currency::class.java, "1")
currency.code = "AUD"
val b1 = realm.createObject(Bankroll::class.java, "1")
val b2 = realm.createObject(Bankroll::class.java, "2")
b2.currency = currency
val s1 = Session.testInstance(100.0, false, Date(), 1, b1)
s1.cgBigBlind = 1.0
s1.cgSmallBlind = 0.5
val s2 = Session.testInstance(100.0, false, Date(), 1, b1)
s2.cgBigBlind = 1.0
s2.cgSmallBlind = 0.5
val s3 = Session.testInstance(100.0, false, Date(), 1, b1)
s3.cgBigBlind = 2.0
s3.cgSmallBlind = 1.0
realm.commitTransaction()
val filter = SessionFilterable.BLINDS
filter.valueMap = mapOf("map" to arrayOf(mapOf(
"sb" to null,
"bb" to 1.0,
"code" to null
)))
val sessions = FilterManager().filter(
realm,
Session::class.java,
arrayListOf(filter)
)
Assert.assertEquals(2, sessions.size)
sessions.map {
Assert.assertTrue(arrayListOf(s1.id, s2.id).contains((it as Session).id))
}
}
@Test
fun testSingleBlindCurrencyFilter() {
val realm = this.mockRealm
realm.beginTransaction()
val currency = realm.createObject(net.pokeranalytics.android.model.realm.Currency::class.java, "1")
currency.code = "AUD"
val b1 = realm.createObject(Bankroll::class.java, "1")
val b2 = realm.createObject(Bankroll::class.java, "2")
b2.currency = currency
val s1 = Session.testInstance(100.0, false, Date(), 1, b1)
s1.cgBigBlind = 1.0
s1.cgSmallBlind = 0.5
val s2 = Session.testInstance(100.0, false, Date(), 1, b1)
s2.cgBigBlind = 1.0
s2.cgSmallBlind = 0.5
val s3 = Session.testInstance(100.0, false, Date(), 1, b2)
s3.cgBigBlind = 2.0
s3.cgSmallBlind = 1.0
realm.commitTransaction()
val filter = SessionFilterable.BLINDS
filter.valueMap = mapOf("map" to arrayOf(mapOf(
"sb" to 1.0,
"bb" to 2.0,
"code" to "AUD"
)))
val sessions = FilterManager().filter(
realm,
Session::class.java,
arrayListOf(filter)
)
Assert.assertEquals(1, sessions.size)
sessions.map {
Assert.assertEquals(s3.id, (it as Session).id)
}
}
@Test
fun testMultiBlindNoCurrencyFilter() {
val realm = this.mockRealm
realm.beginTransaction()
val currency = realm.createObject(net.pokeranalytics.android.model.realm.Currency::class.java, "1")
currency.code = "AUD"
val b1 = realm.createObject(Bankroll::class.java, "1")
val b2 = realm.createObject(Bankroll::class.java, "2")
b2.currency = currency
val s1 = Session.testInstance(100.0, false, Date(), 1, b1)
s1.cgBigBlind = 1.0
s1.cgSmallBlind = 0.5
val s2 = Session.testInstance(100.0, false, Date(), 1, b1)
s2.cgBigBlind = 2.0
s2.cgSmallBlind = 1.0
val s3 = Session.testInstance(100.0, false, Date(), 1, b2)
s3.cgBigBlind = 2.0
s3.cgSmallBlind = 1.0
realm.commitTransaction()
val filter = SessionFilterable.BLINDS
filter.valueMap = mapOf("map" to arrayOf(
mapOf(
"sb" to 1.0,
"bb" to 2.0,
"code" to null
),
mapOf(
"sb" to 0.5,
"bb" to 1.0,
"code" to null
)))
val sessions = FilterManager().filter(
realm,
Session::class.java,
arrayListOf(filter)
)
Assert.assertEquals(2, sessions.size)
sessions.map {
Assert.assertTrue(arrayListOf(s1.id, s2.id).contains((it as Session).id))
}
}
}

@ -0,0 +1,274 @@
package net.pokeranalytics.android.filter
import androidx.test.ext.junit.runners.AndroidJUnit4
import net.pokeranalytics.android.model.filter.DateFilterable
import net.pokeranalytics.android.model.filter.FilterManager
import net.pokeranalytics.android.model.realm.Session
import org.junit.Assert
import org.junit.Test
import org.junit.runner.RunWith
import java.util.*
@RunWith(AndroidJUnit4::class)
class DateFilterInstrumentedUnitTest : BaseFilterInstrumentedUnitTest() {
@Test
fun testDayOfWeekFilter() {
val realm = this.mockRealm
realm.beginTransaction()
val cal = Calendar.getInstance() // creates calendar
cal.time = Date() // sets calendar time/date
val s1 = Session.testInstance(100.0, false, cal.time)
cal.add(Calendar.DAY_OF_MONTH, 1) // adds one hour
Session.testInstance(100.0, true, cal.time)
realm.commitTransaction()
val filter = DateFilterable.DAY_OF_WEEK
cal.time = s1.startDate
filter.valueMap = mapOf("dayOfWeek" to cal.get(Calendar.DAY_OF_WEEK))
val sessions = FilterManager().filter(
realm,
Session::class.java,
arrayListOf(filter)
)
Assert.assertEquals(1, sessions.size)
sessions[0]?.run {
Assert.assertEquals(s1.id, (this as Session).id)
}
}
@Test
fun testMonthFilter() {
val realm = this.mockRealm
realm.beginTransaction()
val cal = Calendar.getInstance()
cal.time = Date()
val s1 = Session.testInstance(100.0, false, cal.time)
cal.add(Calendar.MONTH, 1)
Session.testInstance(100.0, true, cal.time)
realm.commitTransaction()
val filter = DateFilterable.MONTH
cal.time = s1.startDate
filter.valueMap = mapOf("month" to cal.get(Calendar.MONTH))
val sessions = FilterManager().filter(
realm,
Session::class.java,
arrayListOf(filter)
)
Assert.assertEquals(1, sessions.size)
sessions[0]?.run {
Assert.assertEquals(s1.id, (this as Session).id)
}
}
@Test
fun testYearFilter() {
val realm = this.mockRealm
realm.beginTransaction()
val cal = Calendar.getInstance()
cal.time = Date()
val s1 = Session.testInstance(100.0, false, cal.time)
cal.add(Calendar.YEAR, 1)
Session.testInstance(100.0, true, cal.time)
realm.commitTransaction()
val filter = DateFilterable.YEAR
cal.time = s1.startDate
filter.valueMap = mapOf("year" to cal.get(Calendar.YEAR))
val sessions = FilterManager().filter(
realm,
Session::class.java,
arrayListOf(filter)
)
Assert.assertEquals(1, sessions.size)
sessions[0]?.run {
Assert.assertEquals(s1.id, (this as Session).id)
}
}
@Test
fun testWeekEndFilter() {
val realm = this.mockRealm
realm.beginTransaction()
val cal = Calendar.getInstance()
cal.time = Date()
cal.set(Calendar.DAY_OF_WEEK, Calendar.SATURDAY)
val s1 = Session.testInstance(100.0, false, cal.time)
cal.set(Calendar.DAY_OF_WEEK, Calendar.TUESDAY)
Session.testInstance(100.0, true, cal.time)
realm.commitTransaction()
val sessions = FilterManager().filter(
realm,
Session::class.java,
arrayListOf(DateFilterable.WEEK_END)
)
Assert.assertEquals(1, sessions.size)
sessions[0]?.run {
Assert.assertEquals(s1.id, (this as Session).id)
}
}
@Test
fun testWeekDayFilter() {
val realm = this.mockRealm
realm.beginTransaction()
val cal = Calendar.getInstance()
cal.time = Date()
cal.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY)
val s1 = Session.testInstance(100.0, false, cal.time)
cal.set(Calendar.DAY_OF_WEEK, Calendar.SUNDAY)
Session.testInstance(100.0, true, cal.time)
realm.commitTransaction()
val sessions = FilterManager().filter(
realm,
Session::class.java,
arrayListOf(DateFilterable.WEEK_DAY)
)
Assert.assertEquals(1, sessions.size)
sessions[0]?.run {
Assert.assertEquals(s1.id, (this as Session).id)
}
}
@Test
fun testStartedFomDateFilter() {
val realm = this.mockRealm
realm.beginTransaction()
val cal = Calendar.getInstance() // creates calendar
cal.time = Date() // sets calendar time/date
Session.testInstance(100.0, false, cal.time, 1)
cal.add(Calendar.HOUR_OF_DAY, 2) // adds one hour
val s2 = Session.testInstance(100.0, true, cal.time, 1)
realm.commitTransaction()
val filter = DateFilterable.STARTED_FROM_DATE
filter.valueMap = mapOf("date" to s2.startDate)
val sessions = FilterManager().filter(
realm,
Session::class.java,
arrayListOf(filter)
)
Assert.assertEquals(1, sessions.size)
sessions[0]?.run {
Assert.assertEquals(s2.id, (this as Session).id)
}
}
@Test
fun testStartedToDateFilter() {
val realm = this.mockRealm
realm.beginTransaction()
val cal = Calendar.getInstance() // creates calendar
cal.time = Date() // sets calendar time/date
val s1 = Session.testInstance(100.0, false, cal.time, 1)
cal.add(Calendar.HOUR_OF_DAY, 2) // adds one hour
Session.testInstance(100.0, true, cal.time, 1)
realm.commitTransaction()
val filter = DateFilterable.STARTED_TO_DATE
filter.valueMap = mapOf("date" to s1.startDate)
val sessions = FilterManager().filter(
realm,
Session::class.java,
arrayListOf(filter)
)
Assert.assertEquals(1, sessions.size)
sessions[0]?.run {
Assert.assertEquals(s1.id, (this as Session).id)
}
}
@Test
fun testEndedFomDateFilter() {
val realm = this.mockRealm
realm.beginTransaction()
val cal = Calendar.getInstance() // creates calendar
cal.time = Date() // sets calendar time/date
Session.testInstance(100.0, false, cal.time, 1)
cal.add(Calendar.HOUR_OF_DAY, 2) // adds one hour
val s2 = Session.testInstance(100.0, true, cal.time, 1)
realm.commitTransaction()
val filter = DateFilterable.ENDED_FROM_DATE
filter.valueMap = mapOf("date" to s2.endDate)
val sessions = FilterManager().filter(
realm,
Session::class.java,
arrayListOf(filter)
)
Assert.assertEquals(1, sessions.size)
sessions[0]?.run {
Assert.assertEquals(s2.id, (this as Session).id)
}
}
@Test
fun testEndedToDateFilter() {
val realm = this.mockRealm
realm.beginTransaction()
val cal = Calendar.getInstance() // creates calendar
cal.time = Date() // sets calendar time/date
val s1 = Session.testInstance(100.0, false, cal.time, 1)
cal.add(Calendar.HOUR_OF_DAY, 2) // adds one hour
Session.testInstance(100.0, true, cal.time, 1)
realm.commitTransaction()
val filter = DateFilterable.ENDED_TO_DATE
filter.valueMap = mapOf("date" to s1.endDate)
val sessions = FilterManager().filter(
realm,
Session::class.java,
arrayListOf(filter)
)
Assert.assertEquals(1, sessions.size)
sessions[0]?.run {
Assert.assertEquals(s1.id, (this as Session).id)
}
}
}

@ -0,0 +1,55 @@
package net.pokeranalytics.android.filter
import androidx.test.ext.junit.runners.AndroidJUnit4
import net.pokeranalytics.android.exceptions.FilterValueMapException
import net.pokeranalytics.android.model.filter.DateFilterable
import net.pokeranalytics.android.model.filter.FilterManager
import net.pokeranalytics.android.model.filter.SessionFilterable
import net.pokeranalytics.android.model.realm.Session
import org.junit.Test
import org.junit.runner.RunWith
import java.util.*
@RunWith(AndroidJUnit4::class)
class ExceptionFilterInstrumentedTest: BaseFilterInstrumentedUnitTest() {
@Test(expected = FilterValueMapException::class)
fun testFilterException() {
val realm = this.mockRealm
FilterManager().filter(
realm,
Session::class.java,
arrayListOf(SessionFilterable.BLINDS)
)
}
@Test(expected = FilterValueMapException::class)
fun testValueKeyFilterException() {
val filter = DateFilterable.STARTED_FROM_DATE
filter.valueMap = mapOf("bob" to Date())
val realm = this.mockRealm
FilterManager().filter(
realm,
Session::class.java,
arrayListOf(filter)
)
}
@Test(expected = FilterValueMapException::class)
fun testSubValueKeyFilterException() {
val filter = SessionFilterable.BLINDS
filter.valueMap = mapOf("map" to arrayOf(mapOf(
"bob" to 0.5,
"bb" to 1.0,
"code" to null
)))
val realm = this.mockRealm
FilterManager().filter(
realm,
Session::class.java,
arrayListOf(filter)
)
}
}

@ -0,0 +1,567 @@
package net.pokeranalytics.android.filter
import androidx.test.ext.junit.runners.AndroidJUnit4
import io.realm.RealmList
import net.pokeranalytics.android.model.filter.FilterManager
import net.pokeranalytics.android.model.filter.SessionFilterable
import net.pokeranalytics.android.model.realm.*
import org.junit.Assert
import org.junit.Test
import org.junit.runner.RunWith
import java.util.*
@RunWith(AndroidJUnit4::class)
class SessionFilterInstrumentedUnitTest : BaseFilterInstrumentedUnitTest() {
@Test
fun testCashFilter() {
val realm = this.mockRealm
realm.beginTransaction()
Session.testInstance(100.0, false, Date(), 1)
Session.testInstance(100.0, true, Date(), 1)
realm.commitTransaction()
val sessions = FilterManager().filter(
realm,
Session::class.java,
arrayListOf(SessionFilterable.CASH)
)
Assert.assertEquals(1, sessions.size)
sessions[0]?.run {
Assert.assertEquals(Session.Type.CASH_GAME.ordinal, (this as Session).type)
}
}
@Test
fun testTournamentFilter() {
val realm = this.mockRealm
realm.beginTransaction()
Session.testInstance(100.0, false, Date(), 1)
Session.testInstance(100.0, true, Date(), 1)
realm.commitTransaction()
val sessions = FilterManager().filter(
realm,
Session::class.java,
arrayListOf(SessionFilterable.TOURNAMENT)
)
Assert.assertEquals(1, sessions.size)
sessions[0]?.run {
Assert.assertEquals(Session.Type.TOURNAMENT.ordinal, (this as Session).type)
}
}
@Test
fun testLiveFilter() {
val realm = this.mockRealm
realm.beginTransaction()
val b1 = realm.createObject(Bankroll::class.java, "1")
val b2 = realm.createObject(Bankroll::class.java, "2")
b1.live = true
b2.live = false
Session.testInstance(100.0, false, Date(), 1, b1)
Session.testInstance(100.0, true, Date(), 1, b2)
realm.commitTransaction()
val sessions = FilterManager().filter(
realm,
Session::class.java,
arrayListOf(SessionFilterable.LIVE)
)
Assert.assertEquals(1, sessions.size)
(sessions[0] as Session).bankroll?.run {
Assert.assertEquals(true, this.live)
}
}
@Test
fun testOnlineFilter() {
val realm = this.mockRealm
realm.beginTransaction()
val b1 = realm.createObject(Bankroll::class.java, "1")
val b2 = realm.createObject(Bankroll::class.java, "2")
b1.live = false
b2.live = true
Session.testInstance(100.0, false, Date(), 1, b1)
Session.testInstance(100.0, true, Date(), 1, b2)
realm.commitTransaction()
val sessions = FilterManager().filter(
realm,
Session::class.java,
arrayListOf(SessionFilterable.ONLINE)
)
Assert.assertEquals(1, sessions.size)
(sessions[0] as Session).bankroll?.run {
Assert.assertEquals(false, this.live)
}
}
@Test
fun testBankrollFilter() {
val realm = this.mockRealm
realm.beginTransaction()
val b1 = realm.createObject(Bankroll::class.java, "1")
val b2 = realm.createObject(Bankroll::class.java, "2")
b1.live = false
b2.live = true
Session.testInstance(bankroll = b1)
Session.testInstance(bankroll = b2)
realm.commitTransaction()
val filter = SessionFilterable.BANKROLL
filter.valueMap = mapOf("ids" to arrayOf(b1.id))
val sessions = FilterManager().filter(
realm,
Session::class.java,
arrayListOf(filter)
)
Assert.assertEquals(1, sessions.size)
(sessions[0] as Session).bankroll?.run {
Assert.assertEquals(b1.id, this.id)
}
}
@Test
fun testMultipleBankrollFilter() {
val realm = this.mockRealm
realm.beginTransaction()
val b1 = realm.createObject(Bankroll::class.java, "1")
val b2 = realm.createObject(Bankroll::class.java, "2")
val b3 = realm.createObject(Bankroll::class.java, "3")
Session.testInstance(bankroll = b1)
Session.testInstance(bankroll = b2)
Session.testInstance(bankroll = b3)
Session.testInstance(bankroll = b1)
Session.testInstance(bankroll = b2)
Session.testInstance(bankroll = b3)
Session.testInstance(bankroll = b1)
Session.testInstance(bankroll = b2)
Session.testInstance(bankroll = b3)
realm.commitTransaction()
val filter = SessionFilterable.BANKROLL
filter.valueMap = mapOf("ids" to arrayOf(b1.id, b2.id))
val sessions = FilterManager().filter(
realm,
Session::class.java,
arrayListOf(filter)
)
Assert.assertEquals(6, sessions.size)
val result = arrayListOf(b1.id, b2.id)
sessions.forEach {
Assert.assertTrue(result.contains((it as Session).bankroll?.id))
}
}
@Test
fun testGameFilter() {
val realm = this.mockRealm
realm.beginTransaction()
val g1 = realm.createObject(Game::class.java, "1")
val g2 = realm.createObject(Game::class.java, "2")
Session.testInstance(game = g1)
Session.testInstance(game = g2)
realm.commitTransaction()
val filter = SessionFilterable.GAME
filter.valueMap = mapOf("ids" to arrayOf(g2.id))
val sessions = FilterManager().filter(
realm,
Session::class.java,
arrayListOf(filter)
)
Assert.assertEquals(1, sessions.size)
(sessions[0] as Session).game?.run {
Assert.assertEquals(g2.id, this.id)
}
}
@Test
fun testMultipleGameFilter() {
val realm = this.mockRealm
realm.beginTransaction()
val g1 = realm.createObject(Game::class.java, "1")
val g2 = realm.createObject(Game::class.java, "2")
val g3 = realm.createObject(Game::class.java, "3")
Session.testInstance(game = g1)
Session.testInstance(game = g2)
Session.testInstance(game = g3)
Session.testInstance(game = g1)
Session.testInstance(game = g2)
Session.testInstance(game = g3)
Session.testInstance(game = g1)
Session.testInstance(game = g2)
Session.testInstance(game = g3)
realm.commitTransaction()
val filter = SessionFilterable.GAME
filter.valueMap = mapOf("ids" to arrayOf(g2.id, g3.id))
val sessions = FilterManager().filter(
realm,
Session::class.java,
arrayListOf(filter)
)
Assert.assertEquals(6, sessions.size)
val result = arrayListOf(g2.id, g3.id)
sessions.forEach {
Assert.assertTrue(result.contains((it as Session).game?.id))
}
}
@Test
fun testLocationFilter() {
val realm = this.mockRealm
realm.beginTransaction()
val l1 = realm.createObject(Location::class.java, "1")
val l2 = realm.createObject(Location::class.java, "2")
Session.testInstance(location = l1)
Session.testInstance(location = l2)
realm.commitTransaction()
val filter = SessionFilterable.LOCATION
filter.valueMap = mapOf("ids" to arrayOf(l1.id))
val sessions = FilterManager().filter(
realm,
Session::class.java,
arrayListOf(filter)
)
Assert.assertEquals(1, sessions.size)
(sessions[0] as Session).location?.run {
Assert.assertEquals(l1.id, this.id)
}
}
@Test
fun testMultipleLocationFilter() {
val realm = this.mockRealm
realm.beginTransaction()
val l1 = realm.createObject(Location::class.java, "1")
val l2 = realm.createObject(Location::class.java, "2")
val l3 = realm.createObject(Location::class.java, "3")
Session.testInstance(location = l1)
Session.testInstance(location = l2)
Session.testInstance(location = l3)
Session.testInstance(location = l1)
Session.testInstance(location = l2)
Session.testInstance(location = l3)
Session.testInstance(location = l1)
Session.testInstance(location = l2)
Session.testInstance(location = l3)
realm.commitTransaction()
val filter = SessionFilterable.LOCATION
filter.valueMap = mapOf("ids" to arrayOf(l1.id, l3.id))
val sessions = FilterManager().filter(
realm,
Session::class.java,
arrayListOf(filter)
)
Assert.assertEquals(6, sessions.size)
val result = arrayListOf(l2.id, l3.id)
sessions.forEach {
Assert.assertTrue(result.contains((it as Session).location?.id))
}
}
@Test
fun testTournamentNameFilter() {
val realm = this.mockRealm
realm.beginTransaction()
val t1 = realm.createObject(TournamentName::class.java, "1")
val t2 = realm.createObject(TournamentName::class.java, "2")
Session.testInstance(tournamentName = t1)
Session.testInstance(tournamentName = t2)
realm.commitTransaction()
val filter = SessionFilterable.TOURNAMENT_NAME
filter.valueMap = mapOf("ids" to arrayOf(t1.id))
val sessions = FilterManager().filter(
realm,
Session::class.java,
arrayListOf(filter)
)
Assert.assertEquals(1, sessions.size)
(sessions[0] as Session).tournamentName?.run {
Assert.assertEquals(t1.id, this.id)
}
}
@Test
fun testMultipleTournamentNameFilter() {
val realm = this.mockRealm
realm.beginTransaction()
val t1 = realm.createObject(TournamentName::class.java, "1")
val t2 = realm.createObject(TournamentName::class.java, "2")
val t3 = realm.createObject(TournamentName::class.java, "3")
Session.testInstance(tournamentName = t1)
Session.testInstance(tournamentName = t2)
Session.testInstance(tournamentName = t3)
Session.testInstance(tournamentName = t1)
Session.testInstance(tournamentName = t2)
Session.testInstance(tournamentName = t3)
Session.testInstance(tournamentName = t1)
Session.testInstance(tournamentName = t2)
Session.testInstance(tournamentName = t3)
realm.commitTransaction()
val filter = SessionFilterable.TOURNAMENT_NAME
filter.valueMap = mapOf("ids" to arrayOf(t1.id, t2.id))
val sessions = FilterManager().filter(
realm,
Session::class.java,
arrayListOf(filter)
)
Assert.assertEquals(6, sessions.size)
val result = arrayListOf(t1.id, t2.id)
sessions.forEach {
Assert.assertTrue(result.contains((it as Session).tournamentName?.id))
}
}
@Test
fun testAllTournamentFeatureFilter() {
val realm = this.mockRealm
realm.beginTransaction()
val t1 = realm.createObject(TournamentFeature::class.java, "1")
val t2 = realm.createObject(TournamentFeature::class.java, "2")
val t3 = realm.createObject(TournamentFeature::class.java, "3")
val t4 = realm.createObject(TournamentFeature::class.java, "4")
Session.testInstance(tournamentFeatures = RealmList(t1,t2))
Session.testInstance(tournamentFeatures = RealmList(t2,t3))
Session.testInstance(tournamentFeatures = RealmList(t3,t4))
val s = Session.testInstance(tournamentFeatures = RealmList(t1,t2,t3,t4))
Session.testInstance(tournamentFeatures = RealmList(t1,t4))
Session.testInstance(tournamentFeatures = RealmList(t1,t3))
Session.testInstance(tournamentFeatures = RealmList(t2,t4, t3))
Session.testInstance(tournamentFeatures = RealmList(t1))
realm.commitTransaction()
val filter = SessionFilterable.ALL_TOURNAMENT_FEATURES
filter.valueMap = mapOf("ids" to arrayOf(t1.id, t2.id, t3.id, t4.id))
val sessions = FilterManager().filter(
realm,
Session::class.java,
arrayListOf(filter)
)
Assert.assertEquals(1, sessions.size)
(sessions[0] as Session)?.run {
Assert.assertEquals(s.id, this.id)
}
}
@Test
fun testAnyTournamentFeatureFilter() {
val realm = this.mockRealm
realm.beginTransaction()
val t1 = realm.createObject(TournamentFeature::class.java, "1")
val t2 = realm.createObject(TournamentFeature::class.java, "2")
val t3 = realm.createObject(TournamentFeature::class.java, "3")
val t4 = realm.createObject(TournamentFeature::class.java, "4")
Session.testInstance(tournamentFeatures = RealmList(t1,t2))
Session.testInstance(tournamentFeatures = RealmList(t2,t3))
Session.testInstance(tournamentFeatures = RealmList(t3,t4))
Session.testInstance(tournamentFeatures = RealmList(t1,t2,t3,t4))
Session.testInstance(tournamentFeatures = RealmList(t1,t4))
Session.testInstance(tournamentFeatures = RealmList(t1,t3))
Session.testInstance(tournamentFeatures = RealmList(t2,t4, t3))
Session.testInstance(tournamentFeatures = RealmList(t1))
realm.commitTransaction()
val filter = SessionFilterable.ANY_TOURNAMENT_FEATURES
filter.valueMap = mapOf("ids" to arrayOf(t1.id, t2.id, t3.id, t4.id))
val sessions = FilterManager().filter(
realm,
Session::class.java,
arrayListOf(filter)
)
Assert.assertEquals(8, sessions.size)
}
@Test
fun testSingleAnyTournamentFeatureFilter() {
val realm = this.mockRealm
realm.beginTransaction()
val t1 = realm.createObject(TournamentFeature::class.java, "1")
val t2 = realm.createObject(TournamentFeature::class.java, "2")
val t3 = realm.createObject(TournamentFeature::class.java, "3")
val t4 = realm.createObject(TournamentFeature::class.java, "4")
val s1 = Session.testInstance(tournamentFeatures = RealmList(t1,t2))
val s2 = Session.testInstance(tournamentFeatures = RealmList(t2,t3))
Session.testInstance(tournamentFeatures = RealmList(t3,t4))
val s3 = Session.testInstance(tournamentFeatures = RealmList(t1,t2,t3,t4))
Session.testInstance(tournamentFeatures = RealmList(t1,t4))
Session.testInstance(tournamentFeatures = RealmList(t1,t3))
val s4 = Session.testInstance(tournamentFeatures = RealmList(t2,t4, t3))
Session.testInstance(tournamentFeatures = RealmList(t1))
realm.commitTransaction()
val filter = SessionFilterable.ANY_TOURNAMENT_FEATURES
filter.valueMap = mapOf("ids" to arrayOf(t2.id))
val sessions = FilterManager().filter(
realm,
Session::class.java,
arrayListOf(filter)
)
val result = arrayListOf(s1.id, s2.id, s3.id, s4.id)
Assert.assertEquals(4, sessions.size)
sessions.forEach {
Assert.assertTrue(result.contains((it as Session).id))
}
}
@Test
fun testTableSizeFilter() {
val realm = this.mockRealm
realm.beginTransaction()
val s1 = Session.testInstance(tableSize = 2)
val s2 = Session.testInstance(tableSize = 4)
Session.testInstance(tableSize = 9)
Session.testInstance(tableSize = 10)
realm.commitTransaction()
val filter = SessionFilterable.TABLE_SIZE
filter.valueMap = mapOf("values" to arrayOf(2,4))
val sessions = FilterManager().filter(
realm,
Session::class.java,
arrayListOf(filter)
)
Assert.assertEquals(2, sessions.size)
val result = arrayListOf(s1.id, s2.id)
sessions.forEach {
Assert.assertTrue(result.contains((it as Session).id))
}
}
@Test
fun testMoreThanNetResultFilter() {
val realm = this.mockRealm
realm.beginTransaction()
Session.testInstance(netResult = 200.0)
val s1 = Session.testInstance(netResult = 500.0)
Session.testInstance(netResult = 50.0)
val s2 = Session.testInstance(netResult = 570.0)
realm.commitTransaction()
val filter = SessionFilterable.MORE_THAN_NET_RESULT
filter.valueMap = mapOf("net" to 204.0)
val sessions = FilterManager().filter(
realm,
Session::class.java,
arrayListOf(filter)
)
Assert.assertEquals(2, sessions.size)
val result = arrayListOf(s1.id, s2.id)
sessions.forEach {
Assert.assertTrue(result.contains((it as Session).id))
}
}
@Test
fun testLessThanNetResultFilter() {
val realm = this.mockRealm
realm.beginTransaction()
val s1 = Session.testInstance(netResult = 200.0)
val s2 = Session.testInstance(netResult = 500.0)
val s3 = Session.testInstance(netResult = 50.0)
Session.testInstance(netResult = 570.0)
realm.commitTransaction()
val filter = SessionFilterable.LESS_THAN_NET_RESULT
filter.valueMap = mapOf("net" to 540.0)
val sessions = FilterManager().filter(
realm,
Session::class.java,
arrayListOf(filter)
)
Assert.assertEquals(3, sessions.size)
val result = arrayListOf(s1.id, s2.id, s3.id)
sessions.forEach {
Assert.assertTrue(result.contains((it as Session).id))
}
}
@Test
fun tesNetResultFilter() {
val realm = this.mockRealm
realm.beginTransaction()
val s1 = Session.testInstance(netResult = 200.0)
val s2 = Session.testInstance(netResult = 500.0)
val s3 = Session.testInstance(netResult = 50.0)
Session.testInstance(netResult = 570.0)
realm.commitTransaction()
val filterMore = SessionFilterable.MORE_THAN_NET_RESULT
filterMore.valueMap = mapOf("net" to 200.0)
val filterLess = SessionFilterable.LESS_THAN_NET_RESULT
filterLess.valueMap = mapOf("net" to 400.0)
val sessions = FilterManager().filter(
realm,
Session::class.java,
arrayListOf(filterLess, filterMore)
)
Assert.assertEquals(1, sessions.size)
val result = arrayListOf(s1.id)
sessions.forEach {
Assert.assertTrue(result.contains((it as Session).id))
}
}
}

@ -42,9 +42,16 @@
android:launchMode="singleTop" /> android:launchMode="singleTop" />
<activity <activity
android:name=".ui.activity.GDPRActivity" android:name=".ui.activity.FiltersActivity"
android:launchMode="singleTop" />
<activity
android:name=".ui.activity.FilterDetailsActivity"
android:launchMode="singleTop" /> android:launchMode="singleTop" />
<activity
android:name=".ui.activity.GDPRActivity"
android:launchMode="singleTop" />
<meta-data <meta-data
android:name="preloaded_fonts" android:name="preloaded_fonts"

@ -0,0 +1,80 @@
package net.pokeranalytics.android.api
import android.content.Context
import net.pokeranalytics.android.BuildConfig
import net.pokeranalytics.android.R
import net.pokeranalytics.android.model.retrofit.CurrencyConverterValue
import net.pokeranalytics.android.util.URL
import okhttp3.Interceptor
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Call
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import retrofit2.http.GET
import retrofit2.http.Query
import java.util.concurrent.TimeUnit
/**
* Currency Converter API
*/
interface CurrencyConverterApi {
companion object {
private var currencyConverterApi: CurrencyConverterApi? = null
fun getApi(context: Context): CurrencyConverterApi? {
if (currencyConverterApi == null) {
var serviceEndpoint = URL.API_CURRENCY_CONVERTER
val httpClient = OkHttpClient.Builder()
// Logging interceptor
if (BuildConfig.DEBUG) {
val interceptor = HttpLoggingInterceptor()
interceptor.level = HttpLoggingInterceptor.Level.BASIC
httpClient.addInterceptor(interceptor)
}
// Add headers
val interceptor = Interceptor { chain ->
val original = chain.request()
val originalHttpUrl = original.url()
val url = originalHttpUrl.newBuilder()
.addQueryParameter("apiKey", context.getString(R.string.currency_converter_api))
.build()
val requestBuilder = original.newBuilder()
.url(url)
chain.proceed(requestBuilder.build())
}
httpClient.addInterceptor(interceptor)
val client = httpClient
.readTimeout(60, TimeUnit.SECONDS)
.connectTimeout(60, TimeUnit.SECONDS)
.build()
val retrofit = Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create())
.baseUrl(serviceEndpoint.value)
.client(client)
.build()
currencyConverterApi = retrofit.create(CurrencyConverterApi::class.java)
}
return currencyConverterApi
}
}
@GET("convert")
fun convert(@Query("q") currencies: String, @Query("compact") compact: String = "y"): Call<Map<String, CurrencyConverterValue>>
}

@ -5,10 +5,11 @@ import net.pokeranalytics.android.R
import net.pokeranalytics.android.exceptions.FormattingException import net.pokeranalytics.android.exceptions.FormattingException
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.FormatUtils 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 java.util.*
/** /**
* An enum representing all the types of Session statistics * An enum representing all the types of Session statistics
@ -99,7 +100,7 @@ enum class Stat : RowRepresentable {
/** /**
* ComputedStat contains a [stat] and their associated [value] * ComputedStat contains a [stat] and their associated [value]
*/ */
class ComputedStat(stat: Stat, value: Double) { class ComputedStat(var stat: Stat, var value: Double, var currency: Currency? = null) {
constructor(stat: Stat, value: Double, previousValue: Double?) : this(stat, value) { constructor(stat: Stat, value: Double, previousValue: Double?) : this(stat, value) {
if (previousValue != null) { if (previousValue != null) {
@ -107,16 +108,6 @@ class ComputedStat(stat: Stat, value: Double) {
} }
} }
/**
* The statistic type
*/
var stat: Stat = stat
/**
* The stat value
*/
var value: Double = value
/** /**
* The variation of the stat * The variation of the stat
*/ */
@ -135,7 +126,7 @@ class ComputedStat(stat: Stat, value: Double) {
// Amounts + red/green // Amounts + red/green
Stat.NETRESULT, Stat.HOURLY_RATE, Stat.AVERAGE, Stat.NET_BB_PER_100_HANDS, Stat.HOURLY_RATE_BB, Stat.NETRESULT, Stat.HOURLY_RATE, Stat.AVERAGE, Stat.NET_BB_PER_100_HANDS, Stat.HOURLY_RATE_BB,
Stat.AVERAGE_NET_BB -> { Stat.AVERAGE_NET_BB -> {
val numberFormat= FormatUtils.getCurrencyFormatter(context) val numberFormat= CurrencyUtils.getCurrencyFormatter(context, currency)
val color = if (this.value >= this.stat.threshold) R.color.green else R.color.red val color = if (this.value >= this.stat.threshold) R.color.green else R.color.red
return TextFormat(numberFormat.format(this.value), color) return TextFormat(numberFormat.format(this.value), color)
} // white integers } // white integers
@ -148,10 +139,10 @@ class ComputedStat(stat: Stat, value: Double) {
Stat.WIN_RATIO, Stat.ROI -> { Stat.WIN_RATIO, Stat.ROI -> {
val color = if (value * 100 >= this.stat.threshold) R.color.green else R.color.red val color = if (value * 100 >= this.stat.threshold) R.color.green else R.color.red
return TextFormat("${(value * 100).formatted()}%", color) return TextFormat("${(value * 100).formatted()}%", color)
} // white amounts } // 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= FormatUtils.getCurrencyFormatter(context) val numberFormat= CurrencyUtils.getCurrencyFormatter(context, currency)
return TextFormat(numberFormat.format(this.value)) return TextFormat(numberFormat.format(this.value))
} }
else -> throw FormattingException("Stat formatting of ${this.stat.name} not handled") else -> throw FormattingException("Stat formatting of ${this.stat.name} not handled")

@ -11,3 +11,7 @@ class FormattingException(message: String) : Exception(message) {
class RowRepresentableEditDescriptorException(message: String) : Exception(message) { class RowRepresentableEditDescriptorException(message: String) : Exception(message) {
} }
class FilterValueMapException(message: String) : Exception(message) {
}

@ -145,6 +145,9 @@ enum class LiveData : Localizable {
} }
} }
/**
* Return the new entity title
*/
fun newEntityLocalizedTitle(context: Context): String { fun newEntityLocalizedTitle(context: Context): String {
return "${context.getString(R.string.new_entity)} ${this.localizedTitle(context)}" return "${context.getString(R.string.new_entity)} ${this.localizedTitle(context)}"
} }

@ -0,0 +1,77 @@
package net.pokeranalytics.android.model.filter
import io.realm.RealmObject
import io.realm.RealmQuery
import net.pokeranalytics.android.model.filter.interfaces.Filterable
import java.util.*
enum class DateFilterable : Filterable {
STARTED_FROM_DATE,
STARTED_TO_DATE,
ENDED_FROM_DATE,
ENDED_TO_DATE,
DAY_OF_WEEK,
MONTH,
YEAR,
WEEK_DAY,
WEEK_END,
;
private enum class Field(var fieldName:String) {
START_DATE("startDate"),
END_DATE("endDate"),
DAY("dayOfWeek"),
MONTH("month"),
YEAR("year"),
}
override var valueMap : Map<String, Any?>? = null
override val filterValuesExceptedKeys : Array<String>?
get() {
return when (this) {
STARTED_FROM_DATE, STARTED_TO_DATE, ENDED_FROM_DATE, ENDED_TO_DATE -> arrayOf("date")
DAY_OF_WEEK -> arrayOf("dayOfWeek")
MONTH -> arrayOf("month")
YEAR -> arrayOf("year")
else -> null
}
}
override fun filter(realmQuery: RealmQuery<out RealmObject>): RealmQuery<out RealmObject> {
return when (this) {
STARTED_FROM_DATE -> {
val date : Date by filterValues
realmQuery.greaterThanOrEqualTo(Field.START_DATE.fieldName, date)
}
STARTED_TO_DATE -> {
val date : Date by filterValues
realmQuery.lessThanOrEqualTo(Field.START_DATE.fieldName, date)
}
ENDED_FROM_DATE -> {
val date : Date by filterValues
realmQuery.greaterThanOrEqualTo(Field.END_DATE.fieldName, date)
}
ENDED_TO_DATE -> {
val date : Date by filterValues
realmQuery.lessThanOrEqualTo(Field.END_DATE.fieldName, date)
}
DAY_OF_WEEK -> {
val dayOfWeek : Int by filterValues
realmQuery.equalTo(Field.DAY.fieldName, dayOfWeek)
}
MONTH -> {
val month: Int by filterValues
realmQuery.equalTo(Field.MONTH.fieldName, month)
}
YEAR -> {
val year: Int by filterValues
realmQuery.equalTo(Field.YEAR.fieldName, year)
}
WEEK_END -> {
realmQuery.`in`(Field.DAY.fieldName, arrayOf(Calendar.SATURDAY,Calendar.SUNDAY))
}
WEEK_DAY -> WEEK_END.filter(realmQuery.not())
}
}
}

@ -1,118 +1,5 @@
package net.pokeranalytics.android.model.filter package net.pokeranalytics.android.model.filter
import io.realm.RealmObject
import io.realm.RealmQuery
import net.pokeranalytics.android.model.realm.Session
import java.util.*
enum class FilterComponent { enum class FilterComponent {
} }
enum class SessionFilterable(var fieldName:String? = null) : Filterable {
LIVE("bankroll.live"),
CASH("type"),
ONLINE,
TOURNAMENT,
BANKROLL("bankroll.id"),
GAME("game.id"),
LIMIT("limit"),
TABLE_SIZE("tableSize"),
LOCATION("location.id"),
NUMBEROFTABLE("numberOfTable"),
COMMENT("comment"),
TOURNAMENT_TYPE("tournamentType"),
TOURNAMENT_NAME("tournamentName.id"),
TOURNAMENT_FEATURES("tournamentFeature.id"),
TOURNAMENT_NUMBER_OF_PLAYER("tournamentNumberOfPlayers"),
TOURNAMENT_ENTRY_FEE("tournamentEntryFee"),
RESULT_BUYIN("result.ratedBuyin"),
RESULT_CASHED_OUT("result.cashout"),
RESULT_NET("result.ratedNet"),
RESULT_TIPS("result.tips"),
STARTED_FROM_DATE,
STARTED_TO_DATE,
ENDED_FROM_DATE,
ENDED_TO_DATE,
BLINDS,
;
private enum class Field(var fieldName:String) {
START_DATE("startDate"),
END_DATE("endDate"),
CURRENCY("bankroll.currency"),
CURRENCY_CODE("bankroll.currency.code"),
BIG_BLIND("cgBigBlind"),
SMALL_BLIND("cgSmallBlind");
}
var valueMap : Map<String, Any?>? = null
override fun filter(realmQuery: RealmQuery<*>): RealmQuery<out RealmObject> {
return when (this) {
LIVE -> realmQuery.equalTo(this.fieldName, true)
CASH -> realmQuery.equalTo(this.fieldName, Session.Type.CASH_GAME.ordinal)
ONLINE -> LIVE.filter(realmQuery.not())
TOURNAMENT -> CASH.filter(realmQuery.not())
BANKROLL -> {
val ids : Array<String> by valueMap
realmQuery.`in`(this.fieldName, ids)
}
STARTED_FROM_DATE -> {
val date : Date by valueMap
realmQuery.greaterThanOrEqualTo(Field.START_DATE.fieldName, date)
}
STARTED_TO_DATE -> {
val date : Date by valueMap
realmQuery.lessThanOrEqualTo(Field.START_DATE.fieldName, date)
}
ENDED_FROM_DATE -> {
val date : Date by valueMap
realmQuery.greaterThanOrEqualTo(Field.END_DATE.fieldName, date)
}
ENDED_TO_DATE -> {
val date : Date by valueMap
realmQuery.lessThanOrEqualTo(Field.END_DATE.fieldName, date)
}
BLINDS -> {
val map : Array<Map<String,Any?>> by valueMap
var finalQuery = realmQuery
map.forEachIndexed { index, it ->
val sb : Double? by it
val bb : Double? by it
val code : String? by it
finalQuery
.beginGroup()
sb?.let {
finalQuery
.equalTo(Field.SMALL_BLIND.fieldName, sb)
.and()
}
finalQuery
.equalTo(Field.BIG_BLIND.fieldName, bb)
.and()
code?.let {
finalQuery.equalTo(Field.CURRENCY_CODE.fieldName, code)
} ?: run {
finalQuery.isNull(Field.CURRENCY_CODE.fieldName)
}
finalQuery.endGroup()
if (index < map.size - 1) {
finalQuery.or()
}
}
finalQuery
}
else -> realmQuery
} as RealmQuery<out RealmObject>
}
}

@ -4,8 +4,7 @@ import io.realm.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 net.pokeranalytics.android.model.LiveData import net.pokeranalytics.android.model.filter.interfaces.Filterable
import net.pokeranalytics.android.model.realm.*
/** /**
* We want to be able to store filters in the database: * We want to be able to store filters in the database:
@ -33,20 +32,11 @@ import net.pokeranalytics.android.model.realm.*
* *
*/ */
interface Filterable {
fun filter(realmQuery: RealmQuery<*>): RealmQuery<out RealmObject>
}
class FilterManager { class FilterManager {
fun test(realmResults: RealmResults<RealmObject>) {
realmResults.where().greaterThan("test", 5).findAll()
}
fun filter(realm:Realm, relatedEntity: Class<out RealmObject>, queries:List<Filterable>): RealmResults<*> { fun filter(realm:Realm, relatedEntity: Class<out RealmObject>, queries:List<Filterable>): RealmResults<*> {
var realmQuery = realm.where(relatedEntity) var realmQuery : RealmQuery<out RealmObject> = realm.where(relatedEntity)
queries.forEach { queries.forEach {
realmQuery = it.filter(realmQuery).and() realmQuery = (it.filter(realmQuery)).and()
} }
return realmQuery.findAll() return realmQuery.findAll()
} }

@ -0,0 +1,147 @@
package net.pokeranalytics.android.model.filter
import io.realm.RealmObject
import io.realm.RealmQuery
import net.pokeranalytics.android.exceptions.FilterValueMapException
import net.pokeranalytics.android.model.filter.interfaces.Filterable
import net.pokeranalytics.android.model.realm.Session
enum class SessionFilterable(private var fieldName:String? = null): Filterable {
LIVE,
CASH,
ONLINE,
TOURNAMENT,
BANKROLL("bankroll.id"),
GAME("game.id"),
TOURNAMENT_NAME("tournamentName.id"),
ANY_TOURNAMENT_FEATURES,
ALL_TOURNAMENT_FEATURES,
LOCATION("location.id"),
LIMIT("limit"),
TABLE_SIZE("tableSize"),
NUMBER_OF_TABLE("numberOfTable"),
TOURNAMENT_TYPE("tournamentType"),
BLINDS,
LESS_THAN_NET_RESULT,
MORE_THAN_NET_RESULT,
;
private enum class Field(var fieldName:String) {
LIVE("bankroll.live"),
CASH("type"),
CURRENCY("bankroll.currency"),
CURRENCY_CODE("bankroll.currency.code"),
BIG_BLIND("cgBigBlind"),
SMALL_BLIND("cgSmallBlind"),
COMMENT("comment"),
TOURNAMENT_FEATURES("tournamentFeatures.id"),
TOURNAMENT_NUMBER_OF_PLAYER("tournamentNumberOfPlayers"),
TOURNAMENT_ENTRY_FEE("tournamentEntryFee"),
RESULT_BUY_IN("result.buyin"),
RESULT_CASHED_OUT("result.cashout"),
RESULT_NET("result.ratedNet"),
RESULT_TIPS("result.tips"),
;
}
override var valueMap : Map<String, Any?>? = null
override val filterValuesExceptedKeys : Array<String>?
get() {
return when (this) {
BANKROLL, GAME, LOCATION, ANY_TOURNAMENT_FEATURES, ALL_TOURNAMENT_FEATURES -> arrayOf("ids")
LIMIT, TOURNAMENT_TYPE, TABLE_SIZE, NUMBER_OF_TABLE -> arrayOf("values")
BLINDS -> arrayOf("map")
MORE_THAN_NET_RESULT, LESS_THAN_NET_RESULT -> arrayOf("net")
else -> null
}
}
var between: Boolean = false
var moreThan: Boolean = false
var lessThan: Boolean = false
var strict: Boolean = false
override fun filter(realmQuery: RealmQuery<out RealmObject>): RealmQuery<out RealmObject> {
return when (this) {
LIVE -> realmQuery.equalTo(Field.LIVE.fieldName, true)
CASH -> realmQuery.equalTo(Field.CASH.fieldName, Session.Type.CASH_GAME.ordinal)
ONLINE -> LIVE.filter(realmQuery.not())
TOURNAMENT -> CASH.filter(realmQuery.not())
ALL_TOURNAMENT_FEATURES -> {
val ids : Array<String> by filterValues
ids.forEach {
realmQuery.equalTo(Field.TOURNAMENT_FEATURES.fieldName, it)
}
realmQuery
}
ANY_TOURNAMENT_FEATURES -> {
val ids : Array<String> by filterValues
realmQuery.`in`(Field.TOURNAMENT_FEATURES.fieldName, ids)
}
BANKROLL, GAME, LOCATION, TOURNAMENT_NAME -> {
val ids : Array<String> by filterValues
this.fieldName?.let {
realmQuery.`in`(it, ids)
} ?: run {
throw FilterValueMapException("fieldName is missing")
}
}
LIMIT, TOURNAMENT_TYPE, TABLE_SIZE, NUMBER_OF_TABLE -> {
val values : Array<Int?>? by filterValues
this.fieldName?.let {
realmQuery.`in`(it, values)
} ?: run {
throw FilterValueMapException("fieldName is missing")
}
}
MORE_THAN_NET_RESULT, LESS_THAN_NET_RESULT -> {
val net : Double by filterValues
if (this == LESS_THAN_NET_RESULT) {
realmQuery.not()
}
realmQuery.greaterThanOrEqualTo(Field.RESULT_NET.fieldName, net)
}
BLINDS -> {
val map : Array<Map<String,Any?>> by filterValues
val expectedSubKeys = arrayOf("sb", "bb", "code")
map.forEachIndexed { index, subMap ->
val missingKeys = subMap.keys.filter { !expectedSubKeys.contains(it) }
if (subMap.keys.size == expectedSubKeys.size && missingKeys.isNotEmpty()) {
throw FilterValueMapException("subValueMap does not contain $missingKeys")
}
val sb : Double? by subMap
val bb : Double? by subMap
val code : String? by subMap
realmQuery
.beginGroup()
sb?.let {
realmQuery
.equalTo(Field.SMALL_BLIND.fieldName, sb)
.and()
}
realmQuery
.equalTo(Field.BIG_BLIND.fieldName, bb)
.and()
code?.let {
realmQuery.equalTo(Field.CURRENCY_CODE.fieldName, code)
} ?: run {
realmQuery.isNull(Field.CURRENCY_CODE.fieldName)
}
realmQuery.endGroup()
if (index < map.size - 1) {
realmQuery.or()
}
}
realmQuery
}
}
}
}

@ -0,0 +1,8 @@
package net.pokeranalytics.android.model.filter.interfaces
import io.realm.RealmObject
import io.realm.RealmQuery
interface Filterable : ValueFilterable {
fun filter(realmQuery: RealmQuery<out RealmObject>): RealmQuery<out RealmObject>
}

@ -0,0 +1,20 @@
package net.pokeranalytics.android.model.filter.interfaces
import java.util.*
interface TimeFilterable {
var dayOfWeek : Int?
var month : Int?
var year : Int?
fun updateTimeParameter(startDate: Date?) {
startDate?.let {
val cal = Calendar.getInstance()
cal.time = it
dayOfWeek = cal.get(Calendar.DAY_OF_WEEK)
month = cal.get(Calendar.MONTH)
year = cal.get(Calendar.YEAR)
}
}
}

@ -0,0 +1,28 @@
package net.pokeranalytics.android.model.filter.interfaces
import net.pokeranalytics.android.exceptions.FilterValueMapException
interface ValueFilterable {
var valueMap: Map<String, Any?>?
var filterValues : Map<String, Any?>?
get() {
this.filterValuesExceptedKeys?.let { valueMapExceptedKeys ->
valueMap?.let { map ->
var missingKeys = map.keys.filter { !valueMapExceptedKeys.contains(it) }
if (map.keys.size == valueMapExceptedKeys.size && missingKeys.isNotEmpty()) {
throw FilterValueMapException("valueMap does not contain ${missingKeys}")
}
} ?: run {
throw FilterValueMapException("valueMap null not expected")
}
}
return this.valueMap
}
set(value) {
valueMap = value
}
val filterValuesExceptedKeys : Array<String>?
}

@ -14,7 +14,6 @@ interface Timed {
var netDuration: Long var netDuration: Long
/** /**
* Computes the net netDuration of the session * Computes the net netDuration of the session
*/ */

@ -18,6 +18,7 @@ import net.pokeranalytics.android.model.TableSize
import net.pokeranalytics.android.model.TournamentType 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.filter.interfaces.TimeFilterable
import net.pokeranalytics.android.model.interfaces.Manageable import net.pokeranalytics.android.model.interfaces.Manageable
import net.pokeranalytics.android.model.interfaces.Timed import net.pokeranalytics.android.model.interfaces.Timed
import net.pokeranalytics.android.model.utils.SessionSetManager import net.pokeranalytics.android.model.utils.SessionSetManager
@ -29,13 +30,15 @@ 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.extensions.* import net.pokeranalytics.android.util.extensions.*
import java.util.* import java.util.*
import java.util.Currency import java.util.Currency
import kotlin.collections.ArrayList import kotlin.collections.ArrayList
open class Session : RealmObject(), Manageable, StaticRowRepresentableDataSource, RowRepresentable, Timed { open class Session : RealmObject(), Manageable, StaticRowRepresentableDataSource, RowRepresentable, Timed,
TimeFilterable {
// @Ignore // @Ignore
// var rate: Double = 0.0 // var rate: Double = 0.0
@ -87,12 +90,18 @@ open class Session : RealmObject(), Manageable, StaticRowRepresentableDataSource
// Timed interface // Timed interface
override var dayOfWeek : Int? = null
override var month: Int? = null
override var year: Int? = null
/** /**
* The start date of the session * The start date of the session
*/ */
var startDate: Date? = null var startDate: Date? = null
set(value) { set(value) {
field = value field = value
this.updateTimeParameter(field)
this.computeNetDuration() this.computeNetDuration()
// nullifies endate when setting the start date after the end date // nullifies endate when setting the start date after the end date
if (value != null && this.endDate != null && value.after(this.endDate)) { if (value != null && this.endDate != null && value.after(this.endDate)) {
@ -515,7 +524,7 @@ open class Session : RealmObject(), Manageable, StaticRowRepresentableDataSource
CustomizableRowRepresentable( CustomizableRowRepresentable(
RowViewType.HEADER_TITLE_AMOUNT_BIG, RowViewType.HEADER_TITLE_AMOUNT_BIG,
title = getFormattedDuration(), title = getFormattedDuration(),
computedStat = ComputedStat(Stat.NETRESULT, result?.net ?: 0.0) computedStat = ComputedStat(Stat.NETRESULT, result?.net ?: 0.0, CurrencyUtils.getCurrency(bankroll))
) )
) )
rows.add(SeparatorRowRepresentable()) rows.add(SeparatorRowRepresentable())
@ -525,7 +534,7 @@ open class Session : RealmObject(), Manageable, StaticRowRepresentableDataSource
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) computedStat = ComputedStat(Stat.NETRESULT, result?.net ?: 0.0, CurrencyUtils.getCurrency(bankroll))
) )
) )
rows.add(SeparatorRowRepresentable()) rows.add(SeparatorRowRepresentable())
@ -535,14 +544,14 @@ open class Session : RealmObject(), Manageable, StaticRowRepresentableDataSource
CustomizableRowRepresentable( CustomizableRowRepresentable(
RowViewType.HEADER_TITLE_AMOUNT_BIG, RowViewType.HEADER_TITLE_AMOUNT_BIG,
title = getFormattedDuration(), title = getFormattedDuration(),
computedStat = ComputedStat(Stat.NETRESULT, result?.net ?: 0.0) computedStat = ComputedStat(Stat.NETRESULT, result?.net ?: 0.0, CurrencyUtils.getCurrency(bankroll))
) )
) )
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) computedStat = ComputedStat(Stat.HOURLY_RATE, this.hourlyRate, CurrencyUtils.getCurrency(bankroll))
) )
) )
@ -551,7 +560,7 @@ open class Session : RealmObject(), Manageable, StaticRowRepresentableDataSource
CustomizableRowRepresentable( CustomizableRowRepresentable(
RowViewType.HEADER_TITLE_VALUE, RowViewType.HEADER_TITLE_VALUE,
resId = R.string.bankroll_variation, resId = R.string.bankroll_variation,
computedStat = ComputedStat(Stat.HOURLY_RATE, 0.0) computedStat = ComputedStat(Stat.HOURLY_RATE, 0.0, CurrencyUtils.getCurrency(bankroll))
) )
) )
} }
@ -583,18 +592,18 @@ open class Session : RealmObject(), Manageable, StaticRowRepresentableDataSource
SessionRow.BANKROLL -> bankroll?.name ?: NULL_TEXT SessionRow.BANKROLL -> bankroll?.name ?: NULL_TEXT
SessionRow.BLINDS -> getBlinds() SessionRow.BLINDS -> getBlinds()
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() ?: NULL_TEXT SessionRow.BUY_IN -> this.result?.buyin?.toCurrency(CurrencyUtils.getCurrency(bankroll)) ?: NULL_TEXT
SessionRow.CASHED_OUT, SessionRow.PRIZE, SessionRow.NET_RESULT -> this.result?.cashout?.toCurrency() ?: NULL_TEXT SessionRow.CASHED_OUT, SessionRow.PRIZE, SessionRow.NET_RESULT -> this.result?.cashout?.toCurrency(CurrencyUtils.getCurrency(bankroll)) ?: 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 -> getGameTitle() SessionRow.GAME -> getGameTitle()
SessionRow.INITIAL_BUY_IN -> tournamentEntryFee?.toCurrency() ?: NULL_TEXT SessionRow.INITIAL_BUY_IN -> tournamentEntryFee?.toCurrency(CurrencyUtils.getCurrency(bankroll)) ?: 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() ?: NULL_TEXT SessionRow.TIPS -> result?.tips?.toCurrency(CurrencyUtils.getCurrency(bankroll)) ?: 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 {
@ -605,10 +614,12 @@ open class Session : RealmObject(), Manageable, StaticRowRepresentableDataSource
"${tournamentFeatures.subList(0,2).joinToString { "${tournamentFeatures.subList(0,2).joinToString {
it.name it.name
}}, ..." }}, ..."
} else { } else if (tournamentFeatures.size > 0) {
tournamentFeatures.joinToString { tournamentFeatures.joinToString {
it.name it.name
} }
} else {
NULL_TEXT
} }
} }
SessionRow.TOURNAMENT_NAME -> tournamentName?.name ?: NULL_TEXT SessionRow.TOURNAMENT_NAME -> tournamentName?.name ?: NULL_TEXT
@ -711,6 +722,7 @@ open class Session : RealmObject(), Manageable, StaticRowRepresentableDataSource
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)
localResult.buyin = value as Double? localResult.buyin = value as Double?
result = localResult result = localResult
this.updateRowRepresentation()
} }
SessionRow.CASHED_OUT, SessionRow.PRIZE, SessionRow.NET_RESULT -> { SessionRow.CASHED_OUT, SessionRow.PRIZE, SessionRow.NET_RESULT -> {
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)

@ -0,0 +1,11 @@
package net.pokeranalytics.android.model.retrofit
import com.google.gson.annotations.SerializedName
/**
* Currency Converter mapping class
*/
class CurrencyConverterValue {
@SerializedName("val")
var value: Double? = 0.0
}

@ -0,0 +1,60 @@
package net.pokeranalytics.android.ui.activity
import android.content.Context
import android.content.Intent
import android.os.Bundle
import androidx.fragment.app.Fragment
import net.pokeranalytics.android.R
import net.pokeranalytics.android.ui.activity.components.PokerAnalyticsActivity
import net.pokeranalytics.android.ui.fragment.FilterDetailsFragment
class FilterDetailsActivity : PokerAnalyticsActivity() {
enum class IntentKey(val keyName: String) {
FILTER_CATEGORY_ORDINAL("FILTER_CATEGORY_ORDINAL")
}
companion object {
/**
* Default constructor
*/
fun newInstance(context: Context, filterCategoryOrdinal: Int) {
val intent = Intent(context, FilterDetailsActivity::class.java)
intent.putExtra(IntentKey.FILTER_CATEGORY_ORDINAL.keyName, filterCategoryOrdinal)
context.startActivity(intent)
}
/**
* Create a new instance for result
*/
fun newInstanceForResult(fragment: Fragment, filterCategoryOrdinal: Int, requestCode: Int) {
val intent = Intent(fragment.requireContext(), FilterDetailsActivity::class.java)
intent.putExtra(IntentKey.FILTER_CATEGORY_ORDINAL.keyName, filterCategoryOrdinal)
fragment.startActivityForResult(intent, requestCode)
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_filter_details)
initUI()
}
/**
* Init UI
*/
private fun initUI() {
val fragmentManager = supportFragmentManager
val fragmentTransaction = fragmentManager.beginTransaction()
val filterCategoryOrdinal = intent.getIntExtra(IntentKey.FILTER_CATEGORY_ORDINAL.keyName, 0)
val fragment = FilterDetailsFragment()
fragmentTransaction.add(R.id.container, fragment)
fragmentTransaction.commit()
fragment.setData(filterCategoryOrdinal)
}
}

@ -0,0 +1,59 @@
package net.pokeranalytics.android.ui.activity
import android.content.Context
import android.content.Intent
import android.os.Bundle
import androidx.fragment.app.Fragment
import net.pokeranalytics.android.R
import net.pokeranalytics.android.ui.activity.components.PokerAnalyticsActivity
import net.pokeranalytics.android.ui.fragment.FiltersFragment
class FiltersActivity : PokerAnalyticsActivity() {
enum class IntentKey(val keyName: String) {
DATA_TYPE("DATA_TYPE"),
PRIMARY_KEY("PRIMARY_KEY");
}
companion object {
/**
* Default constructor
*/
fun newInstance(context: Context) {
val intent = Intent(context, FiltersActivity::class.java)
context.startActivity(intent)
}
/**
* Create a new instance for result
*/
fun newInstanceForResult(fragment: Fragment, requestCode: Int) {
val intent = Intent(fragment.requireContext(), FiltersActivity::class.java)
fragment.startActivityForResult(intent, requestCode)
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_filters)
initUI()
}
/**
* Init UI
*/
private fun initUI() {
val fragmentManager = supportFragmentManager
val fragmentTransaction = fragmentManager.beginTransaction()
val fragment = FiltersFragment()
fragmentTransaction.add(R.id.container, fragment)
fragmentTransaction.commit()
//fragment.setData(dataType, primaryKey)
}
}

@ -3,6 +3,8 @@ package net.pokeranalytics.android.ui.activity
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.os.Bundle import android.os.Bundle
import android.view.Menu
import android.view.MenuItem
import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AlertDialog
import com.google.android.material.bottomnavigation.BottomNavigationView import com.google.android.material.bottomnavigation.BottomNavigationView
import kotlinx.android.synthetic.main.activity_home.* import kotlinx.android.synthetic.main.activity_home.*
@ -10,6 +12,7 @@ import net.pokeranalytics.android.R
import net.pokeranalytics.android.ui.activity.components.PokerAnalyticsActivity import net.pokeranalytics.android.ui.activity.components.PokerAnalyticsActivity
import net.pokeranalytics.android.ui.adapter.HomePagerAdapter import net.pokeranalytics.android.ui.adapter.HomePagerAdapter
import net.pokeranalytics.android.util.Preferences import net.pokeranalytics.android.util.Preferences
import timber.log.Timber
class HomeActivity : PokerAnalyticsActivity() { class HomeActivity : PokerAnalyticsActivity() {
@ -22,6 +25,8 @@ class HomeActivity : PokerAnalyticsActivity() {
} }
} }
private var homeMenu: Menu? = null
private val mOnNavigationItemSelectedListener = BottomNavigationView.OnNavigationItemSelectedListener { item -> private val mOnNavigationItemSelectedListener = BottomNavigationView.OnNavigationItemSelectedListener { item ->
when (item.itemId) { when (item.itemId) {
net.pokeranalytics.android.R.id.navigation_history -> { net.pokeranalytics.android.R.id.navigation_history -> {
@ -48,10 +53,26 @@ class HomeActivity : PokerAnalyticsActivity() {
checkFirstLaunch() checkFirstLaunch()
} }
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
menuInflater.inflate(R.menu.home_menu, menu)
this.homeMenu = menu
return super.onCreateOptionsMenu(menu)
}
override fun onOptionsItemSelected(item: MenuItem?): Boolean {
when (item?.itemId) {
R.id.filter -> manageFilters()
}
return super.onOptionsItemSelected(item)
}
/** /**
* Init UI * Init UI
*/ */
private fun initUI() { private fun initUI() {
setSupportActionBar(toolbar)
navigation.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener) navigation.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener)
navigation.selectedItemId = net.pokeranalytics.android.R.id.navigation_history navigation.selectedItemId = net.pokeranalytics.android.R.id.navigation_history
@ -80,16 +101,63 @@ class HomeActivity : PokerAnalyticsActivity() {
* Display a new fragment * Display a new fragment
*/ */
private fun displayFragment(index: Int) { private fun displayFragment(index: Int) {
viewPager.setCurrentItem(index, false)
updateToolbar(index)
}
/**
* Update toolbar
*/
private fun updateToolbar(index: Int) {
when (index) {
0 -> {
toolbar.title = getString(R.string.title_history)
homeMenu?.findItem(R.id.filter)?.isVisible = true
}
1 -> {
toolbar.title = getString(R.string.title_stats)
homeMenu?.findItem(R.id.filter)?.isVisible = false
}
2 -> {
toolbar.title = getString(R.string.title_settings)
homeMenu?.findItem(R.id.filter)?.isVisible = false
}
}
}
/**
* Manage filters
*/
private fun manageFilters() {
val filterSelected = false
toolbar.title = when (index) { val choices = ArrayList<CharSequence>()
0 -> getString(R.string.title_history) choices.add(getString(R.string.new_str))
1 -> getString(R.string.title_stats)
2 -> getString(R.string.title_settings) if (filterSelected) {
else -> "" choices.add(getString(R.string.modify_current_filter))
choices.add(getString(R.string.load_from_db))
choices.add(getString(R.string.remove_filter))
}
val builder = AlertDialog.Builder(this)
builder.setTitle(R.string.filter_selection)
.setCancelable(true)
.setItems(choices.toTypedArray()) { _, which ->
Timber.d("Click on $which")
when(which) {
0 -> FiltersActivity.newInstance(this@HomeActivity)
} }
viewPager.setCurrentItem(index, false)
} }
.setNegativeButton(R.string.cancel) {dialog, which ->
Timber.d("Click on cancel")
}
builder.show()
}
} }

@ -4,12 +4,10 @@ import android.app.Activity.RESULT_OK
import android.content.Intent import android.content.Intent
import android.os.Bundle import android.os.Bundle
import android.view.View import android.view.View
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import net.pokeranalytics.android.R import net.pokeranalytics.android.R
import net.pokeranalytics.android.api.CurrencyConverterApi
import net.pokeranalytics.android.model.realm.Bankroll import net.pokeranalytics.android.model.realm.Bankroll
import net.pokeranalytics.android.model.retrofit.CurrencyConverterValue
import net.pokeranalytics.android.ui.activity.CurrenciesActivity import net.pokeranalytics.android.ui.activity.CurrenciesActivity
import net.pokeranalytics.android.ui.adapter.RowRepresentableDataSource import net.pokeranalytics.android.ui.adapter.RowRepresentableDataSource
import net.pokeranalytics.android.ui.adapter.StaticRowRepresentableDataSource import net.pokeranalytics.android.ui.adapter.StaticRowRepresentableDataSource
@ -22,6 +20,8 @@ import net.pokeranalytics.android.ui.view.rowrepresentable.SimpleRow
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.round import net.pokeranalytics.android.util.extensions.round
import retrofit2.Call
import retrofit2.Response
import java.util.* import java.util.*
/** /**
@ -42,6 +42,7 @@ class BankrollDataFragment : EditableDataFragment(), StaticRowRepresentableDataS
private lateinit var defaultCurrency: Currency private lateinit var defaultCurrency: Currency
private val rows = ArrayList<RowRepresentable>() private val rows = ArrayList<RowRepresentable>()
private var isRefreshingRate = false private var isRefreshingRate = false
private var lastRefreshRateCall = 0L
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
@ -111,25 +112,20 @@ class BankrollDataFragment : EditableDataFragment(), StaticRowRepresentableDataS
override fun onRowSelected(position: Int, row: RowRepresentable, fromAction: Boolean) { override fun onRowSelected(position: Int, row: RowRepresentable, fromAction: Boolean) {
when (row) { when (row) {
BankrollRow.CURRENCY -> CurrenciesActivity.newInstanceForResult(this@BankrollDataFragment, BankrollDataFragment.REQUEST_CODE_CURRENCY) BankrollRow.CURRENCY -> CurrenciesActivity.newInstanceForResult(this@BankrollDataFragment, BankrollDataFragment.REQUEST_CODE_CURRENCY)
BankrollRow.REFRESH_RATE -> { BankrollRow.REFRESH_RATE -> refreshRate()
isRefreshingRate = true
//TODO: Call web-service to get the currency rate
GlobalScope.launch(Dispatchers.Main) {
delay(1500)
isRefreshingRate = false
rowRepresentableAdapter.refreshRow(BankrollRow.REFRESH_RATE)
}
rowRepresentableAdapter.refreshRow(BankrollRow.REFRESH_RATE)
}
else -> super.onRowSelected(position, row, fromAction) else -> super.onRowSelected(position, row, fromAction)
} }
} }
override fun onRowValueChanged(value: Any?, row: RowRepresentable) { override fun onRowValueChanged(value: Any?, row: RowRepresentable) {
super.onRowValueChanged(value, row) super.onRowValueChanged(value, row)
updateAdapterUI()
// Clear the value when the currency has been updated
if (row == BankrollRow.CURRENCY) {
lastRefreshRateCall = 0
}
updateAdapterUI()
} }
/** /**
@ -157,8 +153,6 @@ class BankrollDataFragment : EditableDataFragment(), StaticRowRepresentableDataS
rows.add(CustomizableRowRepresentable(customViewType = RowViewType.HEADER_TITLE, resId = R.string.currency)) rows.add(CustomizableRowRepresentable(customViewType = RowViewType.HEADER_TITLE, resId = R.string.currency))
rows.add(BankrollRow.CURRENCY) rows.add(BankrollRow.CURRENCY)
val defaultCurrency = Currency.getInstance(Preferences.getCurrencyLocale(this.parentActivity))
var differentCurrency = false var differentCurrency = false
bankroll.currency?.let { bankrollCurrency -> bankroll.currency?.let { bankrollCurrency ->
differentCurrency = bankrollCurrency.code != defaultCurrency.currencyCode differentCurrency = bankrollCurrency.code != defaultCurrency.currencyCode
@ -186,5 +180,40 @@ class BankrollDataFragment : EditableDataFragment(), StaticRowRepresentableDataS
} }
} }
/**
* Refresh the rate with the Currency Converter API
*/
private fun refreshRate() {
// Check if the last call was older than 10 seconds
if (System.currentTimeMillis() - lastRefreshRateCall < 10 * 1000 || isRefreshingRate) {
return
}
lastRefreshRateCall = System.currentTimeMillis()
val currenciesConverterValue = "${defaultCurrency.currencyCode}_${bankroll?.currency?.code}"
val call = CurrencyConverterApi.getApi(requireContext())?.convert(currenciesConverterValue)
call?.enqueue(object : retrofit2.Callback<Map<String, CurrencyConverterValue>> {
override fun onResponse(call: Call<Map<String, CurrencyConverterValue>>, response: Response<Map<String, CurrencyConverterValue>>) {
response.body()?.let {
it[currenciesConverterValue]?.value?.let {rate ->
onRowValueChanged(rate.toString(), BankrollRow.RATE)
}
}
isRefreshingRate = false
rowRepresentableAdapter.refreshRow(BankrollRow.REFRESH_RATE)
}
override fun onFailure(call: Call<Map<String, CurrencyConverterValue>>, t: Throwable) {
isRefreshingRate = false
rowRepresentableAdapter.refreshRow(BankrollRow.REFRESH_RATE)
}
})
isRefreshingRate = true
rowRepresentableAdapter.refreshRow(BankrollRow.REFRESH_RATE)
}
} }

@ -111,7 +111,7 @@ open class EditableDataFragment : PokerAnalyticsFragment(), RowRepresentableDele
isUpdating = true isUpdating = true
} ?: run { } ?: run {
//TODO: Localize //TODO: Localize
this.appBar.toolbar.title = "New ${this.liveDataType.localizedTitle(this.parentActivity).toLowerCase().capitalize()}" this.appBar.toolbar.title = this.liveDataType.newEntityLocalizedTitle(requireContext())
} }
this.item = this.liveDataType.updateOrCreate(this.getRealm(), primaryKey) this.item = this.liveDataType.updateOrCreate(this.getRealm(), primaryKey)

@ -0,0 +1,245 @@
package net.pokeranalytics.android.ui.fragment
import android.os.Bundle
import android.view.*
import androidx.recyclerview.widget.LinearLayoutManager
import io.realm.RealmObject
import kotlinx.android.synthetic.main.fragment_filter_details.*
import kotlinx.android.synthetic.main.fragment_filter_details.view.*
import net.pokeranalytics.android.R
import net.pokeranalytics.android.ui.activity.components.PokerAnalyticsActivity
import net.pokeranalytics.android.ui.adapter.RowRepresentableAdapter
import net.pokeranalytics.android.ui.adapter.RowRepresentableDataSource
import net.pokeranalytics.android.ui.adapter.RowRepresentableDelegate
import net.pokeranalytics.android.ui.fragment.components.PokerAnalyticsFragment
import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.RowViewType
import net.pokeranalytics.android.ui.view.rowrepresentable.FilterCategoryRow
import net.pokeranalytics.android.ui.view.rowrepresentable.FilterSubcategoryRow
import timber.log.Timber
open class FilterDetailsFragment : PokerAnalyticsFragment(), RowRepresentableDataSource, RowRepresentableDelegate {
lateinit var parentActivity: PokerAnalyticsActivity
lateinit var item: RealmObject
lateinit var rowRepresentableAdapter: RowRepresentableAdapter
private var rows: ArrayList<RowRepresentable> = ArrayList()
private var filterMenu: Menu? = null
private var filterCategory: FilterCategoryRow? = null
var isUpdating = false
var shouldOpenKeyboard = true
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.fragment_filter_details, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
initUI()
initData()
}
override fun onCreateOptionsMenu(menu: Menu?, inflater: MenuInflater?) {
/*
inflater?.inflate(R.menu.editable_data, menu)
this.filterMenu = menu
*/
updateMenuUI()
super.onCreateOptionsMenu(menu, inflater)
}
override fun onOptionsItemSelected(item: MenuItem?): Boolean {
when (item!!.itemId) {
R.id.save -> saveData()
R.id.delete -> deleteData()
}
return true
}
override fun onRowSelected(position: Int, row: RowRepresentable, fromAction: Boolean) {
super.onRowSelected(position, row, fromAction)
filterCategory?.let {
for (subcategory in it.getSubcategories()) {
if (subcategory.getFilterRows(getRealm()).contains(row)) {
if (subcategory.getType() == FilterSubcategoryRow.Type.SINGLE) {
for (filterRow in subcategory.getFilterRows(getRealm())) {
selectedRows.remove(filterRow)
}
}
}
}
}
if (selectedRows.contains(row)) {
selectedRows.remove(row)
} else {
selectedRows.add(row)
}
rowRepresentableAdapter.notifyDataSetChanged()
}
val selectedRows = ArrayList<RowRepresentable>()
override fun isSelected(row: RowRepresentable): Boolean {
return selectedRows.contains(row)
}
override fun onRowValueChanged(value: Any?, row: RowRepresentable) {
super.onRowValueChanged(value, row)
}
override fun adapterRows(): List<RowRepresentable>? {
return rows
}
override fun rowRepresentableForPosition(position: Int): RowRepresentable? {
return rows[position]
}
override fun numberOfRows(): Int {
return rows.size
}
override fun viewTypeForPosition(position: Int): Int {
val rowViewType = rowRepresentableForPosition(position)?.viewType ?: -1
return if (rowViewType != -1) rowViewType else RowViewType.TITLE_CHECK.ordinal
}
override fun indexForRow(row: RowRepresentable): Int {
return rows.indexOf(row)
}
/**
* Init UI
*/
private fun initUI() {
parentActivity = activity as PokerAnalyticsActivity
parentActivity.setSupportActionBar(toolbar)
parentActivity.supportActionBar?.setDisplayHomeAsUpEnabled(true)
setHasOptionsMenu(true)
val viewManager = LinearLayoutManager(requireContext())
recyclerView.apply {
setHasFixedSize(true)
layoutManager = viewManager
}
}
/**
* Init data
*/
private fun initData() {
Timber.d("initData")
this.appBar.toolbar.title = getString(R.string.filter)
filterCategory?.let {
this.appBar.toolbar.title = it.localizedTitle(requireContext())
this.rows.clear()
for (subcategory in it.getSubcategories()) {
this.rows.add(subcategory)
this.rows.addAll(subcategory.getFilterRows(getRealm()))
}
this.rowRepresentableAdapter = RowRepresentableAdapter(this, this)
this.recyclerView.adapter = rowRepresentableAdapter
}
}
/**
* Update menu UI
*/
private fun updateMenuUI() {
/*
editableMenu?.findItem(R.id.delete)?.isVisible = isUpdating
editableMenu?.findItem(R.id.save)?.isVisible = true
*/
}
/**
* Save data
*/
fun saveData() {
/*
if ((this.item as Savable).isValidForSave()) {
this.getRealm().executeTransaction {
val item = it.copyToRealmOrUpdate(this.item)
val uniqueIdentifier = if (item is Identifiable) {
item.id
} else ""
finishActivityWithResult(uniqueIdentifier)
}
} else {
val message = (this.item as Savable).getFailedSaveMessage()
val builder = AlertDialog.Builder(requireContext())
.setMessage(message)
.setNegativeButton(R.string.ok, null)
builder.show()
}
*/
}
/**
* Delete data
*/
private fun deleteData() {
/*
val builder = AlertDialog.Builder(requireContext())
builder.setTitle(R.string.warning)
.setMessage(R.string.are_you_sure_you_want_to_do_that_)
.setNegativeButton(R.string.no, null)
.setPositiveButton(R.string.yes) { _, _ ->
//TODO: Maybe update this code, does the object need to be managed?
this.getRealm().executeTransaction {
this.liveDataType.deleteData(it, (this.item as Manageable))
}
this.activity?.finish()
}
builder.show()
*/
}
/**
* Finish the activity with a result
*/
private fun finishActivityWithResult(uniqueIdentifier: String) {
/*
val intent = Intent()
intent.putExtra(EditableDataActivity.IntentKey.DATA_TYPE.keyName, dataType)
intent.putExtra(EditableDataActivity.IntentKey.PRIMARY_KEY.keyName, uniqueIdentifier)
activity?.setResult(RESULT_OK, intent)
*/
activity?.finish()
}
/**
* Set fragment data
*/
fun setData(filterCategory: Int) {
this.filterCategory = FilterCategoryRow.values()[filterCategory]
/*
this.dataType = dataType
this.liveDataType = LiveData.values()[dataType]
this.primaryKey = primaryKey
*/
}
}

@ -0,0 +1,191 @@
package net.pokeranalytics.android.ui.fragment
import android.os.Bundle
import android.view.*
import androidx.recyclerview.widget.LinearLayoutManager
import io.realm.RealmObject
import kotlinx.android.synthetic.main.fragment_editable_data.*
import kotlinx.android.synthetic.main.fragment_filters.view.*
import net.pokeranalytics.android.R
import net.pokeranalytics.android.ui.activity.FilterDetailsActivity
import net.pokeranalytics.android.ui.activity.components.PokerAnalyticsActivity
import net.pokeranalytics.android.ui.adapter.RowRepresentableAdapter
import net.pokeranalytics.android.ui.adapter.RowRepresentableDelegate
import net.pokeranalytics.android.ui.adapter.StaticRowRepresentableDataSource
import net.pokeranalytics.android.ui.fragment.components.PokerAnalyticsFragment
import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.rowrepresentable.FilterCategoryRow
import timber.log.Timber
open class FiltersFragment : PokerAnalyticsFragment(), StaticRowRepresentableDataSource, RowRepresentableDelegate {
lateinit var parentActivity: PokerAnalyticsActivity
lateinit var item: RealmObject
lateinit var rowRepresentableAdapter: RowRepresentableAdapter
private var rows: ArrayList<RowRepresentable> = ArrayList()
private var filterMenu: Menu? = null
private var dataType: Int? = null
private var primaryKey: String? = null
var isUpdating = false
var shouldOpenKeyboard = true
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.fragment_filters, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
initUI()
initData()
}
override fun onCreateOptionsMenu(menu: Menu?, inflater: MenuInflater?) {
/*
inflater?.inflate(R.menu.editable_data, menu)
this.filterMenu = menu
*/
updateMenuUI()
super.onCreateOptionsMenu(menu, inflater)
}
override fun onOptionsItemSelected(item: MenuItem?): Boolean {
when (item!!.itemId) {
R.id.save -> saveData()
R.id.delete -> deleteData()
}
return true
}
override fun adapterRows(): List<RowRepresentable>? {
return rows
}
override fun onRowSelected(position: Int, row: RowRepresentable, fromAction: Boolean) {
super.onRowSelected(position, row, fromAction)
if (row is FilterCategoryRow) {
Timber.d("Subcategories: ${row.getSubcategories()}")
FilterDetailsActivity.newInstanceForResult(this, row.ordinal, 1000)
}
}
override fun onRowValueChanged(value: Any?, row: RowRepresentable) {
super.onRowValueChanged(value, row)
}
/**
* Init UI
*/
private fun initUI() {
parentActivity = activity as PokerAnalyticsActivity
parentActivity.setSupportActionBar(toolbar)
parentActivity.supportActionBar?.setDisplayHomeAsUpEnabled(true)
setHasOptionsMenu(true)
val viewManager = LinearLayoutManager(requireContext())
recyclerView.apply {
setHasFixedSize(true)
layoutManager = viewManager
}
}
/**
* Init data
*/
private fun initData() {
this.appBar.toolbar.title = getString(R.string.filter)
rows.addAll(FilterCategoryRow.values())
this.rowRepresentableAdapter = RowRepresentableAdapter(this, this)
this.recyclerView.adapter = rowRepresentableAdapter
}
/**
* Update menu UI
*/
private fun updateMenuUI() {
/*
editableMenu?.findItem(R.id.delete)?.isVisible = isUpdating
editableMenu?.findItem(R.id.save)?.isVisible = true
*/
}
/**
* Save data
*/
fun saveData() {
/*
if ((this.item as Savable).isValidForSave()) {
this.getRealm().executeTransaction {
val item = it.copyToRealmOrUpdate(this.item)
val uniqueIdentifier = if (item is Identifiable) {
item.id
} else ""
finishActivityWithResult(uniqueIdentifier)
}
} else {
val message = (this.item as Savable).getFailedSaveMessage()
val builder = AlertDialog.Builder(requireContext())
.setMessage(message)
.setNegativeButton(R.string.ok, null)
builder.show()
}
*/
}
/**
* Delete data
*/
private fun deleteData() {
/*
val builder = AlertDialog.Builder(requireContext())
builder.setTitle(R.string.warning)
.setMessage(R.string.are_you_sure_you_want_to_do_that_)
.setNegativeButton(R.string.no, null)
.setPositiveButton(R.string.yes) { _, _ ->
//TODO: Maybe update this code, does the object need to be managed?
this.getRealm().executeTransaction {
this.liveDataType.deleteData(it, (this.item as Manageable))
}
this.activity?.finish()
}
builder.show()
*/
}
/**
* Finish the activity with a result
*/
private fun finishActivityWithResult(uniqueIdentifier: String) {
/*
val intent = Intent()
intent.putExtra(EditableDataActivity.IntentKey.DATA_TYPE.keyName, dataType)
intent.putExtra(EditableDataActivity.IntentKey.PRIMARY_KEY.keyName, uniqueIdentifier)
activity?.setResult(RESULT_OK, intent)
*/
activity?.finish()
}
/**
* Set fragment data
*/
fun setData(dataType: Int, primaryKey: String?) {
/*
this.dataType = dataType
this.liveDataType = LiveData.values()[dataType]
this.primaryKey = primaryKey
*/
}
}

@ -5,7 +5,6 @@ import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.core.view.isVisible import androidx.core.view.isVisible
import androidx.lifecycle.LiveData
import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.DiffUtil
import io.realm.RealmResults import io.realm.RealmResults
import io.realm.Sort import io.realm.Sort
@ -14,11 +13,7 @@ import kotlinx.android.synthetic.main.fragment_history.*
import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import net.pokeranalytics.android.R import net.pokeranalytics.android.R
import net.pokeranalytics.android.model.filter.FilterManager
import net.pokeranalytics.android.model.filter.Filterable
import net.pokeranalytics.android.model.filter.SessionFilterable
import net.pokeranalytics.android.model.interfaces.Manageable import net.pokeranalytics.android.model.interfaces.Manageable
import net.pokeranalytics.android.model.realm.Bankroll
import net.pokeranalytics.android.model.realm.Session import net.pokeranalytics.android.model.realm.Session
import net.pokeranalytics.android.ui.activity.SessionActivity import net.pokeranalytics.android.ui.activity.SessionActivity
import net.pokeranalytics.android.ui.adapter.LiveRowRepresentableDataSource import net.pokeranalytics.android.ui.adapter.LiveRowRepresentableDataSource
@ -97,20 +92,6 @@ class HistoryFragment : PokerAnalyticsFragment(), LiveRowRepresentableDataSource
* Init data * Init data
*/ */
private fun initData() { private fun initData() {
/*
var brs = (net.pokeranalytics.android.model.LiveData.BANKROLL.items(getRealm()) as RealmResults<Bankroll>).toArray().map{
(it as Bankroll).id
}
var br = SessionFilterable.BANKROLL
br.valueMap = mapOf("ids" to arrayOf(brs.last()))
realmSessions = FilterManager().filter(getRealm(), Session::class.java, arrayListOf<Filterable>(br))
.sort("creationDate", Sort.DESCENDING) as RealmResults<Session>
// realmSessions = FilterManager().filter(getRealm(), Session::class.java, arrayListOf<Filterable>(SessionFilterable.ONLINE, SessionFilterable.CASH)).sort("creationDate", Sort.DESCENDING) as RealmResults<Session>
*/
realmSessions = getRealm().where<Session>().findAll().sort("creationDate", Sort.DESCENDING) realmSessions = getRealm().where<Session>().findAll().sort("creationDate", Sort.DESCENDING)
val viewManager = SmoothScrollLinearLayoutManager(requireContext()) val viewManager = SmoothScrollLinearLayoutManager(requireContext())

@ -26,6 +26,7 @@ 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.*
@ -99,9 +100,9 @@ class SessionFragment : PokerAnalyticsFragment(), RowRepresentableDelegate {
currentSession.startDate currentSession.startDate
) )
SessionRow.BANKROLL -> { SessionRow.BANKROLL -> {
BottomSheetFragment.create(fragmentManager, row, this, data, false) BottomSheetFragment.create(fragmentManager, row, this, data, false, CurrencyUtils.getCurrency(currentSession.bankroll))
} }
else -> BottomSheetFragment.create(fragmentManager, row, this, data) else -> BottomSheetFragment.create(fragmentManager, row, this, data, currentCurrency = CurrencyUtils.getCurrency(currentSession.bankroll))
} }
} }

@ -30,6 +30,9 @@ class StatsFragment : SessionObserverFragment(), StaticRowRepresentableDataSourc
get() = Dispatchers.Main get() = Dispatchers.Main
private var rowRepresentables: ArrayList<RowRepresentable> = ArrayList() private var rowRepresentables: ArrayList<RowRepresentable> = ArrayList()
private var stringAll = ""
private var stringCashGame = ""
private var stringTournament = ""
private lateinit var statsAdapter: RowRepresentableAdapter private lateinit var statsAdapter: RowRepresentableAdapter
@ -55,6 +58,8 @@ class StatsFragment : SessionObserverFragment(), StaticRowRepresentableDataSourc
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
initData() initData()
initUI()
launchStatComputation()
} }
// Row Representable DS // Row Representable DS
@ -104,10 +109,28 @@ class StatsFragment : SessionObserverFragment(), StaticRowRepresentableDataSourc
*/ */
private fun initData() { private fun initData() {
this.stringAll = getString(R.string.all)
this.stringCashGame = getString(R.string.cash_game)
this.stringTournament = getString(R.string.tournament)
this.statsAdapter = RowRepresentableAdapter(this) this.statsAdapter = RowRepresentableAdapter(this)
this.launchStatComputation()
} }
/**
* Init UI
*/
private fun initUI() {
val viewManager = LinearLayoutManager(requireContext())
recyclerView.apply {
setHasFixedSize(true)
layoutManager = viewManager
adapter = statsAdapter
}
}
private fun launchStatComputation() { private fun launchStatComputation() {
GlobalScope.launch(coroutineContext) { GlobalScope.launch(coroutineContext) {
@ -125,8 +148,11 @@ class StatsFragment : SessionObserverFragment(), StaticRowRepresentableDataSourc
} }
test.await() test.await()
if (!isDetached) {
showResults(results) showResults(results)
} }
}
} }
@ -163,8 +189,6 @@ class StatsFragment : SessionObserverFragment(), StaticRowRepresentableDataSourc
val tStats: List<Stat> = listOf(Stat.NETRESULT, Stat.HOURLY_RATE, Stat.ROI, Stat.WIN_RATIO, Stat.NUMBER_OF_GAMES, Stat.AVERAGE_BUYIN) val tStats: List<Stat> = listOf(Stat.NETRESULT, Stat.HOURLY_RATE, Stat.ROI, Stat.WIN_RATIO, Stat.NUMBER_OF_GAMES, Stat.AVERAGE_BUYIN)
val tSessionGroup = ComputableGroup(getString(R.string.tournament), tSessions, tStats) val tSessionGroup = ComputableGroup(getString(R.string.tournament), tSessions, tStats)
Timber.d(">>>>> Start computations...") Timber.d(">>>>> Start computations...")
return Calculator.computeGroups(listOf(allSessionGroup, cgSessionGroup, tSessionGroup), Calculator.Options()) return Calculator.computeGroups(listOf(allSessionGroup, cgSessionGroup, tSessionGroup), Calculator.Options())
@ -172,16 +196,8 @@ class StatsFragment : SessionObserverFragment(), StaticRowRepresentableDataSourc
} }
private fun showResults(results: List<ComputedResults>) { private fun showResults(results: List<ComputedResults>) {
this.rowRepresentables = this.convertResultsIntoRepresentables(results) this.rowRepresentables = this.convertResultsIntoRepresentables(results)
statsAdapter.notifyDataSetChanged()
val viewManager = LinearLayoutManager(requireContext())
recyclerView.apply {
setHasFixedSize(true)
layoutManager = viewManager
adapter = statsAdapter
}
} }
private fun convertResultsIntoRepresentables(results: List<ComputedResults>) : ArrayList<RowRepresentable> { private fun convertResultsIntoRepresentables(results: List<ComputedResults>) : ArrayList<RowRepresentable> {

@ -22,11 +22,13 @@ 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.rowrepresentable.SessionRow import net.pokeranalytics.android.ui.view.rowrepresentable.SessionRow
import net.pokeranalytics.android.ui.view.rowrepresentable.TransactionRow import net.pokeranalytics.android.ui.view.rowrepresentable.TransactionRow
import java.util.*
open class BottomSheetFragment : BottomSheetDialogFragment() { open class BottomSheetFragment : BottomSheetDialogFragment() {
lateinit var row: RowRepresentable lateinit var row: RowRepresentable
lateinit var delegate: RowRepresentableDelegate lateinit var delegate: RowRepresentableDelegate
var currentCurrency: Currency? = null
private var isClearable: Boolean = true private var isClearable: Boolean = true
private var rowRepresentableEditDescriptors: ArrayList<RowRepresentableEditDescriptor>? = null private var rowRepresentableEditDescriptors: ArrayList<RowRepresentableEditDescriptor>? = null
@ -40,7 +42,8 @@ open class BottomSheetFragment : BottomSheetDialogFragment() {
row: RowRepresentable, row: RowRepresentable,
delegate: RowRepresentableDelegate, delegate: RowRepresentableDelegate,
rowRepresentableEditDescriptors: ArrayList<RowRepresentableEditDescriptor>?, rowRepresentableEditDescriptors: ArrayList<RowRepresentableEditDescriptor>?,
isClearable: Boolean? = true isClearable: Boolean? = true,
currentCurrency: Currency? = null
): BottomSheetFragment { ): BottomSheetFragment {
val bottomSheetFragment = row.bottomSheetType.newInstance() val bottomSheetFragment = row.bottomSheetType.newInstance()
bottomSheetFragment.show(fragmentManager, "bottomSheet") bottomSheetFragment.show(fragmentManager, "bottomSheet")
@ -48,7 +51,7 @@ open class BottomSheetFragment : BottomSheetDialogFragment() {
bottomSheetFragment.delegate = delegate bottomSheetFragment.delegate = delegate
bottomSheetFragment.rowRepresentableEditDescriptors = rowRepresentableEditDescriptors bottomSheetFragment.rowRepresentableEditDescriptors = rowRepresentableEditDescriptors
bottomSheetFragment.isClearable = isClearable ?: true bottomSheetFragment.isClearable = isClearable ?: true
bottomSheetFragment.currentCurrency = currentCurrency
return bottomSheetFragment return bottomSheetFragment
} }
} }

@ -2,18 +2,14 @@ package net.pokeranalytics.android.ui.fragment.components.bottomsheet
import android.app.Activity import android.app.Activity
import android.content.Intent import android.content.Intent
import android.os.Bundle
import android.view.View
import io.realm.RealmList import io.realm.RealmList
import io.realm.RealmObject import io.realm.RealmObject
import io.realm.RealmResults
import net.pokeranalytics.android.exceptions.RowRepresentableEditDescriptorException import net.pokeranalytics.android.exceptions.RowRepresentableEditDescriptorException
import net.pokeranalytics.android.model.LiveData import net.pokeranalytics.android.model.LiveData
import net.pokeranalytics.android.ui.activity.EditableDataActivity import net.pokeranalytics.android.ui.activity.EditableDataActivity
import net.pokeranalytics.android.ui.activity.components.PokerAnalyticsActivity import net.pokeranalytics.android.ui.activity.components.PokerAnalyticsActivity
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 timber.log.Timber
/** /**
* Manage multiple items selection in a bottom sheet list * Manage multiple items selection in a bottom sheet list
@ -38,7 +34,6 @@ open class BottomSheetMultiSelectionFragment : BottomSheetListFragment() {
} }
} }
//TODO: Set the correct values
override fun getValue(): Any? { override fun getValue(): Any? {
return selectedRows return selectedRows
} }
@ -50,16 +45,6 @@ open class BottomSheetMultiSelectionFragment : BottomSheetListFragment() {
selectedRows.add(row) selectedRows.add(row)
} }
dataAdapter.refreshRow(row) dataAdapter.refreshRow(row)
/*
realmData?.let {
val selectedData = it[position]
selectedData?.let {data ->
this.delegate.onRowValueChanged(data, this.row)
dismiss()
}
}
*/
} }
override fun isSelected(row: RowRepresentable): Boolean { override fun isSelected(row: RowRepresentable): Boolean {

@ -63,7 +63,7 @@ class BottomSheetSumFragment : BottomSheetFragment() {
0.0 0.0
} }
currentValue.text = currentDefaultValue.toCurrency() currentValue.text = currentDefaultValue.toCurrency(currentCurrency)
// First value // First value
val defaultValue1 = try { val defaultValue1 = try {
@ -72,7 +72,7 @@ class BottomSheetSumFragment : BottomSheetFragment() {
0.0 0.0
} }
button1.text = "+ ${defaultValue1.toCurrency()}" button1.text = "+ ${defaultValue1.toCurrency(currentCurrency)}"
button1.visibility = if (defaultValue1 > 0) View.VISIBLE else View.GONE button1.visibility = if (defaultValue1 > 0) View.VISIBLE else View.GONE
button1.setOnClickListener { button1.setOnClickListener {
this.delegate.onRowValueChanged(currentDefaultValue + defaultValue1, row) this.delegate.onRowValueChanged(currentDefaultValue + defaultValue1, row)
@ -86,7 +86,7 @@ class BottomSheetSumFragment : BottomSheetFragment() {
0.0 0.0
} }
button2.text = "+ ${defaultValue2.toCurrency()}" button2.text = "+ ${defaultValue2.toCurrency(currentCurrency)}"
button2.visibility = if (defaultValue2 > 0) View.VISIBLE else View.GONE button2.visibility = if (defaultValue2 > 0) View.VISIBLE else View.GONE
button2.setOnClickListener { button2.setOnClickListener {
this.delegate.onRowValueChanged(currentDefaultValue + defaultValue2, row) this.delegate.onRowValueChanged(currentDefaultValue + defaultValue2, row)

@ -41,6 +41,7 @@ enum class RowViewType(private var layoutRes: Int) {
INFO(R.layout.row_info), INFO(R.layout.row_info),
// Row // Row
CLASSIC_HEADER_TITLE(R.layout.row_header_title),
TITLE(R.layout.row_title), TITLE(R.layout.row_title),
TITLE_ARROW(R.layout.row_title_arrow), TITLE_ARROW(R.layout.row_title_arrow),
TITLE_VALUE(R.layout.row_title_value), TITLE_VALUE(R.layout.row_title_value),
@ -75,7 +76,7 @@ enum class RowViewType(private var layoutRes: Int) {
HEADER_TITLE, HEADER_TITLE_VALUE, HEADER_TITLE_AMOUNT, HEADER_TITLE_AMOUNT_BIG, LOCATION_TITLE, INFO -> CustomizableRowViewHolder(layout) HEADER_TITLE, HEADER_TITLE_VALUE, HEADER_TITLE_AMOUNT, HEADER_TITLE_AMOUNT_BIG, LOCATION_TITLE, INFO -> CustomizableRowViewHolder(layout)
// Row View Holder // Row View Holder
TITLE, TITLE_ARROW, TITLE_VALUE, TITLE_VALUE_ARROW, TITLE_GRID, TITLE_SWITCH, TITLE_CHECK, DATA, BOTTOM_SHEET_DATA, LOADER -> RowViewHolder( CLASSIC_HEADER_TITLE, TITLE, TITLE_ARROW, TITLE_VALUE, TITLE_VALUE_ARROW, TITLE_GRID, TITLE_SWITCH, TITLE_CHECK, DATA, BOTTOM_SHEET_DATA, LOADER -> RowViewHolder(
layout layout
) )

@ -14,6 +14,7 @@ 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.realm.Session import net.pokeranalytics.android.model.realm.Session
import net.pokeranalytics.android.util.CurrencyUtils
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
@ -65,7 +66,7 @@ class SessionRowView : FrameLayout {
var title = "" var title = ""
if (session.isTournament()) { if (session.isTournament()) {
if (session.tournamentEntryFee != null) { if (session.tournamentEntryFee != null) {
title += session.tournamentEntryFee?.toCurrency() title += session.tournamentEntryFee?.toCurrency(CurrencyUtils.getCurrency(session.bankroll))
} }
session.game?.let { session.game?.let {
title += (if (title.isNotEmpty()) " " else "") + session.getGameTitle() title += (if (title.isNotEmpty()) " " else "") + session.getGameTitle()
@ -140,7 +141,7 @@ 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).format(context) val formattedStat = ComputedStat(Stat.NETRESULT, result, currency = CurrencyUtils.getCurrency(session.bankroll)).format(context)
rowHistorySession.gameResult.setTextColor(formattedStat.getColor(context)) rowHistorySession.gameResult.setTextColor(formattedStat.getColor(context))
rowHistorySession.gameResult.text = formattedStat.text rowHistorySession.gameResult.text = formattedStat.text
} }

@ -0,0 +1,91 @@
package net.pokeranalytics.android.ui.view.rowrepresentable
import net.pokeranalytics.android.R
import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.RowViewType
enum class FilterCategoryRow : RowRepresentable {
GENERAL,
DATE,
DURATION,
SESSION,
CASH,
TOURNAMENT,
ONLINE,
RESULT,
TRANSACTION_TYPES,
// Title Custom fields
LOCATION,
BANKROLL,
PLAYERS;
override val resId: Int?
get() {
return when (this) {
GENERAL -> R.string.general
DATE -> R.string.date
DURATION -> R.string.duration
SESSION -> R.string.session
CASH -> R.string.cash
TOURNAMENT -> R.string.tournament
ONLINE -> R.string.online
RESULT -> R.string.result
TRANSACTION_TYPES -> R.string.operation_types
LOCATION -> R.string.location
BANKROLL -> R.string.bankroll
PLAYERS -> R.string.players
}
}
override val viewType: Int
get() {
return when (this) {
GENERAL, DATE, DURATION, SESSION, CASH, TOURNAMENT, ONLINE, RESULT, TRANSACTION_TYPES,
LOCATION, BANKROLL, PLAYERS -> RowViewType.TITLE_VALUE_ARROW.ordinal
}
}
/**
* Get subcategories of filters
*/
fun getSubcategories(): ArrayList<FilterSubcategoryRow> {
val subcategories = ArrayList<FilterSubcategoryRow>()
when (this) {
GENERAL -> subcategories.addAll(
arrayListOf(
FilterSubcategoryRow.CASH_TOURNAMENT, FilterSubcategoryRow.LIVE_ONLINE, FilterSubcategoryRow.GAME,
FilterSubcategoryRow.LIMIT_TYPE, FilterSubcategoryRow.TABLE_SIZE
)
)
DATE -> subcategories.addAll(
arrayListOf(
FilterSubcategoryRow.DYNAMIC_DATE, FilterSubcategoryRow.FIXED_DATE, FilterSubcategoryRow.DURATION, FilterSubcategoryRow.YEAR,
FilterSubcategoryRow.WEEKDAYS_OR_WEEKEND, FilterSubcategoryRow.DAY_OF_WEEK, FilterSubcategoryRow.MONTH_OF_YEAR
)
)
DURATION -> subcategories.addAll(arrayListOf(FilterSubcategoryRow.SESSION_DURATION, FilterSubcategoryRow.RANGE))
SESSION -> subcategories.addAll(arrayListOf())
CASH -> subcategories.addAll(arrayListOf(FilterSubcategoryRow.BLINDS, FilterSubcategoryRow.CASH_RE_BUY_COUNT))
TOURNAMENT -> subcategories.addAll(
arrayListOf(
FilterSubcategoryRow.TOURNAMENT_TYPE, FilterSubcategoryRow.COMPLETION_PERCENTAGE, FilterSubcategoryRow.PLACE,
FilterSubcategoryRow.PLAYERS_COUNT, FilterSubcategoryRow.TOURNAMENT_RE_BUY_COUNT, FilterSubcategoryRow.BUY_IN
)
)
ONLINE -> subcategories.addAll(arrayListOf(FilterSubcategoryRow.MULTI_TABLING))
RESULT -> subcategories.addAll(arrayListOf(FilterSubcategoryRow.VALUE))
TRANSACTION_TYPES -> subcategories.addAll(arrayListOf())
LOCATION -> subcategories.addAll(arrayListOf(FilterSubcategoryRow.LOCATION))
BANKROLL -> subcategories.addAll(arrayListOf(FilterSubcategoryRow.BANKROLL))
PLAYERS -> subcategories.addAll(arrayListOf(FilterSubcategoryRow.NUMBER_OF_PLAYERS, FilterSubcategoryRow.MULTI_PLAYER))
}
return subcategories
}
}

@ -0,0 +1,27 @@
package net.pokeranalytics.android.ui.view.rowrepresentable
import net.pokeranalytics.android.R
import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.RowViewType
enum class FilterRow : RowRepresentable {
// General
CASH_GAME,
TOURNAMENT,
LIVE,
ONLINE;
override val resId: Int?
get() {
return when (this) {
CASH_GAME -> R.string.cash_game
TOURNAMENT -> R.string.tournament
LIVE -> R.string.live
ONLINE -> R.string.online
}
}
override val viewType: Int = RowViewType.TITLE_CHECK.ordinal
}

@ -0,0 +1,146 @@
package net.pokeranalytics.android.ui.view.rowrepresentable
import io.realm.Realm
import io.realm.RealmResults
import net.pokeranalytics.android.R
import net.pokeranalytics.android.model.Limit
import net.pokeranalytics.android.model.LiveData
import net.pokeranalytics.android.model.realm.Game
import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.RowViewType
enum class FilterSubcategoryRow : RowRepresentable {
// General
CASH_TOURNAMENT,
LIVE_ONLINE,
GAME,
LIMIT_TYPE,
TABLE_SIZE,
// Date
DYNAMIC_DATE,
FIXED_DATE,
DURATION,
YEAR,
WEEKDAYS_OR_WEEKEND,
DAY_OF_WEEK,
MONTH_OF_YEAR,
// Duration
SESSION_DURATION,
RANGE,
// Sessions
// -
// Cash
BLINDS,
CASH_RE_BUY_COUNT,
// Tournament
TOURNAMENT_TYPE,
COMPLETION_PERCENTAGE,
PLACE,
PLAYERS_COUNT,
TOURNAMENT_RE_BUY_COUNT,
BUY_IN,
// Online
MULTI_TABLING,
// Result
VALUE,
// Transaction types
// -
// Location
LOCATION,
// Bankroll
BANKROLL,
// Players
NUMBER_OF_PLAYERS,
MULTI_PLAYER;
enum class Type {
SINGLE,
MULTIPLE,
}
override val resId: Int?
get() {
return when(this) {
CASH_TOURNAMENT -> R.string.cash_or_tournament
LIVE_ONLINE -> R.string.live_or_online
GAME -> R.string.game
LIMIT_TYPE -> R.string.type_de_limite
TABLE_SIZE -> R.string.table_size
DYNAMIC_DATE -> R.string.dynamic_date
FIXED_DATE -> R.string.fixed_date
DURATION -> R.string.duration
YEAR -> R.string.year
WEEKDAYS_OR_WEEKEND -> R.string.weekdays_or_weekend
DAY_OF_WEEK -> R.string.day_of_the_week
MONTH_OF_YEAR -> R.string.month_of_the_year
SESSION_DURATION -> R.string.session_duration
RANGE -> R.string.hour_slot
BLINDS -> R.string.blinds
CASH_RE_BUY_COUNT -> R.string.rebuy_count
TOURNAMENT_TYPE -> R.string.tournament_type
COMPLETION_PERCENTAGE -> R.string.tournament_completion_percentage_interval
PLACE -> R.string.place
PLAYERS_COUNT -> R.string.players_count
TOURNAMENT_RE_BUY_COUNT -> R.string.rebuy_count
BUY_IN -> R.string.buyin
MULTI_TABLING -> R.string.multi_tabling
VALUE -> R.string.value
LOCATION -> R.string.location
BANKROLL -> R.string.bankroll
NUMBER_OF_PLAYERS -> R.string.number_of_players
MULTI_PLAYER -> R.string.multiplayer
}
}
override val viewType: Int = RowViewType.CLASSIC_HEADER_TITLE.ordinal
/**
* Return the type of the selection
*/
fun getType() : Type {
return when(this) {
GAME -> Type.MULTIPLE
else -> Type.SINGLE
}
}
/**
* Returns the filter rows
*/
fun getFilterRows(realm: Realm) : ArrayList<RowRepresentable> {
val rows = ArrayList<RowRepresentable>()
when(this) {
CASH_TOURNAMENT -> rows.addAll(arrayListOf(FilterRow.CASH_GAME, FilterRow.TOURNAMENT))
LIVE_ONLINE -> rows.addAll(arrayListOf(FilterRow.LIVE, FilterRow.ONLINE))
GAME -> {
val games = realm.copyFromRealm(LiveData.GAME.items(realm) as RealmResults<Game>)
rows.addAll(games)
}
LIMIT_TYPE -> rows.addAll(Limit.values())
else -> rows.addAll(arrayListOf())
}
return rows
}
}

@ -6,7 +6,6 @@ import net.pokeranalytics.android.R
import net.pokeranalytics.android.model.TournamentType 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.Game
import net.pokeranalytics.android.model.realm.Session import net.pokeranalytics.android.model.realm.Session
import net.pokeranalytics.android.ui.fragment.components.bottomsheet.BottomSheetType import net.pokeranalytics.android.ui.fragment.components.bottomsheet.BottomSheetType
import net.pokeranalytics.android.ui.view.RowRepresentable import net.pokeranalytics.android.ui.view.RowRepresentable
@ -277,8 +276,6 @@ enum class SessionRow : RowRepresentable {
} }
else -> null else -> null
} }
} }
} }

@ -27,6 +27,7 @@ enum class SettingRow : RowRepresentable {
TOURNAMENT_NAME, TOURNAMENT_NAME,
TOURNAMENT_FEATURE, TOURNAMENT_FEATURE,
TRANSACTION, TRANSACTION,
TRANSACTION_TYPE,
// Terms // Terms
PRIVACY_POLICY, PRIVACY_POLICY,
@ -56,7 +57,7 @@ enum class SettingRow : RowRepresentable {
resId = R.string.data_management resId = R.string.data_management
) )
) )
rows.addAll(arrayListOf(BANKROLL, GAME, LOCATION, TOURNAMENT_NAME, TOURNAMENT_FEATURE, TRANSACTION)) rows.addAll(arrayListOf(BANKROLL, GAME, LOCATION, TOURNAMENT_NAME, TOURNAMENT_FEATURE, TRANSACTION, TRANSACTION_TYPE))
rows.add(CustomizableRowRepresentable(customViewType = RowViewType.HEADER_TITLE, resId = R.string.terms)) rows.add(CustomizableRowRepresentable(customViewType = RowViewType.HEADER_TITLE, resId = R.string.terms))
rows.addAll(arrayListOf(PRIVACY_POLICY, TERMS_OF_USE, GDPR)) rows.addAll(arrayListOf(PRIVACY_POLICY, TERMS_OF_USE, GDPR))
@ -106,6 +107,7 @@ enum class SettingRow : RowRepresentable {
TOURNAMENT_NAME -> LiveData.TOURNAMENT_NAME TOURNAMENT_NAME -> LiveData.TOURNAMENT_NAME
TOURNAMENT_FEATURE -> LiveData.TOURNAMENT_FEATURE TOURNAMENT_FEATURE -> LiveData.TOURNAMENT_FEATURE
TRANSACTION -> LiveData.TRANSACTION TRANSACTION -> LiveData.TRANSACTION
TRANSACTION_TYPE -> LiveData.TRANSACTION_TYPE
else -> null else -> null
} }
} }

@ -0,0 +1,35 @@
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 ?: Currency.getInstance(Locale.getDefault()).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
}
}
}

@ -1,20 +0,0 @@
package net.pokeranalytics.android.util
import android.content.Context
import java.text.NumberFormat
import java.util.*
class FormatUtils {
companion object {
fun getCurrencyFormatter(context: Context) : NumberFormat {
val formatter = NumberFormat.getCurrencyInstance(Preferences.getCurrencyLocale(context))
formatter.minimumFractionDigits = 0
formatter.maximumFractionDigits = 2
return formatter
}
}
}

@ -16,8 +16,10 @@ enum class URL(var value: String) {
FACEBOOK("https://www.facebook.com/171053452998758"), FACEBOOK("https://www.facebook.com/171053452998758"),
// Support // Support
SUPPORT_EMAIL("support@pokeranalytics.net") SUPPORT_EMAIL("support@pokeranalytics.net"),
// Currency Converter API
API_CURRENCY_CONVERTER("https://free.currencyconverterapi.com/api/v5/")
} }

@ -2,6 +2,7 @@ package net.pokeranalytics.android.util.extensions
import java.text.DecimalFormat import java.text.DecimalFormat
import java.text.NumberFormat import java.text.NumberFormat
import java.util.*
// Double // Double
@ -18,11 +19,16 @@ fun Double.formatted(): String {
return format.format(this) return format.format(this)
} }
fun Double.toCurrency(): String { fun Double.toCurrency(currency: Currency? = null): String {
val format = NumberFormat.getCurrencyInstance()
format.maximumFractionDigits = 2 val currencyFormatter = NumberFormat.getCurrencyInstance()
format.minimumFractionDigits = 0 currency?.let {
return format.format(this) currencyFormatter.currency = currency
}
currencyFormatter.maximumFractionDigits = 2
currencyFormatter.minimumFractionDigits = 0
return currencyFormatter.format(this)
} }
fun Double.formattedHourlyDuration() : String { fun Double.formattedHourlyDuration() : String {

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent">
</FrameLayout>

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent">
</FrameLayout>

@ -0,0 +1,61 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.core.widget.NestedScrollView
android:id="@+id/nestedScrollView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.core.widget.NestedScrollView>
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/appBar"
android:layout_width="match_parent"
android:layout_height="128dp"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">
<com.google.android.material.appbar.CollapsingToolbarLayout
android:id="@+id/collapsingToolbar"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:collapsedTitleTextAppearance="@style/PokerAnalyticsTheme.Toolbar.CollapsedTitleAppearance"
app:contentScrim="?attr/colorPrimary"
app:expandedTitleGravity="bottom"
app:expandedTitleMarginStart="72dp"
app:expandedTitleTextAppearance="@style/PokerAnalyticsTheme.Toolbar.ExpandedTitleAppearance"
app:layout_scrollFlags="scroll|exitUntilCollapsed|snap">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_collapseMode="pin"
app:title="Poker Analytics"
app:titleTextColor="@color/white" />
</com.google.android.material.appbar.CollapsingToolbarLayout>
</com.google.android.material.appbar.AppBarLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>

@ -0,0 +1,61 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.core.widget.NestedScrollView
android:id="@+id/nestedScrollView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.core.widget.NestedScrollView>
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/appBar"
android:layout_width="match_parent"
android:layout_height="128dp"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">
<com.google.android.material.appbar.CollapsingToolbarLayout
android:id="@+id/collapsingToolbar"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:collapsedTitleTextAppearance="@style/PokerAnalyticsTheme.Toolbar.CollapsedTitleAppearance"
app:contentScrim="?attr/colorPrimary"
app:expandedTitleGravity="bottom"
app:expandedTitleMarginStart="72dp"
app:expandedTitleTextAppearance="@style/PokerAnalyticsTheme.Toolbar.ExpandedTitleAppearance"
app:layout_scrollFlags="scroll|exitUntilCollapsed|snap">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_collapseMode="pin"
app:title="Poker Analytics"
app:titleTextColor="@color/white" />
</com.google.android.material.appbar.CollapsingToolbarLayout>
</com.google.android.material.appbar.AppBarLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/filter"
android:icon="@drawable/ic_outline_filter_list"
android:title="@string/filter"
app:showAsAction="always" />
</menu>

@ -1,4 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<string name="google_places_api" translatable="false">AIzaSyCg-vgW4YnFsQ_s1iWjgzSq2vT0te3R1Hw</string> <string name="google_places_api" translatable="false">AIzaSyCg-vgW4YnFsQ_s1iWjgzSq2vT0te3R1Hw</string>
<string name="currency_converter_api" translatable="false">5ba8d38995282fe8b1c8</string>
</resources> </resources>

@ -185,7 +185,7 @@
<style name="PokerAnalyticsTheme.AlertDialog" parent="Theme.MaterialComponents.Dialog"> <style name="PokerAnalyticsTheme.AlertDialog" parent="Theme.MaterialComponents.Dialog">
<item name="colorAccent">@color/green</item> <item name="colorAccent">@color/green</item>
<item name="android:textColorPrimary">@color/white</item> <item name="android:textColorPrimary">@color/white</item>
<item name="android:background">@color/gray_dark</item> <item name="android:windowBackground">@color/gray_dark</item>
</style> </style>

Loading…
Cancel
Save