merge blinds branch

powerreport
Laurent 3 years ago
commit 33f04d9519
  1. 10
      app/build.gradle
  2. 19
      app/src/androidTest/java/net/pokeranalytics/android/unitTests/FavoriteSessionUnitTest.kt
  3. 4
      app/src/androidTest/java/net/pokeranalytics/android/unitTests/StatsInstrumentedUnitTest.kt
  4. 70
      app/src/androidTest/java/net/pokeranalytics/android/unitTests/filter/BlindFilterInstrumentedTest.kt
  5. 4
      app/src/androidTest/java/net/pokeranalytics/android/unitTests/filter/SessionFilterInstrumentedUnitTest.kt
  6. 11
      app/src/main/AndroidManifest.xml
  7. 2
      app/src/main/java/net/pokeranalytics/android/PokerAnalyticsApplication.kt
  8. 2
      app/src/main/java/net/pokeranalytics/android/calculus/optimalduration/CashGameOptimalDurationCalculator.kt
  9. 26
      app/src/main/java/net/pokeranalytics/android/model/Criteria.kt
  10. 13
      app/src/main/java/net/pokeranalytics/android/model/Stakes.kt
  11. 4
      app/src/main/java/net/pokeranalytics/android/model/extensions/SessionExtensions.kt
  12. 19
      app/src/main/java/net/pokeranalytics/android/model/filter/QueryCondition.kt
  13. 56
      app/src/main/java/net/pokeranalytics/android/model/handhistory/HandSetup.kt
  14. 186
      app/src/main/java/net/pokeranalytics/android/model/interfaces/StakesHolder.kt
  15. 29
      app/src/main/java/net/pokeranalytics/android/model/migrations/Patcher.kt
  16. 30
      app/src/main/java/net/pokeranalytics/android/model/migrations/PokerAnalyticsMigration.kt
  17. 2
      app/src/main/java/net/pokeranalytics/android/model/realm/ComputableResult.kt
  18. 2
      app/src/main/java/net/pokeranalytics/android/model/realm/Result.kt
  19. 230
      app/src/main/java/net/pokeranalytics/android/model/realm/Session.kt
  20. 127
      app/src/main/java/net/pokeranalytics/android/model/realm/handhistory/HandHistory.kt
  21. 15
      app/src/main/java/net/pokeranalytics/android/model/utils/DataUtils.kt
  22. 6
      app/src/main/java/net/pokeranalytics/android/model/utils/FavoriteSessionFinder.kt
  23. 21
      app/src/main/java/net/pokeranalytics/android/ui/fragment/ImportFragment.kt
  24. 2
      app/src/main/java/net/pokeranalytics/android/ui/fragment/SettingsFragment.kt
  25. 4
      app/src/main/java/net/pokeranalytics/android/ui/fragment/components/bottomsheet/BottomSheetDoubleEditTextFragment.kt
  26. 2
      app/src/main/java/net/pokeranalytics/android/ui/fragment/components/bottomsheet/BottomSheetEditTextFragment.kt
  27. 1
      app/src/main/java/net/pokeranalytics/android/ui/fragment/components/bottomsheet/BottomSheetFragment.kt
  28. 2
      app/src/main/java/net/pokeranalytics/android/ui/fragment/components/bottomsheet/BottomSheetListFragment.kt
  29. 2
      app/src/main/java/net/pokeranalytics/android/ui/fragment/components/bottomsheet/BottomSheetListGameFragment.kt
  30. 2
      app/src/main/java/net/pokeranalytics/android/ui/fragment/components/bottomsheet/BottomSheetNumericTextFragment.kt
  31. 150
      app/src/main/java/net/pokeranalytics/android/ui/fragment/components/bottomsheet/BottomSheetStakesFragment.kt
  32. 2
      app/src/main/java/net/pokeranalytics/android/ui/fragment/components/bottomsheet/BottomSheetStaticListFragment.kt
  33. 2
      app/src/main/java/net/pokeranalytics/android/ui/fragment/components/bottomsheet/BottomSheetSumFragment.kt
  34. 4
      app/src/main/java/net/pokeranalytics/android/ui/fragment/components/bottomsheet/BottomSheetTableSizeGridFragment.kt
  35. 5
      app/src/main/java/net/pokeranalytics/android/ui/fragment/components/bottomsheet/BottomSheetType.kt
  36. 3
      app/src/main/java/net/pokeranalytics/android/ui/modules/handhistory/editor/EditorAdapter.kt
  37. 4
      app/src/main/java/net/pokeranalytics/android/ui/modules/handhistory/model/ActionList.kt
  38. 17
      app/src/main/java/net/pokeranalytics/android/ui/modules/handhistory/model/EditorViewModel.kt
  39. 9
      app/src/main/java/net/pokeranalytics/android/ui/modules/handhistory/views/AbstractKeyboardView.kt
  40. 26
      app/src/main/java/net/pokeranalytics/android/ui/modules/handhistory/views/KeyboardAmountView.kt
  41. 3
      app/src/main/java/net/pokeranalytics/android/ui/modules/handhistory/views/RowHandHistoryViewHolder.kt
  42. 24
      app/src/main/java/net/pokeranalytics/android/ui/modules/session/SessionFragment.kt
  43. 79
      app/src/main/java/net/pokeranalytics/android/ui/view/keyboard/StakesKeyboardView.kt
  44. 2
      app/src/main/java/net/pokeranalytics/android/ui/view/rows/FilterCategoryRow.kt
  45. 4
      app/src/main/java/net/pokeranalytics/android/ui/view/rows/FilterSectionRow.kt
  46. 2
      app/src/main/java/net/pokeranalytics/android/ui/view/rows/ReportRow.kt
  47. 49
      app/src/main/java/net/pokeranalytics/android/ui/view/rows/SessionPropertiesRow.kt
  48. 9
      app/src/main/java/net/pokeranalytics/android/ui/viewmodel/BottomSheetViewModel.kt
  49. 10
      app/src/main/java/net/pokeranalytics/android/util/FakeDataManager.kt
  50. 3
      app/src/main/java/net/pokeranalytics/android/util/Global.kt
  51. 5
      app/src/main/java/net/pokeranalytics/android/util/Preferences.kt
  52. 1
      app/src/main/java/net/pokeranalytics/android/util/csv/CSVDescriptor.kt
  53. 18
      app/src/main/java/net/pokeranalytics/android/util/csv/CSVImporter.kt
  54. 51
      app/src/main/java/net/pokeranalytics/android/util/csv/PACSVDescriptor.kt
  55. 41
      app/src/main/java/net/pokeranalytics/android/util/csv/ProductCSVDescriptors.kt
  56. 7
      app/src/main/java/net/pokeranalytics/android/util/csv/SessionCSVDescriptor.kt
  57. 1
      app/src/main/res/layout/activity_color_picker.xml
  58. 71
      app/src/main/res/layout/activity_new_data.xml
  59. 74
      app/src/main/res/layout/bottom_sheet_stakes.xml
  60. 2
      app/src/main/res/layout/row_hand_action.xml
  61. 134
      app/src/main/res/layout/view_keyboard_stakes.xml
  62. 3
      app/src/main/res/values-fr/strings.xml
  63. 1
      app/src/main/res/values/strings.xml
  64. 26
      app/src/main/res/values/styles.xml

