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 {
compileSdkVersion 30
compileSdkVersion 32
buildToolsVersion "30.0.2"
compileOptions {
@ -34,9 +34,9 @@ android {
defaultConfig {
applicationId "net.pokeranalytics.android"
minSdkVersion 23
targetSdkVersion 30
versionCode 135
versionName "5.4.11"
targetSdkVersion 32
versionCode 136
versionName "5.5"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
@ -108,7 +108,7 @@ dependencies {
implementation 'com.google.android.material:material:1.3.0'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
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
// Places

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

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

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

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

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

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

@ -41,7 +41,7 @@ class CashGameOptimalDurationCalculator {
val query = Query().add(QueryCondition.IsCash) // cash game
query.add(if (isLive) { QueryCondition.IsLive } else { QueryCondition.IsOnline }) // live / online
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 sessionsByDuration = sessions.groupBy {

@ -7,10 +7,10 @@ import net.pokeranalytics.android.R
import net.pokeranalytics.android.exceptions.PAIllegalStateException
import net.pokeranalytics.android.exceptions.PokerAnalyticsException
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.Limits.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.TournamentFeatures.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 {
objects.add(QueryCondition.CustomFieldListQuery(it))
}
objects.sorted()
objects.sort()
realm.close()
return objects.map { Query(it) }
}
@ -104,11 +104,10 @@ sealed class Criteria(override var uniqueIdentifier: Int) : IntIdentifiable, Row
}
objects.add(condition)
}
objects.sorted()
objects.sort()
return objects.map { Query(it) }
}
QueryCondition.distinct<Session, T, S>()?.let {
val values = it.mapNotNull { session ->
when (this) {
@ -124,8 +123,8 @@ sealed class Criteria(override var uniqueIdentifier: Int) : IntIdentifiable, Row
is TournamentFees -> if (session.tournamentEntryFee is S) {
session.tournamentEntryFee as S
} else throw PokerAnalyticsException.QueryValueMapUnexpectedValue
is Blinds -> if (session.blinds is S) {
session.blinds as S
is Stakes -> if (session.cgStakes is S) {
session.cgStakes as S
} else throw PokerAnalyticsException.QueryValueMapUnexpectedValue
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 Years : ListCriteria(15)
object AllMonthsUpToNow : ListCriteria(16)
object Blinds : ListCriteria(17)
object Stakes : ListCriteria(17)
object TournamentFees : ListCriteria(18)
object Cash : SimpleCriteria(listOf(QueryCondition.IsCash), 19)
object Tournament : SimpleCriteria(listOf(QueryCondition.IsTournament), 20)
@ -237,7 +236,7 @@ sealed class Criteria(override var uniqueIdentifier: Int) : IntIdentifiable, Row
realm.close()
years
}
is Blinds -> comparison<QueryCondition.AnyBlind, String>()
is Stakes -> comparison<QueryCondition.AnyStake, String>()
is ListCustomFields -> comparison<CustomFieldEntry>()
is ValueCustomFields -> {
val realm = Realm.getDefaultInstance()
@ -271,7 +270,7 @@ sealed class Criteria(override var uniqueIdentifier: Int) : IntIdentifiable, Row
DayPeriods -> R.string.weekdays_or_weekend
Years -> R.string.year
AllMonthsUpToNow -> R.string.month
Blinds -> R.string.blind
Stakes -> R.string.blind
TournamentFees -> R.string.entry_fees
// is ListCustomFields -> 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> {
val objects = mutableListOf<S>()
val realm = Realm.getDefaultInstance()
realm.where<T>().findAll().forEach {
realm.where<T>().sort("name").findAll().forEach {
val condition = (QueryCondition.getInstance<T>() as S).apply {
setObject(it)
}
objects.add(condition)
}
objects.sorted()
// objects.sort()
realm.close()
return objects.map { Query(it) }
}
@ -303,7 +302,7 @@ sealed class Criteria(override var uniqueIdentifier: Int) : IntIdentifiable, Row
}
objects.add(condition)
}
objects.sorted()
objects.sort()
return objects.map { Query(it) }
}
@ -319,7 +318,8 @@ sealed class Criteria(override var uniqueIdentifier: Int) : IntIdentifiable, Row
TournamentFeatures, Limits, TableSizes, TournamentTypes,
MonthsOfYear, DaysOfWeek, SessionTypes,
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())
}
} else {
if (cgSmallBlind != null && cgBigBlind != null) {
parameters.add(getFormattedBlinds())
if (this.cgAnte != null || this.cgBlinds != null) {
parameters.add(getFormattedStakes())
}
game?.let {
parameters.add(getFormattedGame())

@ -12,8 +12,10 @@ import net.pokeranalytics.android.exceptions.PokerAnalyticsException
import net.pokeranalytics.android.model.Limit
import net.pokeranalytics.android.model.TableSize
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.NameManageable
import net.pokeranalytics.android.model.interfaces.StakesHolder
import net.pokeranalytics.android.model.realm.*
import net.pokeranalytics.android.ui.fragment.components.bottomsheet.BottomSheetType
import net.pokeranalytics.android.ui.view.RowRepresentable
@ -322,6 +324,7 @@ sealed class QueryCondition : RowRepresentable {
val query = realm.where(entity)
return query.equalTo("id", value).findFirst()?.name ?: NULL_TEXT
}
}
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 {
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() {
@ -615,7 +628,7 @@ sealed class QueryCondition : RowRepresentable {
object DateNotNull : NotNullQueryCondition()
object EndDateNotNull : NotNullQueryCondition()
object BigBlindNotNull : NotNullQueryCondition()
object BiggestBetNotNull : NotNullQueryCondition()
class StartedFromTime(date: Date) : TimeQuery(date) {
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.util.extensions.findById
import timber.log.Timber
import java.util.*
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) {
this.smallBlind = handHistory.smallBlind
this.bigBlind = handHistory.bigBlind
this.blinds = handHistory.blinds
this.bigBlindAnte = handHistory.bigBlindAnte
this.ante = handHistory.ante
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.type = session.sessionType
this.smallBlind = session.cgSmallBlind
this.bigBlind = session.cgBigBlind
this.blinds = session.cgBlinds
this.ante = session.cgAnte
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()
private set
val blindValues = session.blindValues
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.QueryCondition
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.SessionSetManager
import net.pokeranalytics.android.util.BLIND_SEPARATOR
import net.pokeranalytics.android.util.Preferences
import java.text.NumberFormat
class Patcher {
@ -32,8 +35,8 @@ class Patcher {
Preferences.executeOnce(Preferences.Keys.PATCH_TRANSACTION_TYPES_NAMES, context) {
patchDefaultTransactionTypes(context)
}
Preferences.executeOnce(Preferences.Keys.PATCH_BLINDS_FORMAT, context) {
patchBlindFormat()
Preferences.executeOnce(Preferences.Keys.PATCH_STAKES, context) {
patchStakes()
}
Preferences.executeOnce(Preferences.Keys.PATCH_NEGATIVE_LIMITS, context) {
patchNegativeLimits()
@ -98,7 +101,8 @@ class Patcher {
it.computeStats()
}
sessions.forEach {
it.formatBlinds()
it.generateStakes()
it.defineHighestBet()
}
results.forEach {
it.computeNumberOfRebuy()
@ -123,13 +127,28 @@ class Patcher {
realm.close()
}
private fun patchBlindFormat() {
private fun patchStakes() {
val realm = Realm.getDefaultInstance()
realm.executeTransaction {
val sessions = realm.where(Session::class.java).findAll()
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()
}

@ -252,6 +252,36 @@ class PokerAnalyticsMigration : RealmMigration {
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 {

@ -36,7 +36,7 @@ open class ComputableResult : RealmObject(), Filterable {
}
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.bbPer100Hands =
session.bbNet / (session.numberOfHandsPerHour * session.hourlyDuration) * 100

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

@ -16,6 +16,7 @@ import net.pokeranalytics.android.calculus.StatFormattingException
import net.pokeranalytics.android.exceptions.ModelException
import net.pokeranalytics.android.exceptions.PAIllegalStateException
import net.pokeranalytics.android.model.Limit
import net.pokeranalytics.android.model.Stakes
import net.pokeranalytics.android.model.TableSize
import net.pokeranalytics.android.model.TournamentType
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.interfaces.*
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.ui.adapter.UnmanagedRowRepresentableException
import net.pokeranalytics.android.ui.graph.Graph
import net.pokeranalytics.android.ui.view.*
import net.pokeranalytics.android.ui.view.rows.SessionPropertiesRow
import net.pokeranalytics.android.util.NULL_TEXT
import net.pokeranalytics.android.util.TextFormat
import net.pokeranalytics.android.util.UserDefaults
import net.pokeranalytics.android.util.extensions.*
import net.pokeranalytics.android.util.*
import net.pokeranalytics.android.util.extensions.hourMinute
import net.pokeranalytics.android.util.extensions.shortDateTime
import net.pokeranalytics.android.util.extensions.toCurrency
import net.pokeranalytics.android.util.extensions.toMinutes
import java.text.DateFormat
import java.text.NumberFormat
import java.text.ParseException
import java.util.*
import java.util.Currency
typealias BB = Double
open class Session : RealmObject(), Savable, RowUpdatable, RowRepresentable, Timed,
TimeFilterable, Filterable, DatedBankrollGraphEntry {
TimeFilterable, Filterable, DatedBankrollGraphEntry, StakesHolder {
enum class Type(val value: String) {
CASH_GAME("Cash Game"),
@ -96,7 +99,7 @@ open class Session : RealmObject(), Savable, RowUpdatable, RowRepresentable, Tim
AnyLimit::class.java -> "limit"
AnyTableSize::class.java -> "tableSize"
AnyTournamentType::class.java -> "tournamentType"
AnyBlind::class.java -> "blinds"
AnyStake::class.java -> "cgStakes"
NumberOfTable::class.java -> "numberOfTables"
NetAmountWon::class.java, NetAmountLost::class.java -> "computableResults.ratedNet"
NumberOfRebuy::class.java -> "result.numberOfRebuy"
@ -118,7 +121,7 @@ open class Session : RealmObject(), Savable, RowUpdatable, RowRepresentable, Tim
CustomFieldQuery::class.java -> "customFieldEntries.customFields.id"
DateNotNull::class.java -> "startDate"
EndDateNotNull::class.java -> "endDate"
BigBlindNotNull::class.java -> "cgBigBlind"
BiggestBetNotNull::class.java -> "cgBiggestBet"
else -> null
}
}
@ -264,7 +267,7 @@ open class Session : RealmObject(), Savable, RowUpdatable, RowRepresentable, Tim
override var bankroll: Bankroll? = null
set(value) {
field = value
this.formatBlinds()
this.generateStakes()
this.computeStats()
// this.updateRowRepresentation()
}
@ -290,6 +293,10 @@ open class Session : RealmObject(), Savable, RowUpdatable, RowRepresentable, Tim
// The number of tables played at the same time
var numberOfTables: Int = 1
set(value) {
field = value
this.computeStats()
}
// The hand histories of the session
@LinkingObjects("session")
@ -304,23 +311,43 @@ open class Session : RealmObject(), Savable, RowUpdatable, RowRepresentable, Tim
// Cash Game
// The small blind value
var cgSmallBlind: Double? = null
var cgOldSmallBlind: Double? = null
set(value) {
field = value
formatBlinds()
}
// 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) {
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()
formatBlinds()
this.result?.computeNumberOfRebuy()
}
var blinds: String? = null
private set
var cgBiggestBet: Double? = null
var cgStakes: String? = null
// Tournament
@ -354,7 +381,7 @@ open class Session : RealmObject(), Savable, RowUpdatable, RowRepresentable, Tim
}
fun bankrollHasBeenUpdated() {
formatBlinds()
this.generateStakes()
}
/**
@ -405,7 +432,7 @@ open class Session : RealmObject(), Savable, RowUpdatable, RowRepresentable, Tim
*/
val bbNet: BB
get() {
val bb = this.cgBigBlind
val bb = this.cgBiggestBet
val result = this.result
return if (bb != null && result != null) {
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 config = UserConfig.getConfiguration(this.realm)
val playerHandsPerHour = if (this.isLive) config.liveDealtHandsPerHour else config.onlineDealtHandsPerHour
return playerHandsPerHour / tableSize.toDouble()
return this.numberOfTables * playerHandsPerHour / tableSize.toDouble()
}
val hourlyRate: Double
@ -646,23 +673,42 @@ open class Session : RealmObject(), Savable, RowUpdatable, RowRepresentable, Tim
return if (gameTitle.isNotBlank()) gameTitle else NULL_TEXT
}
fun getFormattedBlinds(): String {
return blinds ?: NULL_TEXT
fun getFormattedStakes(): String {
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() {
blinds = null
if (cgBigBlind == null) return
cgBigBlind?.let { bb ->
val sb = cgSmallBlind ?: bb / 2.0
val preFormattedBlinds = "${sb.formatted}/${bb.round()}"
println("<<<<<< bb.toCurrency(currency) : ${bb.toCurrency(currency)}")
println("<<<<<< preFormattedBlinds : $preFormattedBlinds")
val regex = Regex("-?\\d+(\\.\\d+)?")
blinds = bb.toCurrency(currency).replace(regex, preFormattedBlinds)
println("<<<<<< blinds = $blinds")
}
}
// fun formatBlinds() {
// blinds = null
// if (cgBigBlind == null) return
// cgBigBlind?.let { bb ->
// val sb = cgSmallBlind ?: bb / 2.0
// val preFormattedBlinds = "${sb.formatted}/${bb.round()}"
// println("<<<<<< bb.toCurrency(currency) : ${bb.toCurrency(currency)}")
// println("<<<<<< preFormattedBlinds : $preFormattedBlinds")
// val regex = Regex("-?\\d+(\\.\\d+)?")
// blinds = bb.toCurrency(currency).replace(regex, preFormattedBlinds)
// println("<<<<<< blinds = $blinds")
// }
// }
// LifeCycle
@ -703,8 +749,8 @@ open class Session : RealmObject(), Savable, RowUpdatable, RowRepresentable, Tim
copy.game = this.game
copy.limit = this.limit
copy.cgSmallBlind = this.cgSmallBlind
copy.cgBigBlind = this.cgBigBlind
copy.cgBiggestBet = this.cgBiggestBet
copy.cgAnte = this.cgAnte
copy.tournamentEntryFee = this.tournamentEntryFee
copy.tournamentFeatures = this.tournamentFeatures
copy.tournamentName = this.tournamentName
@ -726,27 +772,36 @@ open class Session : RealmObject(), Savable, RowUpdatable, RowRepresentable, Tim
when (row) {
SessionPropertiesRow.BANKROLL -> bankroll = value as Bankroll?
SessionPropertiesRow.BLINDS -> if (value is ArrayList<*>) {
cgSmallBlind = try {
(value[0] as String? ?: "0").toDouble()
} catch (e: Exception) {
null
}
SessionPropertiesRow.STAKES -> if (value is Stakes) {
cgBigBlind = try {
(value[1] as String? ?: "0").toDouble()
} catch (e: Exception) {
null
if (value.ante != null) {
this.cgAnte = value.ante
}
cgBigBlind?.let {
if (cgSmallBlind == null || cgSmallBlind == 0.0) {
cgSmallBlind = it / 2.0
}
if (value.blinds != null) {
this.cgBlinds = value.blinds
}
// 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) {
cgSmallBlind = null
cgBigBlind = null
this.cgBlinds = null
this.cgAnte = null
}
SessionPropertiesRow.BREAK_TIME -> {
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.NUMBER_OF_TABLES -> this.numberOfTables = (value as Double?)?.toInt() ?: 1
is CustomField -> {
customFieldEntries.filter { it.customField?.id == row.id }.let {
customFieldEntries.removeAll(it)
@ -964,7 +1020,7 @@ open class Session : RealmObject(), Savable, RowUpdatable, RowRepresentable, Tim
return when (row) {
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.BUY_IN -> this.result?.buyin?.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.HANDS -> this.handHistories?.size.toString()
SessionPropertiesRow.HANDS_COUNT -> this.handsCountFormatted(context)
SessionPropertiesRow.NUMBER_OF_TABLES -> this.numberOfTables.toString()
is CustomField -> {
customFieldEntries.find { it.customField?.id == row.id }?.let { customFieldEntry ->
return customFieldEntry.getFormattedValue(currency)
@ -1026,4 +1083,73 @@ open class Session : RealmObject(), Savable, RowUpdatable, RowRepresentable, Tim
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.Position
import net.pokeranalytics.android.model.handhistory.Street
import net.pokeranalytics.android.model.interfaces.Deletable
import net.pokeranalytics.android.model.interfaces.DeleteValidityStatus
import net.pokeranalytics.android.model.interfaces.Identifiable
import net.pokeranalytics.android.model.interfaces.TimeFilterable
import net.pokeranalytics.android.model.interfaces.*
import net.pokeranalytics.android.model.realm.Bankroll
import net.pokeranalytics.android.model.realm.Session
import net.pokeranalytics.android.ui.modules.handhistory.evaluator.EvaluatorBridge
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)
open class HandHistory : RealmObject(), Deletable, RowRepresentable, Filterable, TimeFilterable,
CardHolder, Comparator<PositionAmount> {
CardHolder, Comparator<PositionAmount>, StakesHolder {
@PrimaryKey
override var id = UUID.randomUUID().toString()
@ -64,34 +62,67 @@ open class HandHistory : RealmObject(), Deletable, RowRepresentable, Filterable,
/***
* The small blind
*/
var smallBlind: Double? = null
var oldSmallBlind: Double? = null
set(value) {
field = value
if (this.bigBlind == null && value != null) {
this.bigBlind = value * 2
}
// if (this.bigBlind == null && value != null) {
// this.bigBlind = value * 2
// }
}
/***
* The big blind
*/
var bigBlind: Double? = null
var oldBigBlind: Double? = null
set(value) {
field = value
if (this.smallBlind == null && value != null) {
this.smallBlind = value / 2
}
// if (this.smallBlind == null && value != null) {
// this.smallBlind = value / 2
// }
}
/***
* Big blind ante
*/
var bigBlindAnte: Boolean = false
/***
* 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
@ -164,8 +195,8 @@ open class HandHistory : RealmObject(), Deletable, RowRepresentable, Filterable,
this.playerSetups.removeAll(this.playerSetups)
handSetup.tableSize?.let { this.numberOfPlayers = it }
handSetup.smallBlind?.let { this.smallBlind = it }
handSetup.bigBlind?.let { this.bigBlind = it }
handSetup.ante?.let { this.ante = it }
handSetup.blinds?.let { this.blinds = it }
this.session = handSetup.session
this.date = this.session?.handHistoryAutomaticDate ?: Date()
@ -180,18 +211,32 @@ open class HandHistory : RealmObject(), Deletable, RowRepresentable, Filterable,
this.actions.clear()
this.addAction(0, Action.Type.POST_SB, this.smallBlind)
this.addAction(1, Action.Type.POST_BB, this.bigBlind)
// var lastStraddler: Int? = null
var blindValues = this.blindValues
if (blindValues.isNotEmpty()) {
blindValues.forEachIndexed { index, blind ->
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)
handSetup.straddlePositions.forEach { position -> // position are sorted here
handSetup.straddlePositions.forEachIndexed { index, position -> // position are sorted here
val positionIndex = positions.indexOf(position)
this.addAction(positionIndex, Action.Type.STRADDLE)
// lastStraddler = positionIndex
val amount = if (index < blindValues.size) { blindValues[index] } else null
this.addAction(positionIndex, Action.Type.STRADDLE, amount)
}
// var lastStraddler: Int? = null
// val totalActions = this.actions.size
// val startingPosition = lastStraddler?.let { it + 1 } ?: totalActions
@ -237,9 +282,9 @@ open class HandHistory : RealmObject(), Deletable, RowRepresentable, Filterable,
val anteSum: Double
get() {
return if (bigBlindAnte) {
this.bigBlind ?: 0.0
this.biggestBet ?: 0.0
} 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 firstLineComponents = mutableListOf(this.date.fullDate(), players)
this.smallBlind?.let { sb ->
this.bigBlind?.let { bb ->
firstLineComponents.add("${sb.formatted}/${bb.formatted}")
this.blinds?.let { firstLineComponents.add(it) }
// 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.addLineReturn(2)
@ -373,12 +424,12 @@ open class HandHistory : RealmObject(), Deletable, RowRepresentable, Filterable,
fun anteForPosition(position: Position): Double {
return if (this.bigBlindAnte) {
if (position == Position.BB) {
this.bigBlind ?: 0.0
this.biggestBet ?: 0.0
} else {
0.0
}
} 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)
playerItems.add("- $heroString")
}
playerItems.add("[${playerSetup.cards.formatted(context)}]")
if (playerSetup.cards.isNotEmpty()) {
playerItems.add("[${playerSetup.cards.formatted(context)}]")
}
playerSetup.stack?.let { stack ->
playerItems.add("- $stack")
}

@ -11,15 +11,18 @@ class DataUtils {
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 {
val sessions = realm.where(Session::class.java)
fun sessionCount(realm: Realm, startDate: Date, endDate: Date?, net: Double): Int {
var sessionQuery = realm.where(Session::class.java)
.equalTo("startDate", startDate)
.equalTo("endDate", endDate)
.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 -> {
return listOf(
SessionPropertiesRow.GAME,
SessionPropertiesRow.BLINDS,
SessionPropertiesRow.STAKES,
SessionPropertiesRow.BANKROLL,
SessionPropertiesRow.TABLE_SIZE
)
@ -86,8 +86,8 @@ class FavoriteSessionFinder {
when (session.type) {
Session.Type.CASH_GAME.ordinal -> {
session.cgSmallBlind = fav.cgSmallBlind
session.cgBigBlind = fav.cgBigBlind
session.cgAnte = fav.cgAnte
session.cgBlinds = fav.cgBlinds
}
Session.Type.TOURNAMENT.ordinal -> {
session.tournamentEntryFee = fav.tournamentEntryFee

@ -31,7 +31,9 @@ class ImportFragment : RealmFragment(), ImportDelegate {
private var _binding: FragmentImportBinding? = null
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 {
super.onCreateView(inflater, container, savedInstanceState)
@ -44,7 +46,6 @@ class ImportFragment : RealmFragment(), ImportDelegate {
_binding = null
}
fun setData(path: String) {
this.filePath = path
}
@ -90,7 +91,6 @@ class ImportFragment : RealmFragment(), ImportDelegate {
this.importer = CSVImporter(inputStream)
this.importer.delegate = this
var exception: Exception? = null
GlobalScope.launch(coroutineContext) {
@ -98,11 +98,8 @@ class ImportFragment : RealmFragment(), ImportDelegate {
val s = Date()
Timber.d(">>> Start Import...")
try {
importer.start()
} catch (e: Exception) {
exception = e
}
importer.start()
val e = Date()
val duration = (e.time - s.time) / 1000.0
Timber.d(">>> Import ended in $duration seconds")
@ -110,9 +107,9 @@ class ImportFragment : RealmFragment(), ImportDelegate {
}
test.await()
val exceptionMessage = exception?.message
val exceptionMessage = exceptions.firstOrNull()?.message
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)
snackBar.setAction(R.string.ok) {
snackBar.dismiss()
@ -160,4 +157,8 @@ class ImportFragment : RealmFragment(), ImportDelegate {
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() {
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")
}

@ -12,12 +12,12 @@ import net.pokeranalytics.android.exceptions.RowRepresentableEditDescriptorExcep
import net.pokeranalytics.android.util.extensions.round
class BottomSheetDoubleEditTextFragment : BottomSheetFragment() {
open class BottomSheetDoubleEditTextFragment : BottomSheetFragment() {
private var _binding: BottomSheetDoubleEditTextBinding? = null
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)
return binding.root
}

@ -16,7 +16,7 @@ class BottomSheetEditTextFragment : BottomSheetFragment() {
private var _binding: BottomSheetEditTextBinding? = null
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)
return binding.root
}

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

@ -18,7 +18,7 @@ open class BottomSheetListFragment : BottomSheetFragment(), LiveRowRepresentable
private var _binding: BottomSheetListBinding? = null
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)
return binding.root
}

@ -22,7 +22,7 @@ class BottomSheetListGameFragment : BottomSheetListFragment() {
private var _binding: BottomSheetGameListBinding? = null
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)
return binding.root
}

@ -17,7 +17,7 @@ class BottomSheetNumericTextFragment : BottomSheetFragment() {
private var _binding: BottomSheetEditTextBinding? = null
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)
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 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)
return binding.root
}

@ -19,7 +19,7 @@ class BottomSheetSumFragment : BottomSheetFragment() {
private var _binding: BottomSheetSumBinding? = null
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)
return binding.root
}

@ -19,7 +19,7 @@ class BottomSheetTableSizeGridFragment : BottomSheetFragment(), StaticRowReprese
private var _binding: BottomSheetGridBinding? = null
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)
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)
}

@ -12,7 +12,8 @@ enum class BottomSheetType {
EDIT_TEXT_MULTI_LINES,
DOUBLE_EDIT_TEXT,
NUMERIC_TEXT,
SUM;
SUM,
CASH_GAME_STAKES;
val validationRequired: Boolean
get() = when (this) {
@ -25,7 +26,7 @@ enum class BottomSheetType {
val addRequired: Boolean
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
}
}

@ -192,7 +192,8 @@ class EditorAdapter(
"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)
// Enabled

@ -536,9 +536,9 @@ class ActionList(var listener: ActionListListener? = null) : ArrayList<ComputedA
*/
override fun blindsUpdated(type: Action.Type, amount: Double) {
when (type) {
Action.Type.POST_SB -> this.handHistory.smallBlind = amount
Action.Type.POST_SB -> this.handHistory.oldSmallBlind = amount
Action.Type.POST_BB -> {
this.handHistory.bigBlind = amount
this.handHistory.oldBigBlind = amount
if (this.handHistory.bigBlindAnte) {
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.formatted
import timber.log.Timber
import java.lang.Exception
import java.text.DecimalFormat
import java.text.ParseException
import kotlin.coroutines.CoroutineContext
@ -63,6 +62,10 @@ class EditorViewModel : ViewModel(), RowRepresentableDataSource, CardCentralizer
* The hand setup
*/
private var handSetup: HandSetup = HandSetup()
set(value) {
field = value
this.straddlePositions.addAll(value.straddlePositions)
}
/***
* 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(HandRowType.PLAYER_NUMBER)
if (this.handHistory.ante > 0) {
rows.add(HandRowType.ANTE)
this.handHistory.ante?.let {
if (it > 0) {
rows.add(HandRowType.ANTE)
}
}
if (this.handHistory.bigBlindAnte) {
@ -796,7 +801,7 @@ class EditorViewModel : ViewModel(), RowRepresentableDataSource, CardCentralizer
val string = when (row) {
HandRowType.PLAYER_NUMBER -> this.handHistory.numberOfPlayers.toString()
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.HERO_POSITION -> context.getString(R.string.set_hero_position)
// HandRowType.PLAYER_POSITION -> context.getString(R.string.set_position_details)
@ -901,8 +906,8 @@ class EditorViewModel : ViewModel(), RowRepresentableDataSource, CardCentralizer
fun changeStraddleSelection(positions: LinkedHashSet<Position>) {
if (positions.isEmpty()) {
this.firstStraddlePosition = null
this.handSetup.clearStraddles()
this.firstStraddlePosition = null
this.handSetup.clearStraddles()
} else {
if (this.firstStraddlePosition == null) {

@ -1,9 +1,16 @@
package net.pokeranalytics.android.ui.modules.handhistory.views
import android.content.Context
import android.util.AttributeSet
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
set(value) {

@ -1,6 +1,7 @@
package net.pokeranalytics.android.ui.modules.handhistory.views
import android.content.Context
import android.util.AttributeSet
import android.view.LayoutInflater
import android.view.inputmethod.EditorInfo
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.RowViewType
import net.pokeranalytics.android.util.extensions.noGroupingFormatted
import timber.log.Timber
import java.text.DecimalFormatSymbols
class NumericKey : RowRepresentable {
@ -63,9 +65,16 @@ class NumericKey : RowRepresentable {
}
class KeyboardAmountView(context: Context) : AbstractKeyboardView(context),
class KeyboardAmountView : AbstractKeyboardView,
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
*/
@ -144,16 +153,19 @@ class KeyboardAmountView(context: Context) : AbstractKeyboardView(context),
// Timber.d("edit text = $editText")
this.editText = editText
this.setInputConnection(editText)
editText.setText(amount?.noGroupingFormatted)
editText.requestFocus()
editText.isEnabled = true // avoid crashes due to input connection null
}
fun setInputConnection(editText: EditText) {
this.editText = editText
editText.onCreateInputConnection(EditorInfo())?.let {
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> {
@ -175,6 +187,8 @@ class KeyboardAmountView(context: Context) : AbstractKeyboardView(context),
val key = row as NumericKey
Timber.d("this.inputConnection = ${this.inputConnection}")
this.inputConnection?.let {
when {
@ -190,9 +204,7 @@ class KeyboardAmountView(context: Context) : AbstractKeyboardView(context),
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)
amount.text = handHistory.potSizeForStreet(Street.SUMMARY).formatted
val heroWins = handHistory.heroWins
val colorId = when(heroWins) {
val colorId = when(handHistory.heroWins) {
true -> R.color.green
false -> R.color.red
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.interfaces.SaveValidityStatus
import net.pokeranalytics.android.model.realm.*
import net.pokeranalytics.android.util.CrashLogging
import net.pokeranalytics.android.model.utils.FavoriteSessionFinder
import net.pokeranalytics.android.ui.adapter.RowRepresentableAdapter
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.view.*
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.extensions.*
import timber.log.Timber
@ -206,9 +206,10 @@ class SessionFragment : RealmFragment(), RowRepresentableDelegate, StaticRowRepr
currentSession.location = realmLocation
}
updateSessionUI(true)
this.updateSessionUI(true)
}
}
sessionHasBeenUserCustomized = false
}
}
@ -264,7 +265,7 @@ class SessionFragment : RealmFragment(), RowRepresentableDelegate, StaticRowRepr
when (row) {
SessionPropertiesRow.CASHED_OUT, SessionPropertiesRow.PRIZE, SessionPropertiesRow.NET_RESULT,
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 -> {
updateSessionUI()
updateMenuUI() // result capture method
@ -577,15 +578,15 @@ class SessionFragment : RealmFragment(), RowRepresentableDelegate, StaticRowRepr
"defaultValue" to session.tableSize
)
)
SessionPropertiesRow.BLINDS -> row.editingDescriptors(
SessionPropertiesRow.STAKES -> row.editingDescriptors(
mapOf(
"sb" to session.cgSmallBlind?.round(),
"bb" to session.cgBigBlind?.round()
"blinds" to session.cgBlinds,
"ante" to session.cgAnte
)
)
SessionPropertiesRow.BUY_IN -> row.editingDescriptors(
mapOf(
"bb" to session.cgBigBlind,
"bb" to session.cgBiggestBet,
"fee" to session.tournamentEntryFee,
"ratedBuyin" to session.result?.buyin
)
@ -626,10 +627,15 @@ class SessionFragment : RealmFragment(), RowRepresentableDelegate, StaticRowRepr
"defaultValue" to session.handsCount
)
)
SessionPropertiesRow.NUMBER_OF_TABLES -> row.editingDescriptors(
mapOf(
"defaultValue" to session.numberOfTables
)
)
SessionPropertiesRow.TIPS -> row.editingDescriptors(
mapOf(
"sb" to session.cgSmallBlind?.round(),
"bb" to session.cgBigBlind?.round(),
"sb" to session.cgBiggestBet?.round(),
"bb" to session.cgBiggestBet?.round(),
"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
)
CASH -> arrayListOf(
Blind
Stakes
)
TOURNAMENT -> arrayListOf(
TournamentType,

@ -26,7 +26,7 @@ sealed class FilterSectionRow(override val resId: Int?) : RowRepresentable {
object SessionDuration: FilterSectionRow(R.string.session_duration)
object TimeFrameRange: FilterSectionRow(R.string.hour_slot)
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 TournamentType: FilterSectionRow(R.string.tournament_types)
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())
// Cash
Blind -> Criteria.Blinds.queryConditions.mapFirstCondition()
Stakes -> Criteria.Stakes.queryConditions.mapFirstCondition()
// CashRebuyCount -> QueryCondition.moreOrLess<QueryCondition.Rebuy>()
// Tournament

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

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

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

@ -90,9 +90,13 @@ class FakeDataManager {
if (isTournament) {
session.tournamentEntryFee = buyin
} else {
val bigBlind = arrayListOf(1.0, 2.0, 4.0).random()
session.cgBigBlind = bigBlind
session.cgSmallBlind = bigBlind / 2.0
session.cgAnte = arrayListOf(1.0, null).random()
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 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_SESSION_SETS("patchSessionSet"),
PATCH_TRANSACTION_TYPES_NAMES("patchTransactionTypesNames"),
PATCH_BLINDS_FORMAT("patchBlindFormat"),
// PATCH_BLINDS_FORMAT("patchBlindFormat"),
PATCH_COMPUTABLE_RESULTS("patchPositiveSessions"),
SHOW_STOP_NOTIFICATIONS("showStopNotifications"),
ADD_NEW_TRANSACTION_TYPES("addNewTransactionTypes"),
@ -43,7 +43,8 @@ class Preferences {
LAST_BLOG_TIPS_RETRIEVAL("lastBlogTipsRetrieval"),
SHOW_BLOG_TIPS("showBlogTips"),
LAST_REVIEW_REQUEST_DATE("lastReviewRequestDate"),
PATCH_NEGATIVE_LIMITS("negativeLimits")
PATCH_NEGATIVE_LIMITS("negativeLimits"),
PATCH_STAKES("patchStakes")
}
enum class FeedMessage {

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

@ -18,6 +18,7 @@ class ImportException(message: String) : Exception(message)
interface ImportDelegate {
fun parsingCountUpdate(importedCount: Int, totalCount: Int)
fun exceptionCaught(e: Exception)
}
/**
@ -107,7 +108,7 @@ open class CSVImporter(istream: InputStream) {
realm.beginTransaction()
parser.forEachIndexed { index, record ->
this.parser.forEachIndexed { index, record ->
// Timber.d("line $index")
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)
this.descriptorFindingAttempts = 0
} else {
val count = it.parse(realm, record)
this.importedRecords += count
this.totalParsedRecords++
try {
val count = it.parse(realm, record)
this.importedRecords += count
this.totalParsedRecords++
this.notifyDelegate()
} catch (e: Exception) {
this.delegate?.exceptionCaught(e)
}
this.notifyDelegate()
}
} ?: run {
realm.cancelTransaction()

@ -1,19 +1,21 @@
package net.pokeranalytics.android.util.csv
import net.pokeranalytics.android.model.interfaces.Identifiable
import io.realm.Realm
import net.pokeranalytics.android.exceptions.PAIllegalStateException
import net.pokeranalytics.android.model.Limit
import net.pokeranalytics.android.model.TableSize
import net.pokeranalytics.android.model.TournamentType
import net.pokeranalytics.android.model.interfaces.Identifiable
import net.pokeranalytics.android.model.realm.*
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.getOrCreate
import net.pokeranalytics.android.util.extensions.setHourMinutes
import org.apache.commons.csv.CSVRecord
import timber.log.Timber
import java.text.DateFormat
import java.text.NumberFormat
import java.text.ParseException
import java.text.SimpleDateFormat
import java.util.*
@ -57,6 +59,9 @@ abstract class PACSVDescriptor<T : Identifiable>(source: DataSource,
var stackingIn: Double? = null
var stackingOut: Double? = null
var sb: Double? = null
var bb: Double? = null
this.fields.forEach { field ->
this.fieldMapping[field]?.let { index ->
@ -75,7 +80,9 @@ abstract class PACSVDescriptor<T : Identifiable>(source: DataSource,
} else {}
}
is SessionField.End -> {
endDate = parseDate(field, value)
if (value.isNotEmpty()) {
endDate = parseDate(field, value)
}
}
is SessionField.StartTime -> {
startDate?.setHourMinutes(value)
@ -169,38 +176,17 @@ abstract class PACSVDescriptor<T : Identifiable>(source: DataSource,
is SessionField.Bankroll -> bankrollName = value
is SessionField.LimitType -> session.limit = Limit.getInstance(value)?.ordinal
is SessionField.Comment -> session.comment = value
is SessionField.Blind -> { // 1/2
val blinds = field.parse(value)
session.cgSmallBlind = blinds?.first
session.cgBigBlind = blinds?.second
is SessionField.Blind, is SessionField.Blinds -> { // 1/2
session.cgBlinds = value
}
is SessionField.SmallBlind -> {
val sb = field.parse(value)
if (sb != null && sb > 0.0) {
session.cgSmallBlind = sb
} else {}
sb = field.parse(value)
}
is SessionField.BigBlind -> {
val 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())
}
}
bb = field.parse(value)
}
is SessionField.Ante -> {
// unmanaged atm
session.cgAnte = field.parse(value)
}
is SessionField.TableSize -> session.tableSize = TableSize.valueForLabel(value)
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)
session.bankroll = bankroll
@ -264,9 +255,9 @@ abstract class PACSVDescriptor<T : Identifiable>(source: DataSource,
}
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
val count = DataUtils.sessionCount(realm, startDate!!, endDate!!, net)
val count = DataUtils.sessionCount(realm, startDate!!, endDate, net)
if (this.noSessionImport || count == 0) {
val managedSession = realm.copyToRealm(session)

@ -18,7 +18,8 @@ class ProductCSVDescriptors {
runGoodTournaments,
pokerAnalyticsiOS,
pokerAnalytics6iOS,
pokerAnalyticsAndroid,
pokerAnalyticsAndroidSessions,
pokerAnalyticsAndroid6Sessions,
pokerAnalyticsAndroidTransactions
)
@ -239,7 +240,7 @@ class ProductCSVDescriptors {
)
}
val pokerAnalyticsAndroid: SessionCSVDescriptor
val pokerAnalyticsAndroidSessions: SessionCSVDescriptor
get() {
return SessionCSVDescriptor(
DataSource.POKER_ANALYTICS,
@ -273,6 +274,42 @@ class ProductCSVDescriptors {
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.Session
import org.apache.commons.csv.CSVRecord
import timber.log.Timber
/**
* 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.CurrencyCode -> data.bankroll?.currency?.code
is SessionField.CurrencyRate -> field.format(data.bankroll?.currency?.rate)
is SessionField.SmallBlind -> field.format(data.cgSmallBlind)
is SessionField.BigBlind -> field.format(data.cgBigBlind)
// is SessionField.SmallBlind -> field.format(data.cgSmallBlind)
// 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.TournamentTypeName -> {
data.tournamentType?.let { tt ->

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

@ -7,23 +7,23 @@
android:layout_height="match_parent">
<LinearLayout
android:id="@+id/menuContainer"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginEnd="16dp"
android:layout_marginBottom="72dp"
android:background="@color/kaki_darker"
android:elevation="4dp"
android:orientation="vertical"
android:visibility="invisible"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
tools:visibility="visible">
android:id="@+id/menuContainer"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginEnd="16dp"
android:layout_marginBottom="72dp"
android:background="@color/kaki_darkest"
android:elevation="4dp"
android:orientation="vertical"
android:visibility="invisible"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
tools:visibility="visible">
<LinearLayout
android:id="@+id/newTransaction"
android:layout_width="match_parent"
android:layout_width="wrap_content"
android:layout_height="48dp"
android:layout_marginBottom="8dp"
android:background="?selectableItemBackground"
@ -50,9 +50,8 @@
<LinearLayout
android:id="@+id/new_hand_history"
android:layout_width="match_parent"
android:layout_width="wrap_content"
android:layout_height="48dp"
android:layout_marginBottom="8dp"
android:background="?selectableItemBackground"
android:gravity="center_vertical"
android:orientation="horizontal"
@ -76,7 +75,7 @@
<LinearLayout
android:id="@+id/newTournament"
android:layout_width="match_parent"
android:layout_width="wrap_content"
android:layout_height="48dp"
android:background="?selectableItemBackground"
android:gravity="center_vertical"
@ -101,29 +100,29 @@
</LinearLayout>
<LinearLayout
android:id="@+id/newCashGame"
android:layout_width="match_parent"
android:layout_height="48dp"
android:layout_marginTop="8dp"
android:background="?selectableItemBackground"
android:gravity="center_vertical"
android:orientation="horizontal"
android:paddingStart="16dp"
android:paddingEnd="16dp">
android:id="@+id/newCashGame"
android:layout_width="wrap_content"
android:layout_height="48dp"
android:layout_marginTop="8dp"
android:background="?selectableItemBackground"
android:gravity="center_vertical"
android:orientation="horizontal"
android:paddingStart="16dp"
android:paddingEnd="16dp">
<androidx.appcompat.widget.AppCompatImageView
android:layout_width="32dp"
android:layout_height="32dp"
android:tint="@color/green"
app:srcCompat="@drawable/add_cash_game" />
android:layout_width="32dp"
android:layout_height="32dp"
android:tint="@color/green"
app:srcCompat="@drawable/add_cash_game" />
<androidx.appcompat.widget.AppCompatTextView
style="@style/PokerAnalyticsTheme.TextView.RowTitle"
android:layout_width="160dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:text="@string/new_cash_game"
app:layout_constraintEnd_toEndOf="parent" />
style="@style/PokerAnalyticsTheme.TextView.RowTitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:text="@string/new_cash_game"
app:layout_constraintEnd_toEndOf="parent" />
</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
android:id="@+id/actionButton"
style="@style/PokerAnalyticsTheme.HHButton"
android:layout_width="84dp"
android:layout_width="92dp"
android:layout_height="44dp"
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_initial_en_bb_">Tapis initial (en grosses blindes)</string>
<string name="stacks">Tapis</string>
<string name="stakes">Montants</string>
<string name="stakes">Mises</string>
<string name="standard">Standard</string>
<string name="standard_deviation">Ecart type</string>
<string name="start">Démarrer</string>
@ -778,4 +778,5 @@
<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="dealt_hands_per_hour">Mains par heure</string>
<string name="errors">erreur(s)</string>
</resources>

@ -821,5 +821,6 @@
<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="proceed">proceed</string>
<string name="errors">error(s)</string>
</resources>

@ -386,6 +386,32 @@
<item name="backgroundTint">@color/kaki_darker</item>
</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">
<!-- <item name="android:backgroundTint">@color/kaki_light</item>-->
<!-- <item name="android:background">@drawable/circle</item>-->

Loading…
Cancel
Save