@ -15,7 +15,7 @@ repositories {
android { android {
compileSdkVersion 30 compileSdkVersion 32
buildToolsVersion "30.0.2" buildToolsVersion "30.0.2"
compileOptions { compileOptions {
@ -34,9 +34,9 @@ android {
defaultConfig { defaultConfig {
applicationId "net.pokeranalytics.android" applicationId "net.pokeranalytics.android"
minSdkVersion 23 minSdkVersion 23
targetSdkVersion 30 targetSdkVersion 32
versionCode 135 versionCode 136
versionName "5.4.11" versionName "5.5"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
} }
@ -108,7 +108,7 @@ dependencies {
implementation 'com.google.android.material:material:1.3.0' implementation 'com.google.android.material:material:1.3.0'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3' implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0' implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
implementation 'androidx.work:work-runtime-ktx:2.4.0' implementation 'androidx.work:work-runtime-ktx:2.7.1'
implementation 'com.google.android.play:core-ktx:1.8.1' // In-app Reviews implementation 'com.google.android.play:core-ktx:1.8.1' // In-app Reviews
// Places // Places

@ -30,12 +30,9 @@ class FavoriteSessionUnitTest : RealmInstrumentedUnitTest() {
s2.endDate = Date() s2.endDate = Date()
s3.endDate = Date() s3.endDate = Date()
s1.cgBigBlind = 4.0 s1.cgBlinds = "2/4"
s1.cgSmallBlind = 2.0 s2.cgBlinds = "2/4"
s2.cgBigBlind = 4.0 s3.cgBlinds = "1/2"
s2.cgSmallBlind = 2.0
s3.cgBigBlind = 1.0
s3.cgSmallBlind = 1.0
realm.insert(s1) realm.insert(s1)
realm.insert(s2) realm.insert(s2)
@ -45,7 +42,7 @@ class FavoriteSessionUnitTest : RealmInstrumentedUnitTest() {
val favSession = FavoriteSessionFinder.favoriteSession(Session.Type.CASH_GAME.ordinal, null, realm, InstrumentationRegistry.getInstrumentation().targetContext) val favSession = FavoriteSessionFinder.favoriteSession(Session.Type.CASH_GAME.ordinal, null, realm, InstrumentationRegistry.getInstrumentation().targetContext)
if (favSession != null) { if (favSession != null) {
Assert.assertEquals(4.0, favSession.cgBigBlind) Assert.assertEquals(4.0, favSession.cgBiggestBet)
} else { } else {
Assert.fail("session shouldn't be null") Assert.fail("session shouldn't be null")
} }
@ -65,9 +62,9 @@ class FavoriteSessionUnitTest : RealmInstrumentedUnitTest() {
val loc1 = realm.createObject(Location::class.java, "1") val loc1 = realm.createObject(Location::class.java, "1")
val loc2 = realm.createObject(Location::class.java, "2") val loc2 = realm.createObject(Location::class.java, "2")
s1.cgBigBlind = 4.0 s1.cgBiggestBet = 4.0
s2.cgBigBlind = 4.0 s2.cgBiggestBet = 4.0
s3.cgBigBlind = 1.0 s3.cgBiggestBet = 1.0
s1.location = loc1 s1.location = loc1
s2.location = loc1 s2.location = loc1
@ -81,7 +78,7 @@ class FavoriteSessionUnitTest : RealmInstrumentedUnitTest() {
val favSession = FavoriteSessionFinder.favoriteSession(Session.Type.CASH_GAME.ordinal, loc2, realm, InstrumentationRegistry.getInstrumentation().targetContext) val favSession = FavoriteSessionFinder.favoriteSession(Session.Type.CASH_GAME.ordinal, loc2, realm, InstrumentationRegistry.getInstrumentation().targetContext)
if (favSession != null) { if (favSession != null) {
Assert.assertEquals(1.0, favSession.cgBigBlind) Assert.assertEquals(1.0, favSession.cgBiggestBet)
} else { } else {
Assert.fail("session shouldn't be null") Assert.fail("session shouldn't be null")
} }

@ -44,8 +44,8 @@ class StatsInstrumentedUnitTest : SessionInstrumentedUnitTest() {
s2.result?.buyin = 200.0 s2.result?.buyin = 200.0
s2.result?.cashout = 500.0 // net result = 300 s2.result?.cashout = 500.0 // net result = 300
s1.cgBigBlind = 0.5 // bb net result = -200bb s1.cgBlinds = "0.5" // bb net result = -200bb
s2.cgBigBlind = 2.0 // bb net result = 150bb s2.cgBlinds = "2.0" // bb net result = 150bb
s2.tableSize = 5 s2.tableSize = 5

@ -28,28 +28,25 @@ class BlindFilterInstrumentedTest : BaseFilterInstrumentedUnitTest() {
b2.currency = currency b2.currency = currency
val s1 = Session.testInstance(100.0, false, Date(), 1, b1) val s1 = Session.testInstance(100.0, false, Date(), 1, b1)
s1.cgBigBlind = 1.0 s1.cgBlinds = "0.5/1"
s1.cgSmallBlind = 0.5
val s2 = Session.testInstance(100.0, false, Date(), 1, b1) val s2 = Session.testInstance(100.0, false, Date(), 1, b1)
s2.cgBigBlind = 1.0 s2.cgBlinds = "0.5/1"
s2.cgSmallBlind = 0.5
val s3 = Session.testInstance(100.0, false, Date(), 1, b1) val s3 = Session.testInstance(100.0, false, Date(), 1, b1)
s3.cgBigBlind = 2.0 s3.cgBlinds = "1/2"
s3.cgSmallBlind = 1.0
realm.commitTransaction() realm.commitTransaction()
val filter = QueryCondition.AnyBlind() val filter = QueryCondition.AnyStake()
val blind = QueryCondition.AnyBlind().apply { val blind = QueryCondition.AnyStake().apply {
listOfValues = arrayListOf(s1.blinds!!) listOfValues = arrayListOf(s1.blinds!!)
} }
// blind.filterSectionRow = FilterSectionRow.Blind // blind.filterSectionRow = FilterSectionRow.Blind
val filterElement = FilterCondition(arrayListOf(blind), FilterSectionRow.Blind) val filterElement = FilterCondition(arrayListOf(blind), FilterSectionRow.Stakes)
filter.updateValueBy(filterElement) filter.updateValueBy(filterElement)
val sessions = Filter.queryOn<Session>(realm, Query(filter)) val sessions = Filter.queryOn<Session>(realm, Query(filter))
@ -74,30 +71,27 @@ class BlindFilterInstrumentedTest : BaseFilterInstrumentedUnitTest() {
b2.currency = currency b2.currency = currency
val s1 = Session.testInstance(100.0, false, Date(), 1, b1) val s1 = Session.testInstance(100.0, false, Date(), 1, b1)
s1.cgBigBlind = 1.0 s1.cgBlinds = "0.5/1"
s1.cgSmallBlind = 0.5
val s2 = Session.testInstance(100.0, false, Date(), 1, b1) val s2 = Session.testInstance(100.0, false, Date(), 1, b1)
s2.cgBigBlind = 1.0 s2.cgBlinds = "0.5/1"
s2.cgSmallBlind = 0.5
val s3 = Session.testInstance(100.0, false, Date(), 1, b1) val s3 = Session.testInstance(100.0, false, Date(), 1, b1)
s3.cgBigBlind = 2.0 s3.cgBlinds = "1/2"
s3.cgSmallBlind = 1.0
realm.commitTransaction() realm.commitTransaction()
val filter = QueryCondition.AnyBlind() val filter = QueryCondition.AnyStake()
val blind1 = QueryCondition.AnyBlind().apply { val blind1 = QueryCondition.AnyStake().apply {
listOfValues = arrayListOf(s1.blinds!!) listOfValues = arrayListOf(s1.blinds!!)
} }
val blind2 = QueryCondition.AnyBlind().apply { val blind2 = QueryCondition.AnyStake().apply {
listOfValues = arrayListOf(s2.blinds!!) listOfValues = arrayListOf(s2.blinds!!)
} }
val filterElements = FilterCondition(arrayListOf(blind1, blind2), FilterSectionRow.Blind) val filterElements = FilterCondition(arrayListOf(blind1, blind2), FilterSectionRow.Stakes)
filter.updateValueBy(filterElements) filter.updateValueBy(filterElements)
val sessions = Filter.queryOn<Session>(realm, Query(filter)) val sessions = Filter.queryOn<Session>(realm, Query(filter))
@ -122,28 +116,24 @@ class BlindFilterInstrumentedTest : BaseFilterInstrumentedUnitTest() {
b2.currency = currency b2.currency = currency
val s1 = Session.testInstance(100.0, false, Date(), 1, b1) val s1 = Session.testInstance(100.0, false, Date(), 1, b1)
s1.cgBlinds = "0.5/1"
s1.cgBigBlind = 1.0
s1.cgSmallBlind = 0.5
val s2 = Session.testInstance(100.0, false, Date(), 1, b1) val s2 = Session.testInstance(100.0, false, Date(), 1, b1)
s2.cgBigBlind = 1.0 s2.cgBlinds = "0.5/1"
s2.cgSmallBlind = 0.5
val s3 = Session.testInstance(100.0, false, Date(), 1, b2) val s3 = Session.testInstance(100.0, false, Date(), 1, b2)
s3.cgBigBlind = 2.0 s3.cgBlinds = "1/2"
s3.cgSmallBlind = 1.0
realm.commitTransaction() realm.commitTransaction()
val filter = QueryCondition.AnyBlind() val filter = QueryCondition.AnyStake()
val blind = QueryCondition.AnyBlind().apply { val blind = QueryCondition.AnyStake().apply {
listOfValues = arrayListOf(s3.blinds!!) listOfValues = arrayListOf(s3.blinds!!)
} }
val filterElement = FilterCondition(arrayListOf(blind), FilterSectionRow.Blind) val filterElement = FilterCondition(arrayListOf(blind), FilterSectionRow.Stakes)
filter.updateValueBy(filterElement) filter.updateValueBy(filterElement)
val sessions = Filter.queryOn<Session>(realm, Query(filter)) val sessions = Filter.queryOn<Session>(realm, Query(filter))
@ -167,31 +157,27 @@ class BlindFilterInstrumentedTest : BaseFilterInstrumentedUnitTest() {
b2.currency = currency b2.currency = currency
val s1 = Session.testInstance(100.0, false, Date(), 1, b1) val s1 = Session.testInstance(100.0, false, Date(), 1, b1)
s1.cgBigBlind = 1.0 s1.cgBlinds = "0.5/1"
s1.cgSmallBlind = 0.5
val s2 = Session.testInstance(100.0, false, Date(), 1, b1) val s2 = Session.testInstance(100.0, false, Date(), 1, b1)
s2.cgBigBlind = 2.0 s2.cgBlinds = "0.5/1"
s2.cgSmallBlind = 1.0
val s3 = Session.testInstance(100.0, false, Date(), 1, b2) val s3 = Session.testInstance(100.0, false, Date(), 1, b2)
s3.cgBigBlind = 2.0 s3.cgBlinds = "1/2"
s3.cgSmallBlind = 1.0
realm.commitTransaction() realm.commitTransaction()
val filter = QueryCondition.AnyStake()
val filter = QueryCondition.AnyBlind() val stake1 = QueryCondition.AnyStake().apply {
listOfValues = arrayListOf(s1.cgStakes!!)
val blind1 = QueryCondition.AnyBlind().apply {
listOfValues = arrayListOf(s1.blinds!!)
} }
val blind2 = QueryCondition.AnyBlind().apply { val stake2 = QueryCondition.AnyStake().apply {
listOfValues = arrayListOf(s2.blinds!!) listOfValues = arrayListOf(s2.cgStakes!!)
} }
val filterElement = FilterCondition(arrayListOf(blind1, blind2), FilterSectionRow.Blind) val filterElement = FilterCondition(arrayListOf(stake1, stake2), FilterSectionRow.Stakes)
filter.updateValueBy(filterElement) filter.updateValueBy(filterElement)
val sessions = Filter.queryOn<Session>(realm, Query(filter)) val sessions = Filter.queryOn<Session>(realm, Query(filter))

@ -536,11 +536,11 @@ class SessionFilterInstrumentedUnitTest : BaseFilterInstrumentedUnitTest() {
val s3 = Session.testInstance(netResult = 500.0) val s3 = Session.testInstance(netResult = 500.0)
s3.cgBigBlind = 2.0 s3.cgBlinds = "2.0"
s3.result!!.buyin = 1000.0 s3.result!!.buyin = 1000.0
val s4 = Session.testInstance(netResult = 570.0) val s4 = Session.testInstance(netResult = 570.0)
s4.cgBigBlind = 5.0 s4.cgBlinds = "5.0"
s4.result!!.buyin = 200.0 s4.result!!.buyin = 200.0
realm.commitTransaction() realm.commitTransaction()

@ -29,7 +29,8 @@
android:name="net.pokeranalytics.android.ui.activity.HomeActivity" android:name="net.pokeranalytics.android.ui.activity.HomeActivity"
android:label="@string/app_name" android:label="@string/app_name"
android:launchMode="singleTop" android:launchMode="singleTop"
android:screenOrientation="portrait"> android:screenOrientation="portrait"
android:exported="true">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN" /> <action android:name="android.intent.action.MAIN" />
<action android:name="android.intent.action.VIEW" /> <action android:name="android.intent.action.VIEW" />
@ -42,7 +43,8 @@
<activity <activity
android:name="net.pokeranalytics.android.ui.activity.ImportActivity" android:name="net.pokeranalytics.android.ui.activity.ImportActivity"
android:launchMode="singleTop" android:launchMode="singleTop"
android:screenOrientation="portrait"> android:screenOrientation="portrait"
android:exported="true">
<intent-filter tools:ignore="AppLinkUrlError"> <intent-filter tools:ignore="AppLinkUrlError">
<action android:name="android.intent.action.VIEW" /> <action android:name="android.intent.action.VIEW" />
@ -60,8 +62,7 @@
<activity <activity
android:name="net.pokeranalytics.android.ui.modules.session.SessionActivity" android:name="net.pokeranalytics.android.ui.modules.session.SessionActivity"
android:launchMode="singleTop" android:launchMode="singleTop"
android:screenOrientation="portrait" android:screenOrientation="portrait" />
android:windowSoftInputMode="adjustNothing" />
<!-- No screenOrientation="portrait" to fix Oreo crash --> <!-- No screenOrientation="portrait" to fix Oreo crash -->
<activity <activity
@ -132,7 +133,7 @@
<activity <activity
android:name="net.pokeranalytics.android.ui.modules.data.EditableDataActivity" android:name="net.pokeranalytics.android.ui.modules.data.EditableDataActivity"
android:launchMode="singleTop" android:launchMode="standard"
android:screenOrientation="portrait" /> android:screenOrientation="portrait" />
<activity <activity

@ -47,7 +47,7 @@ class PokerAnalyticsApplication : Application() {
Realm.init(this) Realm.init(this)
val realmConfiguration = RealmConfiguration.Builder() val realmConfiguration = RealmConfiguration.Builder()
.name(Realm.DEFAULT_REALM_NAME) .name(Realm.DEFAULT_REALM_NAME)
.schemaVersion(11) .schemaVersion(12)
.allowWritesOnUiThread(true) .allowWritesOnUiThread(true)
.migration(PokerAnalyticsMigration()) .migration(PokerAnalyticsMigration())
.initialData(Seed(this)) .initialData(Seed(this))

@ -41,7 +41,7 @@ class CashGameOptimalDurationCalculator {
val query = Query().add(QueryCondition.IsCash) // cash game val query = Query().add(QueryCondition.IsCash) // cash game
query.add(if (isLive) { QueryCondition.IsLive } else { QueryCondition.IsOnline }) // live / online query.add(if (isLive) { QueryCondition.IsLive } else { QueryCondition.IsOnline }) // live / online
query.add(QueryCondition.EndDateNotNull) // ended query.add(QueryCondition.EndDateNotNull) // ended
query.add(QueryCondition.BigBlindNotNull) // has BB value query.add(QueryCondition.BiggestBetNotNull) // has BB value
val sessions = query.queryWith(realm.where(Session::class.java)).findAll() val sessions = query.queryWith(realm.where(Session::class.java)).findAll()
val sessionsByDuration = sessions.groupBy { val sessionsByDuration = sessions.groupBy {

@ -7,10 +7,10 @@ import net.pokeranalytics.android.R
import net.pokeranalytics.android.exceptions.PAIllegalStateException import net.pokeranalytics.android.exceptions.PAIllegalStateException
import net.pokeranalytics.android.exceptions.PokerAnalyticsException import net.pokeranalytics.android.exceptions.PokerAnalyticsException
import net.pokeranalytics.android.model.Criteria.Bankrolls.comparison import net.pokeranalytics.android.model.Criteria.Bankrolls.comparison
import net.pokeranalytics.android.model.Criteria.Blinds.comparison
import net.pokeranalytics.android.model.Criteria.Games.comparison import net.pokeranalytics.android.model.Criteria.Games.comparison
import net.pokeranalytics.android.model.Criteria.Limits.comparison import net.pokeranalytics.android.model.Criteria.Limits.comparison
import net.pokeranalytics.android.model.Criteria.Locations.comparison import net.pokeranalytics.android.model.Criteria.Locations.comparison
import net.pokeranalytics.android.model.Criteria.Stakes.comparison
import net.pokeranalytics.android.model.Criteria.TableSizes.comparison import net.pokeranalytics.android.model.Criteria.TableSizes.comparison
import net.pokeranalytics.android.model.Criteria.TournamentFeatures.comparison import net.pokeranalytics.android.model.Criteria.TournamentFeatures.comparison
import net.pokeranalytics.android.model.Criteria.TournamentFees.comparison import net.pokeranalytics.android.model.Criteria.TournamentFees.comparison
@ -68,7 +68,7 @@ sealed class Criteria(override var uniqueIdentifier: Int) : IntIdentifiable, Row
realm.findById(CustomField::class.java, this.customFieldId)?.entries?.forEach { realm.findById(CustomField::class.java, this.customFieldId)?.entries?.forEach {
objects.add(QueryCondition.CustomFieldListQuery(it)) objects.add(QueryCondition.CustomFieldListQuery(it))
} }
objects.sorted() objects.sort()
realm.close() realm.close()
return objects.map { Query(it) } return objects.map { Query(it) }
} }
@ -104,11 +104,10 @@ sealed class Criteria(override var uniqueIdentifier: Int) : IntIdentifiable, Row
} }
objects.add(condition) objects.add(condition)
} }
objects.sorted() objects.sort()
return objects.map { Query(it) } return objects.map { Query(it) }
} }
QueryCondition.distinct<Session, T, S>()?.let { QueryCondition.distinct<Session, T, S>()?.let {
val values = it.mapNotNull { session -> val values = it.mapNotNull { session ->
when (this) { when (this) {
@ -124,8 +123,8 @@ sealed class Criteria(override var uniqueIdentifier: Int) : IntIdentifiable, Row
is TournamentFees -> if (session.tournamentEntryFee is S) { is TournamentFees -> if (session.tournamentEntryFee is S) {
session.tournamentEntryFee as S session.tournamentEntryFee as S
} else throw PokerAnalyticsException.QueryValueMapUnexpectedValue } else throw PokerAnalyticsException.QueryValueMapUnexpectedValue
is Blinds -> if (session.blinds is S) { is Stakes -> if (session.cgStakes is S) {
session.blinds as S session.cgStakes as S
} else throw PokerAnalyticsException.QueryValueMapUnexpectedValue } else throw PokerAnalyticsException.QueryValueMapUnexpectedValue
else -> null else -> null
} }
@ -159,7 +158,7 @@ sealed class Criteria(override var uniqueIdentifier: Int) : IntIdentifiable, Row
object DayPeriods : SimpleCriteria(listOf(QueryCondition.IsWeekDay, QueryCondition.IsWeekEnd), 14) object DayPeriods : SimpleCriteria(listOf(QueryCondition.IsWeekDay, QueryCondition.IsWeekEnd), 14)
object Years : ListCriteria(15) object Years : ListCriteria(15)
object AllMonthsUpToNow : ListCriteria(16) object AllMonthsUpToNow : ListCriteria(16)
object Blinds : ListCriteria(17) object Stakes : ListCriteria(17)
object TournamentFees : ListCriteria(18) object TournamentFees : ListCriteria(18)
object Cash : SimpleCriteria(listOf(QueryCondition.IsCash), 19) object Cash : SimpleCriteria(listOf(QueryCondition.IsCash), 19)
object Tournament : SimpleCriteria(listOf(QueryCondition.IsTournament), 20) object Tournament : SimpleCriteria(listOf(QueryCondition.IsTournament), 20)
@ -237,7 +236,7 @@ sealed class Criteria(override var uniqueIdentifier: Int) : IntIdentifiable, Row
realm.close() realm.close()
years years
} }
is Blinds -> comparison<QueryCondition.AnyBlind, String>() is Stakes -> comparison<QueryCondition.AnyStake, String>()
is ListCustomFields -> comparison<CustomFieldEntry>() is ListCustomFields -> comparison<CustomFieldEntry>()
is ValueCustomFields -> { is ValueCustomFields -> {
val realm = Realm.getDefaultInstance() val realm = Realm.getDefaultInstance()
@ -271,7 +270,7 @@ sealed class Criteria(override var uniqueIdentifier: Int) : IntIdentifiable, Row
DayPeriods -> R.string.weekdays_or_weekend DayPeriods -> R.string.weekdays_or_weekend
Years -> R.string.year Years -> R.string.year
AllMonthsUpToNow -> R.string.month AllMonthsUpToNow -> R.string.month
Blinds -> R.string.blind Stakes -> R.string.blind
TournamentFees -> R.string.entry_fees TournamentFees -> R.string.entry_fees
// is ListCustomFields -> this.customField.resId // is ListCustomFields -> this.customField.resId
// is ValueCustomFields -> this.customField.resId // is ValueCustomFields -> this.customField.resId
@ -284,13 +283,13 @@ sealed class Criteria(override var uniqueIdentifier: Int) : IntIdentifiable, Row
inline fun <reified S : QueryCondition.QueryDataCondition<NameManageable>, reified T : NameManageable> compare(): List<Query> { inline fun <reified S : QueryCondition.QueryDataCondition<NameManageable>, reified T : NameManageable> compare(): List<Query> {
val objects = mutableListOf<S>() val objects = mutableListOf<S>()
val realm = Realm.getDefaultInstance() val realm = Realm.getDefaultInstance()
realm.where<T>().findAll().forEach { realm.where<T>().sort("name").findAll().forEach {
val condition = (QueryCondition.getInstance<T>() as S).apply { val condition = (QueryCondition.getInstance<T>() as S).apply {
setObject(it) setObject(it)
} }
objects.add(condition) objects.add(condition)
} }
objects.sorted() // objects.sort()
realm.close() realm.close()
return objects.map { Query(it) } return objects.map { Query(it) }
} }
@ -303,7 +302,7 @@ sealed class Criteria(override var uniqueIdentifier: Int) : IntIdentifiable, Row
} }
objects.add(condition) objects.add(condition)
} }
objects.sorted() objects.sort()
return objects.map { Query(it) } return objects.map { Query(it) }
} }
@ -319,7 +318,8 @@ sealed class Criteria(override var uniqueIdentifier: Int) : IntIdentifiable, Row
TournamentFeatures, Limits, TableSizes, TournamentTypes, TournamentFeatures, Limits, TableSizes, TournamentTypes,
MonthsOfYear, DaysOfWeek, SessionTypes, MonthsOfYear, DaysOfWeek, SessionTypes,
BankrollTypes, DayPeriods, Years, BankrollTypes, DayPeriods, Years,
AllMonthsUpToNow, Blinds, TournamentFees AllMonthsUpToNow,
Stakes, TournamentFees
) )
} }
} }

@ -0,0 +1,13 @@
package net.pokeranalytics.android.model
data class Stakes(var blinds: String?, var ante: Double?) {
companion object {
}
}

@ -75,8 +75,8 @@ fun Session.getFormattedGameType(context: Context): String {
parameters.add(context.getString(R.string.tournament).capitalize()) parameters.add(context.getString(R.string.tournament).capitalize())
} }
} else { } else {
if (cgSmallBlind != null && cgBigBlind != null) { if (this.cgAnte != null || this.cgBlinds != null) {
parameters.add(getFormattedBlinds()) parameters.add(getFormattedStakes())
} }
game?.let { game?.let {
parameters.add(getFormattedGame()) parameters.add(getFormattedGame())

@ -12,8 +12,10 @@ import net.pokeranalytics.android.exceptions.PokerAnalyticsException
import net.pokeranalytics.android.model.Limit import net.pokeranalytics.android.model.Limit
import net.pokeranalytics.android.model.TableSize import net.pokeranalytics.android.model.TableSize
import net.pokeranalytics.android.model.TournamentType import net.pokeranalytics.android.model.TournamentType
import net.pokeranalytics.android.model.interfaces.CodedStake
import net.pokeranalytics.android.model.interfaces.Identifiable import net.pokeranalytics.android.model.interfaces.Identifiable
import net.pokeranalytics.android.model.interfaces.NameManageable import net.pokeranalytics.android.model.interfaces.NameManageable
import net.pokeranalytics.android.model.interfaces.StakesHolder
import net.pokeranalytics.android.model.realm.* import net.pokeranalytics.android.model.realm.*
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
@ -322,6 +324,7 @@ sealed class QueryCondition : RowRepresentable {
val query = realm.where(entity) val query = realm.where(entity)
return query.equalTo("id", value).findFirst()?.name ?: NULL_TEXT return query.equalTo("id", value).findFirst()?.name ?: NULL_TEXT
} }
} }
interface DateTime { interface DateTime {
@ -458,10 +461,20 @@ sealed class QueryCondition : RowRepresentable {
} }
} }
class AnyBlind : ListOfString() { class AnyStake : ListOfString() {
override fun labelForValue(value: String, context: Context): String {
return StakesHolder.readableStakes(value)
}
override fun entityName(context: Context): String { override fun entityName(context: Context): String {
return context.getString(R.string.blinds) return context.getString(R.string.stakes)
} }
override fun compareTo(other: ListOfValues<String>): Int {
return CodedStake(this.listOfValues.first()).compareTo(CodedStake(other.listOfValues.first()))
}
} }
class NumberOfTable : ListOfInt() { class NumberOfTable : ListOfInt() {
@ -615,7 +628,7 @@ sealed class QueryCondition : RowRepresentable {
object DateNotNull : NotNullQueryCondition() object DateNotNull : NotNullQueryCondition()
object EndDateNotNull : NotNullQueryCondition() object EndDateNotNull : NotNullQueryCondition()
object BigBlindNotNull : NotNullQueryCondition() object BiggestBetNotNull : NotNullQueryCondition()
class StartedFromTime(date: Date) : TimeQuery(date) { class StartedFromTime(date: Date) : TimeQuery(date) {
override var operator = Operator.MORE override var operator = Operator.MORE

@ -6,7 +6,6 @@ import net.pokeranalytics.android.model.realm.Session
import net.pokeranalytics.android.model.realm.handhistory.HandHistory import net.pokeranalytics.android.model.realm.handhistory.HandHistory
import net.pokeranalytics.android.util.extensions.findById import net.pokeranalytics.android.util.extensions.findById
import timber.log.Timber import timber.log.Timber
import java.util.*
class HandSetup { class HandSetup {
@ -36,9 +35,31 @@ class HandSetup {
} }
var type: Session.Type? = null
var blinds: String? = null
// var bigBlind: Double? = null
var ante: Double? = null
var tableSize: Int? = null
var bigBlindAnte: Boolean = false
var game: Game? = null
var session: Session? = null
var straddlePositions: MutableList<Position> = mutableListOf()
private set
fun clearStraddles() {
this.straddlePositions.clear()
}
private fun configure(handHistory: HandHistory) { private fun configure(handHistory: HandHistory) {
this.smallBlind = handHistory.smallBlind this.blinds = handHistory.blinds
this.bigBlind = handHistory.bigBlind
this.bigBlindAnte = handHistory.bigBlindAnte this.bigBlindAnte = handHistory.bigBlindAnte
this.ante = handHistory.ante this.ante = handHistory.ante
this.tableSize = handHistory.numberOfPlayers this.tableSize = handHistory.numberOfPlayers
@ -56,32 +77,15 @@ class HandSetup {
this.game = session.game // we don't want to force the max number of cards if unsure this.game = session.game // we don't want to force the max number of cards if unsure
} }
this.type = session.sessionType this.type = session.sessionType
this.smallBlind = session.cgSmallBlind this.blinds = session.cgBlinds
this.bigBlind = session.cgBigBlind this.ante = session.cgAnte
this.tableSize = session.tableSize this.tableSize = session.tableSize
}
var type: Session.Type? = null
var smallBlind: Double? = null
var bigBlind: Double? = null
var ante: Double? = null
var tableSize: Int? = null
var bigBlindAnte: Boolean = false
var game: Game? = null
var session: Session? = null
var straddlePositions: MutableList<Position> = mutableListOf() val blindValues = session.blindValues
private set if (blindValues.size > 2) {
this.straddlePositions = Position.positionsPerPlayers(10).drop(2).take(blindValues.size - 2).toMutableList()
}
fun clearStraddles() {
this.straddlePositions.clear()
} }
/*** /***

@ -0,0 +1,186 @@
package net.pokeranalytics.android.model.interfaces
import net.pokeranalytics.android.model.realm.Bankroll
import net.pokeranalytics.android.util.BLIND_SEPARATOR
import net.pokeranalytics.android.util.NULL_TEXT
import net.pokeranalytics.android.util.UserDefaults
import net.pokeranalytics.android.util.extensions.formatted
import net.pokeranalytics.android.util.extensions.toCurrency
import java.lang.Integer.min
import java.text.NumberFormat
import java.text.ParseException
import java.util.*
data class CodedStake(var stakes: String) : Comparable<CodedStake> {
var ante: Double? = null
var blinds: String? = null
var currency: Currency
init {
var currencyCode: String? = null
val parameters = this.stakes.split(StakesHolder.cbSeparator)
parameters.forEach { param ->
when {
param.contains(StakesHolder.cbAnte) -> ante = param.removePrefix(StakesHolder.cbAnte).let { NumberFormat.getInstance().parse(it)?.toDouble() }
param.contains(StakesHolder.cbBlinds) -> blinds = param.removePrefix(StakesHolder.cbBlinds)
param.contains(StakesHolder.cbCode) -> currencyCode = param.removePrefix(
StakesHolder.cbCode
)
}
}
this.currency = currencyCode?.let { Currency.getInstance(it) }
?: run { UserDefaults.currency }
}
override fun compareTo(other: CodedStake): Int {
if (this.currency == other.currency) {
this.blinds?.let { b1 ->
other.blinds?.let { b2 ->
if (b1 == b2) {
return this.compareAnte(other)
} else {
val bv1 = this.reversedBlindsArray(b1)
val bv2 = this.reversedBlindsArray(b2)
for (i in 0 until min(bv1.size, bv2.size)) {
if (bv1[i] != bv2[i]) {
return bv1[i].compareTo(bv2[i])
} else {
continue
}
}
return bv1.size.compareTo(bv2.size)
}
} ?: run {
return 1
}
} ?: run {
return this.compareAnte(other)
}
} else {
return this.currency.currencyCode.compareTo(other.currency.currencyCode)
}
}
private fun compareAnte(other: CodedStake): Int {
this.ante?.let { a1 ->
other.ante?.let { a2 ->
return a1.compareTo(a2)
} ?: run {
return 1
}
} ?: run {
return -1
}
}
private fun reversedBlindsArray(blinds: String): List<Double> {
return blinds.split(BLIND_SEPARATOR).mapNotNull { NumberFormat.getInstance().parse(it)?.toDouble() }.reversed()
}
fun formattedStakes(): String {
val components = arrayListOf<String>()
this.formattedBlinds()?.let { components.add(it) }
this.formattedAnte()?.let { components.add("($it)") }
return if (components.isNotEmpty()) {
components.joinToString(" ")
} else {
NULL_TEXT
}
}
private fun formattedBlinds(): String? {
this.blinds?.let {
val placeholder = 1.0
val regex = Regex("-?\\d+(\\.\\d+)?")
return placeholder.toCurrency(currency).replace(regex, it)
}
return null
}
private fun formattedAnte(): String? {
this.ante?.let {
return it.toCurrency(this.currency)
}
return null
}
}
interface StakesHolder {
companion object {
const val cbSeparator = ";"
const val cbAnte = "A="
const val cbBlinds = "B="
const val cbCode = "C="
fun readableStakes(value: String): String {
return CodedStake(value).formattedStakes()
}
}
val ante: Double?
val blinds: String?
val biggestBet: Double?
val stakes: String?
val bankroll: Bankroll?
fun setHolderStakes(stakes: String?)
fun setHolderBiggestBet(biggestBet: Double?)
val blindValues: List<Double>
get() {
this.blinds?.let { blinds ->
val blindsSplit = blinds.split(BLIND_SEPARATOR)
return blindsSplit.mapNotNull {
try {
NumberFormat.getInstance().parse(it)?.toDouble()
} catch (e: ParseException) {
null
}
}
}
return listOf()
}
fun generateStakes() {
if (this.ante == null && this.blinds == null) {
setHolderStakes(null)
return
}
val components = arrayListOf<String>()
this.blinds?.let { components.add("${cbBlinds}${it}") }
this.ante?.let { components.add("${cbAnte}${it.formatted}") }
val code = this.bankroll?.currency?.code ?: UserDefaults.currency.currencyCode
components.add("${cbCode}${code}")
setHolderStakes(components.joinToString(cbSeparator))
}
fun defineHighestBet() {
val bets = arrayListOf<Double>()
this.ante?.let { bets.add(it) }
bets.addAll(this.blindValues)
setHolderBiggestBet(bets.maxOrNull())
}
}

@ -5,9 +5,12 @@ import io.realm.Realm
import net.pokeranalytics.android.model.filter.Query import net.pokeranalytics.android.model.filter.Query
import net.pokeranalytics.android.model.filter.QueryCondition import net.pokeranalytics.android.model.filter.QueryCondition
import net.pokeranalytics.android.model.realm.* import net.pokeranalytics.android.model.realm.*
import net.pokeranalytics.android.model.realm.handhistory.HandHistory
import net.pokeranalytics.android.model.utils.Seed import net.pokeranalytics.android.model.utils.Seed
import net.pokeranalytics.android.model.utils.SessionSetManager import net.pokeranalytics.android.model.utils.SessionSetManager
import net.pokeranalytics.android.util.BLIND_SEPARATOR
import net.pokeranalytics.android.util.Preferences import net.pokeranalytics.android.util.Preferences
import java.text.NumberFormat
class Patcher { class Patcher {
@ -32,8 +35,8 @@ class Patcher {
Preferences.executeOnce(Preferences.Keys.PATCH_TRANSACTION_TYPES_NAMES, context) { Preferences.executeOnce(Preferences.Keys.PATCH_TRANSACTION_TYPES_NAMES, context) {
patchDefaultTransactionTypes(context) patchDefaultTransactionTypes(context)
} }
Preferences.executeOnce(Preferences.Keys.PATCH_BLINDS_FORMAT, context) { Preferences.executeOnce(Preferences.Keys.PATCH_STAKES, context) {
patchBlindFormat() patchStakes()
} }
Preferences.executeOnce(Preferences.Keys.PATCH_NEGATIVE_LIMITS, context) { Preferences.executeOnce(Preferences.Keys.PATCH_NEGATIVE_LIMITS, context) {
patchNegativeLimits() patchNegativeLimits()
@ -98,7 +101,8 @@ class Patcher {
it.computeStats() it.computeStats()
} }
sessions.forEach { sessions.forEach {
it.formatBlinds() it.generateStakes()
it.defineHighestBet()
} }
results.forEach { results.forEach {
it.computeNumberOfRebuy() it.computeNumberOfRebuy()
@ -123,13 +127,28 @@ class Patcher {
realm.close() realm.close()
} }
private fun patchBlindFormat() { private fun patchStakes() {
val realm = Realm.getDefaultInstance() val realm = Realm.getDefaultInstance()
realm.executeTransaction { realm.executeTransaction {
val sessions = realm.where(Session::class.java).findAll() val sessions = realm.where(Session::class.java).findAll()
sessions.forEach { session -> sessions.forEach { session ->
session.formatBlinds() val blinds = arrayListOf(session.cgOldSmallBlind, session.cgOldBigBlind).filterNotNull()
val blindsFormatted = blinds.map { NumberFormat.getInstance().format(it) }
session.cgAnte = null
if (blindsFormatted.isNotEmpty()) {
session.cgBlinds = blindsFormatted.joinToString(BLIND_SEPARATOR)
}
} }
val handHistories = realm.where(HandHistory::class.java).findAll()
handHistories.forEach { hh ->
val blinds = arrayListOf(hh.oldSmallBlind, hh.oldBigBlind).filterNotNull()
val blindsFormatted = blinds.map { NumberFormat.getInstance().format(it) }
if (blindsFormatted.isNotEmpty()) {
hh.blinds = blindsFormatted.joinToString(BLIND_SEPARATOR)
}
}
} }
realm.close() realm.close()
} }

@ -252,6 +252,36 @@ class PokerAnalyticsMigration : RealmMigration {
currentVersion++ currentVersion++
} }
// Migrate to version 12
if (currentVersion == 11) {
schema.get("Session")?.let { ss ->
ss.addField("cgAnte", Double::class.java)
?.setNullable("cgAnte", true)
ss.addField("cgBiggestBet", Double::class.java)
?.setNullable("cgBiggestBet", true)
ss.addField("cgStakes", String::class.java)
ss.addField("cgBlinds", String::class.java)
ss.removeField("blinds")
ss.renameField("cgSmallBlind", "cgOldSmallBlind")
ss.renameField("cgBigBlind", "cgOldBigBlind")
}
schema.get("HandHistory")?.let { hs ->
hs.setNullable("ante", true)
hs.addField("stakes", String::class.java)
hs.addField("blinds", String::class.java)
hs.addField("biggestBet", Double::class.java)
?.setNullable("biggestBet", true)
hs.renameField("smallBlind", "oldSmallBlind")
hs.renameField("bigBlind", "oldBigBlind")
}
currentVersion++
}
} }
override fun equals(other: Any?): Boolean { override fun equals(other: Any?): Boolean {

@ -36,7 +36,7 @@ open class ComputableResult : RealmObject(), Filterable {
} }
this.bbNet = session.bbNet this.bbNet = session.bbNet
this.hasBigBlind = if (session.cgBigBlind != null) 1 else 0 this.hasBigBlind = if (session.cgBiggestBet != null) 1 else 0
this.estimatedHands = session.estimatedHands this.estimatedHands = session.estimatedHands
this.bbPer100Hands = this.bbPer100Hands =
session.bbNet / (session.numberOfHandsPerHour * session.hourlyDuration) * 100 session.bbNet / (session.numberOfHandsPerHour * session.hourlyDuration) * 100

@ -150,7 +150,7 @@ open class Result : RealmObject(), Filterable {
fun computeNumberOfRebuy() { fun computeNumberOfRebuy() {
this.session?.let { this.session?.let {
if (it.isCashGame()) { if (it.isCashGame()) {
it.cgBigBlind?.let { bb -> it.cgBiggestBet?.let { bb ->
if (bb > 0.0) { if (bb > 0.0) {
this.numberOfRebuy = (this.buyin ?: 0.0) / (bb * 100.0) this.numberOfRebuy = (this.buyin ?: 0.0) / (bb * 100.0)
} else { } else {

@ -16,6 +16,7 @@ import net.pokeranalytics.android.calculus.StatFormattingException
import net.pokeranalytics.android.exceptions.ModelException import net.pokeranalytics.android.exceptions.ModelException
import net.pokeranalytics.android.exceptions.PAIllegalStateException import net.pokeranalytics.android.exceptions.PAIllegalStateException
import net.pokeranalytics.android.model.Limit import net.pokeranalytics.android.model.Limit
import net.pokeranalytics.android.model.Stakes
import net.pokeranalytics.android.model.TableSize 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
@ -26,24 +27,26 @@ import net.pokeranalytics.android.model.filter.QueryCondition
import net.pokeranalytics.android.model.filter.QueryCondition.* import net.pokeranalytics.android.model.filter.QueryCondition.*
import net.pokeranalytics.android.model.interfaces.* import net.pokeranalytics.android.model.interfaces.*
import net.pokeranalytics.android.model.realm.handhistory.HandHistory import net.pokeranalytics.android.model.realm.handhistory.HandHistory
import net.pokeranalytics.android.util.CrashLogging
import net.pokeranalytics.android.model.utils.SessionSetManager import net.pokeranalytics.android.model.utils.SessionSetManager
import net.pokeranalytics.android.ui.adapter.UnmanagedRowRepresentableException import net.pokeranalytics.android.ui.adapter.UnmanagedRowRepresentableException
import net.pokeranalytics.android.ui.graph.Graph import net.pokeranalytics.android.ui.graph.Graph
import net.pokeranalytics.android.ui.view.* import net.pokeranalytics.android.ui.view.*
import net.pokeranalytics.android.ui.view.rows.SessionPropertiesRow import net.pokeranalytics.android.ui.view.rows.SessionPropertiesRow
import net.pokeranalytics.android.util.NULL_TEXT import net.pokeranalytics.android.util.*
import net.pokeranalytics.android.util.TextFormat import net.pokeranalytics.android.util.extensions.hourMinute
import net.pokeranalytics.android.util.UserDefaults import net.pokeranalytics.android.util.extensions.shortDateTime
import net.pokeranalytics.android.util.extensions.* import net.pokeranalytics.android.util.extensions.toCurrency
import net.pokeranalytics.android.util.extensions.toMinutes
import java.text.DateFormat import java.text.DateFormat
import java.text.NumberFormat
import java.text.ParseException
import java.util.* import java.util.*
import java.util.Currency import java.util.Currency
typealias BB = Double typealias BB = Double
open class Session : RealmObject(), Savable, RowUpdatable, RowRepresentable, Timed, open class Session : RealmObject(), Savable, RowUpdatable, RowRepresentable, Timed,
TimeFilterable, Filterable, DatedBankrollGraphEntry { TimeFilterable, Filterable, DatedBankrollGraphEntry, StakesHolder {
enum class Type(val value: String) { enum class Type(val value: String) {
CASH_GAME("Cash Game"), CASH_GAME("Cash Game"),
@ -96,7 +99,7 @@ open class Session : RealmObject(), Savable, RowUpdatable, RowRepresentable, Tim
AnyLimit::class.java -> "limit" AnyLimit::class.java -> "limit"
AnyTableSize::class.java -> "tableSize" AnyTableSize::class.java -> "tableSize"
AnyTournamentType::class.java -> "tournamentType" AnyTournamentType::class.java -> "tournamentType"
AnyBlind::class.java -> "blinds" AnyStake::class.java -> "cgStakes"
NumberOfTable::class.java -> "numberOfTables" NumberOfTable::class.java -> "numberOfTables"
NetAmountWon::class.java, NetAmountLost::class.java -> "computableResults.ratedNet" NetAmountWon::class.java, NetAmountLost::class.java -> "computableResults.ratedNet"
NumberOfRebuy::class.java -> "result.numberOfRebuy" NumberOfRebuy::class.java -> "result.numberOfRebuy"
@ -118,7 +121,7 @@ open class Session : RealmObject(), Savable, RowUpdatable, RowRepresentable, Tim
CustomFieldQuery::class.java -> "customFieldEntries.customFields.id" CustomFieldQuery::class.java -> "customFieldEntries.customFields.id"
DateNotNull::class.java -> "startDate" DateNotNull::class.java -> "startDate"
EndDateNotNull::class.java -> "endDate" EndDateNotNull::class.java -> "endDate"
BigBlindNotNull::class.java -> "cgBigBlind" BiggestBetNotNull::class.java -> "cgBiggestBet"
else -> null else -> null
} }
} }
@ -264,7 +267,7 @@ open class Session : RealmObject(), Savable, RowUpdatable, RowRepresentable, Tim
override var bankroll: Bankroll? = null override var bankroll: Bankroll? = null
set(value) { set(value) {
field = value field = value
this.formatBlinds() this.generateStakes()
this.computeStats() this.computeStats()
// this.updateRowRepresentation() // this.updateRowRepresentation()
} }
@ -290,6 +293,10 @@ open class Session : RealmObject(), Savable, RowUpdatable, RowRepresentable, Tim
// The number of tables played at the same time // The number of tables played at the same time
var numberOfTables: Int = 1 var numberOfTables: Int = 1
set(value) {
field = value
this.computeStats()
}
// The hand histories of the session // The hand histories of the session
@LinkingObjects("session") @LinkingObjects("session")
@ -304,23 +311,43 @@ open class Session : RealmObject(), Savable, RowUpdatable, RowRepresentable, Tim
// Cash Game // Cash Game
// The small blind value // The small blind value
var cgSmallBlind: Double? = null var cgOldSmallBlind: Double? = null
set(value) { set(value) {
field = value field = value
formatBlinds()
} }
// The big blind value // The big blind value
var cgBigBlind: Double? = null var cgOldBigBlind: Double? = null
set(value) {
field = value
this.computeStats()
this.result?.computeNumberOfRebuy()
}
// var blinds: String? = null
// private set
var cgAnte: Double? = null
set(value) { set(value) {
field = value field = value
this.generateStakes()
this.defineHighestBet()
this.computeStats()
this.result?.computeNumberOfRebuy()
}
var cgBlinds: String? = null
set(value) {
field = cleanupBlinds(value)
this.generateStakes()
this.defineHighestBet()
this.computeStats() this.computeStats()
formatBlinds()
this.result?.computeNumberOfRebuy() this.result?.computeNumberOfRebuy()
} }
var blinds: String? = null var cgBiggestBet: Double? = null
private set
var cgStakes: String? = null
// Tournament // Tournament
@ -354,7 +381,7 @@ open class Session : RealmObject(), Savable, RowUpdatable, RowRepresentable, Tim
} }
fun bankrollHasBeenUpdated() { fun bankrollHasBeenUpdated() {
formatBlinds() this.generateStakes()
} }
/** /**
@ -405,7 +432,7 @@ open class Session : RealmObject(), Savable, RowUpdatable, RowRepresentable, Tim
*/ */
val bbNet: BB val bbNet: BB
get() { get() {
val bb = this.cgBigBlind val bb = this.cgBiggestBet
val result = this.result val result = this.result
return if (bb != null && result != null) { return if (bb != null && result != null) {
result.net / bb result.net / bb
@ -474,7 +501,7 @@ open class Session : RealmObject(), Savable, RowUpdatable, RowRepresentable, Tim
val tableSize = this.tableSize ?: 9 // 9 is the default table size if null val tableSize = this.tableSize ?: 9 // 9 is the default table size if null
val config = UserConfig.getConfiguration(this.realm) val config = UserConfig.getConfiguration(this.realm)
val playerHandsPerHour = if (this.isLive) config.liveDealtHandsPerHour else config.onlineDealtHandsPerHour val playerHandsPerHour = if (this.isLive) config.liveDealtHandsPerHour else config.onlineDealtHandsPerHour
return playerHandsPerHour / tableSize.toDouble() return this.numberOfTables * playerHandsPerHour / tableSize.toDouble()
} }
val hourlyRate: Double val hourlyRate: Double
@ -646,23 +673,42 @@ open class Session : RealmObject(), Savable, RowUpdatable, RowRepresentable, Tim
return if (gameTitle.isNotBlank()) gameTitle else NULL_TEXT return if (gameTitle.isNotBlank()) gameTitle else NULL_TEXT
} }
fun getFormattedBlinds(): String { fun getFormattedStakes(): String {
return blinds ?: NULL_TEXT
return this.cgStakes?.let { StakesHolder.readableStakes(it) } ?: run { NULL_TEXT }
//
// val formattedBlinds = StakesHolder.formattedBlinds(this.cgBlinds, this.currency)
// val formattedAntes = StakesHolder.formattedAnte(this.cgAnte, this.currency)
//
// return StakesHolder.formattedStakes(formattedBlinds, formattedAntes)
//
//
// val components = arrayListOf<String>()
// this.formattedBlinds?.let { components.add(it) }
// this.formattedAnte?.let { components.add("($it)") }
//
// return if (components.isNotEmpty()) {
// components.joinToString(" ")
// } else {
// NULL_TEXT
// }
} }
fun formatBlinds() { // fun formatBlinds() {
blinds = null // blinds = null
if (cgBigBlind == null) return // if (cgBigBlind == null) return
cgBigBlind?.let { bb -> // cgBigBlind?.let { bb ->
val sb = cgSmallBlind ?: bb / 2.0 // val sb = cgSmallBlind ?: bb / 2.0
val preFormattedBlinds = "${sb.formatted}/${bb.round()}" // val preFormattedBlinds = "${sb.formatted}/${bb.round()}"
println("<<<<<< bb.toCurrency(currency) : ${bb.toCurrency(currency)}") // println("<<<<<< bb.toCurrency(currency) : ${bb.toCurrency(currency)}")
println("<<<<<< preFormattedBlinds : $preFormattedBlinds") // println("<<<<<< preFormattedBlinds : $preFormattedBlinds")
val regex = Regex("-?\\d+(\\.\\d+)?") // val regex = Regex("-?\\d+(\\.\\d+)?")
blinds = bb.toCurrency(currency).replace(regex, preFormattedBlinds) // blinds = bb.toCurrency(currency).replace(regex, preFormattedBlinds)
println("<<<<<< blinds = $blinds") // println("<<<<<< blinds = $blinds")
} // }
} // }
// LifeCycle // LifeCycle
@ -703,8 +749,8 @@ open class Session : RealmObject(), Savable, RowUpdatable, RowRepresentable, Tim
copy.game = this.game copy.game = this.game
copy.limit = this.limit copy.limit = this.limit
copy.cgSmallBlind = this.cgSmallBlind copy.cgBiggestBet = this.cgBiggestBet
copy.cgBigBlind = this.cgBigBlind copy.cgAnte = this.cgAnte
copy.tournamentEntryFee = this.tournamentEntryFee copy.tournamentEntryFee = this.tournamentEntryFee
copy.tournamentFeatures = this.tournamentFeatures copy.tournamentFeatures = this.tournamentFeatures
copy.tournamentName = this.tournamentName copy.tournamentName = this.tournamentName
@ -726,27 +772,36 @@ open class Session : RealmObject(), Savable, RowUpdatable, RowRepresentable, Tim
when (row) { when (row) {
SessionPropertiesRow.BANKROLL -> bankroll = value as Bankroll? SessionPropertiesRow.BANKROLL -> bankroll = value as Bankroll?
SessionPropertiesRow.BLINDS -> if (value is ArrayList<*>) { SessionPropertiesRow.STAKES -> if (value is Stakes) {
cgSmallBlind = try {
(value[0] as String? ?: "0").toDouble()
} catch (e: Exception) {
null
}
cgBigBlind = try { if (value.ante != null) {
(value[1] as String? ?: "0").toDouble() this.cgAnte = value.ante
} catch (e: Exception) {
null
} }
cgBigBlind?.let { if (value.blinds != null) {
if (cgSmallBlind == null || cgSmallBlind == 0.0) { this.cgBlinds = value.blinds
cgSmallBlind = it / 2.0
}
} }
// cgSmallBlind = try {
// (value[0] as String? ?: "0").toDouble()
// } catch (e: Exception) {
// null
// }
//
// cgBigBlind = try {
// (value[1] as String? ?: "0").toDouble()
// } catch (e: Exception) {
// null
// }
//
// cgBigBlind?.let {
// if (cgSmallBlind == null || cgSmallBlind == 0.0) {
// cgSmallBlind = it / 2.0
// }
// }
} else if (value == null) { } else if (value == null) {
cgSmallBlind = null this.cgBlinds = null
cgBigBlind = null this.cgAnte = null
} }
SessionPropertiesRow.BREAK_TIME -> { SessionPropertiesRow.BREAK_TIME -> {
this.breakDuration = (value as Double? ?: 0.0).toLong() * 60 * 1000 this.breakDuration = (value as Double? ?: 0.0).toLong() * 60 * 1000
@ -827,6 +882,7 @@ open class Session : RealmObject(), Savable, RowUpdatable, RowRepresentable, Tim
} }
} }
SessionPropertiesRow.HANDS_COUNT -> handsCount = (value as Double?)?.toInt() SessionPropertiesRow.HANDS_COUNT -> handsCount = (value as Double?)?.toInt()
SessionPropertiesRow.NUMBER_OF_TABLES -> this.numberOfTables = (value as Double?)?.toInt() ?: 1
is CustomField -> { is CustomField -> {
customFieldEntries.filter { it.customField?.id == row.id }.let { customFieldEntries.filter { it.customField?.id == row.id }.let {
customFieldEntries.removeAll(it) customFieldEntries.removeAll(it)
@ -964,7 +1020,7 @@ open class Session : RealmObject(), Savable, RowUpdatable, RowRepresentable, Tim
return when (row) { return when (row) {
SessionPropertiesRow.BANKROLL -> bankroll?.name ?: NULL_TEXT SessionPropertiesRow.BANKROLL -> bankroll?.name ?: NULL_TEXT
SessionPropertiesRow.BLINDS -> getFormattedBlinds() SessionPropertiesRow.STAKES -> getFormattedStakes()
SessionPropertiesRow.BREAK_TIME -> if (this.breakDuration > 0.0) this.breakDuration.toMinutes() else NULL_TEXT SessionPropertiesRow.BREAK_TIME -> if (this.breakDuration > 0.0) this.breakDuration.toMinutes() else NULL_TEXT
SessionPropertiesRow.BUY_IN -> this.result?.buyin?.toCurrency(currency) ?: NULL_TEXT SessionPropertiesRow.BUY_IN -> this.result?.buyin?.toCurrency(currency) ?: NULL_TEXT
SessionPropertiesRow.CASHED_OUT, SessionPropertiesRow.PRIZE -> this.result?.cashout?.toCurrency(currency) ?: NULL_TEXT SessionPropertiesRow.CASHED_OUT, SessionPropertiesRow.PRIZE -> this.result?.cashout?.toCurrency(currency) ?: NULL_TEXT
@ -1002,6 +1058,7 @@ open class Session : RealmObject(), Savable, RowUpdatable, RowRepresentable, Tim
SessionPropertiesRow.TOURNAMENT_NAME -> tournamentName?.name ?: NULL_TEXT SessionPropertiesRow.TOURNAMENT_NAME -> tournamentName?.name ?: NULL_TEXT
SessionPropertiesRow.HANDS -> this.handHistories?.size.toString() SessionPropertiesRow.HANDS -> this.handHistories?.size.toString()
SessionPropertiesRow.HANDS_COUNT -> this.handsCountFormatted(context) SessionPropertiesRow.HANDS_COUNT -> this.handsCountFormatted(context)
SessionPropertiesRow.NUMBER_OF_TABLES -> this.numberOfTables.toString()
is CustomField -> { is CustomField -> {
customFieldEntries.find { it.customField?.id == row.id }?.let { customFieldEntry -> customFieldEntries.find { it.customField?.id == row.id }?.let { customFieldEntry ->
return customFieldEntry.getFormattedValue(currency) return customFieldEntry.getFormattedValue(currency)
@ -1026,4 +1083,73 @@ open class Session : RealmObject(), Savable, RowUpdatable, RowRepresentable, Tim
this.result?.netResult = null this.result?.netResult = null
} }
/// Stakes
// fun generateStakes() {
//
// if (this.cgAnte == null && this.cgAnte == null) {
// this.cgStakes = null
// return
// }
//
// val components = arrayListOf<String>()
//
// this.cgBlinds?.let { components.add("${cbBlinds}${it}") }
// this.cgAnte?.let { components.add("${cbAnte}${it.formatted}") }
//
// val code = this.bankroll?.currency?.code ?: UserDefaults.currency.currencyCode
// components.add("${cbCode}${code}")
//
// this.cgStakes = components.joinToString(cbSeparator)
// }
//
// fun defineHighestBet() {
// val bets = arrayListOf<Double>()
// this.cgAnte?.let { bets.add(it) }
// bets.addAll(this.blindValues)
// this.cgBiggestBet = bets.maxOrNull()
// }
private fun cleanupBlinds(blinds: String?): String? {
if (blinds == null) {
return null
}
val blindValues = blinds.split(BLIND_SEPARATOR).mapNotNull {
try {
NumberFormat.getInstance().parse(it)
} catch (e: ParseException) {
null
}
}
return if (blindValues.isNotEmpty()) {
blindValues.joinToString(BLIND_SEPARATOR)
} else {
null
}
}
/// StakesHolder
override val ante: Double?
get() { return this.cgAnte }
override val blinds: String?
get() { return this.cgBlinds }
override val biggestBet: Double?
get() { return this.cgBiggestBet }
override val stakes: String?
get() { return this.cgStakes }
override fun setHolderStakes(stakes: String?) {
this.cgStakes = stakes
}
override fun setHolderBiggestBet(biggestBet: Double?) {
this.cgBiggestBet = biggestBet
}
} }

@ -15,10 +15,8 @@ import net.pokeranalytics.android.model.filter.Filterable
import net.pokeranalytics.android.model.handhistory.HandSetup import net.pokeranalytics.android.model.handhistory.HandSetup
import net.pokeranalytics.android.model.handhistory.Position import net.pokeranalytics.android.model.handhistory.Position
import net.pokeranalytics.android.model.handhistory.Street import net.pokeranalytics.android.model.handhistory.Street
import net.pokeranalytics.android.model.interfaces.Deletable import net.pokeranalytics.android.model.interfaces.*
import net.pokeranalytics.android.model.interfaces.DeleteValidityStatus import net.pokeranalytics.android.model.realm.Bankroll
import net.pokeranalytics.android.model.interfaces.Identifiable
import net.pokeranalytics.android.model.interfaces.TimeFilterable
import net.pokeranalytics.android.model.realm.Session import net.pokeranalytics.android.model.realm.Session
import net.pokeranalytics.android.ui.modules.handhistory.evaluator.EvaluatorBridge import net.pokeranalytics.android.ui.modules.handhistory.evaluator.EvaluatorBridge
import net.pokeranalytics.android.ui.modules.handhistory.model.ActionReadRow import net.pokeranalytics.android.ui.modules.handhistory.model.ActionReadRow
@ -35,7 +33,7 @@ import kotlin.math.max
data class PositionAmount(var position: Int, var amount: Double, var isAllin: Boolean) data class PositionAmount(var position: Int, var amount: Double, var isAllin: Boolean)
open class HandHistory : RealmObject(), Deletable, RowRepresentable, Filterable, TimeFilterable, open class HandHistory : RealmObject(), Deletable, RowRepresentable, Filterable, TimeFilterable,
CardHolder, Comparator<PositionAmount> { CardHolder, Comparator<PositionAmount>, StakesHolder {
@PrimaryKey @PrimaryKey
override var id = UUID.randomUUID().toString() override var id = UUID.randomUUID().toString()
@ -64,34 +62,67 @@ open class HandHistory : RealmObject(), Deletable, RowRepresentable, Filterable,
/*** /***
* The small blind * The small blind
*/ */
var smallBlind: Double? = null var oldSmallBlind: Double? = null
set(value) { set(value) {
field = value field = value
if (this.bigBlind == null && value != null) { // if (this.bigBlind == null && value != null) {
this.bigBlind = value * 2 // this.bigBlind = value * 2
} // }
} }
/*** /***
* The big blind * The big blind
*/ */
var bigBlind: Double? = null var oldBigBlind: Double? = null
set(value) { set(value) {
field = value field = value
if (this.smallBlind == null && value != null) { // if (this.smallBlind == null && value != null) {
this.smallBlind = value / 2 // this.smallBlind = value / 2
} // }
} }
/***
* Big blind ante
*/
var bigBlindAnte: Boolean = false
/*** /***
* The ante * The ante
*/ */
var ante: Double = 0.0 override var ante: Double? = 0.0
set(value) {
field = value
this.generateStakes()
this.defineHighestBet()
}
/***
* The blinds
*/
override var blinds: String? = null
set(value) {
field = value
this.generateStakes()
this.defineHighestBet()
}
override var biggestBet: Double? = null
/*** /***
* Big blind ante * The coded stakes
*/ */
var bigBlindAnte: Boolean = false override var stakes: String? = null
override val bankroll: Bankroll?
get() { return this.session?.bankroll }
override fun setHolderStakes(stakes: String?) {
this.stakes = stakes
}
override fun setHolderBiggestBet(biggestBet: Double?) {
this.biggestBet = biggestBet
}
/*** /***
* Number of players in the hand * Number of players in the hand
@ -164,8 +195,8 @@ open class HandHistory : RealmObject(), Deletable, RowRepresentable, Filterable,
this.playerSetups.removeAll(this.playerSetups) this.playerSetups.removeAll(this.playerSetups)
handSetup.tableSize?.let { this.numberOfPlayers = it } handSetup.tableSize?.let { this.numberOfPlayers = it }
handSetup.smallBlind?.let { this.smallBlind = it } handSetup.ante?.let { this.ante = it }
handSetup.bigBlind?.let { this.bigBlind = it } handSetup.blinds?.let { this.blinds = it }
this.session = handSetup.session this.session = handSetup.session
this.date = this.session?.handHistoryAutomaticDate ?: Date() this.date = this.session?.handHistoryAutomaticDate ?: Date()
@ -180,18 +211,32 @@ open class HandHistory : RealmObject(), Deletable, RowRepresentable, Filterable,
this.actions.clear() this.actions.clear()
this.addAction(0, Action.Type.POST_SB, this.smallBlind) var blindValues = this.blindValues
this.addAction(1, Action.Type.POST_BB, this.bigBlind) if (blindValues.isNotEmpty()) {
blindValues.forEachIndexed { index, blind ->
// var lastStraddler: Int? = null val action = when(index) {
0 -> Action.Type.POST_SB
1 -> Action.Type.POST_BB
else -> null
}
action?.let { this.addAction(index, action, blind) }
}
} else {
this.addAction(0, Action.Type.POST_SB, this.oldSmallBlind)
this.addAction(1, Action.Type.POST_BB, this.oldBigBlind)
}
blindValues = blindValues.drop(2)
val positions = Position.positionsPerPlayers(this.numberOfPlayers) val positions = Position.positionsPerPlayers(this.numberOfPlayers)
handSetup.straddlePositions.forEach { position -> // position are sorted here handSetup.straddlePositions.forEachIndexed { index, position -> // position are sorted here
val positionIndex = positions.indexOf(position) val positionIndex = positions.indexOf(position)
this.addAction(positionIndex, Action.Type.STRADDLE) val amount = if (index < blindValues.size) { blindValues[index] } else null
// lastStraddler = positionIndex this.addAction(positionIndex, Action.Type.STRADDLE, amount)
} }
// var lastStraddler: Int? = null
// val totalActions = this.actions.size // val totalActions = this.actions.size
// val startingPosition = lastStraddler?.let { it + 1 } ?: totalActions // val startingPosition = lastStraddler?.let { it + 1 } ?: totalActions
@ -237,9 +282,9 @@ open class HandHistory : RealmObject(), Deletable, RowRepresentable, Filterable,
val anteSum: Double val anteSum: Double
get() { get() {
return if (bigBlindAnte) { return if (bigBlindAnte) {
this.bigBlind ?: 0.0 this.biggestBet ?: 0.0
} else { } else {
this.ante * this.numberOfPlayers (this.ante ?: 0.0) * this.numberOfPlayers
} }
} }
@ -303,14 +348,20 @@ open class HandHistory : RealmObject(), Deletable, RowRepresentable, Filterable,
val players = "${this.numberOfPlayers} ${context.getString(R.string.players)}" val players = "${this.numberOfPlayers} ${context.getString(R.string.players)}"
val firstLineComponents = mutableListOf(this.date.fullDate(), players) val firstLineComponents = mutableListOf(this.date.fullDate(), players)
this.smallBlind?.let { sb -> this.blinds?.let { firstLineComponents.add(it) }
this.bigBlind?.let { bb ->
firstLineComponents.add("${sb.formatted}/${bb.formatted}") // this.smallBlind?.let { sb ->
// this.bigBlind?.let { bb ->
// firstLineComponents.add("${sb.formatted}/${bb.formatted}")
// }
// }
this.ante?.let {
if (it > 0.0) {
firstLineComponents.add("ante ${this.ante}")
} }
} }
if (this.ante > 0.0) {
firstLineComponents.add("ante ${this.ante}")
}
string = string.plus(firstLineComponents.joinToString(" - ")) string = string.plus(firstLineComponents.joinToString(" - "))
string = string.addLineReturn(2) string = string.addLineReturn(2)
@ -373,12 +424,12 @@ open class HandHistory : RealmObject(), Deletable, RowRepresentable, Filterable,
fun anteForPosition(position: Position): Double { fun anteForPosition(position: Position): Double {
return if (this.bigBlindAnte) { return if (this.bigBlindAnte) {
if (position == Position.BB) { if (position == Position.BB) {
this.bigBlind ?: 0.0 this.biggestBet ?: 0.0
} else { } else {
0.0 0.0
} }
} else { } else {
this.ante this.ante ?: 0.0
} }
} }
@ -394,7 +445,11 @@ open class HandHistory : RealmObject(), Deletable, RowRepresentable, Filterable,
val heroString = context.getString(R.string.hero) val heroString = context.getString(R.string.hero)
playerItems.add("- $heroString") playerItems.add("- $heroString")
} }
playerItems.add("[${playerSetup.cards.formatted(context)}]")
if (playerSetup.cards.isNotEmpty()) {
playerItems.add("[${playerSetup.cards.formatted(context)}]")
}
playerSetup.stack?.let { stack -> playerSetup.stack?.let { stack ->
playerItems.add("- $stack") playerItems.add("- $stack")
} }

@ -11,15 +11,18 @@ class DataUtils {
companion object { companion object {
/** /**
* Returns true if the provided parameters doesn't correspond to an existing session * Returns the number of sessions corresponding to the provided parameters
*/ */
fun sessionCount(realm: Realm, startDate: Date, endDate: Date, net: Double): Int { fun sessionCount(realm: Realm, startDate: Date, endDate: Date?, net: Double): Int {
val sessions = realm.where(Session::class.java) var sessionQuery = realm.where(Session::class.java)
.equalTo("startDate", startDate) .equalTo("startDate", startDate)
.equalTo("endDate", endDate)
.equalTo("result.net", net) .equalTo("result.net", net)
.findAll()
return sessions.size endDate?.let {
sessionQuery = sessionQuery.equalTo("endDate", it)
}
return sessionQuery.findAll().size
} }
/** /**

@ -39,7 +39,7 @@ private fun Session.significantFields(): List<SessionPropertiesRow> {
Session.Type.CASH_GAME.ordinal -> { Session.Type.CASH_GAME.ordinal -> {
return listOf( return listOf(
SessionPropertiesRow.GAME, SessionPropertiesRow.GAME,
SessionPropertiesRow.BLINDS, SessionPropertiesRow.STAKES,
SessionPropertiesRow.BANKROLL, SessionPropertiesRow.BANKROLL,
SessionPropertiesRow.TABLE_SIZE SessionPropertiesRow.TABLE_SIZE
) )
@ -86,8 +86,8 @@ class FavoriteSessionFinder {
when (session.type) { when (session.type) {
Session.Type.CASH_GAME.ordinal -> { Session.Type.CASH_GAME.ordinal -> {
session.cgSmallBlind = fav.cgSmallBlind session.cgAnte = fav.cgAnte
session.cgBigBlind = fav.cgBigBlind session.cgBlinds = fav.cgBlinds
} }
Session.Type.TOURNAMENT.ordinal -> { Session.Type.TOURNAMENT.ordinal -> {
session.tournamentEntryFee = fav.tournamentEntryFee session.tournamentEntryFee = fav.tournamentEntryFee

@ -31,7 +31,9 @@ class ImportFragment : RealmFragment(), ImportDelegate {
private var _binding: FragmentImportBinding? = null private var _binding: FragmentImportBinding? = null
private val binding get() = _binding!! private val binding get() = _binding!!
// Life Cycle private val exceptions: MutableList<Exception> = mutableListOf()
// Life Cycle
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
super.onCreateView(inflater, container, savedInstanceState) super.onCreateView(inflater, container, savedInstanceState)
@ -44,7 +46,6 @@ class ImportFragment : RealmFragment(), ImportDelegate {
_binding = null _binding = null
} }
fun setData(path: String) { fun setData(path: String) {
this.filePath = path this.filePath = path
} }
@ -90,7 +91,6 @@ class ImportFragment : RealmFragment(), ImportDelegate {
this.importer = CSVImporter(inputStream) this.importer = CSVImporter(inputStream)
this.importer.delegate = this this.importer.delegate = this
var exception: Exception? = null
GlobalScope.launch(coroutineContext) { GlobalScope.launch(coroutineContext) {
@ -98,11 +98,8 @@ class ImportFragment : RealmFragment(), ImportDelegate {
val s = Date() val s = Date()
Timber.d(">>> Start Import...") Timber.d(">>> Start Import...")
try { importer.start()
importer.start()
} catch (e: Exception) {
exception = e
}
val e = Date() val e = Date()
val duration = (e.time - s.time) / 1000.0 val duration = (e.time - s.time) / 1000.0
Timber.d(">>> Import ended in $duration seconds") Timber.d(">>> Import ended in $duration seconds")
@ -110,9 +107,9 @@ class ImportFragment : RealmFragment(), ImportDelegate {
} }
test.await() test.await()
val exceptionMessage = exception?.message val exceptionMessage = exceptions.firstOrNull()?.message
if (exceptionMessage != null && view != null) { if (exceptionMessage != null && view != null) {
val message = exceptionMessage + ". " + requireContext().getString(R.string.import_error) val message = "${exceptions.size} " + requireContext().getString(R.string.errors) + ":\n" + exceptionMessage + ".\n" + requireContext().getString(R.string.import_error)
val snackBar = Snackbar.make(view!!, message, Snackbar.LENGTH_INDEFINITE) val snackBar = Snackbar.make(view!!, message, Snackbar.LENGTH_INDEFINITE)
snackBar.setAction(R.string.ok) { snackBar.setAction(R.string.ok) {
snackBar.dismiss() snackBar.dismiss()
@ -160,4 +157,8 @@ class ImportFragment : RealmFragment(), ImportDelegate {
binding.totalCounter.text = this.numberFormatter.format(totalCount) binding.totalCounter.text = this.numberFormatter.format(totalCount)
} }
override fun exceptionCaught(e: Exception) {
this.exceptions.add(e)
}
} }

@ -292,7 +292,7 @@ class SettingsFragment : RealmFragment(), RowRepresentableDelegate, StaticRowRep
private fun sessionsCSVExport() { private fun sessionsCSVExport() {
val sessions = getRealm().where(Session::class.java).findAll().sort("startDate") val sessions = getRealm().where(Session::class.java).findAll().sort("startDate")
val csv = ProductCSVDescriptors.pokerAnalyticsAndroid.toCSV(sessions) val csv = ProductCSVDescriptors.pokerAnalyticsAndroidSessions.toCSV(sessions)
this.shareCSV(csv, "Sessions") this.shareCSV(csv, "Sessions")
} }

@ -12,12 +12,12 @@ import net.pokeranalytics.android.exceptions.RowRepresentableEditDescriptorExcep
import net.pokeranalytics.android.util.extensions.round import net.pokeranalytics.android.util.extensions.round
class BottomSheetDoubleEditTextFragment : BottomSheetFragment() { open class BottomSheetDoubleEditTextFragment : BottomSheetFragment() {
private var _binding: BottomSheetDoubleEditTextBinding? = null private var _binding: BottomSheetDoubleEditTextBinding? = null
private val binding get() = _binding!! private val binding get() = _binding!!
override fun inflateContentView(inflater: LayoutInflater, container: ViewGroup): View? { override fun inflateContentView(inflater: LayoutInflater, container: ViewGroup): View {
_binding = BottomSheetDoubleEditTextBinding.inflate(inflater, container, true) _binding = BottomSheetDoubleEditTextBinding.inflate(inflater, container, true)
return binding.root return binding.root
} }

@ -16,7 +16,7 @@ class BottomSheetEditTextFragment : BottomSheetFragment() {
private var _binding: BottomSheetEditTextBinding? = null private var _binding: BottomSheetEditTextBinding? = null
private val binding get() = _binding!! private val binding get() = _binding!!
override fun inflateContentView(inflater: LayoutInflater, container: ViewGroup): View? { override fun inflateContentView(inflater: LayoutInflater, container: ViewGroup): View {
_binding = BottomSheetEditTextBinding.inflate(inflater, container, true) _binding = BottomSheetEditTextBinding.inflate(inflater, container, true)
return binding.root return binding.root
} }

@ -86,6 +86,7 @@ open class BottomSheetFragment : BottomSheetDialogFragment() {
BottomSheetType.DOUBLE_EDIT_TEXT -> BottomSheetDoubleEditTextFragment() BottomSheetType.DOUBLE_EDIT_TEXT -> BottomSheetDoubleEditTextFragment()
BottomSheetType.NUMERIC_TEXT -> BottomSheetNumericTextFragment() BottomSheetType.NUMERIC_TEXT -> BottomSheetNumericTextFragment()
BottomSheetType.SUM -> BottomSheetSumFragment() BottomSheetType.SUM -> BottomSheetSumFragment()
BottomSheetType.CASH_GAME_STAKES -> BottomSheetStakesFragment()
} }
} }

@ -18,7 +18,7 @@ open class BottomSheetListFragment : BottomSheetFragment(), LiveRowRepresentable
private var _binding: BottomSheetListBinding? = null private var _binding: BottomSheetListBinding? = null
private val binding get() = _binding!! private val binding get() = _binding!!
override fun inflateContentView(inflater: LayoutInflater, container: ViewGroup): View? { override fun inflateContentView(inflater: LayoutInflater, container: ViewGroup): View {
_binding = BottomSheetListBinding.inflate(inflater, container, true) _binding = BottomSheetListBinding.inflate(inflater, container, true)
return binding.root return binding.root
} }

@ -22,7 +22,7 @@ class BottomSheetListGameFragment : BottomSheetListFragment() {
private var _binding: BottomSheetGameListBinding? = null private var _binding: BottomSheetGameListBinding? = null
private val binding get() = _binding!! private val binding get() = _binding!!
override fun inflateContentView(inflater: LayoutInflater, container: ViewGroup): View? { override fun inflateContentView(inflater: LayoutInflater, container: ViewGroup): View {
_binding = BottomSheetGameListBinding.inflate(inflater, container, true) _binding = BottomSheetGameListBinding.inflate(inflater, container, true)
return binding.root return binding.root
} }

@ -17,7 +17,7 @@ class BottomSheetNumericTextFragment : BottomSheetFragment() {
private var _binding: BottomSheetEditTextBinding? = null private var _binding: BottomSheetEditTextBinding? = null
private val binding get() = _binding!! private val binding get() = _binding!!
override fun inflateContentView(inflater: LayoutInflater, container: ViewGroup): View? { override fun inflateContentView(inflater: LayoutInflater, container: ViewGroup): View {
_binding = BottomSheetEditTextBinding.inflate(inflater, container, true) _binding = BottomSheetEditTextBinding.inflate(inflater, container, true)
return binding.root return binding.root
} }

@ -0,0 +1,150 @@
package net.pokeranalytics.android.ui.fragment.components.bottomsheet
import android.content.Context
import android.os.Bundle
import android.text.InputType
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.inputmethod.EditorInfo
import android.view.inputmethod.InputMethodManager
import android.widget.EditText
import androidx.core.widget.addTextChangedListener
import kotlinx.android.synthetic.main.view_keyboard_stakes.view.*
import net.pokeranalytics.android.databinding.BottomSheetStakesBinding
import net.pokeranalytics.android.exceptions.RowRepresentableEditDescriptorException
import java.text.NumberFormat
import java.text.ParseException
class BottomSheetStakesFragment : BottomSheetFragment() {
private var _binding: BottomSheetStakesBinding? = null
private val binding get() = _binding!!
override fun inflateContentView(inflater: LayoutInflater, container: ViewGroup): View {
_binding = BottomSheetStakesBinding.inflate(inflater, container, true)
return binding.root
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
initData()
initUI()
}
override fun onStart() {
super.onStart()
}
/**
* Init data
*/
private fun initData() {
// this.viewModel.isEditingBlinds = this.viewModel.row == SessionRow.BLINDS
}
private fun focusEditTextAndHideKeyboard(editText: EditText) {
editText.requestFocus()
editText.onCreateInputConnection(EditorInfo())?.let {
binding.stakesKeyboard.inputConnection = it
}
val mgr: InputMethodManager? =
requireContext().getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager?
mgr?.hideSoftInputFromWindow(editText.windowToken, InputMethodManager.SHOW_FORCED)
}
/**
* Init UI
*/
private fun initUI() {
val data = getDescriptors()?:throw RowRepresentableEditDescriptorException("RowRepresentableEditDescriptor not found")
if (data.size != 2) {
throw RowRepresentableEditDescriptorException("RowRepresentableEditDescriptor inconsistency")
}
// Ante
val anteED = data[0]
anteED.defaultValue?.let {
binding.anteEditText.hint = NumberFormat.getInstance().format(it as Double)
} ?: run {
anteED.hintResId?.let { binding.anteEditText.hint = getString(it) }
}
// binding.anteEditText.inputType = anteED.inputType ?: InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_FLAG_CAP_SENTENCES
// binding.anteKeyboard.toolbar.isVisible = false
// binding.anteKeyboard.visibility = View.GONE
binding.anteEditText.setRawInputType(InputType.TYPE_CLASS_NUMBER)
binding.anteEditText.showSoftInputOnFocus = false
// Blinds
val blindsED = data[1]
blindsED.defaultValue?.let {
binding.blindsEditText.hint = it as? String
} ?: run {
blindsED.hintResId?.let { binding.blindsEditText.hint = getString(it) }
}
binding.blindsEditText.onCreateInputConnection(EditorInfo())?.let {
binding.stakesKeyboard.inputConnection = it
}
binding.blindsEditText.setRawInputType(InputType.TYPE_CLASS_NUMBER)
binding.blindsEditText.showSoftInputOnFocus = false
binding.blindsEditText.setOnTouchListener { _, _ ->
this.focusEditTextAndHideKeyboard(binding.blindsEditText)
// binding.stakesKeyboard.visibility = View.VISIBLE
binding.stakesKeyboard.value_separator.visibility = View.VISIBLE
return@setOnTouchListener true
}
binding.anteEditText.setOnTouchListener { _, _ ->
// binding.anteKeyboard.setInputConnection(binding.anteEditText)
this.focusEditTextAndHideKeyboard(binding.anteEditText)
binding.stakesKeyboard.value_separator.visibility = View.GONE
// binding.stakesKeyboard.visibility = View.VISIBLE
// binding.stakesKeyboard.visibility = View.GONE
return@setOnTouchListener true
}
binding.anteEditText.addTextChangedListener { text ->
text?.let {
val ante = try {
NumberFormat.getInstance().parse(it.toString())
} catch(e: ParseException) {
null
}
this.model.ante = ante?.toDouble()
}
}
binding.blindsEditText.addTextChangedListener {
this.model.secondStringValue = it?.toString()
}
}
}

@ -17,7 +17,7 @@ class BottomSheetStaticListFragment : BottomSheetFragment(), StaticRowRepresenta
private var _binding: BottomSheetListBinding? = null private var _binding: BottomSheetListBinding? = null
private val binding get() = _binding!! private val binding get() = _binding!!
override fun inflateContentView(inflater: LayoutInflater, container: ViewGroup): View? { override fun inflateContentView(inflater: LayoutInflater, container: ViewGroup): View {
_binding = BottomSheetListBinding.inflate(inflater, container, true) _binding = BottomSheetListBinding.inflate(inflater, container, true)
return binding.root return binding.root
} }

@ -19,7 +19,7 @@ class BottomSheetSumFragment : BottomSheetFragment() {
private var _binding: BottomSheetSumBinding? = null private var _binding: BottomSheetSumBinding? = null
private val binding get() = _binding!! private val binding get() = _binding!!
override fun inflateContentView(inflater: LayoutInflater, container: ViewGroup): View? { override fun inflateContentView(inflater: LayoutInflater, container: ViewGroup): View {
_binding = BottomSheetSumBinding.inflate(inflater, container, true) _binding = BottomSheetSumBinding.inflate(inflater, container, true)
return binding.root return binding.root
} }

@ -19,7 +19,7 @@ class BottomSheetTableSizeGridFragment : BottomSheetFragment(), StaticRowReprese
private var _binding: BottomSheetGridBinding? = null private var _binding: BottomSheetGridBinding? = null
private val binding get() = _binding!! private val binding get() = _binding!!
override fun inflateContentView(inflater: LayoutInflater, container: ViewGroup): View? { override fun inflateContentView(inflater: LayoutInflater, container: ViewGroup): View {
_binding = BottomSheetGridBinding.inflate(inflater, container, true) _binding = BottomSheetGridBinding.inflate(inflater, container, true)
return binding.root return binding.root
} }
@ -61,7 +61,7 @@ class BottomSheetTableSizeGridFragment : BottomSheetFragment(), StaticRowReprese
} }
} }
override fun adapterRows(): List<RowRepresentable>? { override fun adapterRows(): List<RowRepresentable> {
return TableSize.all(this.model.alternativeLabels) return TableSize.all(this.model.alternativeLabels)
} }

@ -12,7 +12,8 @@ enum class BottomSheetType {
EDIT_TEXT_MULTI_LINES, EDIT_TEXT_MULTI_LINES,
DOUBLE_EDIT_TEXT, DOUBLE_EDIT_TEXT,
NUMERIC_TEXT, NUMERIC_TEXT,
SUM; SUM,
CASH_GAME_STAKES;
val validationRequired: Boolean val validationRequired: Boolean
get() = when (this) { get() = when (this) {
@ -25,7 +26,7 @@ enum class BottomSheetType {
val addRequired: Boolean val addRequired: Boolean
get() = when (this) { get() = when (this) {
EDIT_TEXT, NUMERIC_TEXT, DOUBLE_EDIT_TEXT, EDIT_TEXT_MULTI_LINES, GRID, LIST_STATIC, SUM -> false EDIT_TEXT, NUMERIC_TEXT, DOUBLE_EDIT_TEXT, EDIT_TEXT_MULTI_LINES, GRID, LIST_STATIC, SUM, CASH_GAME_STAKES -> false
else -> true else -> true
} }
} }

@ -192,7 +192,8 @@ class EditorAdapter(
"Edit Text not found for tag: $tag, class: $this" "Edit Text not found for tag: $tag, class: $this"
) )
// hides soft input view // hides soft input view,
// 22/06/22: does not seem useful as - I believe - manifest activity has android:windowSoftInputMode="stateAlwaysHidden"
editText.setTextIsSelectable(true) editText.setTextIsSelectable(true)
// Enabled // Enabled

@ -536,9 +536,9 @@ class ActionList(var listener: ActionListListener? = null) : ArrayList<ComputedA
*/ */
override fun blindsUpdated(type: Action.Type, amount: Double) { override fun blindsUpdated(type: Action.Type, amount: Double) {
when (type) { when (type) {
Action.Type.POST_SB -> this.handHistory.smallBlind = amount Action.Type.POST_SB -> this.handHistory.oldSmallBlind = amount
Action.Type.POST_BB -> { Action.Type.POST_BB -> {
this.handHistory.bigBlind = amount this.handHistory.oldBigBlind = amount
if (this.handHistory.bigBlindAnte) { if (this.handHistory.bigBlindAnte) {
this.updateBigBlindRemainingStack() this.updateBigBlindRemainingStack()
} }

@ -30,7 +30,6 @@ import net.pokeranalytics.android.util.CrashLogging
import net.pokeranalytics.android.util.extensions.findById import net.pokeranalytics.android.util.extensions.findById
import net.pokeranalytics.android.util.extensions.formatted import net.pokeranalytics.android.util.extensions.formatted
import timber.log.Timber import timber.log.Timber
import java.lang.Exception
import java.text.DecimalFormat import java.text.DecimalFormat
import java.text.ParseException import java.text.ParseException
import kotlin.coroutines.CoroutineContext import kotlin.coroutines.CoroutineContext
@ -63,6 +62,10 @@ class EditorViewModel : ViewModel(), RowRepresentableDataSource, CardCentralizer
* The hand setup * The hand setup
*/ */
private var handSetup: HandSetup = HandSetup() private var handSetup: HandSetup = HandSetup()
set(value) {
field = value
this.straddlePositions.addAll(value.straddlePositions)
}
/*** /***
* Indicates whether the HH is new or not * Indicates whether the HH is new or not
@ -261,8 +264,10 @@ class EditorViewModel : ViewModel(), RowRepresentableDataSource, CardCentralizer
rows.add(CustomizableRowRepresentable(customViewType = HandRowType.HEADER, resId = R.string.settings, value = "")) rows.add(CustomizableRowRepresentable(customViewType = HandRowType.HEADER, resId = R.string.settings, value = ""))
rows.add(HandRowType.PLAYER_NUMBER) rows.add(HandRowType.PLAYER_NUMBER)
if (this.handHistory.ante > 0) { this.handHistory.ante?.let {
rows.add(HandRowType.ANTE) if (it > 0) {
rows.add(HandRowType.ANTE)
}
} }
if (this.handHistory.bigBlindAnte) { if (this.handHistory.bigBlindAnte) {
@ -796,7 +801,7 @@ class EditorViewModel : ViewModel(), RowRepresentableDataSource, CardCentralizer
val string = when (row) { val string = when (row) {
HandRowType.PLAYER_NUMBER -> this.handHistory.numberOfPlayers.toString() HandRowType.PLAYER_NUMBER -> this.handHistory.numberOfPlayers.toString()
HandRowType.COMMENT -> this.handHistory.comment ?: context.getString(R.string.comment) HandRowType.COMMENT -> this.handHistory.comment ?: context.getString(R.string.comment)
HandRowType.ANTE -> this.handHistory.ante.formatted HandRowType.ANTE -> this.handHistory.ante?.formatted
HandRowType.BIG_BLIND_ANTE_READ -> context.getString(R.string.yes) HandRowType.BIG_BLIND_ANTE_READ -> context.getString(R.string.yes)
// HandRowType.HERO_POSITION -> context.getString(R.string.set_hero_position) // HandRowType.HERO_POSITION -> context.getString(R.string.set_hero_position)
// HandRowType.PLAYER_POSITION -> context.getString(R.string.set_position_details) // HandRowType.PLAYER_POSITION -> context.getString(R.string.set_position_details)
@ -901,8 +906,8 @@ class EditorViewModel : ViewModel(), RowRepresentableDataSource, CardCentralizer
fun changeStraddleSelection(positions: LinkedHashSet<Position>) { fun changeStraddleSelection(positions: LinkedHashSet<Position>) {
if (positions.isEmpty()) { if (positions.isEmpty()) {
this.firstStraddlePosition = null this.firstStraddlePosition = null
this.handSetup.clearStraddles() this.handSetup.clearStraddles()
} else { } else {
if (this.firstStraddlePosition == null) { if (this.firstStraddlePosition == null) {

@ -1,9 +1,16 @@
package net.pokeranalytics.android.ui.modules.handhistory.views package net.pokeranalytics.android.ui.modules.handhistory.views
import android.content.Context import android.content.Context
import android.util.AttributeSet
import android.widget.FrameLayout import android.widget.FrameLayout
abstract class AbstractKeyboardView(context: Context) : FrameLayout(context) { abstract class AbstractKeyboardView : FrameLayout {
constructor(context: Context) : super(context)
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr)
var keyboardListener: KeyboardListener? = null var keyboardListener: KeyboardListener? = null
set(value) { set(value) {

@ -1,6 +1,7 @@
package net.pokeranalytics.android.ui.modules.handhistory.views package net.pokeranalytics.android.ui.modules.handhistory.views
import android.content.Context import android.content.Context
import android.util.AttributeSet
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.inputmethod.EditorInfo import android.view.inputmethod.EditorInfo
import android.view.inputmethod.InputConnection import android.view.inputmethod.InputConnection
@ -19,6 +20,7 @@ import net.pokeranalytics.android.ui.view.GridSpacingItemDecoration
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.extensions.noGroupingFormatted import net.pokeranalytics.android.util.extensions.noGroupingFormatted
import timber.log.Timber
import java.text.DecimalFormatSymbols import java.text.DecimalFormatSymbols
class NumericKey : RowRepresentable { class NumericKey : RowRepresentable {
@ -63,9 +65,16 @@ class NumericKey : RowRepresentable {
} }
class KeyboardAmountView(context: Context) : AbstractKeyboardView(context), class KeyboardAmountView : AbstractKeyboardView,
StaticRowRepresentableDataSource, RowRepresentableDelegate { StaticRowRepresentableDataSource, RowRepresentableDelegate {
constructor(context: Context) : super(context)
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr)
/*** /***
* The adapter managing the grid displayed keyboard * The adapter managing the grid displayed keyboard
*/ */
@ -144,16 +153,19 @@ class KeyboardAmountView(context: Context) : AbstractKeyboardView(context),
// Timber.d("edit text = $editText") // Timber.d("edit text = $editText")
this.editText = editText this.setInputConnection(editText)
editText.setText(amount?.noGroupingFormatted) editText.setText(amount?.noGroupingFormatted)
editText.requestFocus() editText.requestFocus()
editText.isEnabled = true // avoid crashes due to input connection null editText.isEnabled = true // avoid crashes due to input connection null
}
fun setInputConnection(editText: EditText) {
this.editText = editText
editText.onCreateInputConnection(EditorInfo())?.let { editText.onCreateInputConnection(EditorInfo())?.let {
this.inputConnection = it this.inputConnection = it
} ?: run { throw PAIllegalStateException("EditText did not return an input Connection") } } ?: throw PAIllegalStateException("EditText did not return an input Connection")
} }
override fun adapterRows(): List<RowRepresentable> { override fun adapterRows(): List<RowRepresentable> {
@ -175,6 +187,8 @@ class KeyboardAmountView(context: Context) : AbstractKeyboardView(context),
val key = row as NumericKey val key = row as NumericKey
Timber.d("this.inputConnection = ${this.inputConnection}")
this.inputConnection?.let { this.inputConnection?.let {
when { when {
@ -190,9 +204,7 @@ class KeyboardAmountView(context: Context) : AbstractKeyboardView(context),
this.keyboardListener?.amountChanged(this.editText.text.toString()) this.keyboardListener?.amountChanged(this.editText.text.toString())
} ?: run { } ?: throw PAIllegalStateException("Requires an input connection to handle key selections")
throw PAIllegalStateException("Requires an input connection to handle key selections")
}
} }

@ -35,8 +35,7 @@ class RowHandHistoryViewHolder(itemView: View) : RecyclerView.ViewHolder(itemVie
val amount = itemView.findViewById<TextView>(R.id.amount) val amount = itemView.findViewById<TextView>(R.id.amount)
amount.text = handHistory.potSizeForStreet(Street.SUMMARY).formatted amount.text = handHistory.potSizeForStreet(Street.SUMMARY).formatted
val heroWins = handHistory.heroWins val colorId = when(handHistory.heroWins) {
val colorId = when(heroWins) {
true -> R.color.green true -> R.color.green
false -> R.color.red false -> R.color.red
else -> R.color.kaki_light else -> R.color.kaki_light

@ -26,7 +26,6 @@ import net.pokeranalytics.android.model.extensions.getState
import net.pokeranalytics.android.model.extensions.scheduleStopNotification import net.pokeranalytics.android.model.extensions.scheduleStopNotification
import net.pokeranalytics.android.model.interfaces.SaveValidityStatus import net.pokeranalytics.android.model.interfaces.SaveValidityStatus
import net.pokeranalytics.android.model.realm.* import net.pokeranalytics.android.model.realm.*
import net.pokeranalytics.android.util.CrashLogging
import net.pokeranalytics.android.model.utils.FavoriteSessionFinder import net.pokeranalytics.android.model.utils.FavoriteSessionFinder
import net.pokeranalytics.android.ui.adapter.RowRepresentableAdapter import net.pokeranalytics.android.ui.adapter.RowRepresentableAdapter
import net.pokeranalytics.android.ui.adapter.RowRepresentableDelegate import net.pokeranalytics.android.ui.adapter.RowRepresentableDelegate
@ -38,6 +37,7 @@ import net.pokeranalytics.android.ui.modules.datalist.DataListActivity
import net.pokeranalytics.android.ui.modules.handhistory.HandHistoryActivity import net.pokeranalytics.android.ui.modules.handhistory.HandHistoryActivity
import net.pokeranalytics.android.ui.view.* import net.pokeranalytics.android.ui.view.*
import net.pokeranalytics.android.ui.view.rows.SessionPropertiesRow import net.pokeranalytics.android.ui.view.rows.SessionPropertiesRow
import net.pokeranalytics.android.util.CrashLogging
import net.pokeranalytics.android.util.Preferences import net.pokeranalytics.android.util.Preferences
import net.pokeranalytics.android.util.extensions.* import net.pokeranalytics.android.util.extensions.*
import timber.log.Timber import timber.log.Timber
@ -206,9 +206,10 @@ class SessionFragment : RealmFragment(), RowRepresentableDelegate, StaticRowRepr
currentSession.location = realmLocation currentSession.location = realmLocation
} }
updateSessionUI(true) this.updateSessionUI(true)
} }
} }
sessionHasBeenUserCustomized = false sessionHasBeenUserCustomized = false
} }
} }
@ -264,7 +265,7 @@ class SessionFragment : RealmFragment(), RowRepresentableDelegate, StaticRowRepr
when (row) { when (row) {
SessionPropertiesRow.CASHED_OUT, SessionPropertiesRow.PRIZE, SessionPropertiesRow.NET_RESULT, SessionPropertiesRow.CASHED_OUT, SessionPropertiesRow.PRIZE, SessionPropertiesRow.NET_RESULT,
SessionPropertiesRow.BUY_IN, SessionPropertiesRow.TIPS, SessionPropertiesRow.START_DATE, SessionPropertiesRow.BUY_IN, SessionPropertiesRow.TIPS, SessionPropertiesRow.START_DATE,
SessionPropertiesRow.END_DATE, SessionPropertiesRow.BREAK_TIME -> updateSessionUI() SessionPropertiesRow.END_DATE, SessionPropertiesRow.BREAK_TIME, SessionPropertiesRow.NUMBER_OF_TABLES -> updateSessionUI()
SessionPropertiesRow.BANKROLL -> { SessionPropertiesRow.BANKROLL -> {
updateSessionUI() updateSessionUI()
updateMenuUI() // result capture method updateMenuUI() // result capture method
@ -577,15 +578,15 @@ class SessionFragment : RealmFragment(), RowRepresentableDelegate, StaticRowRepr
"defaultValue" to session.tableSize "defaultValue" to session.tableSize
) )
) )
SessionPropertiesRow.BLINDS -> row.editingDescriptors( SessionPropertiesRow.STAKES -> row.editingDescriptors(
mapOf( mapOf(
"sb" to session.cgSmallBlind?.round(), "blinds" to session.cgBlinds,
"bb" to session.cgBigBlind?.round() "ante" to session.cgAnte
) )
) )
SessionPropertiesRow.BUY_IN -> row.editingDescriptors( SessionPropertiesRow.BUY_IN -> row.editingDescriptors(
mapOf( mapOf(
"bb" to session.cgBigBlind, "bb" to session.cgBiggestBet,
"fee" to session.tournamentEntryFee, "fee" to session.tournamentEntryFee,
"ratedBuyin" to session.result?.buyin "ratedBuyin" to session.result?.buyin
) )
@ -626,10 +627,15 @@ class SessionFragment : RealmFragment(), RowRepresentableDelegate, StaticRowRepr
"defaultValue" to session.handsCount "defaultValue" to session.handsCount
) )
) )
SessionPropertiesRow.NUMBER_OF_TABLES -> row.editingDescriptors(
mapOf(
"defaultValue" to session.numberOfTables
)
)
SessionPropertiesRow.TIPS -> row.editingDescriptors( SessionPropertiesRow.TIPS -> row.editingDescriptors(
mapOf( mapOf(
"sb" to session.cgSmallBlind?.round(), "sb" to session.cgBiggestBet?.round(),
"bb" to session.cgBigBlind?.round(), "bb" to session.cgBiggestBet?.round(),
"tips" to session.result?.tips "tips" to session.result?.tips
) )
) )

@ -0,0 +1,79 @@
package net.pokeranalytics.android.ui.view.keyboard
import android.content.Context
import android.util.AttributeSet
import android.view.LayoutInflater
import android.view.inputmethod.InputConnection
import android.widget.FrameLayout
import androidx.appcompat.widget.LinearLayoutCompat
import kotlinx.android.synthetic.main.view_keyboard_stakes.view.*
import net.pokeranalytics.android.R
import net.pokeranalytics.android.exceptions.PAIllegalStateException
import net.pokeranalytics.android.util.BLIND_SEPARATOR
import java.text.DecimalFormatSymbols
class StakesKeyboardView : LinearLayoutCompat {
var inputConnection: InputConnection? = null
constructor(context: Context) : super(context) {
init(context, null)
}
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) {
init(context, attrs)
}
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {
init(context, attrs)
}
private fun init(context: Context, attrs: AttributeSet?) {
val layoutInflater = LayoutInflater.from(context)
val view = layoutInflater.inflate(R.layout.view_keyboard_stakes, this, false)
view.value_0.text = "0"
view.value_1.text = "1"
view.value_2.text = "2"
view.value_3.text = "3"
view.value_4.text = "4"
view.value_5.text = "5"
view.value_6.text = "6"
view.value_7.text = "7"
view.value_8.text = "8"
view.value_9.text = "9"
view.value_decimal.text = DecimalFormatSymbols.getInstance().decimalSeparator.toString()
view.value_back.text = ""
view.value_separator.text = "/"
view.value_0.setOnClickListener { this.commitText("0") }
view.value_1.setOnClickListener { this.commitText("1") }
view.value_2.setOnClickListener { this.commitText("2") }
view.value_3.setOnClickListener { this.commitText("3") }
view.value_4.setOnClickListener { this.commitText("4") }
view.value_5.setOnClickListener { this.commitText("5") }
view.value_6.setOnClickListener { this.commitText("6") }
view.value_7.setOnClickListener { this.commitText("7") }
view.value_8.setOnClickListener { this.commitText("8") }
view.value_9.setOnClickListener { this.commitText("9") }
view.value_decimal.setOnClickListener { this.commitText(DecimalFormatSymbols.getInstance().decimalSeparator.toString()) }
view.value_separator.setOnClickListener { this.commitText(BLIND_SEPARATOR) }
view.value_back.setOnClickListener { this.deleteText() }
val layoutParams = FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.WRAP_CONTENT
)
addView(view, layoutParams)
}
private fun commitText(string: String) {
this.inputConnection?.commitText(string, 1) ?: throw PAIllegalStateException("No input connection")
}
private fun deleteText() {
this.inputConnection?.deleteSurroundingText(1, 0) ?: throw PAIllegalStateException("No input connection")
}
}

@ -101,7 +101,7 @@ enum class FilterCategoryRow(override val resId: Int?, override val viewType: In
Bankroll Bankroll
) )
CASH -> arrayListOf( CASH -> arrayListOf(
Blind Stakes
) )
TOURNAMENT -> arrayListOf( TOURNAMENT -> arrayListOf(
TournamentType, TournamentType,

@ -26,7 +26,7 @@ sealed class FilterSectionRow(override val resId: Int?) : RowRepresentable {
object SessionDuration: FilterSectionRow(R.string.session_duration) object SessionDuration: FilterSectionRow(R.string.session_duration)
object TimeFrameRange: FilterSectionRow(R.string.hour_slot) object TimeFrameRange: FilterSectionRow(R.string.hour_slot)
object Sessions: FilterSectionRow(R.string.sessions) object Sessions: FilterSectionRow(R.string.sessions)
object Blind: FilterSectionRow(R.string.blinds) object Stakes: FilterSectionRow(R.string.stakes)
object CashRebuyCount: FilterSectionRow(R.string.rebuy_count) object CashRebuyCount: FilterSectionRow(R.string.rebuy_count)
object TournamentType: FilterSectionRow(R.string.tournament_types) object TournamentType: FilterSectionRow(R.string.tournament_types)
object TournamentName: FilterSectionRow(R.string.tournament_name) object TournamentName: FilterSectionRow(R.string.tournament_name)
@ -134,7 +134,7 @@ sealed class FilterSectionRow(override val resId: Int?) : RowRepresentable {
//Sessions -> arrayListOf(QueryCondition.LastGame(), QueryCondition.LastSession()) //Sessions -> arrayListOf(QueryCondition.LastGame(), QueryCondition.LastSession())
// Cash // Cash
Blind -> Criteria.Blinds.queryConditions.mapFirstCondition() Stakes -> Criteria.Stakes.queryConditions.mapFirstCondition()
// CashRebuyCount -> QueryCondition.moreOrLess<QueryCondition.Rebuy>() // CashRebuyCount -> QueryCondition.moreOrLess<QueryCondition.Rebuy>()
// Tournament // Tournament

@ -49,7 +49,7 @@ enum class ReportRow : RowRepresentable {
val criteria: List<Criteria> val criteria: List<Criteria>
get() { get() {
return when (this) { return when (this) {
BLINDS -> listOf(Criteria.Blinds) BLINDS -> listOf(Criteria.Stakes)
BUY_IN -> listOf(Criteria.TournamentFees) BUY_IN -> listOf(Criteria.TournamentFees)
DAY_OF_WEEKS -> listOf(Criteria.DaysOfWeek) DAY_OF_WEEKS -> listOf(Criteria.DaysOfWeek)
GENERAL -> listOf(Criteria.SessionTypes, Criteria.BankrollTypes) GENERAL -> listOf(Criteria.SessionTypes, Criteria.BankrollTypes)

@ -28,13 +28,14 @@ enum class SessionPropertiesRow : RowRepresentable {
TIPS, TIPS,
GAME, GAME,
BLINDS, STAKES,
LOCATION, LOCATION,
BANKROLL, BANKROLL,
TABLE_SIZE, TABLE_SIZE,
TOURNAMENT_TYPE, TOURNAMENT_TYPE,
TOURNAMENT_NAME, TOURNAMENT_NAME,
TOURNAMENT_FEATURE, TOURNAMENT_FEATURE,
NUMBER_OF_TABLES,
START_DATE, START_DATE,
END_DATE, END_DATE,
@ -104,7 +105,11 @@ enum class SessionPropertiesRow : RowRepresentable {
Session.Type.CASH_GAME.ordinal -> { Session.Type.CASH_GAME.ordinal -> {
when (state) { when (state) {
SessionState.PENDING, SessionState.PLANNED -> { SessionState.PENDING, SessionState.PLANNED -> {
return arrayListOf(GAME, BLINDS, LOCATION, BANKROLL, TABLE_SIZE, START_DATE, END_DATE) return if (session.isLive) {
arrayListOf(GAME, STAKES, LOCATION, BANKROLL, TABLE_SIZE, START_DATE, END_DATE)
} else {
arrayListOf(GAME, STAKES, LOCATION, BANKROLL, TABLE_SIZE, NUMBER_OF_TABLES, START_DATE, END_DATE)
}
} }
SessionState.STARTED, SessionState.PAUSED, SessionState.FINISHED -> { SessionState.STARTED, SessionState.PAUSED, SessionState.FINISHED -> {
@ -132,18 +137,28 @@ enum class SessionPropertiesRow : RowRepresentable {
fields.add(HANDS) fields.add(HANDS)
} }
fields.add(SeparatorRow()) fields.add(SeparatorRow())
fields.addAll(listOf( fields.addAll(
listOf(
GAME, GAME,
BLINDS, STAKES,
LOCATION, LOCATION,
BANKROLL, BANKROLL,
TABLE_SIZE, TABLE_SIZE
)
)
if (!session.isLive) {
fields.add(NUMBER_OF_TABLES)
}
fields.addAll(
listOf(
SeparatorRow(), SeparatorRow(),
START_DATE, START_DATE,
END_DATE, END_DATE,
BREAK_TIME BREAK_TIME
) )
) )
if (state == SessionState.FINISHED) { if (state == SessionState.FINISHED) {
fields.add(HANDS_COUNT) fields.add(HANDS_COUNT)
} }
@ -168,13 +183,14 @@ enum class SessionPropertiesRow : RowRepresentable {
BUY_IN -> R.string.buyin BUY_IN -> R.string.buyin
TIPS -> R.string.tips TIPS -> R.string.tips
GAME -> R.string.game GAME -> R.string.game
BLINDS -> R.string.blinds STAKES -> R.string.stakes
LOCATION -> R.string.location LOCATION -> R.string.location
BANKROLL -> R.string.bankroll BANKROLL -> R.string.bankroll
TABLE_SIZE -> R.string.table_size TABLE_SIZE -> R.string.table_size
TOURNAMENT_TYPE -> R.string.tournament_type TOURNAMENT_TYPE -> R.string.tournament_type
TOURNAMENT_NAME -> R.string.tournament_name TOURNAMENT_NAME -> R.string.tournament_name
TOURNAMENT_FEATURE -> R.string.tournament_feature TOURNAMENT_FEATURE -> R.string.tournament_feature
NUMBER_OF_TABLES -> R.string.number_of_tables
START_DATE -> R.string.start_date START_DATE -> R.string.start_date
END_DATE -> R.string.end_date END_DATE -> R.string.end_date
BREAK_TIME -> R.string.break_time BREAK_TIME -> R.string.break_time
@ -188,9 +204,9 @@ enum class SessionPropertiesRow : RowRepresentable {
get() { get() {
return when (this) { return when (this) {
NET_RESULT, PRIZE, POSITION, PLAYERS, CASHED_OUT, INITIAL_BUY_IN, BUY_IN, TIPS, NET_RESULT, PRIZE, POSITION, PLAYERS, CASHED_OUT, INITIAL_BUY_IN, BUY_IN, TIPS,
GAME, BLINDS, LOCATION, BANKROLL, TABLE_SIZE, COMMENT, GAME, STAKES, LOCATION, BANKROLL, TABLE_SIZE, COMMENT,
TOURNAMENT_TYPE, TOURNAMENT_NAME, TOURNAMENT_FEATURE, HANDS, TOURNAMENT_TYPE, TOURNAMENT_NAME, TOURNAMENT_FEATURE, HANDS,
START_DATE, END_DATE, BREAK_TIME, HANDS_COUNT -> RowViewType.TITLE_VALUE.ordinal START_DATE, END_DATE, BREAK_TIME, HANDS_COUNT, NUMBER_OF_TABLES -> RowViewType.TITLE_VALUE.ordinal
} }
} }
@ -198,9 +214,9 @@ enum class SessionPropertiesRow : RowRepresentable {
get() { get() {
return when (this) { return when (this) {
NET_RESULT, CASHED_OUT, INITIAL_BUY_IN, BREAK_TIME, POSITION, PLAYERS, NET_RESULT, CASHED_OUT, INITIAL_BUY_IN, BREAK_TIME, POSITION, PLAYERS,
PRIZE, HANDS_COUNT -> BottomSheetType.NUMERIC_TEXT PRIZE, HANDS_COUNT, NUMBER_OF_TABLES -> BottomSheetType.NUMERIC_TEXT
BUY_IN, TIPS -> BottomSheetType.SUM BUY_IN, TIPS -> BottomSheetType.SUM
BLINDS -> BottomSheetType.DOUBLE_EDIT_TEXT STAKES -> BottomSheetType.CASH_GAME_STAKES
GAME -> BottomSheetType.LIST_GAME GAME -> BottomSheetType.LIST_GAME
TOURNAMENT_TYPE -> BottomSheetType.LIST_STATIC TOURNAMENT_TYPE -> BottomSheetType.LIST_STATIC
LOCATION, BANKROLL, TOURNAMENT_NAME -> BottomSheetType.LIST LOCATION, BANKROLL, TOURNAMENT_NAME -> BottomSheetType.LIST
@ -214,17 +230,16 @@ enum class SessionPropertiesRow : RowRepresentable {
override fun editingDescriptors(map: Map<String, Any?>): ArrayList<RowRepresentableEditDescriptor>? { override fun editingDescriptors(map: Map<String, Any?>): ArrayList<RowRepresentableEditDescriptor>? {
return when (this) { return when (this) {
BLINDS -> { STAKES -> {
val sb: String? by map val ante: Double? by map
val bb: String? by map val blinds: String? by map
arrayListOf( arrayListOf(
RowRepresentableEditDescriptor( RowRepresentableEditDescriptor(
sb, R.string.smallblind, InputType.TYPE_CLASS_NUMBER ante, R.string.ante, InputType.TYPE_CLASS_NUMBER
or InputType.TYPE_NUMBER_FLAG_DECIMAL or InputType.TYPE_NUMBER_FLAG_DECIMAL
), ),
RowRepresentableEditDescriptor( RowRepresentableEditDescriptor(
bb, R.string.bigblind, InputType.TYPE_CLASS_NUMBER blinds, R.string.blinds, InputType.TYPE_CLASS_TEXT
or InputType.TYPE_NUMBER_FLAG_DECIMAL
) )
) )
} }
@ -279,7 +294,7 @@ enum class SessionPropertiesRow : RowRepresentable {
) )
) )
} }
HANDS_COUNT -> { HANDS_COUNT, NUMBER_OF_TABLES -> {
arrayListOf( arrayListOf(
RowRepresentableEditDescriptor(inputType = InputType.TYPE_CLASS_NUMBER RowRepresentableEditDescriptor(inputType = InputType.TYPE_CLASS_NUMBER
or InputType.TYPE_NUMBER_FLAG_SIGNED) or InputType.TYPE_NUMBER_FLAG_SIGNED)

@ -6,6 +6,7 @@ import io.realm.RealmList
import io.realm.RealmResults import io.realm.RealmResults
import net.pokeranalytics.android.exceptions.PAIllegalStateException import net.pokeranalytics.android.exceptions.PAIllegalStateException
import net.pokeranalytics.android.exceptions.RowRepresentableEditDescriptorException import net.pokeranalytics.android.exceptions.RowRepresentableEditDescriptorException
import net.pokeranalytics.android.model.Stakes
import net.pokeranalytics.android.ui.adapter.RowRepresentableDelegate import net.pokeranalytics.android.ui.adapter.RowRepresentableDelegate
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
@ -93,6 +94,11 @@ class BottomSheetViewModel(var row: RowRepresentable) : ViewModel() {
var limit: Int? = 0 var limit: Int? = 0
val someValues = ArrayList<Any?>() val someValues = ArrayList<Any?>()
/**
* Stakes
*/
var ante: Double? = null
fun load() { fun load() {
when(this.row.bottomSheetType) { when(this.row.bottomSheetType) {
@ -102,7 +108,7 @@ class BottomSheetViewModel(var row: RowRepresentable) : ViewModel() {
throw RowRepresentableEditDescriptorException("RowRepresentableEditDescriptor inconsistency") throw RowRepresentableEditDescriptorException("RowRepresentableEditDescriptor inconsistency")
} }
this.isEditingBlinds = this.row == SessionPropertiesRow.BLINDS this.isEditingBlinds = this.row == SessionPropertiesRow.STAKES
this.stringValue = descriptors[0].defaultValue as? String this.stringValue = descriptors[0].defaultValue as? String
this.secondStringValue = descriptors[1].defaultValue as? String this.secondStringValue = descriptors[1].defaultValue as? String
@ -211,6 +217,7 @@ class BottomSheetViewModel(var row: RowRepresentable) : ViewModel() {
BottomSheetType.DOUBLE_LIST, BottomSheetType.LIST_GAME -> this.someValues BottomSheetType.DOUBLE_LIST, BottomSheetType.LIST_GAME -> this.someValues
BottomSheetType.LIST_STATIC -> this.selectedRows.firstOrNull() BottomSheetType.LIST_STATIC -> this.selectedRows.firstOrNull()
BottomSheetType.SUM -> this.doubleValue BottomSheetType.SUM -> this.doubleValue
BottomSheetType.CASH_GAME_STAKES -> Stakes(this.secondStringValue, this.ante)
else -> null else -> null
} }
} }

@ -90,9 +90,13 @@ class FakeDataManager {
if (isTournament) { if (isTournament) {
session.tournamentEntryFee = buyin session.tournamentEntryFee = buyin
} else { } else {
val bigBlind = arrayListOf(1.0, 2.0, 4.0).random()
session.cgBigBlind = bigBlind session.cgAnte = arrayListOf(1.0, null).random()
session.cgSmallBlind = bigBlind / 2.0 session.cgBlinds = arrayListOf("1/2", "2/5/10", "2").random()
// val bigBlind = arrayListOf(1.0, 2.0, 4.0).random()
// session.cgBigBlind = bigBlind
// session.cgSmallBlind = bigBlind / 2.0
} }
} }

@ -2,4 +2,5 @@ package net.pokeranalytics.android.util
const val NULL_TEXT: String = "--" const val NULL_TEXT: String = "--"
const val RANDOM_PLAYER: String = "" const val RANDOM_PLAYER: String = ""
const val FFMPEG_DESCRIPTOR_FILE = "descriptor.txt" const val FFMPEG_DESCRIPTOR_FILE = "descriptor.txt"
const val BLIND_SEPARATOR: String = "/"

@ -32,7 +32,7 @@ class Preferences {
PATCH_BREAK("patchBreaks"), PATCH_BREAK("patchBreaks"),
PATCH_SESSION_SETS("patchSessionSet"), PATCH_SESSION_SETS("patchSessionSet"),
PATCH_TRANSACTION_TYPES_NAMES("patchTransactionTypesNames"), PATCH_TRANSACTION_TYPES_NAMES("patchTransactionTypesNames"),
PATCH_BLINDS_FORMAT("patchBlindFormat"), // PATCH_BLINDS_FORMAT("patchBlindFormat"),
PATCH_COMPUTABLE_RESULTS("patchPositiveSessions"), PATCH_COMPUTABLE_RESULTS("patchPositiveSessions"),
SHOW_STOP_NOTIFICATIONS("showStopNotifications"), SHOW_STOP_NOTIFICATIONS("showStopNotifications"),
ADD_NEW_TRANSACTION_TYPES("addNewTransactionTypes"), ADD_NEW_TRANSACTION_TYPES("addNewTransactionTypes"),
@ -43,7 +43,8 @@ class Preferences {
LAST_BLOG_TIPS_RETRIEVAL("lastBlogTipsRetrieval"), LAST_BLOG_TIPS_RETRIEVAL("lastBlogTipsRetrieval"),
SHOW_BLOG_TIPS("showBlogTips"), SHOW_BLOG_TIPS("showBlogTips"),
LAST_REVIEW_REQUEST_DATE("lastReviewRequestDate"), LAST_REVIEW_REQUEST_DATE("lastReviewRequestDate"),
PATCH_NEGATIVE_LIMITS("negativeLimits") PATCH_NEGATIVE_LIMITS("negativeLimits"),
PATCH_STAKES("patchStakes")
} }
enum class FeedMessage { enum class FeedMessage {

@ -14,6 +14,7 @@ import timber.log.Timber
*/ */
enum class DataSource { enum class DataSource {
POKER_ANALYTICS, POKER_ANALYTICS,
POKER_ANALYTICS_6,
POKER_INCOME, POKER_INCOME,
POKER_BANKROLL_TRACKER, POKER_BANKROLL_TRACKER,
RUN_GOOD, RUN_GOOD,

@ -18,6 +18,7 @@ class ImportException(message: String) : Exception(message)
interface ImportDelegate { interface ImportDelegate {
fun parsingCountUpdate(importedCount: Int, totalCount: Int) fun parsingCountUpdate(importedCount: Int, totalCount: Int)
fun exceptionCaught(e: Exception)
} }
/** /**
@ -107,7 +108,7 @@ open class CSVImporter(istream: InputStream) {
realm.beginTransaction() realm.beginTransaction()
parser.forEachIndexed { index, record -> this.parser.forEachIndexed { index, record ->
// Timber.d("line $index") // Timber.d("line $index")
this.notifyDelegate() this.notifyDelegate()
@ -146,12 +147,19 @@ open class CSVImporter(istream: InputStream) {
null // reset descriptor when encountering an empty line (multiple descriptors can be found in a single file) null // reset descriptor when encountering an empty line (multiple descriptors can be found in a single file)
this.descriptorFindingAttempts = 0 this.descriptorFindingAttempts = 0
} else { } else {
val count = it.parse(realm, record)
this.importedRecords += count try {
this.totalParsedRecords++ val count = it.parse(realm, record)
this.importedRecords += count
this.totalParsedRecords++
this.notifyDelegate()
} catch (e: Exception) {
this.delegate?.exceptionCaught(e)
}
this.notifyDelegate()
} }
} ?: run { } ?: run {
realm.cancelTransaction() realm.cancelTransaction()

@ -1,19 +1,21 @@
package net.pokeranalytics.android.util.csv package net.pokeranalytics.android.util.csv
import net.pokeranalytics.android.model.interfaces.Identifiable
import io.realm.Realm import io.realm.Realm
import net.pokeranalytics.android.exceptions.PAIllegalStateException import net.pokeranalytics.android.exceptions.PAIllegalStateException
import net.pokeranalytics.android.model.Limit import net.pokeranalytics.android.model.Limit
import net.pokeranalytics.android.model.TableSize import net.pokeranalytics.android.model.TableSize
import net.pokeranalytics.android.model.TournamentType import net.pokeranalytics.android.model.TournamentType
import net.pokeranalytics.android.model.interfaces.Identifiable
import net.pokeranalytics.android.model.realm.* import net.pokeranalytics.android.model.realm.*
import net.pokeranalytics.android.model.utils.DataUtils import net.pokeranalytics.android.model.utils.DataUtils
import net.pokeranalytics.android.util.BLIND_SEPARATOR
import net.pokeranalytics.android.util.extensions.count import net.pokeranalytics.android.util.extensions.count
import net.pokeranalytics.android.util.extensions.getOrCreate import net.pokeranalytics.android.util.extensions.getOrCreate
import net.pokeranalytics.android.util.extensions.setHourMinutes import net.pokeranalytics.android.util.extensions.setHourMinutes
import org.apache.commons.csv.CSVRecord import org.apache.commons.csv.CSVRecord
import timber.log.Timber import timber.log.Timber
import java.text.DateFormat import java.text.DateFormat
import java.text.NumberFormat
import java.text.ParseException import java.text.ParseException
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.* import java.util.*
@ -57,6 +59,9 @@ abstract class PACSVDescriptor<T : Identifiable>(source: DataSource,
var stackingIn: Double? = null var stackingIn: Double? = null
var stackingOut: Double? = null var stackingOut: Double? = null
var sb: Double? = null
var bb: Double? = null
this.fields.forEach { field -> this.fields.forEach { field ->
this.fieldMapping[field]?.let { index -> this.fieldMapping[field]?.let { index ->
@ -75,7 +80,9 @@ abstract class PACSVDescriptor<T : Identifiable>(source: DataSource,
} else {} } else {}
} }
is SessionField.End -> { is SessionField.End -> {
endDate = parseDate(field, value) if (value.isNotEmpty()) {
endDate = parseDate(field, value)
}
} }
is SessionField.StartTime -> { is SessionField.StartTime -> {
startDate?.setHourMinutes(value) startDate?.setHourMinutes(value)
@ -169,38 +176,17 @@ abstract class PACSVDescriptor<T : Identifiable>(source: DataSource,
is SessionField.Bankroll -> bankrollName = value is SessionField.Bankroll -> bankrollName = value
is SessionField.LimitType -> session.limit = Limit.getInstance(value)?.ordinal is SessionField.LimitType -> session.limit = Limit.getInstance(value)?.ordinal
is SessionField.Comment -> session.comment = value is SessionField.Comment -> session.comment = value
is SessionField.Blind -> { // 1/2 is SessionField.Blind, is SessionField.Blinds -> { // 1/2
val blinds = field.parse(value) session.cgBlinds = value
session.cgSmallBlind = blinds?.first
session.cgBigBlind = blinds?.second
} }
is SessionField.SmallBlind -> { is SessionField.SmallBlind -> {
val sb = field.parse(value) sb = field.parse(value)
if (sb != null && sb > 0.0) {
session.cgSmallBlind = sb
} else {}
} }
is SessionField.BigBlind -> { is SessionField.BigBlind -> {
val bb = field.parse(value) bb = field.parse(value)
if (bb != null && bb > 0.0) {
session.cgBigBlind = bb
} else {}
}
is SessionField.Blinds -> {
val blinds = value.split("/")
when (blinds.size) {
0 -> {}
1 -> {
session.cgBigBlind = field.parse(blinds.first())
}
else -> {
session.cgSmallBlind = field.parse(blinds[blinds.size - 2])
session.cgBigBlind = field.parse(blinds.last())
}
}
} }
is SessionField.Ante -> { is SessionField.Ante -> {
// unmanaged atm session.cgAnte = field.parse(value)
} }
is SessionField.TableSize -> session.tableSize = TableSize.valueForLabel(value) is SessionField.TableSize -> session.tableSize = TableSize.valueForLabel(value)
is SessionField.TournamentPosition -> session.result?.tournamentFinalPosition = is SessionField.TournamentPosition -> session.result?.tournamentFinalPosition =
@ -256,6 +242,11 @@ abstract class PACSVDescriptor<T : Identifiable>(source: DataSource,
} }
val blinds = arrayListOf(sb, bb).filterNotNull()
if (blinds.isNotEmpty()) {
session.cgBlinds = blinds.joinToString(BLIND_SEPARATOR) { NumberFormat.getInstance().format(it) }
}
val bankroll = Bankroll.getOrCreate(realm, bankrollName, isLive, currencyCode, currencyRate) val bankroll = Bankroll.getOrCreate(realm, bankrollName, isLive, currencyCode, currencyRate)
session.bankroll = bankroll session.bankroll = bankroll
@ -264,9 +255,9 @@ abstract class PACSVDescriptor<T : Identifiable>(source: DataSource,
} }
val net = session.result?.net val net = session.result?.net
if (startDate != null && endDate != null && net != null) { // valid session if (startDate != null && net != null) { // valid session
// session already in realm, we'd love not put it in Realm before doing the check // session already in realm, we'd love not put it in Realm before doing the check
val count = DataUtils.sessionCount(realm, startDate!!, endDate!!, net) val count = DataUtils.sessionCount(realm, startDate!!, endDate, net)
if (this.noSessionImport || count == 0) { if (this.noSessionImport || count == 0) {
val managedSession = realm.copyToRealm(session) val managedSession = realm.copyToRealm(session)

@ -18,7 +18,8 @@ class ProductCSVDescriptors {
runGoodTournaments, runGoodTournaments,
pokerAnalyticsiOS, pokerAnalyticsiOS,
pokerAnalytics6iOS, pokerAnalytics6iOS,
pokerAnalyticsAndroid, pokerAnalyticsAndroidSessions,
pokerAnalyticsAndroid6Sessions,
pokerAnalyticsAndroidTransactions pokerAnalyticsAndroidTransactions
) )
@ -239,7 +240,7 @@ class ProductCSVDescriptors {
) )
} }
val pokerAnalyticsAndroid: SessionCSVDescriptor val pokerAnalyticsAndroidSessions: SessionCSVDescriptor
get() { get() {
return SessionCSVDescriptor( return SessionCSVDescriptor(
DataSource.POKER_ANALYTICS, DataSource.POKER_ANALYTICS,
@ -273,6 +274,42 @@ class ProductCSVDescriptors {
SessionField.Comment("Comment") SessionField.Comment("Comment")
) )
} }
val pokerAnalyticsAndroid6Sessions: SessionCSVDescriptor
get() {
return SessionCSVDescriptor(
DataSource.POKER_ANALYTICS_6,
true,
SessionField.Start("Start Date", dateFormat = "MM/dd/yy HH:mm:ss"),
SessionField.End("End Date", dateFormat = "MM/dd/yy HH:mm:ss"),
SessionField.Break("Break"),
SessionField.SessionType("Type"),
SessionField.Live("Live"),
SessionField.NumberOfTables("Tables"),
SessionField.Buyin("Buyin"),
SessionField.CashedOut("Cashed Out"),
SessionField.NetResult("Online Net"),
SessionField.Tips("Tips"),
SessionField.HandsCount("Hands Count"),
SessionField.LimitType("Limit"),
SessionField.Game("Game"),
SessionField.TableSize("Table Size"),
SessionField.Location("Location"),
SessionField.Bankroll("Bankroll"),
SessionField.CurrencyCode("Currency Code"),
SessionField.CurrencyRate("Currency Rate"),
SessionField.Ante("Antes"),
SessionField.Blinds("Blinds"),
SessionField.TournamentTypeName("Tournament Type"),
SessionField.TournamentName("Tournament Name"),
SessionField.TournamentEntryFee("Entry fee"),
SessionField.TournamentNumberOfPlayers("Number of players"),
SessionField.TournamentFeatures("Tournament Features"),
SessionField.TournamentPosition("Position"),
SessionField.Comment("Comment")
)
}
} }
} }

@ -7,7 +7,6 @@ import net.pokeranalytics.android.model.TournamentType
import net.pokeranalytics.android.model.realm.CustomField import net.pokeranalytics.android.model.realm.CustomField
import net.pokeranalytics.android.model.realm.Session import net.pokeranalytics.android.model.realm.Session
import org.apache.commons.csv.CSVRecord import org.apache.commons.csv.CSVRecord
import timber.log.Timber
/** /**
* A SessionCSVDescriptor is a CSVDescriptor specialized in parsing Session objects * A SessionCSVDescriptor is a CSVDescriptor specialized in parsing Session objects
@ -63,8 +62,10 @@ class SessionCSVDescriptor(source: DataSource, isTournament: Boolean?, vararg el
is SessionField.Bankroll -> data.bankroll?.name is SessionField.Bankroll -> data.bankroll?.name
is SessionField.CurrencyCode -> data.bankroll?.currency?.code is SessionField.CurrencyCode -> data.bankroll?.currency?.code
is SessionField.CurrencyRate -> field.format(data.bankroll?.currency?.rate) is SessionField.CurrencyRate -> field.format(data.bankroll?.currency?.rate)
is SessionField.SmallBlind -> field.format(data.cgSmallBlind) // is SessionField.SmallBlind -> field.format(data.cgSmallBlind)
is SessionField.BigBlind -> field.format(data.cgBigBlind) // is SessionField.BigBlind -> field.format(data.cgBigBlind)
is SessionField.Blinds -> data.cgBlinds
is SessionField.Ante -> field.format(data.cgAnte)
is SessionField.TournamentType -> field.format(data.tournamentType) is SessionField.TournamentType -> field.format(data.tournamentType)
is SessionField.TournamentTypeName -> { is SessionField.TournamentTypeName -> {
data.tournamentType?.let { tt -> data.tournamentType?.let { tt ->

@ -87,7 +87,6 @@
app:layout_constraintStart_toEndOf="@+id/color5" app:layout_constraintStart_toEndOf="@+id/color5"
app:layout_constraintTop_toBottomOf="@+id/color2" /> app:layout_constraintTop_toBottomOf="@+id/color2" />
<androidx.appcompat.widget.AppCompatImageView <androidx.appcompat.widget.AppCompatImageView
android:id="@+id/color7" android:id="@+id/color7"
android:layout_width="@dimen/color_picker_circle_size" android:layout_width="@dimen/color_picker_circle_size"

@ -7,23 +7,23 @@
android:layout_height="match_parent"> android:layout_height="match_parent">
<LinearLayout <LinearLayout
android:id="@+id/menuContainer" android:id="@+id/menuContainer"
android:layout_width="wrap_content" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="center" android:layout_gravity="center"
android:layout_marginEnd="16dp" android:layout_marginEnd="16dp"
android:layout_marginBottom="72dp" android:layout_marginBottom="72dp"
android:background="@color/kaki_darker" android:background="@color/kaki_darkest"
android:elevation="4dp" android:elevation="4dp"
android:orientation="vertical" android:orientation="vertical"
android:visibility="invisible" android:visibility="invisible"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
tools:visibility="visible"> tools:visibility="visible">
<LinearLayout <LinearLayout
android:id="@+id/newTransaction" android:id="@+id/newTransaction"
android:layout_width="match_parent" android:layout_width="wrap_content"
android:layout_height="48dp" android:layout_height="48dp"
android:layout_marginBottom="8dp" android:layout_marginBottom="8dp"
android:background="?selectableItemBackground" android:background="?selectableItemBackground"
@ -50,9 +50,8 @@
<LinearLayout <LinearLayout
android:id="@+id/new_hand_history" android:id="@+id/new_hand_history"
android:layout_width="match_parent" android:layout_width="wrap_content"
android:layout_height="48dp" android:layout_height="48dp"
android:layout_marginBottom="8dp"
android:background="?selectableItemBackground" android:background="?selectableItemBackground"
android:gravity="center_vertical" android:gravity="center_vertical"
android:orientation="horizontal" android:orientation="horizontal"
@ -76,7 +75,7 @@
<LinearLayout <LinearLayout
android:id="@+id/newTournament" android:id="@+id/newTournament"
android:layout_width="match_parent" android:layout_width="wrap_content"
android:layout_height="48dp" android:layout_height="48dp"
android:background="?selectableItemBackground" android:background="?selectableItemBackground"
android:gravity="center_vertical" android:gravity="center_vertical"
@ -101,29 +100,29 @@
</LinearLayout> </LinearLayout>
<LinearLayout <LinearLayout
android:id="@+id/newCashGame" android:id="@+id/newCashGame"
android:layout_width="match_parent" android:layout_width="wrap_content"
android:layout_height="48dp" android:layout_height="48dp"
android:layout_marginTop="8dp" android:layout_marginTop="8dp"
android:background="?selectableItemBackground" android:background="?selectableItemBackground"
android:gravity="center_vertical" android:gravity="center_vertical"
android:orientation="horizontal" android:orientation="horizontal"
android:paddingStart="16dp" android:paddingStart="16dp"
android:paddingEnd="16dp"> android:paddingEnd="16dp">
<androidx.appcompat.widget.AppCompatImageView <androidx.appcompat.widget.AppCompatImageView
android:layout_width="32dp" android:layout_width="32dp"
android:layout_height="32dp" android:layout_height="32dp"
android:tint="@color/green" android:tint="@color/green"
app:srcCompat="@drawable/add_cash_game" /> app:srcCompat="@drawable/add_cash_game" />
<androidx.appcompat.widget.AppCompatTextView <androidx.appcompat.widget.AppCompatTextView
style="@style/PokerAnalyticsTheme.TextView.RowTitle" style="@style/PokerAnalyticsTheme.TextView.RowTitle"
android:layout_width="160dp" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginStart="16dp" android:layout_marginStart="16dp"
android:text="@string/new_cash_game" android:text="@string/new_cash_game"
app:layout_constraintEnd_toEndOf="parent" /> app:layout_constraintEnd_toEndOf="parent" />
</LinearLayout> </LinearLayout>

@ -0,0 +1,74 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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="wrap_content"
android:orientation="vertical"
tools:background="@color/grey_darkest">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/top_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent">
<androidx.appcompat.widget.AppCompatEditText
android:id="@+id/blindsEditText"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:layout_marginEnd="16dp"
android:layout_marginBottom="16dp"
android:gravity="center"
android:lines="1"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@id/anteEditText"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.0"
tools:text="20" />
<androidx.appcompat.widget.AppCompatEditText
android:id="@+id/anteEditText"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:layout_marginEnd="16dp"
android:layout_marginBottom="16dp"
android:gravity="center"
android:imeOptions="actionNext"
android:lines="1"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@id/blindsEditText"
app:layout_constraintTop_toTopOf="parent"
tools:text="10" />
</androidx.constraintlayout.widget.ConstraintLayout>
<net.pokeranalytics.android.ui.view.keyboard.StakesKeyboardView
android:id="@+id/stakes_keyboard"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@id/top_container"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent" />
<!-- <net.pokeranalytics.android.ui.modules.handhistory.views.KeyboardAmountView-->
<!-- android:id="@+id/ante_keyboard"-->
<!-- android:layout_width="match_parent"-->
<!-- android:layout_height="wrap_content"-->
<!-- app:layout_constraintTop_toBottomOf="@id/top_container"-->
<!-- app:layout_constraintStart_toStartOf="parent"-->
<!-- app:layout_constraintEnd_toEndOf="parent"-->
<!-- app:layout_constraintBottom_toBottomOf="parent" />-->
</androidx.constraintlayout.widget.ConstraintLayout>

@ -23,7 +23,7 @@
<com.google.android.material.button.MaterialButton <com.google.android.material.button.MaterialButton
android:id="@+id/actionButton" android:id="@+id/actionButton"
style="@style/PokerAnalyticsTheme.HHButton" style="@style/PokerAnalyticsTheme.HHButton"
android:layout_width="84dp" android:layout_width="92dp"
android:layout_height="44dp" android:layout_height="44dp"
android:layout_marginStart="8dp"/> android:layout_marginStart="8dp"/>

@ -0,0 +1,134 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.appcompat.widget.LinearLayoutCompat android:layout_width="match_parent"
android:layout_height="216dp"
android:orientation="horizontal"
xmlns:android="http://schemas.android.com/apk/res/android">
<androidx.appcompat.widget.LinearLayoutCompat
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:orientation="vertical">
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/value_1"
style="@style/PokerAnalyticsTheme.KeyboardButton"
android:layout_marginBottom="1dp"
android:layout_marginEnd="1dp"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/value_4"
style="@style/PokerAnalyticsTheme.KeyboardButton"
android:layout_marginVertical="1dp"
android:layout_marginEnd="1dp"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/value_7"
style="@style/PokerAnalyticsTheme.KeyboardButton"
android:layout_marginVertical="1dp"
android:layout_marginEnd="1dp"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/value_decimal"
style="@style/PokerAnalyticsTheme.KeyboardButton"
android:layout_marginEnd="1dp"
android:layout_marginTop="1dp"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
</androidx.appcompat.widget.LinearLayoutCompat>
<androidx.appcompat.widget.LinearLayoutCompat
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:orientation="vertical">
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/value_2"
style="@style/PokerAnalyticsTheme.KeyboardButton"
android:layout_marginBottom="1dp"
android:layout_marginHorizontal="1dp"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/value_5"
style="@style/PokerAnalyticsTheme.KeyboardButton"
android:layout_marginVertical="1dp"
android:layout_marginHorizontal="1dp"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/value_8"
style="@style/PokerAnalyticsTheme.KeyboardButton"
android:layout_marginVertical="1dp"
android:layout_marginHorizontal="1dp"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/value_0"
style="@style/PokerAnalyticsTheme.KeyboardButton"
android:layout_marginHorizontal="1dp"
android:layout_marginTop="1dp"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
</androidx.appcompat.widget.LinearLayoutCompat>
<androidx.appcompat.widget.LinearLayoutCompat
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:orientation="vertical">
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/value_3"
style="@style/PokerAnalyticsTheme.KeyboardButton"
android:layout_marginBottom="1dp"
android:layout_marginHorizontal="1dp"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/value_6"
style="@style/PokerAnalyticsTheme.KeyboardButton"
android:layout_marginVertical="1dp"
android:layout_marginHorizontal="1dp"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/value_9"
style="@style/PokerAnalyticsTheme.KeyboardButton"
android:layout_marginVertical="1dp"
android:layout_marginHorizontal="1dp"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/value_back"
style="@style/PokerAnalyticsTheme.KeyboardButton"
android:layout_marginHorizontal="1dp"
android:layout_marginTop="1dp"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
</androidx.appcompat.widget.LinearLayoutCompat>
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/value_separator"
android:layout_marginStart="1dp"
style="@style/PokerAnalyticsTheme.KeyboardHighlightedButton"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</androidx.appcompat.widget.LinearLayoutCompat>

@ -529,7 +529,7 @@
<string name="stack">Jetons</string> <string name="stack">Jetons</string>
<string name="stack_initial_en_bb_">Tapis initial (en grosses blindes)</string> <string name="stack_initial_en_bb_">Tapis initial (en grosses blindes)</string>
<string name="stacks">Tapis</string> <string name="stacks">Tapis</string>
<string name="stakes">Montants</string> <string name="stakes">Mises</string>
<string name="standard">Standard</string> <string name="standard">Standard</string>
<string name="standard_deviation">Ecart type</string> <string name="standard_deviation">Ecart type</string>
<string name="start">Démarrer</string> <string name="start">Démarrer</string>
@ -778,4 +778,5 @@
<string name="estimated">estimation</string> <string name="estimated">estimation</string>
<string name="dhph_explanation">Vous pouvez changer le nombre de mains distribuées par heure. Cette valeur correspond au nombre total de mains distribuées à tous les joueur d\'une table en une heure. Exemple: Vous jouez 25 mains par heure sur des tables de 10 joueurs, entrez: 10 x 25 = 250.</string> <string name="dhph_explanation">Vous pouvez changer le nombre de mains distribuées par heure. Cette valeur correspond au nombre total de mains distribuées à tous les joueur d\'une table en une heure. Exemple: Vous jouez 25 mains par heure sur des tables de 10 joueurs, entrez: 10 x 25 = 250.</string>
<string name="dealt_hands_per_hour">Mains par heure</string> <string name="dealt_hands_per_hour">Mains par heure</string>
<string name="errors">erreur(s)</string>
</resources> </resources>

@ -821,5 +821,6 @@
<string name="report_name_cannot_be_empty">You need to give a name to the report</string> <string name="report_name_cannot_be_empty">You need to give a name to the report</string>
<string name="wildcards_warning">The hand you\'ve created has suit wildcards. By convenience - sorry! - we\'re currently removing such cards to determine which hand wins, resulting in potentially wrong chip distribution.</string> <string name="wildcards_warning">The hand you\'ve created has suit wildcards. By convenience - sorry! - we\'re currently removing such cards to determine which hand wins, resulting in potentially wrong chip distribution.</string>
<string name="proceed">proceed</string> <string name="proceed">proceed</string>
<string name="errors">error(s)</string>
</resources> </resources>

@ -386,6 +386,32 @@
<item name="backgroundTint">@color/kaki_darker</item> <item name="backgroundTint">@color/kaki_darker</item>
</style> </style>
<style name="PokerAnalyticsTheme.KeyboardButton" parent="Widget.MaterialComponents.Button">
<item name="iconPadding">0dp</item>
<item name="android:height">48dp</item>
<item name="android:letterSpacing">0</item>
<item name="android:fontFamily">@font/roboto_medium</item>
<item name="android:textColor">@color/white</item>
<item name="android:paddingStart">4dp</item>
<item name="android:paddingEnd">8dp</item>
<item name="android:textSize">16sp</item>
<item name="android:background">@color/kaki</item>
<item name="backgroundTint">@color/kaki</item>
</style>
<style name="PokerAnalyticsTheme.KeyboardHighlightedButton" parent="Widget.MaterialComponents.Button">
<item name="iconPadding">0dp</item>
<item name="android:height">48dp</item>
<item name="android:letterSpacing">0</item>
<item name="android:fontFamily">@font/roboto_medium</item>
<item name="android:textColor">@color/white</item>
<item name="android:paddingStart">4dp</item>
<item name="android:paddingEnd">8dp</item>
<item name="android:textSize">32sp</item>
<item name="android:background">@color/green</item>
<item name="backgroundTint">@color/green</item>
</style>
<style name="PokerAnalyticsTheme.PlayerButton"> <style name="PokerAnalyticsTheme.PlayerButton">
<!-- <item name="android:backgroundTint">@color/kaki_light</item>--> <!-- <item name="android:backgroundTint">@color/kaki_light</item>-->
<!-- <item name="android:background">@drawable/circle</item>--> <!-- <item name="android:background">@drawable/circle</item>-->

Loading…
Cancel
Save