Compare commits

...

46 Commits

Author SHA1 Message Date
Laurent cd6d5ab2ae Change placeholder when player name is empty 6 years ago
Laurent 26cd102e46 code refactoring 6 years ago
Laurent 73b72deeb9 Player UI minor update 6 years ago
Laurent d9c07bf291 gradle update 6 years ago
Laurent ea8bad6acc excluded build favlors 6 years ago
Aurelien Hubert c734898241 Update style for Player details 6 years ago
Aurelien Hubert 75a2248469 Add fake players data 6 years ago
Aurelien Hubert dcc6be514a Improve search behavior 6 years ago
Aurelien Hubert eef60124ed Add search for DataList 6 years ago
Aurelien Hubert 1aef1c9745 Clean code 6 years ago
Aurelien Hubert 28699f594f Avoid to display initial when user has an picture 6 years ago
Aurelien Hubert f1b47a6e51 Update dependance and clean code 6 years ago
Aurelien Hubert 3843ab4185 Update dialog dependance 6 years ago
Aurelien Hubert 75b4097851 Improve UI 6 years ago
Aurelien Hubert 071a39c241 Clean code 6 years ago
Aurelien Hubert dff498ffa5 Add creation test 6 years ago
Aurelien Hubert d90aaa72bc Improve comment deletion 6 years ago
Aurelien Hubert 9ad428152c Improve comments for Player 6 years ago
Aurelien Hubert 54b6457fc9 Working on player comments 6 years ago
Aurelien Hubert 48868992a4 Improve UI when view is not clickable 6 years ago
Aurelien Hubert 358c65f9aa Add color picker for player 6 years ago
Aurelien Hubert 5dfb008261 Clean code 6 years ago
Aurelien Hubert 3fa447e26c Fix player creation / edition 6 years ago
Aurelien Hubert 599c29989a Add link to players 6 years ago
Aurelien Hubert 2ca63b3a1a Fix camera & library management 6 years ago
Aurelien Hubert 2751850a92 Merge branch 'dev' of gitlab.com:stax-river/poker-analytics into feature/players 6 years ago
Razmig Sarkissian 7abf6fd268 delete unused LocaleUtils 6 years ago
Razmig Sarkissian 7474b33a7e renaming exception 6 years ago
Razmig Sarkissian 7653ea86ce Merge branch 'master' into dev 6 years ago
Razmig Sarkissian c025f35d43 rename bottomsheetFragment to inputFragment for clarity 6 years ago
Razmig Sarkissian e8f83ba08b clean up bottom sheet and datetimepicker management 6 years ago
Razmig Sarkissian 8835a7d4d6 fix crash when creating a new transaction 6 years ago
Razmig Sarkissian 5882fd8cd6 WIP refactoring editDescriptor 6 years ago
Razmig Sarkissian 63d6c9b5b9 wip refactoring editDescriptor 6 years ago
Razmig Sarkissian 20494c7849 Merge branch 'master' into dev 6 years ago
Razmig Sarkissian 5689b8dfe4 wip refactoring editDescriptor 6 years ago
Razmig Sarkissian a2e9b8309c Merge branch 'master' into dev 6 years ago
Razmig Sarkissian ac2000ea8c Merge branch 'master' into dev 6 years ago
Razmig Sarkissian 86a2f3bb1b Merge branch 'master' into dev 6 years ago
Razmig Sarkissian fa5e098b31 fix issue with current week filter 6 years ago
Aurelien Hubert 45bdd93b78 Improve swipe to delete for players 7 years ago
Aurelien Hubert f1423257b1 Improve Player management 7 years ago
Aurelien Hubert 047a08c2a0 Clean Player code 7 years ago
Aurelien Hubert b1064100a6 Improve Player picture management 7 years ago
Aurelien Hubert c2f79015bc Improve Player details, work in progress 7 years ago
Aurelien Hubert 75248ffdec Add Players view 7 years ago
  1. 3
      .gitignore
  2. 10
      app/build.gradle
  3. 25
      app/src/main/AndroidManifest.xml
  4. 2
      app/src/main/java/net/pokeranalytics/android/PokerAnalyticsApplication.kt
  5. 2
      app/src/main/java/net/pokeranalytics/android/exceptions/Exceptions.kt
  6. 5
      app/src/main/java/net/pokeranalytics/android/model/LiveData.kt
  7. 14
      app/src/main/java/net/pokeranalytics/android/model/filter/QueryCondition.kt
  8. 304
      app/src/main/java/net/pokeranalytics/android/model/migrations/PokerAnalyticsMigration.kt
  9. 12
      app/src/main/java/net/pokeranalytics/android/model/realm/Bankroll.kt
  10. 83
      app/src/main/java/net/pokeranalytics/android/model/realm/Comment.kt
  11. 70
      app/src/main/java/net/pokeranalytics/android/model/realm/CustomField.kt
  12. 25
      app/src/main/java/net/pokeranalytics/android/model/realm/CustomFieldEntry.kt
  13. 27
      app/src/main/java/net/pokeranalytics/android/model/realm/Filter.kt
  14. 18
      app/src/main/java/net/pokeranalytics/android/model/realm/Game.kt
  15. 172
      app/src/main/java/net/pokeranalytics/android/model/realm/Player.kt
  16. 111
      app/src/main/java/net/pokeranalytics/android/model/realm/Session.kt
  17. 2
      app/src/main/java/net/pokeranalytics/android/model/realm/TimeFrame.kt
  18. 14
      app/src/main/java/net/pokeranalytics/android/model/realm/TournamentFeature.kt
  19. 13
      app/src/main/java/net/pokeranalytics/android/model/realm/TournamentName.kt
  20. 11
      app/src/main/java/net/pokeranalytics/android/model/realm/TransactionType.kt
  21. 2
      app/src/main/java/net/pokeranalytics/android/model/utils/SessionSetManager.kt
  22. 77
      app/src/main/java/net/pokeranalytics/android/ui/activity/ColorPickerActivity.kt
  23. 33
      app/src/main/java/net/pokeranalytics/android/ui/activity/ComparisonChartActivity.kt
  24. 35
      app/src/main/java/net/pokeranalytics/android/ui/activity/EditableDataActivity.kt
  25. 268
      app/src/main/java/net/pokeranalytics/android/ui/activity/components/MediaActivity.kt
  26. 2
      app/src/main/java/net/pokeranalytics/android/ui/activity/components/PokerAnalyticsActivity.kt
  27. 4
      app/src/main/java/net/pokeranalytics/android/ui/adapter/HomePagerAdapter.kt
  28. 9
      app/src/main/java/net/pokeranalytics/android/ui/adapter/RowRepresentableAdapter.kt
  29. 15
      app/src/main/java/net/pokeranalytics/android/ui/adapter/RowRepresentableDataSource.kt
  30. 14
      app/src/main/java/net/pokeranalytics/android/ui/extensions/UIExtensions.kt
  31. 10
      app/src/main/java/net/pokeranalytics/android/ui/fragment/BankrollDetailsFragment.kt
  32. 115
      app/src/main/java/net/pokeranalytics/android/ui/fragment/ComparisonChartFragment.kt
  33. 122
      app/src/main/java/net/pokeranalytics/android/ui/fragment/DataListFragment.kt
  34. 15
      app/src/main/java/net/pokeranalytics/android/ui/fragment/FeedFragment.kt
  35. 32
      app/src/main/java/net/pokeranalytics/android/ui/fragment/FilterDetailsFragment.kt
  36. 10
      app/src/main/java/net/pokeranalytics/android/ui/fragment/FiltersFragment.kt
  37. 12
      app/src/main/java/net/pokeranalytics/android/ui/fragment/FiltersListFragment.kt
  38. 196
      app/src/main/java/net/pokeranalytics/android/ui/fragment/MoreFragment.kt
  39. 14
      app/src/main/java/net/pokeranalytics/android/ui/fragment/ReportCreationFragment.kt
  40. 42
      app/src/main/java/net/pokeranalytics/android/ui/fragment/SessionFragment.kt
  41. 198
      app/src/main/java/net/pokeranalytics/android/ui/fragment/SettingsFragment.kt
  42. 2
      app/src/main/java/net/pokeranalytics/android/ui/fragment/components/DeletableItemFragment.kt
  43. 7
      app/src/main/java/net/pokeranalytics/android/ui/fragment/components/FilterableFragment.kt
  44. 2
      app/src/main/java/net/pokeranalytics/android/ui/fragment/components/LoaderDialogFragment.kt
  45. 13
      app/src/main/java/net/pokeranalytics/android/ui/fragment/components/PokerAnalyticsFragment.kt
  46. 50
      app/src/main/java/net/pokeranalytics/android/ui/fragment/components/bottomsheet/BottomSheetType.kt
  47. 8
      app/src/main/java/net/pokeranalytics/android/ui/fragment/components/input/InputDoubleEditTextFragment.kt
  48. 8
      app/src/main/java/net/pokeranalytics/android/ui/fragment/components/input/InputEditTextFragment.kt
  49. 8
      app/src/main/java/net/pokeranalytics/android/ui/fragment/components/input/InputEditTextMultiLinesFragment.kt
  50. 70
      app/src/main/java/net/pokeranalytics/android/ui/fragment/components/input/InputFragment.kt
  51. 50
      app/src/main/java/net/pokeranalytics/android/ui/fragment/components/input/InputFragmentType.kt
  52. 17
      app/src/main/java/net/pokeranalytics/android/ui/fragment/components/input/InputListFragment.kt
  53. 17
      app/src/main/java/net/pokeranalytics/android/ui/fragment/components/input/InputListGameFragment.kt
  54. 8
      app/src/main/java/net/pokeranalytics/android/ui/fragment/components/input/InputMultiSelectionFragment.kt
  55. 8
      app/src/main/java/net/pokeranalytics/android/ui/fragment/components/input/InputNumericTextFragment.kt
  56. 17
      app/src/main/java/net/pokeranalytics/android/ui/fragment/components/input/InputStaticListFragment.kt
  57. 8
      app/src/main/java/net/pokeranalytics/android/ui/fragment/components/input/InputSumFragment.kt
  58. 8
      app/src/main/java/net/pokeranalytics/android/ui/fragment/components/input/InputTableSizeGridFragment.kt
  59. 20
      app/src/main/java/net/pokeranalytics/android/ui/fragment/data/BankrollDataFragment.kt
  60. 21
      app/src/main/java/net/pokeranalytics/android/ui/fragment/data/CustomFieldDataFragment.kt
  61. 13
      app/src/main/java/net/pokeranalytics/android/ui/fragment/data/DataManagerFragment.kt
  62. 4
      app/src/main/java/net/pokeranalytics/android/ui/fragment/data/EditableDataFragment.kt
  63. 15
      app/src/main/java/net/pokeranalytics/android/ui/fragment/data/LocationDataFragment.kt
  64. 205
      app/src/main/java/net/pokeranalytics/android/ui/fragment/data/PlayerDataFragment.kt
  65. 40
      app/src/main/java/net/pokeranalytics/android/ui/fragment/data/TransactionDataFragment.kt
  66. 5
      app/src/main/java/net/pokeranalytics/android/ui/fragment/data/TransactionTypeDataFragment.kt
  67. 69
      app/src/main/java/net/pokeranalytics/android/ui/helpers/DateTimePickerManager.kt
  68. 144
      app/src/main/java/net/pokeranalytics/android/ui/view/PlayerImageView.kt
  69. 92
      app/src/main/java/net/pokeranalytics/android/ui/view/RowEditableDescriptor.kt
  70. 23
      app/src/main/java/net/pokeranalytics/android/ui/view/RowRepresentable.kt
  71. 14
      app/src/main/java/net/pokeranalytics/android/ui/view/RowRepresentableEditDescriptor.kt
  72. 69
      app/src/main/java/net/pokeranalytics/android/ui/view/RowViewType.kt
  73. 67
      app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/BankrollRow.kt
  74. 33
      app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/CustomFieldRow.kt
  75. 44
      app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/FilterElementRow.kt
  76. 31
      app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/GameRow.kt
  77. 34
      app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/LocationRow.kt
  78. 34
      app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/MoreTabRow.kt
  79. 63
      app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/PlayerRow.kt
  80. 545
      app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/SessionRow.kt
  81. 7
      app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/SettingRow.kt
  82. 7
      app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/SimpleRow.kt
  83. 47
      app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/TournamentFeatureRow.kt
  84. 47
      app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/TournamentNameRow.kt
  85. 99
      app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/TransactionRow.kt
  86. 32
      app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/TransactionTypeRow.kt
  87. 22
      app/src/main/java/net/pokeranalytics/android/util/FakeDataManager.kt
  88. 377
      app/src/main/java/net/pokeranalytics/android/util/ImageUtils.kt
  89. 36
      app/src/main/java/net/pokeranalytics/android/util/LocaleUtils.kt
  90. 2
      app/src/main/java/net/pokeranalytics/android/util/LocationManager.kt
  91. 27
      app/src/main/java/net/pokeranalytics/android/util/extensions/RealmExtensions.kt
  92. 15
      app/src/main/res/drawable/circle_player_color_1.xml
  93. 11
      app/src/main/res/drawable/circle_player_color_2.xml
  94. 11
      app/src/main/res/drawable/circle_player_color_3.xml
  95. 11
      app/src/main/res/drawable/circle_player_color_4.xml
  96. 11
      app/src/main/res/drawable/circle_player_color_5.xml
  97. 11
      app/src/main/res/drawable/circle_player_color_6.xml
  98. 11
      app/src/main/res/drawable/circle_player_color_7.xml
  99. 11
      app/src/main/res/drawable/circle_player_color_8.xml
  100. 11
      app/src/main/res/drawable/circle_player_color_9.xml
  101. Some files were not shown because too many files have changed in this diff Show More

3
.gitignore vendored

@ -22,6 +22,7 @@ gen/
.gradle/
build/
/*/build/
app/*2020
# Local configuration file (sdk path, etc)
local.properties
@ -42,4 +43,4 @@ gen-external-apklibs
# Libraries
/libs/*/*/build
/captures
/captures

@ -49,7 +49,7 @@ android {
def appName = "PokerAnalytics"
def buildType = variant.variantData.variantConfiguration.buildType.name
def newName
if (buildType == 'debug'){
if (buildType == 'debug') {
newName = "${appName}_${defaultConfig.versionName}(${defaultConfig.versionCode})_${formattedDate}_debug.apk"
} else {
newName = "${appName}_${defaultConfig.versionName}(${defaultConfig.versionCode})_${formattedDate}_release.apk"
@ -72,13 +72,13 @@ dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
// Kotlin
implementation"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.1.1'
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.1.1"
implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
// Android
implementation 'androidx.appcompat:appcompat:1.0.2'
implementation 'androidx.appcompat:appcompat:1.1.0-rc01'
implementation 'androidx.core:core-ktx:1.2.0-alpha02'
implementation 'com.google.android.material:material:1.0.0'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
@ -91,6 +91,10 @@ dependencies {
implementation 'com.squareup.okhttp3:logging-interceptor:3.9.1'
implementation 'com.google.code.gson:gson:2.8.5'
// Glide
implementation 'com.github.bumptech.glide:glide:4.9.0'
annotationProcessor 'com.github.bumptech.glide:compiler:4.9.0'
// Places
implementation 'com.google.android.libraries.places:places:1.1.0'

@ -22,8 +22,8 @@
<activity
android:name="net.pokeranalytics.android.ui.activity.HomeActivity"
android:launchMode="singleTop"
android:label="@string/app_name"
android:launchMode="singleTop"
android:screenOrientation="portrait">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
@ -36,8 +36,8 @@
<activity
android:name="net.pokeranalytics.android.ui.activity.ImportActivity"
android:screenOrientation="portrait"
android:launchMode="singleTop">
android:launchMode="singleTop"
android:screenOrientation="portrait">
<intent-filter tools:ignore="AppLinkUrlError">
<action android:name="android.intent.action.VIEW" />
@ -79,6 +79,12 @@
android:launchMode="singleTop"
android:screenOrientation="portrait" />
<activity
android:name="net.pokeranalytics.android.ui.activity.ColorPickerActivity"
android:theme="@style/PokerAnalyticsTheme.AlertDialog"
android:launchMode="singleTop"
android:screenOrientation="portrait" />
<activity
android:name="net.pokeranalytics.android.ui.activity.SettingsActivity"
android:launchMode="singleTop"
@ -104,11 +110,6 @@
android:launchMode="singleTop"
android:screenOrientation="portrait" />
<activity
android:name="net.pokeranalytics.android.ui.activity.ComparisonChartActivity"
android:launchMode="singleTop"
android:screenOrientation="portrait" />
<activity
android:name="net.pokeranalytics.android.ui.activity.DataListActivity"
android:launchMode="singleTop"
@ -154,10 +155,10 @@
android:launchMode="singleTop"
android:screenOrientation="portrait" />
<activity
android:name="net.pokeranalytics.android.ui.activity.TableReportActivity"
android:launchMode="singleTop"
android:screenOrientation="portrait" />
<activity
android:name="net.pokeranalytics.android.ui.activity.TableReportActivity"
android:launchMode="singleTop"
android:screenOrientation="portrait" />
<meta-data
android:name="preloaded_fonts"

@ -33,7 +33,7 @@ class PokerAnalyticsApplication : Application() {
Realm.init(this)
val realmConfiguration = RealmConfiguration.Builder()
.name(Realm.DEFAULT_REALM_NAME)
.schemaVersion(7)
.schemaVersion(8)
.migration(PokerAnalyticsMigration())
.initialData(Seed(this))
.build()

@ -21,6 +21,8 @@ sealed class PokerAnalyticsException(message: String) : Exception(message) {
object QueryTypeUnhandled: PokerAnalyticsException(message = "queryWith type not handled")
object QueryValueMapUnexpectedValue: PokerAnalyticsException(message = "valueMap null not expected")
object FilterElementExpectedValueMissing : PokerAnalyticsException(message = "queryWith is empty or null")
object InputFragmentException : PokerAnalyticsException(message = "RowEditableDelegate must be a Fragment")
object DateTimePickerException: PokerAnalyticsException(message = "DataSource is not a DateRowEditableDescriptor")
data class FilterElementTypeMissing(val filterElementRow: FilterElementRow) : PokerAnalyticsException(message = "queryWith element '$filterElementRow' type is missing")
data class QueryValueMapMissingKeys(val missingKeys: List<String>) : PokerAnalyticsException(message = "valueMap does not contain $missingKeys")
data class UnknownQueryTypeForRow(val filterElementRow: FilterElementRow) : PokerAnalyticsException(message = "no queryWith type for $filterElementRow")

@ -20,6 +20,7 @@ enum class LiveData : Localizable {
TRANSACTION,
TRANSACTION_TYPE,
FILTER,
PLAYER,
CUSTOM_FIELD,
REPORT_SETUP;
@ -36,6 +37,7 @@ enum class LiveData : Localizable {
TRANSACTION -> Transaction::class.java
TRANSACTION_TYPE -> TransactionType::class.java
FILTER -> Filter::class.java
PLAYER -> Player::class.java
CUSTOM_FIELD -> CustomField::class.java
REPORT_SETUP -> ReportSetup::class.java
}
@ -76,6 +78,7 @@ enum class LiveData : Localizable {
TRANSACTION -> R.string.operation
TRANSACTION_TYPE -> R.string.operation_type
FILTER -> R.string.filter
PLAYER -> R.string.player
CUSTOM_FIELD -> R.string.custom_field
REPORT_SETUP -> R.string.custom
}
@ -92,6 +95,7 @@ enum class LiveData : Localizable {
TRANSACTION -> R.string.operations
TRANSACTION_TYPE -> R.string.operation_types
FILTER -> R.string.filters
PLAYER -> R.string.players
CUSTOM_FIELD -> R.string.custom_fields
REPORT_SETUP -> R.string.custom
}
@ -108,6 +112,7 @@ enum class LiveData : Localizable {
TRANSACTION -> R.string.new_operation
TRANSACTION_TYPE -> R.string.new_operation_type
FILTER -> R.string.new_filter
PLAYER -> R.string.new_friend
CUSTOM_FIELD -> R.string.new_custom_field
REPORT_SETUP -> R.string.new_report
}

@ -15,7 +15,7 @@ import net.pokeranalytics.android.model.TournamentType
import net.pokeranalytics.android.model.interfaces.Identifiable
import net.pokeranalytics.android.model.interfaces.NameManageable
import net.pokeranalytics.android.model.realm.*
import net.pokeranalytics.android.ui.fragment.components.bottomsheet.BottomSheetType
import net.pokeranalytics.android.ui.fragment.components.input.InputFragmentType
import net.pokeranalytics.android.ui.view.RowViewType
import net.pokeranalytics.android.ui.view.rowrepresentable.FilterElementRow
import net.pokeranalytics.android.ui.view.rowrepresentable.FilterSectionRow
@ -593,7 +593,7 @@ sealed class QueryCondition : FilterElementRow {
}
override val viewType: Int = RowViewType.TITLE_VALUE_CHECK.ordinal
override val bottomSheetType: BottomSheetType = BottomSheetType.DOUBLE_EDIT_TEXT
override val inputFragmentType: InputFragmentType = InputFragmentType.DOUBLE_EDIT_TEXT
override fun labelForValue(value: Int, context: Context): String {
return value.toMinutes(context)
@ -952,15 +952,15 @@ sealed class QueryCondition : FilterElementRow {
}
}
override val bottomSheetType: BottomSheetType
override val inputFragmentType: InputFragmentType
get() {
return when (this) {
is PastDay -> BottomSheetType.EDIT_TEXT
is PastDay -> InputFragmentType.EDIT_TEXT
else -> {
when (this.operator) {
Operator.MORE -> BottomSheetType.EDIT_TEXT
Operator.LESS -> BottomSheetType.EDIT_TEXT
else -> BottomSheetType.NONE
Operator.MORE -> InputFragmentType.EDIT_TEXT
Operator.LESS -> InputFragmentType.EDIT_TEXT
else -> InputFragmentType.NONE
}
}
}

@ -2,156 +2,176 @@ package net.pokeranalytics.android.model.migrations
import io.realm.DynamicRealm
import io.realm.RealmMigration
import net.pokeranalytics.android.model.realm.Comment
import timber.log.Timber
import java.util.*
class PokerAnalyticsMigration : RealmMigration {
override fun migrate(realm: DynamicRealm, oldVersion: Long, newVersion: Long) {
// DynamicRealm exposes an editable schema
val schema = realm.schema
var currentVersion = oldVersion.toInt()
Timber.d("*** migrate from $oldVersion to $newVersion")
// Migrate to version 1
if (currentVersion == 0) {
Timber.d("*** Running migration 1")
schema.get("Filter")?.addField("entityType", Int::class.java)?.setNullable("entityType", true)
schema.get("FilterElement")?.let {
it.setNullable("filterName", true)
it.setNullable("sectionName", true)
}
schema.get("FilterElementBlind")?.renameField("code", "currencyCode")
currentVersion++
}
// Migrate to version 2
if (currentVersion == 1) {
Timber.d("*** Running migration ${currentVersion + 1}")
schema.rename("FilterElement", "FilterCondition")
schema.get("Filter")?.renameField("filterElements", "filterConditions")
schema.get("SessionSet")?.let {
it.addField("id", String::class.java).setRequired("id", true)
it.addPrimaryKey("id")
}
currentVersion++
}
// Migrate to version 3
if (currentVersion == 2) {
Timber.d("*** Running migration ${currentVersion + 1}")
schema.rename("Report", "ReportSetup")
schema.get("Filter")?.removeField("entityType")
schema.get("Session")?.let {
it.addField("blinds", String::class.java).transform {
}
}
schema.get("FilterCondition")?.let {
it.removeField("blindValues")
it.removeField("numericValues")
it.addField("operator", Integer::class.java)
it.addField("intValue", Integer::class.java)
it.addRealmListField("intValues", Integer::class.java)
it.addField("doubleValue", Double::class.java).setNullable("doubleValue", true)
it.addRealmListField("doubleValues", Double::class.java)
if (it.isRequired("doubleValues")) {
it.setRequired("doubleValues", false)
}
it.addField("stringValue", String::class.java)
}
schema.get("ComputableResult")?.removeField("sessionSet")
schema.get("Bankroll")?.addField("initialValue", Double::class.java)
currentVersion++
}
// Migrate to version 4
if (currentVersion == 3) {
Timber.d("*** Running migration ${currentVersion + 1}")
schema.get("Result")?.addField("numberOfRebuy", Double::class.java)?.setNullable("numberOfRebuy", true)
currentVersion++
}
// Migrate to version 5
if (currentVersion == 4) {
Timber.d("*** Running migration ${currentVersion + 1}")
schema.get("Bankroll")?.removeField("transactions")
currentVersion++
}
// Migrate to version 6
if (currentVersion == 5) {
Timber.d("*** Running migration ${currentVersion + 1}")
schema.get("Transaction")?.let {
it.addField("dayOfWeek", Integer::class.java)
it.addField("month", Integer::class.java)
it.addField("year", Integer::class.java)
it.addField("dayOfMonth", Integer::class.java)
}
val cfEntry = schema.create("CustomFieldEntry")?.let {
it.addField("id", String::class.java).setRequired("id", true)
it.addPrimaryKey("id")
it.addField("value", String::class.java).setNullable("value", false)
it.addField("order", Integer::class.java).setNullable("order", false)
// DynamicRealm exposes an editable schema
val schema = realm.schema
var currentVersion = oldVersion.toInt()
Timber.d("*** migrate from $oldVersion to $newVersion")
// Migrate to version 1
if (currentVersion == 0) {
Timber.d("*** Running migration 1")
schema.get("Filter")?.addField("entityType", Int::class.java)?.setNullable("entityType", true)
schema.get("FilterElement")?.let {
it.setNullable("filterName", true)
it.setNullable("sectionName", true)
}
schema.get("FilterElementBlind")?.renameField("code", "currencyCode")
currentVersion++
}
// Migrate to version 2
if (currentVersion == 1) {
Timber.d("*** Running migration ${currentVersion + 1}")
schema.rename("FilterElement", "FilterCondition")
schema.get("Filter")?.renameField("filterElements", "filterConditions")
schema.get("SessionSet")?.let {
it.addField("id", String::class.java).setRequired("id", true)
it.addPrimaryKey("id")
}
currentVersion++
}
// Migrate to version 3
if (currentVersion == 2) {
Timber.d("*** Running migration ${currentVersion + 1}")
schema.rename("Report", "ReportSetup")
schema.get("Filter")?.removeField("entityType")
schema.get("Session")?.let {
it.addField("blinds", String::class.java).transform {
}
}
schema.get("FilterCondition")?.let {
it.removeField("blindValues")
it.removeField("numericValues")
it.addField("operator", Integer::class.java)
it.addField("intValue", Integer::class.java)
it.addRealmListField("intValues", Integer::class.java)
it.addField("doubleValue", Double::class.java).setNullable("doubleValue", true)
it.addRealmListField("doubleValues", Double::class.java)
if (it.isRequired("doubleValues")) {
it.setRequired("doubleValues", false)
}
it.addField("stringValue", String::class.java)
}
schema.get("ComputableResult")?.removeField("sessionSet")
schema.get("Bankroll")?.addField("initialValue", Double::class.java)
currentVersion++
}
// Migrate to version 4
if (currentVersion == 3) {
Timber.d("*** Running migration ${currentVersion + 1}")
schema.get("Result")?.addField("numberOfRebuy", Double::class.java)?.setNullable("numberOfRebuy", true)
currentVersion++
}
// Migrate to version 5
if (currentVersion == 4) {
Timber.d("*** Running migration ${currentVersion + 1}")
schema.get("Bankroll")?.removeField("transactions")
currentVersion++
}
// Migrate to version 6
if (currentVersion == 5) {
Timber.d("*** Running migration ${currentVersion + 1}")
schema.get("Transaction")?.let {
it.addField("dayOfWeek", Integer::class.java)
it.addField("month", Integer::class.java)
it.addField("year", Integer::class.java)
it.addField("dayOfMonth", Integer::class.java)
}
val cfEntry = schema.create("CustomFieldEntry")?.let {
it.addField("id", String::class.java).setRequired("id", true)
it.addPrimaryKey("id")
it.addField("value", String::class.java).setNullable("value", false)
it.addField("order", Integer::class.java).setNullable("order", false)
// it.addRealmObjectField("customField", it).setNullable("customField", false)
it.addField("numericValue", Double::class.java).setNullable("numericValue", true)
}
cfEntry?.let { customFieldEntrySchema ->
schema.get("CustomField")?.let {
it.addField("type", Integer::class.java).setNullable("type", false)
it.addField("duplicateValue", Boolean::class.java)
it.addField("sortCondition", Integer::class.java).setRequired("sortCondition", true)
it.addRealmListField("entries", customFieldEntrySchema)
}
schema.get("Session")?.let {
it.addField("startDateHourMinuteComponent", Double::class.java)
.setNullable("startDateHourMinuteComponent", true)
it.addField("endDateHourMinuteComponent", Double::class.java)
.setNullable("endDateHourMinuteComponent", true)
it.addRealmListField("customFieldEntries", customFieldEntrySchema)
}
}
schema.get("ReportSetup")?.let {
it.addRealmListField("statIds", Int::class.java).setNullable("statIds", true)
it.addRealmListField("criteriaCustomFieldIds", String::class.java)
it.addRealmListField("criteriaIds", Int::class.java).setNullable("criteriaIds", true)
it.removeField("filters")
schema.get("Filter")?.let { filterSchema ->
it.addRealmObjectField("filter", filterSchema)
}
}
schema.get("Filter")?.addField("filterableTypeUniqueIdentifier", Integer::class.java)
schema.get("Filter")?.addField("useCount", Int::class.java)
schema.get("Filter")?.removeField("usageCount")
currentVersion++
}
// Migrate to version 7
if (currentVersion == 6) {
Timber.d("*** Running migration ${currentVersion + 1}")
schema.get("TransactionType")?.addField("useCount", Int::class.java)
currentVersion++
}
}
it.addField("numericValue", Double::class.java).setNullable("numericValue", true)
}
cfEntry?.let { customFieldEntrySchema ->
schema.get("CustomField")?.let {
it.addField("type", Integer::class.java).setNullable("type", false)
it.addField("duplicateValue", Boolean::class.java)
it.addField("sortCondition", Integer::class.java).setRequired("sortCondition", true)
it.addRealmListField("entries", customFieldEntrySchema)
}
schema.get("Session")?.let {
it.addField("startDateHourMinuteComponent", Double::class.java)
.setNullable("startDateHourMinuteComponent", true)
it.addField("endDateHourMinuteComponent", Double::class.java)
.setNullable("endDateHourMinuteComponent", true)
it.addRealmListField("customFieldEntries", customFieldEntrySchema)
}
}
schema.get("ReportSetup")?.let {
it.addRealmListField("statIds", Int::class.java).setNullable("statIds", true)
it.addRealmListField("criteriaCustomFieldIds", String::class.java)
it.addRealmListField("criteriaIds", Int::class.java).setNullable("criteriaIds", true)
it.removeField("filters")
schema.get("Filter")?.let { filterSchema ->
it.addRealmObjectField("filter", filterSchema)
}
}
schema.get("Filter")?.addField("filterableTypeUniqueIdentifier", Integer::class.java)
schema.get("Filter")?.addField("useCount", Int::class.java)
schema.get("Filter")?.removeField("usageCount")
currentVersion++
}
// Migrate to version 7
if (currentVersion == 6) {
Timber.d("*** Running migration ${currentVersion + 1}")
schema.get("TransactionType")?.addField("useCount", Int::class.java)
currentVersion++
}
// Migrate to version 8
if (currentVersion == 7) {
schema.create("Comment")?.let {
it.addField("id", String::class.java).setRequired("id", true)
it.addField("content", String::class.java)
it.addField("date", Date::class.java)
}
schema.get("Player")?.let {
it.addField("summary", String::class.java).setRequired("summary", true)
it.addField("color", Int::class.java).setNullable("color", true)
it.addField("picture", String::class.java)
it.addRealmListField("comments", Comment::class.java)
}
currentVersion++
}
}
override fun equals(other: Any?): Boolean {
return other is RealmMigration

@ -15,7 +15,6 @@ import net.pokeranalytics.android.model.interfaces.NameManageable
import net.pokeranalytics.android.model.interfaces.SaveValidityStatus
import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.rowrepresentable.BankrollRow
import net.pokeranalytics.android.ui.view.rowrepresentable.SimpleRow
import net.pokeranalytics.android.util.UserDefaults
import java.util.*
@ -46,13 +45,22 @@ open class Bankroll : RealmObject(), NameManageable, RowRepresentable {
return this.currency?.rate ?: Currency.DEFAULT_RATE
}
val javaCurrency: java.util.Currency
get() {
return currency?.code?.let {
java.util.Currency.getInstance(it)
} ?: run {
UserDefaults.currency
}
}
override fun getDisplayName(context: Context): String {
return this.name
}
override fun updateValue(value: Any?, row: RowRepresentable) {
when (row) {
SimpleRow.NAME -> this.name = value as String? ?: ""
BankrollRow.NAME -> this.name = value as String? ?: ""
BankrollRow.LIVE -> {
this.live = if (value is Boolean) !value else false
}

@ -0,0 +1,83 @@
package net.pokeranalytics.android.model.realm
import android.content.Context
import androidx.fragment.app.Fragment
import io.realm.Realm
import io.realm.RealmObject
import io.realm.annotations.Ignore
import io.realm.annotations.PrimaryKey
import net.pokeranalytics.android.R
import net.pokeranalytics.android.exceptions.ModelException
import net.pokeranalytics.android.model.interfaces.DeleteValidityStatus
import net.pokeranalytics.android.model.interfaces.Identifiable
import net.pokeranalytics.android.model.interfaces.Manageable
import net.pokeranalytics.android.model.interfaces.SaveValidityStatus
import net.pokeranalytics.android.ui.adapter.RowRepresentableDelegate
import net.pokeranalytics.android.ui.fragment.components.input.InputFragment
import net.pokeranalytics.android.ui.fragment.components.input.InputFragmentType
import net.pokeranalytics.android.ui.view.RowEditableDataSource
import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.RowViewType
import net.pokeranalytics.android.util.NULL_TEXT
import java.util.*
open class Comment : RealmObject(), Manageable, RowRepresentable {
@PrimaryKey
override var id = UUID.randomUUID().toString()
var content: String = ""
var date: Date = Date()
@Ignore
override val realmObjectClass: Class<out Identifiable> = Comment::class.java
@Ignore
override val viewType: Int = RowViewType.CONTENT.ordinal
@Ignore
override val inputFragmentType: InputFragmentType = InputFragmentType.EDIT_TEXT_MULTI_LINES
@Ignore
override val valueCanBeClearedWhenEditing: Boolean = false
override fun localizedTitle(context: Context): String {
return context.getString(R.string.comment)
}
override fun getDisplayName(context: Context): String {
return if (content.isNotEmpty()) content else NULL_TEXT
}
override fun startEditing(dataSource: Any?, parent: Fragment?) {
if (parent == null) return
if (parent !is RowRepresentableDelegate) return
val data = RowEditableDataSource()
data.append(this.content, R.string.value)
InputFragment.buildAndShow(this, parent, data, isDeletable = true)
}
override fun updateValue(value: Any?, row: RowRepresentable) {
this.content = value as String? ?: ""
}
override fun isValidForSave(): Boolean {
return true
}
override fun alreadyExists(realm: Realm): Boolean {
return realm.where(this::class.java).notEqualTo("id", this.id).findAll().isNotEmpty()
}
override fun getFailedSaveMessage(status: SaveValidityStatus): Int {
throw ModelException("${this::class.java} getFailedSaveMessage for $status not handled")
}
override fun isValidForDelete(realm: Realm): Boolean {
return true
}
override fun getFailedDeleteMessage(status: DeleteValidityStatus): Int {
return R.string.cf_entry_delete_popup_message
}
}

@ -2,6 +2,7 @@ package net.pokeranalytics.android.model.realm
import android.content.Context
import android.text.InputType
import androidx.fragment.app.Fragment
import io.realm.Realm
import io.realm.RealmList
import io.realm.RealmObject
@ -14,14 +15,15 @@ import net.pokeranalytics.android.model.interfaces.DeleteValidityStatus
import net.pokeranalytics.android.model.interfaces.Identifiable
import net.pokeranalytics.android.model.interfaces.NameManageable
import net.pokeranalytics.android.model.interfaces.SaveValidityStatus
import net.pokeranalytics.android.ui.adapter.RowRepresentableDelegate
import net.pokeranalytics.android.ui.adapter.StaticRowRepresentableDataSource
import net.pokeranalytics.android.ui.fragment.components.bottomsheet.BottomSheetType
import net.pokeranalytics.android.ui.fragment.components.input.InputFragment
import net.pokeranalytics.android.ui.fragment.components.input.InputFragmentType
import net.pokeranalytics.android.ui.view.RowEditableDataSource
import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.RowRepresentableEditDescriptor
import net.pokeranalytics.android.ui.view.RowViewType
import net.pokeranalytics.android.ui.view.rowrepresentable.CustomFieldRow
import net.pokeranalytics.android.ui.view.rowrepresentable.CustomizableRowRepresentable
import net.pokeranalytics.android.ui.view.rowrepresentable.SimpleRow
import net.pokeranalytics.android.util.enumerations.IntIdentifiable
import java.util.*
import kotlin.collections.ArrayList
@ -125,9 +127,23 @@ open class CustomField : RealmObject(), NameManageable, StaticRowRepresentableDa
return rowRepresentation
}
override fun startEditing(dataSource: Any?, parent: Fragment?) {
if (dataSource == null) return
if (dataSource !is Session) return
if (parent == null) return
if (parent !is RowRepresentableDelegate) return
val data = RowEditableDataSource()
when (type) {
Type.LIST.uniqueIdentifier -> data.append(dataSource.customFieldEntries.find { it.customField?.id == id }?.value, staticData = entries)
else -> data.append(dataSource.customFieldEntries.find { it.customField?.id == dataSource.id }?.numericValue, inputType = InputType.TYPE_CLASS_NUMBER or InputType.TYPE_NUMBER_FLAG_DECIMAL or InputType.TYPE_NUMBER_FLAG_SIGNED)
}
InputFragment.buildAndShow(this, parent, data)
}
override fun updateValue(value: Any?, row: RowRepresentable) {
when (row) {
SimpleRow.NAME -> this.name = value as String? ?: ""
CustomFieldRow.NAME -> this.name = value as String? ?: ""
CustomFieldRow.TYPE -> this.type = (value as Type?)?.uniqueIdentifier ?: Type.LIST.uniqueIdentifier
CustomFieldRow.COPY_ON_DUPLICATE -> this.duplicateValue = value as Boolean? ?: false
}
@ -161,11 +177,11 @@ open class CustomField : RealmObject(), NameManageable, StaticRowRepresentableDa
return R.string.cf_entry_delete_popup_message
}
override val bottomSheetType: BottomSheetType
override val inputFragmentType: InputFragmentType
get() {
return when (type) {
Type.LIST.uniqueIdentifier -> BottomSheetType.LIST_STATIC
else -> BottomSheetType.NUMERIC_TEXT
Type.LIST.uniqueIdentifier -> InputFragmentType.LIST_STATIC
else -> InputFragmentType.NUMERIC_TEXT
}
}
@ -176,45 +192,12 @@ open class CustomField : RealmObject(), NameManageable, StaticRowRepresentableDa
}
}
override fun editDescriptors(row: RowRepresentable): ArrayList<RowRepresentableEditDescriptor>? {
return when (row) {
is CustomFieldEntry -> row.editingDescriptors(
mapOf(
"defaultValue" to row.value
)
)
else -> null
}
}
override fun editingDescriptors(map: Map<String, Any?>): ArrayList<RowRepresentableEditDescriptor>? {
return when (type) {
Type.LIST.uniqueIdentifier -> {
val defaultValue: Any? by map
val data: RealmList<CustomFieldEntry>? by map
arrayListOf(
RowRepresentableEditDescriptor(defaultValue, staticData = data)
)
}
else -> {
val defaultValue: Double? by map
arrayListOf(
RowRepresentableEditDescriptor(
defaultValue, inputType = InputType.TYPE_CLASS_NUMBER
or InputType.TYPE_NUMBER_FLAG_DECIMAL
or InputType.TYPE_NUMBER_FLAG_SIGNED
)
)
}
}
}
/**
* Update the row representation
*/
private fun updatedRowRepresentationForCurrentState(): List<RowRepresentable> {
val rows = ArrayList<RowRepresentable>()
rows.add(SimpleRow.NAME)
rows.add(CustomFieldRow.NAME)
rows.add(CustomFieldRow.TYPE)
if (type == Type.LIST.uniqueIdentifier && entries.size >= 0) {
@ -270,10 +253,11 @@ open class CustomField : RealmObject(), NameManageable, StaticRowRepresentableDa
updateRowRepresentation()
}
/**
* Cleanup deleted entries
*/
fun cleanupEntries() { // called when saving the custom field
val realm = Realm.getDefaultInstance()
realm.executeTransaction {
this.entriesToDelete.forEach { // entries are out of realm
realm.where<CustomFieldEntry>().equalTo("id", it.id).findFirst()?.deleteFromRealm()

@ -2,6 +2,7 @@ package net.pokeranalytics.android.model.realm
import android.content.Context
import android.text.InputType
import androidx.fragment.app.Fragment
import io.realm.Realm
import io.realm.RealmObject
import io.realm.RealmResults
@ -15,9 +16,11 @@ import net.pokeranalytics.android.model.interfaces.DeleteValidityStatus
import net.pokeranalytics.android.model.interfaces.Identifiable
import net.pokeranalytics.android.model.interfaces.NameManageable
import net.pokeranalytics.android.model.interfaces.SaveValidityStatus
import net.pokeranalytics.android.ui.fragment.components.bottomsheet.BottomSheetType
import net.pokeranalytics.android.ui.adapter.RowRepresentableDelegate
import net.pokeranalytics.android.ui.fragment.components.input.InputFragment
import net.pokeranalytics.android.ui.fragment.components.input.InputFragmentType
import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.RowRepresentableEditDescriptor
import net.pokeranalytics.android.ui.view.RowEditableDataSource
import net.pokeranalytics.android.ui.view.RowViewType
import net.pokeranalytics.android.util.NULL_TEXT
import net.pokeranalytics.android.util.extensions.toCurrency
@ -81,7 +84,7 @@ open class CustomFieldEntry : RealmObject(), NameManageable, RowRepresentable {
}
@Ignore
override val bottomSheetType: BottomSheetType = BottomSheetType.EDIT_TEXT
override val inputFragmentType: InputFragmentType = InputFragmentType.EDIT_TEXT
override fun localizedTitle(context: Context): String {
return context.getString(R.string.value)
@ -91,12 +94,16 @@ open class CustomFieldEntry : RealmObject(), NameManageable, RowRepresentable {
return if (value.isNotEmpty()) value else NULL_TEXT
}
override fun editingDescriptors(map: Map<String, Any?>): ArrayList<RowRepresentableEditDescriptor>? {
val defaultValue: Any? by map
return arrayListOf(
RowRepresentableEditDescriptor(defaultValue, R.string.value, InputType.TYPE_CLASS_TEXT)
)
}
override fun startEditing(dataSource: Any?, parent: Fragment?) {
if (parent == null) return
if (parent !is RowRepresentableDelegate) return
val data = RowEditableDataSource()
data.append(this.value, R.string.value, InputType.TYPE_CLASS_TEXT)
InputFragment.buildAndShow(this, parent, data, isDeletable = true)
}
override val valueCanBeClearedWhenEditing: Boolean
get() = false
override fun isValidForSave(): Boolean {
return true

@ -1,6 +1,7 @@
package net.pokeranalytics.android.model.realm
import android.content.Context
import androidx.fragment.app.Fragment
import io.realm.*
import io.realm.annotations.Ignore
import io.realm.annotations.PrimaryKey
@ -10,12 +11,11 @@ import net.pokeranalytics.android.model.filter.Filterable
import net.pokeranalytics.android.model.filter.Query
import net.pokeranalytics.android.model.filter.QueryCondition
import net.pokeranalytics.android.model.interfaces.*
import net.pokeranalytics.android.ui.fragment.components.bottomsheet.BottomSheetType
import net.pokeranalytics.android.ui.adapter.RowRepresentableDelegate
import net.pokeranalytics.android.ui.fragment.components.input.InputFragment
import net.pokeranalytics.android.ui.fragment.components.input.InputFragmentType
import net.pokeranalytics.android.ui.interfaces.FilterableType
import net.pokeranalytics.android.ui.view.ImageDecorator
import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.RowRepresentableEditDescriptor
import net.pokeranalytics.android.ui.view.RowViewType
import net.pokeranalytics.android.ui.view.*
import net.pokeranalytics.android.ui.view.rowrepresentable.FilterCategoryRow
import timber.log.Timber
import java.util.*
@ -193,20 +193,15 @@ open class Filter : RealmObject(), RowRepresentable, Editable, Deletable, Counta
return R.string.relationship_error
}
override val bottomSheetType: BottomSheetType
override val inputFragmentType: InputFragmentType
get() {
return BottomSheetType.EDIT_TEXT
return InputFragmentType.EDIT_TEXT
}
override fun localizedTitle(context: Context): String {
return context.getString(R.string.name)
}
override fun editingDescriptors(map: Map<String, Any?>): ArrayList<RowRepresentableEditDescriptor>? {
val defaultValue: String? by map
return arrayListOf(RowRepresentableEditDescriptor(defaultValue, R.string.name))
}
override fun updateValue(value: Any?, row: RowRepresentable) {
realm.executeTransaction {
val newName = value as String? ?: ""
@ -215,4 +210,12 @@ open class Filter : RealmObject(), RowRepresentable, Editable, Deletable, Counta
}
}
}
override fun startEditing(dataSource: Any?, parent: Fragment?) {
if (parent == null) return
if (parent !is RowRepresentableDelegate) return
val data = RowEditableDataSource()
data.append(this.name)
InputFragment.buildAndShow(this, parent, data, isDeletable = true, valueHasPlaceholder = false)
}
}

@ -14,9 +14,7 @@ import net.pokeranalytics.android.model.interfaces.NameManageable
import net.pokeranalytics.android.model.interfaces.SaveValidityStatus
import net.pokeranalytics.android.ui.adapter.StaticRowRepresentableDataSource
import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.RowRepresentableEditDescriptor
import net.pokeranalytics.android.ui.view.rowrepresentable.GameRow
import net.pokeranalytics.android.ui.view.rowrepresentable.SimpleRow
import net.pokeranalytics.android.util.NULL_TEXT
import java.util.*
import kotlin.collections.ArrayList
@ -29,7 +27,7 @@ open class Game : RealmObject(), NameManageable, StaticRowRepresentableDataSourc
companion object {
val rowRepresentation : List<RowRepresentable> by lazy {
val rows = ArrayList<RowRepresentable>()
rows.add(SimpleRow.NAME)
rows.add(GameRow.NAME)
// rows.addAll(GameRow.values())
rows
}
@ -62,28 +60,20 @@ open class Game : RealmObject(), NameManageable, StaticRowRepresentableDataSourc
}
override fun adapterRows(): List<RowRepresentable>? {
return Game.rowRepresentation
return rowRepresentation
}
override fun stringForRow(row: RowRepresentable): String {
return when (row) {
SimpleRow.NAME -> if (this.name.isNotEmpty()) this.name else NULL_TEXT
GameRow.NAME -> if (this.name.isNotEmpty()) this.name else NULL_TEXT
GameRow.SHORT_NAME -> this.shortName ?: NULL_TEXT
else -> return super.stringForRow(row)
}
}
override fun editDescriptors(row: RowRepresentable): ArrayList<RowRepresentableEditDescriptor>? {
return when (row) {
SimpleRow.NAME -> row.editingDescriptors(mapOf("defaultValue" to this.name))
GameRow.SHORT_NAME -> row.editingDescriptors(mapOf("defaultValue" to this.shortName))
else -> null
}
}
override fun updateValue(value: Any?, row: RowRepresentable) {
when (row) {
SimpleRow.NAME -> this.name = value as String? ?: ""
GameRow.NAME -> this.name = value as String? ?: ""
GameRow.SHORT_NAME -> this.shortName = value as String? ?: ""
}
}

@ -1,15 +1,175 @@
package net.pokeranalytics.android.model.realm
import android.content.Context
import io.realm.Realm
import io.realm.RealmList
import io.realm.RealmObject
import io.realm.annotations.Ignore
import io.realm.annotations.PrimaryKey
import io.realm.kotlin.where
import net.pokeranalytics.android.R
import net.pokeranalytics.android.model.interfaces.*
import net.pokeranalytics.android.ui.adapter.StaticRowRepresentableDataSource
import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.RowViewType
import net.pokeranalytics.android.ui.view.rowrepresentable.CustomizableRowRepresentable
import net.pokeranalytics.android.ui.view.rowrepresentable.PlayerRow
import net.pokeranalytics.android.ui.view.rowrepresentable.SeparatorRow
import net.pokeranalytics.android.util.NULL_TEXT
import net.pokeranalytics.android.util.extensions.isSameDay
import net.pokeranalytics.android.util.extensions.mediumDate
import java.util.*
open class Player : RealmObject() {
open class Player : RealmObject(), NameManageable, Deletable, StaticRowRepresentableDataSource, RowRepresentable {
@PrimaryKey
var id = UUID.randomUUID().toString()
@PrimaryKey
override var id = UUID.randomUUID().toString()
// The name of the player
var name: String = ""
// The name of the player
override var name: String = ""
}
// New fields
var summary: String = ""
var color: Int? = null
var picture: String? = null
var comments: RealmList<Comment> = RealmList()
@Ignore
override val realmObjectClass: Class<out Identifiable> = Player::class.java
@Ignore
override val viewType: Int = RowViewType.ROW_PLAYER.ordinal
@Ignore
private var rowRepresentation: List<RowRepresentable> = mutableListOf()
@Ignore
private var commentsToDelete: ArrayList<Comment> = ArrayList()
override fun isValidForDelete(realm: Realm): Boolean {
//TODO
return true
}
override fun getFailedSaveMessage(status: SaveValidityStatus): Int {
return when(status) {
SaveValidityStatus.ALREADY_EXISTS -> R.string.duplicate_user_error
else -> super.getFailedSaveMessage(status)
}
}
override fun getFailedDeleteMessage(status: DeleteValidityStatus): Int {
//TODO
return R.string.relationship_error
}
override fun adapterRows(): List<RowRepresentable>? {
return rowRepresentation
}
override fun getDisplayName(context: Context): String {
return this.name
}
override fun stringForRow(row: RowRepresentable): String {
return when (row) {
PlayerRow.NAME -> if (this.name.isNotEmpty()) this.name else NULL_TEXT
else -> return super.stringForRow(row)
}
}
override fun updateValue(value: Any?, row: RowRepresentable) {
when (row) {
PlayerRow.NAME -> this.name = value as String? ?: ""
PlayerRow.SUMMARY -> this.summary = value as String? ?: ""
PlayerRow.IMAGE -> this.picture = value as String? ?: ""
}
}
/**
* Update the row representation
*/
private fun updatedRowRepresentationForCurrentState(): List<RowRepresentable> {
val rows = ArrayList<RowRepresentable>()
rows.add(PlayerRow.IMAGE)
rows.add(PlayerRow.NAME)
rows.add(PlayerRow.SUMMARY)
if (comments.size > 0) {
rows.add(CustomizableRowRepresentable(RowViewType.HEADER_TITLE, R.string.comments))
val currentCommentCalendar = Calendar.getInstance()
val currentDateCalendar = Calendar.getInstance()
val commentsToDisplay = ArrayList<Comment>()
commentsToDisplay.addAll(comments)
commentsToDisplay.sortByDescending { it.date }
commentsToDisplay.forEachIndexed { index, comment ->
currentCommentCalendar.time = comment.date
if (!currentCommentCalendar.isSameDay(currentDateCalendar) || index == 0) {
currentDateCalendar.time = currentCommentCalendar.time
rows.add(CustomizableRowRepresentable(RowViewType.HEADER_SUBTITLE, title = currentDateCalendar.time.mediumDate()))
}
rows.add(comment)
}
rows.add(SeparatorRow())
}
return rows
}
/**
* Return if the player has a picture
*/
fun hasPicture(): Boolean {
return picture != null && picture?.isNotEmpty() == true
}
/**
* Update row representation
*/
fun updateRowRepresentation() {
this.rowRepresentation = this.updatedRowRepresentationForCurrentState()
}
/**
* Add an entry
*/
fun addComment(): Comment {
val entry = Comment()
this.comments.add(entry)
updateRowRepresentation()
return entry
}
/**
* Delete an entry
*/
fun deleteComment(comment: Comment) {
commentsToDelete.add(comment)
this.comments.remove(comment)
updateRowRepresentation()
}
/**
* Clean up deleted entries
*/
fun cleanupComments() { // called when saving the custom field
val realm = Realm.getDefaultInstance()
realm.executeTransaction {
this.commentsToDelete.forEach { // entries are out of realm
realm.where<Comment>().equalTo("id", it.id).findFirst()?.deleteFromRealm()
}
}
realm.close()
this.commentsToDelete.clear()
}
}

@ -834,117 +834,6 @@ open class Session : RealmObject(), Savable, Editable, StaticRowRepresentableDat
}
}
override fun editDescriptors(row: RowRepresentable): ArrayList<RowRepresentableEditDescriptor>? {
return when (row) {
SessionRow.BANKROLL -> row.editingDescriptors(
mapOf(
"defaultValue" to this.bankroll,
"data" to realm.sorted<Bankroll>() // LiveData.Bankroll.items(realm)
)
)
SessionRow.GAME -> row.editingDescriptors(
mapOf(
"limit" to this.limit,
"defaultValue" to this.game,
"data" to realm.sorted<Game>() //LiveData.Game.items(realm)
)
)
SessionRow.LOCATION -> row.editingDescriptors(
mapOf(
"defaultValue" to this.location,
"data" to realm.sorted<Location>() // LiveData.Location.items(realm)
)
)
SessionRow.TOURNAMENT_FEATURE -> row.editingDescriptors(
mapOf(
"defaultValue" to this.tournamentFeatures,
"data" to realm.sorted<TournamentFeature>() //LiveData.TournamentFeature.items(realm)
)
)
SessionRow.TOURNAMENT_NAME -> row.editingDescriptors(
mapOf(
"defaultValue" to this.tournamentName,
"data" to realm.sorted<TournamentName>() //LiveData.TournamentName.items(realm)
)
)
SessionRow.TOURNAMENT_TYPE -> row.editingDescriptors(
mapOf(
"defaultValue" to this.tournamentType
)
)
SessionRow.TABLE_SIZE -> row.editingDescriptors(
mapOf(
"defaultValue" to this.tableSize
)
)
SessionRow.BLINDS -> row.editingDescriptors(
mapOf(
"sb" to cgSmallBlind?.round(),
"bb" to cgBigBlind?.round()
)
)
SessionRow.BUY_IN -> row.editingDescriptors(
mapOf(
"bb" to cgBigBlind,
"fee" to this.tournamentEntryFee,
"ratedBuyin" to result?.buyin
)
)
SessionRow.BREAK_TIME -> row.editingDescriptors(mapOf())
SessionRow.CASHED_OUT, SessionRow.PRIZE -> row.editingDescriptors(
mapOf(
"defaultValue" to result?.cashout
)
)
SessionRow.NET_RESULT -> row.editingDescriptors(
mapOf(
"defaultValue" to result?.netResult
)
)
SessionRow.COMMENT -> row.editingDescriptors(
mapOf(
"defaultValue" to this.comment
)
)
SessionRow.INITIAL_BUY_IN -> row.editingDescriptors(
mapOf(
"defaultValue" to this.tournamentEntryFee
)
)
SessionRow.PLAYERS -> row.editingDescriptors(
mapOf(
"defaultValue" to this.tournamentNumberOfPlayers
)
)
SessionRow.POSITION -> row.editingDescriptors(
mapOf(
"defaultValue" to this.result?.tournamentFinalPosition
)
)
SessionRow.TIPS -> row.editingDescriptors(
mapOf(
"sb" to cgSmallBlind?.round(),
"bb" to cgBigBlind?.round(),
"tips" to result?.tips
)
)
is CustomField -> {
row.editingDescriptors(
when (row.type) {
CustomField.Type.LIST.uniqueIdentifier -> mapOf(
"defaultValue" to customFieldEntries.find { it.customField?.id == row.id }?.value,
"data" to row.entries
)
else -> mapOf(
"defaultValue" to customFieldEntries.find { it.customField?.id == row.id }?.numericValue
)
}
)
}
else -> null
}
}
override fun updateValue(value: Any?, row: RowRepresentable) {
realm.executeTransaction {

@ -233,7 +233,7 @@
//
// /**
// * Multiple session sets update:
// * Merges all sets into one (delete all then create a new one)
// * Merges all sets into one (delete all then buildAndShow a new one)
// */
// private fun mergeSessionGroups(owner: Session, sessionSets: RealmResults<SessionSet>) {
//

@ -14,8 +14,6 @@ import net.pokeranalytics.android.model.interfaces.NameManageable
import net.pokeranalytics.android.model.interfaces.SaveValidityStatus
import net.pokeranalytics.android.ui.adapter.StaticRowRepresentableDataSource
import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.RowRepresentableEditDescriptor
import net.pokeranalytics.android.ui.view.rowrepresentable.SimpleRow
import net.pokeranalytics.android.ui.view.rowrepresentable.TournamentFeatureRow
import net.pokeranalytics.android.util.NULL_TEXT
import java.util.*
@ -27,7 +25,6 @@ open class TournamentFeature : RealmObject(), NameManageable, StaticRowRepresent
companion object {
val rowRepresentation : List<RowRepresentable> by lazy {
val rows = ArrayList<RowRepresentable>()
rows.add(SimpleRow.NAME)
rows.addAll(TournamentFeatureRow.values())
rows
}
@ -53,24 +50,19 @@ open class TournamentFeature : RealmObject(), NameManageable, StaticRowRepresent
}
override fun adapterRows(): List<RowRepresentable>? {
return TournamentFeature.rowRepresentation
return rowRepresentation
}
override fun stringForRow(row: RowRepresentable): String {
return when (row) {
SimpleRow.NAME -> if (this.name.isNotEmpty()) this.name else NULL_TEXT
TournamentFeatureRow.NAME -> if (this.name.isNotEmpty()) this.name else NULL_TEXT
else -> return super.stringForRow(row)
}
}
override fun editDescriptors(row: RowRepresentable): ArrayList<RowRepresentableEditDescriptor>? {
return row.editingDescriptors(mapOf(
"defaultValue" to this.name))
}
override fun updateValue(value: Any?, row: RowRepresentable) {
when (row) {
SimpleRow.NAME -> this.name = value as String? ?: ""
TournamentFeatureRow.NAME -> this.name = value as String? ?: ""
}
}

@ -12,8 +12,6 @@ import net.pokeranalytics.android.model.interfaces.NameManageable
import net.pokeranalytics.android.model.interfaces.SaveValidityStatus
import net.pokeranalytics.android.ui.adapter.StaticRowRepresentableDataSource
import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.RowRepresentableEditDescriptor
import net.pokeranalytics.android.ui.view.rowrepresentable.SimpleRow
import net.pokeranalytics.android.ui.view.rowrepresentable.TournamentNameRow
import net.pokeranalytics.android.util.NULL_TEXT
import java.util.*
@ -24,7 +22,6 @@ open class TournamentName : RealmObject(), NameManageable, StaticRowRepresentabl
companion object {
val rowRepresentation : List<RowRepresentable> by lazy {
val rows = ArrayList<RowRepresentable>()
rows.add(SimpleRow.NAME)
rows.addAll(TournamentNameRow.values())
rows
}
@ -45,25 +42,21 @@ open class TournamentName : RealmObject(), NameManageable, StaticRowRepresentabl
override fun updateValue(value: Any?, row: RowRepresentable) {
when (row) {
SimpleRow.NAME -> this.name = value as String? ?: ""
TournamentNameRow.NAME -> this.name = value as String? ?: ""
}
}
override fun adapterRows(): List<RowRepresentable>? {
return TournamentName.rowRepresentation
return rowRepresentation
}
override fun stringForRow(row: RowRepresentable): String {
return when (row) {
SimpleRow.NAME -> if (this.name.isNotEmpty()) this.name else NULL_TEXT
TournamentNameRow.NAME -> if (this.name.isNotEmpty()) this.name else NULL_TEXT
else -> return super.stringForRow(row)
}
}
override fun editDescriptors(row: RowRepresentable): ArrayList<RowRepresentableEditDescriptor>? {
return row.editingDescriptors(mapOf("defaultValue" to this.name))
}
override fun getFailedSaveMessage(status: SaveValidityStatus): Int {
return when (status) {
SaveValidityStatus.DATA_INVALID -> R.string.tournament_name_empty_field_error

@ -12,8 +12,6 @@ import net.pokeranalytics.android.model.interfaces.*
import net.pokeranalytics.android.ui.adapter.StaticRowRepresentableDataSource
import net.pokeranalytics.android.ui.view.Localizable
import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.RowRepresentableEditDescriptor
import net.pokeranalytics.android.ui.view.rowrepresentable.SimpleRow
import net.pokeranalytics.android.ui.view.rowrepresentable.TransactionTypeRow
import net.pokeranalytics.android.util.enumerations.IntIdentifiable
import net.pokeranalytics.android.util.enumerations.IntSearchable
@ -55,7 +53,6 @@ open class TransactionType : RealmObject(), NameManageable, StaticRowRepresentab
companion object {
val rowRepresentation: List<RowRepresentable> by lazy {
val rows = ArrayList<RowRepresentable>()
rows.add(SimpleRow.NAME)
rows.addAll(TransactionTypeRow.values())
rows
}
@ -108,7 +105,7 @@ open class TransactionType : RealmObject(), NameManageable, StaticRowRepresentab
override fun stringForRow(row: RowRepresentable): String {
return when (row) {
SimpleRow.NAME -> this.name
TransactionTypeRow.NAME -> this.name
else -> return super.stringForRow(row)
}
}
@ -120,13 +117,9 @@ open class TransactionType : RealmObject(), NameManageable, StaticRowRepresentab
}
}
override fun editDescriptors(row: RowRepresentable): ArrayList<RowRepresentableEditDescriptor>? {
return row.editingDescriptors(mapOf("defaultValue" to this.name))
}
override fun updateValue(value: Any?, row: RowRepresentable) {
when (row) {
SimpleRow.NAME -> this.name = value as String? ?: ""
TransactionTypeRow.NAME -> this.name = value as String? ?: ""
TransactionTypeRow.TRANSACTION_ADDITIVE -> this.additive = value as Boolean? ?: false
}
}

@ -97,7 +97,7 @@ class SessionSetManager {
/**
* Multiple session sets update:
* Merges all sets into one (delete all then create a new one)
* Merges all sets into one (delete all then buildAndShow a new one)
*/
private fun mergeSessionGroups(session: Session, sessionSets: RealmResults<SessionSet>) {

@ -0,0 +1,77 @@
package net.pokeranalytics.android.ui.activity
import android.app.Activity
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.view.View
import androidx.fragment.app.Fragment
import kotlinx.android.synthetic.main.activity_color_picker.*
import net.pokeranalytics.android.R
import net.pokeranalytics.android.ui.activity.components.PokerAnalyticsActivity
class ColorPickerActivity : PokerAnalyticsActivity() {
companion object {
const val INTENT_COLOR = "INTENT_COLOR"
fun newInstance(context: Context) {
val intent = Intent(context, ColorPickerActivity::class.java)
context.startActivity(intent)
}
/**
* Create a new instance for result
*/
fun newInstanceForResult(fragment: Fragment, requestCode: Int) {
val intent = Intent(fragment.requireContext(), ColorPickerActivity::class.java)
fragment.startActivityForResult(intent, requestCode)
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_color_picker)
initUI()
}
/**
* Init UI
*/
private fun initUI() {
color1.setOnClickListener { manageSelectedColor(it) }
color2.setOnClickListener { manageSelectedColor(it) }
color3.setOnClickListener { manageSelectedColor(it) }
color4.setOnClickListener { manageSelectedColor(it) }
color5.setOnClickListener { manageSelectedColor(it) }
color6.setOnClickListener { manageSelectedColor(it) }
color7.setOnClickListener { manageSelectedColor(it) }
color8.setOnClickListener { manageSelectedColor(it) }
color9.setOnClickListener { manageSelectedColor(it) }
}
private fun manageSelectedColor(view: View) {
val color = when(view) {
color1 -> getColor(R.color.player_color_1)
color2 -> getColor(R.color.player_color_2)
color3 -> getColor(R.color.player_color_3)
color4 -> getColor(R.color.player_color_4)
color5 -> getColor(R.color.player_color_5)
color6 -> getColor(R.color.player_color_6)
color7 -> getColor(R.color.player_color_7)
color8 -> getColor(R.color.player_color_8)
color9 -> getColor(R.color.player_color_9)
else -> getColor(R.color.player_color_1)
}
val intent = Intent()
intent.putExtra(INTENT_COLOR, color)
setResult(Activity.RESULT_OK, intent)
finish()
}
}

@ -1,33 +0,0 @@
package net.pokeranalytics.android.ui.activity
import android.content.Context
import android.content.Intent
import android.os.Bundle
import androidx.fragment.app.Fragment
import net.pokeranalytics.android.R
import net.pokeranalytics.android.ui.activity.components.PokerAnalyticsActivity
class ComparisonChartActivity : PokerAnalyticsActivity() {
companion object {
fun newInstance(context: Context) {
val intent = Intent(context, ComparisonChartActivity::class.java)
context.startActivity(intent)
}
/**
* Create a new instance for result
*/
fun newInstanceForResult(fragment: Fragment, requestCode: Int) {
val intent = Intent(fragment.requireContext(), ComparisonChartActivity::class.java)
fragment.startActivityForResult(intent, requestCode)
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_comparison_chart)
}
}

@ -6,10 +6,12 @@ import android.os.Bundle
import androidx.fragment.app.Fragment
import net.pokeranalytics.android.R
import net.pokeranalytics.android.model.LiveData
import net.pokeranalytics.android.ui.activity.components.PokerAnalyticsActivity
import net.pokeranalytics.android.ui.activity.components.MediaActivity
import net.pokeranalytics.android.ui.fragment.data.*
import java.io.File
import java.util.*
class EditableDataActivity : PokerAnalyticsActivity() {
class EditableDataActivity : MediaActivity() {
enum class IntentKey(val keyName: String) {
DATA_TYPE("DATA_TYPE"),
@ -43,6 +45,8 @@ class EditableDataActivity : PokerAnalyticsActivity() {
}
private var currentFragment: EditableDataFragment? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_editable_data)
@ -57,20 +61,35 @@ class EditableDataActivity : PokerAnalyticsActivity() {
val dataType = intent.getIntExtra(IntentKey.DATA_TYPE.keyName, 0)
val primaryKey = intent.getStringExtra(IntentKey.PRIMARY_KEY.keyName)
val fragmentManager = supportFragmentManager
val fragmentTransaction = fragmentManager.beginTransaction()
val fragment: EditableDataFragment = when (dataType) {
currentFragment = when (dataType) {
LiveData.BANKROLL.ordinal -> BankrollDataFragment()
LiveData.LOCATION.ordinal -> LocationDataFragment()
LiveData.TRANSACTION.ordinal -> TransactionDataFragment()
LiveData.CUSTOM_FIELD.ordinal -> CustomFieldDataFragment()
LiveData.TRANSACTION_TYPE.ordinal -> TransactionTypeDataFragment()
LiveData.PLAYER.ordinal -> PlayerDataFragment()
else -> EditableDataFragment()
}
fragment.setData(dataType, primaryKey)
fragmentTransaction.add(R.id.container, fragment)
fragmentTransaction.commit()
currentFragment?.let { fragment ->
val fragmentManager = supportFragmentManager
val fragmentTransaction = fragmentManager.beginTransaction()
fragmentTransaction.add(R.id.container, fragment)
fragmentTransaction.commit()
fragment.setData(dataType, primaryKey)
}
}
override fun isLoadingNewPictures() {
super.isLoadingNewPictures()
currentFragment?.isLoadingNewPhotos()
}
override fun getPictures(files: ArrayList<File>) {
super.getPictures(files)
currentFragment?.getPhotos(files)
}
}

@ -0,0 +1,268 @@
package net.pokeranalytics.android.ui.activity.components
import android.Manifest
import android.app.Activity
import android.content.Intent
import android.content.pm.PackageManager
import android.graphics.Bitmap
import android.provider.MediaStore
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import androidx.core.content.FileProvider
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import net.pokeranalytics.android.util.ImageUtils
import timber.log.Timber
import java.io.File
import java.io.IOException
import java.util.*
open class MediaActivity : PokerAnalyticsActivity() {
companion object {
const val SELECTED_CHOICE_TAKE_PICTURE = 10
const val SELECTED_CHOICE_SELECT_PICTURE = 11
const val REQUEST_CODE_TAKE_PICTURE = 100
const val REQUEST_CODE_SELECT_PICTURE = 101
const val PERMISSION_REQUEST_EXTERNAL_STORAGE = 201
const val PERMISSION_REQUEST_CAMERA = 202
}
// Data
private var tempFile: File? = null
private var mCurrentPhotoPath: String? = null
private var selectedChoice = -1
private var multiplePictures = false
override fun onDestroy() {
super.onDestroy()
if (tempFile != null) {
tempFile!!.delete()
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (resultCode == Activity.RESULT_OK) {
if (requestCode == REQUEST_CODE_SELECT_PICTURE || requestCode == REQUEST_CODE_TAKE_PICTURE) {
val filesList = ArrayList<File>()
GlobalScope.launch {
if (tempFile != null) {
tempFile?.let {
GlobalScope.launch(Dispatchers.Main) {
filesList.add(it)
getPictures(filesList)
}
}
} else if (data?.clipData != null) {
data?.clipData?.let { clipData ->
try {
GlobalScope.launch(Dispatchers.Main) {
isLoadingNewPictures()
}
for (i in 0 until clipData.itemCount) {
val item = clipData.getItemAt(i)
val uri = item.uri
val inputStream = contentResolver.openInputStream(uri)
val photoFile = ImageUtils.createTempImageFile(this@MediaActivity)
ImageUtils.copyInputStreamToFile(inputStream!!, photoFile)
filesList.add(photoFile)
}
GlobalScope.launch(Dispatchers.Main) {
getPictures(filesList)
}
} catch (e: Exception) {
e.printStackTrace()
}
}
} else if (data?.data != null) {
data?.data?.let { uri ->
try {
GlobalScope.launch(Dispatchers.Main) {
isLoadingNewPictures()
}
val inputStream = contentResolver.openInputStream(uri)
val photoFile = ImageUtils.createTempImageFile(this@MediaActivity)
ImageUtils.copyInputStreamToFile(inputStream!!, photoFile)
filesList.add(photoFile)
GlobalScope.launch(Dispatchers.Main) {
getPictures(filesList)
}
} catch (e: Exception) {
e.printStackTrace()
}
}
}
}
}
}
}
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
if (grantResults.isNotEmpty()) {
for (result in grantResults) {
if (result != PackageManager.PERMISSION_GRANTED) {
//Toast.makeText(this, getString(R.string.photo_library_add_usage_description), Toast.LENGTH_SHORT).show()
selectedChoice = -1
return
}
}
when (selectedChoice) {
SELECTED_CHOICE_TAKE_PICTURE -> {
openImageCaptureIntent(multiplePictures)
}
SELECTED_CHOICE_SELECT_PICTURE -> {
openImageGalleryIntent(multiplePictures)
}
}
}
selectedChoice = -1
}
/**
* Open the Camera Intent
*/
fun openImageCaptureIntent(multiplePictures: Boolean) {
tempFile = null
this.mCurrentPhotoPath = null
this.multiplePictures = multiplePictures
// Test if we have the permission
if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
selectedChoice = SELECTED_CHOICE_TAKE_PICTURE
askForStoragePermission()
return
}
val takePictureIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
// Ensure that there's a camera activity to handle the intent
if (takePictureIntent.resolveActivity(packageManager) != null) {
// Create the File where the photo should go
try {
tempFile = ImageUtils.createImageFile(this)
mCurrentPhotoPath = "file:" + tempFile?.absolutePath
} catch (ex: IOException) {
// Error occurred while creating the File
}
// Continue only if the File was successfully created
if (tempFile != null) {
Timber.d("tempFile: ${tempFile?.absolutePath}")
val photoURI = FileProvider.getUriForFile(
this,
applicationContext.packageName + ".fileprovider", tempFile!!
)
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI)
startActivityForResult(takePictureIntent, REQUEST_CODE_TAKE_PICTURE)
}
}
}
/**
* Open the gallery intent
*/
fun openImageGalleryIntent(multiplePictures: Boolean) {
tempFile = null
this.multiplePictures = multiplePictures
// Test if we have the permission
if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
selectedChoice = SELECTED_CHOICE_SELECT_PICTURE
askForStoragePermission()
return
}
this.multiplePictures = multiplePictures
val galleryIntent = Intent()
galleryIntent.type = "image/*"
galleryIntent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, multiplePictures)
galleryIntent.action = Intent.ACTION_GET_CONTENT
startActivityForResult(galleryIntent, REQUEST_CODE_SELECT_PICTURE)
}
/**
* Ask for the external storage permission
*/
private fun askForStoragePermission() {
// Here, thisActivity is the current activity
if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE),
PERMISSION_REQUEST_EXTERNAL_STORAGE)
}
}
/**
* Ask for the acmera permission
*/
private fun askForCameraPermission() {
// Here, thisActivity is the current activity
if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.CAMERA),
PERMISSION_REQUEST_CAMERA)
}
}
/**
* Ask for camera and storage permission
*/
private fun askForCameraAndStoragePermissions() {
val permissions = ArrayList<String>()
if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
permissions.add(Manifest.permission.CAMERA)
}
if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
permissions.add(Manifest.permission.WRITE_EXTERNAL_STORAGE)
}
if (permissions.size > 0) {
ActivityCompat.requestPermissions(this, permissions.toArray(arrayOfNulls<String>(permissions.size)), PERMISSION_REQUEST_CAMERA)
}
}
/**
* Called when a bitmap is return
*
* @param bitmap the bitmap returned
*/
open fun getBitmapImage(file: File?, bitmap: Bitmap?) {}
/**
* Called when the user is adding new photos
*/
open fun isLoadingNewPictures() {}
/**
* Called when the user has selected photos
*/
open fun getPictures(files: ArrayList<File>) {}
}

@ -73,7 +73,7 @@ open class PokerAnalyticsActivity : AppCompatActivity() {
}
override fun onOptionsItemSelected(item: MenuItem?): Boolean {
override fun onOptionsItemSelected(item: MenuItem): Boolean {
item?.let {
if (it.itemId == android.R.id.home) {
onBackPressed()

@ -21,7 +21,7 @@ class HomePagerAdapter(fragmentManager: FragmentManager) : FragmentStatePagerAda
1 -> StatisticsFragment.newInstance()
2 -> CalendarFragment.newInstance()
3 -> ReportsFragment.newInstance()
4 -> SettingsFragment.newInstance()
4 -> MoreFragment.newInstance()
else -> FeedFragment.newInstance()
}
}
@ -47,7 +47,7 @@ class HomePagerAdapter(fragmentManager: FragmentManager) : FragmentStatePagerAda
StatisticsFragment::class.java -> 1
CalendarFragment::class.java -> 2
ReportsFragment::class.java -> 3
SettingsFragment::class.java -> 4
MoreFragment::class.java -> 4
else -> -1
}
}

@ -7,10 +7,13 @@ import net.pokeranalytics.android.ui.view.BindableHolder
import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.RowViewType
interface RowRepresentableDelegate {
interface RowRepresentableDelegate: RowEditableDelegate {
fun onRowSelected(position: Int, row: RowRepresentable, fromAction: Boolean = false) {}
fun onRowValueChanged(value: Any?, row: RowRepresentable) {}
fun onRowDeleted(row: RowRepresentable) {}
}
interface RowEditableDelegate {
fun onRowValueChanged(value: Any?, row: RowRepresentable) {}
fun onRowDeleted(row: RowRepresentable) {}
}
/**

@ -3,13 +3,12 @@ package net.pokeranalytics.android.ui.adapter
import android.content.Context
import net.pokeranalytics.android.exceptions.PAIllegalStateException
import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.RowRepresentableEditDescriptor
import net.pokeranalytics.android.util.TextFormat
/**
* Base Interface to provide the RowRepresentable to the adapter
*/
interface RowRepresentableDataSource: EditableDataSource, DisplayableDataSource, SelectableDataSource {
interface RowRepresentableDataSource: DisplayableDataSource, SelectableDataSource {
/**
* Returns a prebuild list of rows
@ -161,18 +160,6 @@ interface DisplayableDataSource {
}
}
/**
* An interface providing a way to describe how the edition of a [RowRepresentable] will be displayed
*/
interface EditableDataSource {
/**
* A list of [RowRepresentableEditDescriptor] object specifying the way the edition will be handled
*/
fun editDescriptors(row: RowRepresentable): ArrayList<RowRepresentableEditDescriptor>? {
return null
}
}
/**
* An interface providing a way to select a row

@ -7,9 +7,11 @@ import android.content.res.Resources
import android.net.Uri
import android.util.TypedValue
import android.view.View
import android.widget.LinearLayout
import android.widget.Toast
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.widget.AppCompatTextView
import androidx.appcompat.widget.SearchView
import androidx.browser.customtabs.CustomTabsIntent
import androidx.core.content.ContextCompat
import androidx.core.content.FileProvider
@ -94,7 +96,7 @@ fun PokerAnalyticsActivity.openContactMail(subjectStringRes: Int, filePath: Stri
// Open custom tab
fun PokerAnalyticsActivity.openUrl(url: String) {
val builder: CustomTabsIntent.Builder = CustomTabsIntent.Builder()
builder.setToolbarColor(ContextCompat.getColor(this, net.pokeranalytics.android.R.color.colorPrimary))
builder.setToolbarColor(ContextCompat.getColor(this, R.color.colorPrimary))
val customTabsIntent = builder.build()
customTabsIntent.launchUrl(this, Uri.parse(url))
}
@ -124,7 +126,7 @@ fun showAlertDialog(
message?.let {
builder.setMessage(message)
}
builder.setPositiveButton(net.pokeranalytics.android.R.string.ok) { _, _ ->
builder.setPositiveButton(R.string.ok) { _, _ ->
positiveAction?.invoke()
}
@ -160,4 +162,12 @@ fun View.showWithAnimation() {
fun View.addCircleRipple() = with(TypedValue()) {
context.theme.resolveAttribute(android.R.attr.selectableItemBackgroundBorderless, this, true)
setBackgroundResource(resourceId)
}
fun SearchView.removeMargins() {
val searchEditFrame = findViewById<LinearLayout?>(R.id.search_edit_frame)
val layoutParams = searchEditFrame?.layoutParams as LinearLayout.LayoutParams?
layoutParams?.leftMargin = 0
layoutParams?.rightMargin = 0
searchEditFrame?.layoutParams = layoutParams
}

@ -72,9 +72,9 @@ class BankrollDetailsFragment : RealmFragment(), StaticRowRepresentableDataSourc
}
}
override fun onCreateOptionsMenu(menu: Menu?, inflater: MenuInflater?) {
menu?.clear()
inflater?.inflate(R.menu.toolbar_comparison_chart, menu) // TODO R.menu.toolbar_comparison_chart?
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
menu.clear()
inflater.inflate(R.menu.toolbar_comparison_chart, menu) // TODO R.menu.toolbar_comparison_chart?
this.bankrollDetailsMenu = menu
updateMenuUI()
super.onCreateOptionsMenu(menu, inflater)
@ -197,8 +197,8 @@ class BankrollDetailsFragment : RealmFragment(), StaticRowRepresentableDataSourc
}
override fun onOptionsItemSelected(item: MenuItem?): Boolean {
when (item?.itemId) {
override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
R.id.settings -> editBankroll()
}
return true

@ -1,115 +0,0 @@
package net.pokeranalytics.android.ui.fragment
import android.os.Bundle
import android.view.*
import kotlinx.android.synthetic.main.fragment_comparison_chart.*
import net.pokeranalytics.android.R
import net.pokeranalytics.android.ui.activity.BankrollActivity
import net.pokeranalytics.android.ui.activity.SettingsActivity
import net.pokeranalytics.android.ui.adapter.ComparisonChartPagerAdapter
import net.pokeranalytics.android.ui.adapter.RowRepresentableDelegate
import net.pokeranalytics.android.ui.adapter.StaticRowRepresentableDataSource
import net.pokeranalytics.android.ui.extensions.toast
import net.pokeranalytics.android.ui.fragment.components.PokerAnalyticsFragment
import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.rowrepresentable.MoreTabRow
class ComparisonChartFragment : PokerAnalyticsFragment(), StaticRowRepresentableDataSource, RowRepresentableDelegate {
companion object {
/**
* Create new instance
*/
fun newInstance(): ComparisonChartFragment {
val fragment = ComparisonChartFragment()
val bundle = Bundle()
fragment.arguments = bundle
return fragment
}
val rowRepresentation: List<RowRepresentable> by lazy {
val rows = ArrayList<RowRepresentable>()
rows.addAll(MoreTabRow.values())
rows
}
}
private lateinit var viewPagerAdapter: ComparisonChartPagerAdapter
private var comparisonChartMenu: Menu? = null
// Life Cycle
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.fragment_comparison_chart, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
initData()
initUI()
}
override fun onCreateOptionsMenu(menu: Menu?, inflater: MenuInflater?) {
menu?.clear()
inflater?.inflate(R.menu.toolbar_comparison_chart, menu)
this.comparisonChartMenu = menu
super.onCreateOptionsMenu(menu, inflater)
}
override fun onOptionsItemSelected(item: MenuItem?): Boolean {
when (item!!.itemId) {
R.id.settings -> openChangeStatistics()
}
return true
}
// Rows
override fun adapterRows(): List<RowRepresentable>? {
return rowRepresentation
}
override fun onRowSelected(position: Int, row: RowRepresentable, fromAction: Boolean) {
super.onRowSelected(position, row, fromAction)
when(row) {
MoreTabRow.BANKROLL -> BankrollActivity.newInstance(requireContext())
MoreTabRow.SETTINGS -> SettingsActivity.newInstance(requireContext())
}
}
// Business
/**
* Init data
*/
private fun initData() {
}
/**
* Init UI
*/
private fun initUI() {
setDisplayHomeAsUpEnabled(true)
setToolbarTitle(getString(R.string.comparison_chart))
parentActivity?.let {
viewPagerAdapter = ComparisonChartPagerAdapter(requireContext(), it.supportFragmentManager)
viewPager.adapter = viewPagerAdapter
viewPager.offscreenPageLimit = 2
tabs.setupWithViewPager(viewPager)
}
}
/**
* Open change statistics
*/
private fun openChangeStatistics() {
//TODO
toast("Open change statistics")
}
}

@ -3,9 +3,8 @@ package net.pokeranalytics.android.ui.fragment
import android.app.Activity
import android.content.Intent
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.*
import androidx.appcompat.widget.SearchView
import androidx.core.view.isVisible
import androidx.recyclerview.widget.ItemTouchHelper
import androidx.recyclerview.widget.LinearLayoutManager
@ -23,10 +22,12 @@ import net.pokeranalytics.android.ui.activity.FiltersActivity
import net.pokeranalytics.android.ui.adapter.LiveRowRepresentableDataSource
import net.pokeranalytics.android.ui.adapter.RowRepresentableAdapter
import net.pokeranalytics.android.ui.adapter.RowRepresentableDelegate
import net.pokeranalytics.android.ui.extensions.removeMargins
import net.pokeranalytics.android.ui.fragment.components.DeletableItemFragment
import net.pokeranalytics.android.ui.helpers.SwipeToDeleteCallback
import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.RowViewType
import net.pokeranalytics.android.util.extensions.find
import net.pokeranalytics.android.util.extensions.sorted
@ -40,6 +41,16 @@ open class DataListFragment : DeletableItemFragment(), LiveRowRepresentableDataS
private lateinit var dataType: LiveData
private lateinit var items: RealmResults<out Deletable>
private val oldRows: ArrayList<RowRepresentable> = ArrayList()
private var dataListMenu: Menu? = null
private var searchView: SearchView? = null
var isSearchable: Boolean = false
set(value) {
field = value
val searchMenuItem = dataListMenu?.findItem(R.id.action_search)
searchMenuItem?.isVisible = value
}
/**
* Set fragment data
@ -51,13 +62,19 @@ open class DataListFragment : DeletableItemFragment(), LiveRowRepresentableDataS
setToolbarTitle(this.dataType.pluralLocalizedTitle(requireContext()))
this.items = this.retrieveItems(getRealm())
oldRows.addAll(this.items as List<RowRepresentable>)
isSearchable = when (this.dataType) {
LiveData.PLAYER, LiveData.LOCATION -> true
else -> false
}
}
open fun retrieveItems(realm: Realm): RealmResults<out Deletable> {
return realm.sorted(this.identifiableClass, editableOnly = true, filterableTypeUniqueIdentifier = dataType.subType)
return realm.sorted(this.identifiableClass, editableOnly = true, filterableTypeUniqueIdentifier = dataType.subType)
}
override fun deletableItems() : List<Deletable> {
override fun deletableItems(): List<Deletable> {
return this.items
}
@ -71,44 +88,32 @@ open class DataListFragment : DeletableItemFragment(), LiveRowRepresentableDataS
initUI()
}
/**
* Init UI
*/
private fun initUI() {
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
setDisplayHomeAsUpEnabled(true)
menu.clear()
inflater.inflate(R.menu.toolbar_data_list, menu)
this.dataListMenu = menu
val viewManager = LinearLayoutManager(requireContext())
dataListAdapter = RowRepresentableAdapter(this, this)
val searchMenuItem = menu.findItem(R.id.action_search)
searchMenuItem.isVisible = isSearchable
val swipeToDelete = SwipeToDeleteCallback(dataListAdapter) { position ->
val item = this.items[position]
if (item != null) {
val itemId = item.id
deleteItem(dataListAdapter, items, itemId)
} else {
throw PAIllegalStateException("Item with position $position not found")
searchView = searchMenuItem.actionView as SearchView?
searchView?.removeMargins()
searchView?.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
override fun onQueryTextSubmit(query: String?): Boolean {
return false
}
}
val itemTouchHelper = ItemTouchHelper(swipeToDelete)
recyclerView.apply {
setHasFixedSize(true)
layoutManager = viewManager
adapter = dataListAdapter
itemTouchHelper.attachToRecyclerView(this)
}
override fun onQueryTextChange(newText: String?): Boolean {
filterItemsWithSearch(newText)
return false
}
})
this.addButton.setOnClickListener {
EditableDataActivity.newInstance(
requireContext(),
dataType = this.dataType.ordinal,
primaryKey = null
)
}
super.onCreateOptionsMenu(menu, inflater)
}
override fun onResume() {
super.onResume()
this.recyclerView?.adapter?.notifyDataSetChanged()
@ -128,6 +133,7 @@ open class DataListFragment : DeletableItemFragment(), LiveRowRepresentableDataS
}
override fun onRowSelected(position: Int, row: RowRepresentable, fromAction: Boolean) {
searchView?.clearFocus()
when (this.dataType) {
LiveData.FILTER -> {
@ -143,6 +149,52 @@ open class DataListFragment : DeletableItemFragment(), LiveRowRepresentableDataS
}
}
/**
* Init UI
*/
private fun initUI() {
setDisplayHomeAsUpEnabled(true)
val viewManager = LinearLayoutManager(requireContext())
dataListAdapter = RowRepresentableAdapter(this, this)
val swipeToDelete = SwipeToDeleteCallback(dataListAdapter) { position ->
val item = this.items[position]
if (item != null) {
val itemId = item.id
deleteItem(dataListAdapter, items, itemId)
} else {
throw PAIllegalStateException("Item with position $position not found")
}
}
val itemTouchHelper = ItemTouchHelper(swipeToDelete)
recyclerView.apply {
setHasFixedSize(true)
layoutManager = viewManager
adapter = dataListAdapter
itemTouchHelper.attachToRecyclerView(this)
}
this.addButton.setOnClickListener {
EditableDataActivity.newInstance(
requireContext(),
dataType = this.dataType.ordinal,
primaryKey = null
)
}
}
/**
* Filter the items list with the given search content
*/
private fun filterItemsWithSearch(searchContent: String?) {
this.items = getRealm().find(this.identifiableClass, searchContent)
dataListAdapter.notifyDataSetChanged()
}
/**
* Update UI
*/

@ -4,7 +4,6 @@ import android.app.Activity.RESULT_OK
import android.content.Intent
import android.os.Bundle
import android.view.*
import android.widget.Toast
import androidx.core.app.ActivityOptionsCompat
import androidx.core.view.isVisible
import androidx.interpolator.view.animation.FastOutSlowInInterpolator
@ -92,18 +91,15 @@ class FeedFragment : FilterableFragment(), RowRepresentableDelegate {
return inflater.inflate(R.layout.fragment_feed, container, false)
}
override fun onCreateContextMenu(menu: ContextMenu?, v: View?, menuInfo: ContextMenu.ContextMenuInfo?) {
override fun onCreateContextMenu(menu: ContextMenu, v: View, menuInfo: ContextMenu.ContextMenuInfo?) {
super.onCreateContextMenu(menu, v, menuInfo)
if (v?.id == R.id.menuRecyclerView) {
if (v.id == R.id.menuRecyclerView) {
activity?.menuInflater?.inflate(R.menu.menu_session, menu)
}
}
override fun onContextItemSelected(item: MenuItem?): Boolean {
when (item?.itemId) {
override fun onContextItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
R.id.duplicate -> {
val info = item.menuInfo as ContextMenuRecyclerView.RecyclerViewContextMenuInfo
val sessionId = this.feedSessionAdapter.sessionIdForPosition(info.position)
@ -336,6 +332,8 @@ class FeedFragment : FilterableFragment(), RowRepresentableDelegate {
* Show end of beta message
* Keep for possible future uses
*/
//TODO: Delete
/*
private fun showEndOfBetaMessage() {
Toast.makeText(
context,
@ -343,6 +341,7 @@ class FeedFragment : FilterableFragment(), RowRepresentableDelegate {
Toast.LENGTH_LONG
).show()
}
*/
// Filter Handler

@ -18,8 +18,6 @@ import net.pokeranalytics.android.ui.adapter.RowRepresentableAdapter
import net.pokeranalytics.android.ui.adapter.RowRepresentableDelegate
import net.pokeranalytics.android.ui.adapter.StaticRowRepresentableDataSource
import net.pokeranalytics.android.ui.fragment.components.RealmFragment
import net.pokeranalytics.android.ui.fragment.components.bottomsheet.BottomSheetFragment
import net.pokeranalytics.android.ui.helpers.DateTimePickerManager
import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.RowViewType
import net.pokeranalytics.android.ui.view.rowrepresentable.FilterCategoryRow
@ -65,35 +63,7 @@ open class FilterDetailsFragment : RealmFragment(), StaticRowRepresentableDataSo
updateRowsSelection(row)
return
}
when (row) {
is QueryCondition.DateQuery -> DateTimePickerManager.create(
requireContext(),
row,
this,
row.singleValue,
onlyDate = !row.showTime,
onlyTime = row.showTime
)
is QueryCondition.Duration -> {
var hours: String? = null
var minutes: String? = null
row.minutes?.let {
hours = if (it / 60 > 0) (it / 60).toString() else null
minutes = if (it % 60 > 0) (it % 60).toString() else null
}
val data = row.editingDescriptors(mapOf("hours" to hours, "minutes" to minutes))
BottomSheetFragment.create(fragmentManager, row, this, data, true)
}
is QueryCondition.ListOfValues<*> -> {
var valueAsString: String? = null
row.listOfValues.firstOrNull()?.let {
valueAsString = row.listOfValues.firstOrNull()?.toString()
}
val data = row.editingDescriptors(mapOf("valueAsString" to valueAsString))
BottomSheetFragment.create(fragmentManager, row, this, data, true)
}
}
row.startEditing(null, this)
}
override fun stringForRow(row: RowRepresentable, context: Context): String {

@ -104,9 +104,9 @@ open class FiltersFragment : RealmFragment(), StaticRowRepresentableDataSource,
}
}
override fun onCreateOptionsMenu(menu: Menu?, inflater: MenuInflater?) {
menu?.clear()
inflater?.inflate(R.menu.toolbar_editable_data, menu)
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
menu.clear()
inflater.inflate(R.menu.toolbar_editable_data, menu)
this.filterMenu = menu
updateMenuUI()
super.onCreateOptionsMenu(menu, inflater)
@ -120,8 +120,8 @@ open class FiltersFragment : RealmFragment(), StaticRowRepresentableDataSource,
}
}
override fun onOptionsItemSelected(item: MenuItem?): Boolean {
when (item!!.itemId) {
override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
R.id.save -> validateUpdates()
}
return true

@ -10,10 +10,8 @@ import net.pokeranalytics.android.model.interfaces.Identifiable
import net.pokeranalytics.android.model.realm.Filter
import net.pokeranalytics.android.ui.activity.EditableDataActivity
import net.pokeranalytics.android.ui.activity.FiltersActivity
import net.pokeranalytics.android.ui.fragment.components.bottomsheet.BottomSheetFragment
import net.pokeranalytics.android.ui.interfaces.FilterHandler.Companion.INTENT_FILTER_UPDATE_FILTER_UI
import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.RowRepresentableEditDescriptor
import net.pokeranalytics.android.ui.view.RowViewType
import net.pokeranalytics.android.util.Preferences
import timber.log.Timber
@ -55,13 +53,6 @@ open class FiltersListFragment : DataListFragment() {
return if (viewType != -1) viewType else RowViewType.DATA.ordinal
}
override fun editDescriptors(row: RowRepresentable): ArrayList<RowRepresentableEditDescriptor>? {
return when (row) {
is Filter -> row.editingDescriptors(mapOf("defaultValue" to row.name))
else -> super.editDescriptors(row)
}
}
override fun onRowValueChanged(value: Any?, row: RowRepresentable) {
when (row) {
is Filter -> {
@ -91,8 +82,7 @@ open class FiltersListFragment : DataListFragment() {
when (row) {
is Filter -> {
if (fromAction) {
val data = row.editingDescriptors(mapOf("defaultValue" to row.name))
BottomSheetFragment.create(fragmentManager, row, this, data, false, isDeletable = true, valueHasPlaceholder = false)
row.startEditing(null, this)
} else {
val intent = Intent()
intent.putExtra(FiltersActivity.IntentKey.FILTER_ID.keyName, row.id)

@ -1,94 +1,198 @@
package net.pokeranalytics.android.ui.fragment
import android.app.Activity
import android.content.ActivityNotFoundException
import android.content.Intent
import android.net.Uri
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.LinearLayoutManager
import io.realm.Realm
import kotlinx.android.synthetic.main.fragment_more.*
import net.pokeranalytics.android.BuildConfig
import net.pokeranalytics.android.R
import net.pokeranalytics.android.ui.activity.BankrollActivity
import net.pokeranalytics.android.ui.activity.SettingsActivity
import net.pokeranalytics.android.ui.activity.Top10Activity
import net.pokeranalytics.android.model.LiveData
import net.pokeranalytics.android.model.realm.Currency
import net.pokeranalytics.android.model.realm.Session
import net.pokeranalytics.android.ui.activity.*
import net.pokeranalytics.android.ui.activity.components.RequestCode
import net.pokeranalytics.android.ui.adapter.RowRepresentableAdapter
import net.pokeranalytics.android.ui.adapter.RowRepresentableDelegate
import net.pokeranalytics.android.ui.adapter.StaticRowRepresentableDataSource
import net.pokeranalytics.android.ui.extensions.openContactMail
import net.pokeranalytics.android.ui.extensions.openPlayStorePage
import net.pokeranalytics.android.ui.extensions.openUrl
import net.pokeranalytics.android.ui.fragment.components.PokerAnalyticsFragment
import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.rowrepresentable.MoreTabRow
import net.pokeranalytics.android.ui.view.rowrepresentable.SettingRow
import net.pokeranalytics.android.util.Preferences
import net.pokeranalytics.android.util.URL
import net.pokeranalytics.android.util.UserDefaults
import net.pokeranalytics.android.util.billing.AppGuard
import net.pokeranalytics.android.util.billing.IAPProducts
import timber.log.Timber
import java.util.*
class MoreFragment : PokerAnalyticsFragment(), StaticRowRepresentableDataSource, RowRepresentableDelegate {
companion object {
class MoreFragment : PokerAnalyticsFragment(), RowRepresentableDelegate, StaticRowRepresentableDataSource {
/**
* Create new instance
*/
fun newInstance(): MoreFragment {
val fragment = MoreFragment()
val bundle = Bundle()
fragment.arguments = bundle
return fragment
}
val rowRepresentation: List<RowRepresentable> by lazy {
val rows = ArrayList<RowRepresentable>()
rows.addAll(MoreTabRow.values())
rows
}
companion object {
}
/**
* Create new instance
*/
fun newInstance(): MoreFragment {
val fragment = MoreFragment()
val bundle = Bundle()
fragment.arguments = bundle
return fragment
}
val rowRepresentation: List<RowRepresentable> by lazy {
val rows = ArrayList<RowRepresentable>()
rows.addAll(SettingRow.getRows())
rows
}
private lateinit var moreAdapter: RowRepresentableAdapter
}
private lateinit var settingsAdapterRow: RowRepresentableAdapter
// Life Cycle
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.fragment_more, container, false)
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.fragment_more, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
initData()
initUI()
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
initData()
initUI()
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
when (requestCode) {
RequestCode.CURRENCY.value -> {
if (resultCode == Activity.RESULT_OK) {
data?.let {
Preferences.setCurrencyCode(data.getStringExtra(CurrenciesFragment.INTENT_CURRENCY_CODE), requireContext())
val realm = Realm.getDefaultInstance()
realm.executeTransaction {
realm.where(Currency::class.java).isNull("code").or().equalTo("code", UserDefaults.currency.currencyCode).findAll()
.forEach { currency ->
currency.rate = Currency.DEFAULT_RATE
}
realm.where(Session::class.java).isNull("bankroll.currency.code").findAll().forEach { session ->
session.bankrollHasBeenUpdated()
}
}
realm.close()
settingsAdapterRow.refreshRow(SettingRow.CURRENCY)
}
}
}
RequestCode.SUBSCRIPTION.value -> {
settingsAdapterRow.refreshRow(SettingRow.SUBSCRIPTION)
}
}
}
// Rows
override fun adapterRows(): List<RowRepresentable>? {
return rowRepresentation
}
override fun onRowSelected(position: Int, row: RowRepresentable, fromAction: Boolean) {
super.onRowSelected(position, row, fromAction)
when(row) {
MoreTabRow.BANKROLL -> BankrollActivity.newInstance(requireContext())
MoreTabRow.TOP_10 -> Top10Activity.newInstance(requireContext())
MoreTabRow.SETTINGS -> SettingsActivity.newInstance(requireContext())
override fun stringForRow(row: RowRepresentable): String {
return when (row) {
SettingRow.SUBSCRIPTION -> AppGuard.subscriptionStatus(requireContext())
SettingRow.VERSION -> BuildConfig.VERSION_NAME + if (BuildConfig.DEBUG) " (${BuildConfig.VERSION_CODE}) DEBUG" else ""
SettingRow.CURRENCY -> UserDefaults.currency.symbol
else -> ""
}
}
// Business
override fun onRowSelected(position: Int, row: RowRepresentable, fromAction: Boolean) {
when (row) {
SettingRow.BANKROLL_REPORT -> BankrollActivity.newInstance(requireContext())
SettingRow.TOP_10 -> Top10Activity.newInstance(requireContext())
SettingRow.PLAYERS -> DataListActivity.newInstance(requireContext(), LiveData.PLAYER.ordinal)
SettingRow.SUBSCRIPTION -> {
if (!AppGuard.isProUser) {
BillingActivity.newInstanceForResult(this, false)
} else {
this.openPlaystoreAccount()
}
}
SettingRow.RATE_APP -> parentActivity?.openPlayStorePage()
SettingRow.CONTACT_US -> parentActivity?.openContactMail(R.string.contact)
SettingRow.BUG_REPORT -> parentActivity?.openContactMail(R.string.bug_report_subject, Realm.getDefaultInstance().path)
SettingRow.CURRENCY -> CurrenciesActivity.newInstanceForResult(this@MoreFragment, RequestCode.CURRENCY.value)
SettingRow.FOLLOW_US -> {
when (position) {
0 -> parentActivity?.openUrl(URL.BLOG.value)
1 -> parentActivity?.openUrl(URL.INSTAGRAM.value)
2 -> parentActivity?.openUrl(URL.TWITTER.value)
3 -> parentActivity?.openUrl(URL.FACEBOOK.value)
}
}
SettingRow.PRIVACY_POLICY -> parentActivity?.openUrl(URL.PRIVACY_POLICY.value)
SettingRow.TERMS_OF_USE -> parentActivity?.openUrl(URL.TERMS.value)
SettingRow.GDPR -> openGDPRActivity()
}
/**
* Init data
*/
private fun initData() {
}
row.relatedResultsRepresentable?.let {
DataListActivity.newInstance(requireContext(), it.ordinal)
}
}
/**
* Init UI
*/
private fun initUI() {
moreAdapter = RowRepresentableAdapter(this, this)
setToolbarTitle(getString(R.string.more))
val viewManager = LinearLayoutManager(requireContext())
settingsAdapterRow = RowRepresentableAdapter(
this, this
)
recyclerView.apply {
setHasFixedSize(true)
layoutManager = viewManager
adapter = moreAdapter
adapter = settingsAdapterRow
}
}
/**
* Init data
*/
private fun initData() {
}
/**
* Open GDPR Activity
*/
private fun openGDPRActivity() {
val intent = Intent(requireContext(), GDPRActivity::class.java)
startActivity(intent)
}
/**
* Open Google Play account
*/
private fun openPlaystoreAccount() {
val packageName = "net.pokeranalytics.android"
val sku = IAPProducts.PRO.identifier
try {
startActivity(Intent(Intent.ACTION_VIEW, Uri.parse("https://play.google.com/store/account/subscriptions?sku=$sku&package=$packageName")))
} catch (e: ActivityNotFoundException) {
Timber.d(e)
}
}

@ -60,16 +60,16 @@ class ReportCreationFragment : RealmFragment(), RowRepresentableDataSource, RowR
}
}
override fun onCreateOptionsMenu(menu: Menu?, inflater: MenuInflater?) {
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
super.onCreateOptionsMenu(menu, inflater)
menu?.clear()
inflater?.inflate(R.menu.toolbar_report_creation, menu)
menu?.findItem(R.id.add)?.isVisible = false
menu.clear()
inflater.inflate(R.menu.toolbar_report_creation, menu)
menu.findItem(R.id.add)?.isVisible = false
reportCreationMenu = menu
}
override fun onOptionsItemSelected(item: MenuItem?): Boolean {
when (item?.itemId) {
override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
R.id.add -> {
if (this.assistant.step == Assistant.Step.FILTER) {
FiltersActivity.newInstanceForResult(
@ -174,7 +174,7 @@ class ReportCreationFragment : RealmFragment(), RowRepresentableDataSource, RowR
0 -> RowViewType.HEADER_TITLE.ordinal
else -> {
val row = this.currentRows[position]
when (row) {
when (this.currentRows[position]) {
is SeparatorRow -> row.viewType
else -> RowViewType.TITLE_CHECK.ordinal
}

@ -23,8 +23,6 @@ import net.pokeranalytics.android.ui.activity.EditableDataActivity
import net.pokeranalytics.android.ui.adapter.RowRepresentableAdapter
import net.pokeranalytics.android.ui.adapter.RowRepresentableDelegate
import net.pokeranalytics.android.ui.fragment.components.RealmFragment
import net.pokeranalytics.android.ui.fragment.components.bottomsheet.BottomSheetFragment
import net.pokeranalytics.android.ui.helpers.DateTimePickerManager
import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.RowRepresentableDiffCallback
import net.pokeranalytics.android.ui.view.SmoothScrollLinearLayoutManager
@ -82,7 +80,7 @@ class SessionFragment : RealmFragment(), RowRepresentableDelegate {
} else {
throw PAIllegalStateException("Session cannot be null here, session id = $sessionId")
}
} else { // create new session
} else { // buildAndShow new session
realm.executeTransaction { executeRealm ->
currentSession = Session.newInstance(executeRealm, isTournament)
FavoriteSessionFinder.copyParametersFromFavoriteSession(currentSession, null, requireContext())
@ -135,16 +133,16 @@ class SessionFragment : RealmFragment(), RowRepresentableDelegate {
handler.removeCallbacksAndMessages(null)
}
override fun onCreateOptionsMenu(menu: Menu?, inflater: MenuInflater?) {
menu?.clear()
inflater?.inflate(R.menu.toolbar_session, menu)
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
menu.clear()
inflater.inflate(R.menu.toolbar_session, menu)
this.sessionMenu = menu
updateMenuUI()
super.onCreateOptionsMenu(menu, inflater)
}
override fun onOptionsItemSelected(item: MenuItem?): Boolean {
when (item!!.itemId) {
override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
R.id.stop -> stopSession()
R.id.newCustomField -> addNewCustomField()
R.id.restart -> restartTimer()
@ -158,30 +156,7 @@ class SessionFragment : RealmFragment(), RowRepresentableDelegate {
Toast.makeText(requireContext(), "Action for row: $row", Toast.LENGTH_SHORT).show()
return
}
val data = currentSession.editDescriptors(row)
when (row) {
SessionRow.START_DATE -> DateTimePickerManager.create(requireContext(), row, this, currentSession.startDate)
SessionRow.END_DATE -> {
if (this.currentSession.startDate == null) {
Toast.makeText(context, R.string.session_missing_start_date, Toast.LENGTH_SHORT).show()
} else {
DateTimePickerManager.create(
requireContext(),
row,
this,
currentSession.endDate ?: currentSession.startDate ?: Date(),
currentSession.startDate
)
}
}
SessionRow.BANKROLL -> {
BottomSheetFragment.create(fragmentManager, row, this, data, false, currentSession.currency)
}
else -> BottomSheetFragment.create(fragmentManager, row, this, data, currentCurrency = currentSession.currency)
}
row.startEditing(currentSession, this)
}
override fun onRowValueChanged(value: Any?, row: RowRepresentable) {
@ -237,8 +212,7 @@ class SessionFragment : RealmFragment(), RowRepresentableDelegate {
val animationDuration = if (firstDisplay) 0L else 300L
val state = currentSession.getState()
when (state) {
when (currentSession.getState()) {
SessionState.PENDING, SessionState.PLANNED -> {
sessionMenu?.findItem(R.id.restart)?.isVisible = false
floatingActionButton.setImageResource(R.drawable.ic_outline_play)

@ -1,198 +0,0 @@
package net.pokeranalytics.android.ui.fragment
import android.app.Activity
import android.content.ActivityNotFoundException
import android.content.Intent
import android.net.Uri
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.LinearLayoutManager
import io.realm.Realm
import kotlinx.android.synthetic.main.fragment_settings.*
import net.pokeranalytics.android.BuildConfig
import net.pokeranalytics.android.R
import net.pokeranalytics.android.model.realm.Currency
import net.pokeranalytics.android.model.realm.Session
import net.pokeranalytics.android.ui.activity.*
import net.pokeranalytics.android.ui.activity.components.RequestCode
import net.pokeranalytics.android.ui.adapter.RowRepresentableAdapter
import net.pokeranalytics.android.ui.adapter.RowRepresentableDelegate
import net.pokeranalytics.android.ui.adapter.StaticRowRepresentableDataSource
import net.pokeranalytics.android.ui.extensions.openContactMail
import net.pokeranalytics.android.ui.extensions.openPlayStorePage
import net.pokeranalytics.android.ui.extensions.openUrl
import net.pokeranalytics.android.ui.fragment.components.PokerAnalyticsFragment
import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.rowrepresentable.SettingRow
import net.pokeranalytics.android.util.Preferences
import net.pokeranalytics.android.util.URL
import net.pokeranalytics.android.util.UserDefaults
import net.pokeranalytics.android.util.billing.AppGuard
import net.pokeranalytics.android.util.billing.IAPProducts
import timber.log.Timber
import java.util.*
class SettingsFragment : PokerAnalyticsFragment(), RowRepresentableDelegate, StaticRowRepresentableDataSource {
companion object {
/**
* Create new instance
*/
fun newInstance(): SettingsFragment {
val fragment = SettingsFragment()
val bundle = Bundle()
fragment.arguments = bundle
return fragment
}
val rowRepresentation: List<RowRepresentable> by lazy {
val rows = ArrayList<RowRepresentable>()
rows.addAll(SettingRow.getRows())
rows
}
}
private lateinit var settingsAdapterRow: RowRepresentableAdapter
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.fragment_settings, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
initData()
initUI()
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
when (requestCode) {
RequestCode.CURRENCY.value -> {
if (resultCode == Activity.RESULT_OK) {
data?.let {
Preferences.setCurrencyCode(data.getStringExtra(CurrenciesFragment.INTENT_CURRENCY_CODE), requireContext())
val realm = Realm.getDefaultInstance()
realm.executeTransaction {
realm.where(Currency::class.java).isNull("code").or().equalTo("code", UserDefaults.currency.currencyCode).findAll().forEach { currency ->
currency.rate = Currency.DEFAULT_RATE
}
realm.where(Session::class.java).isNull("bankroll.currency.code").findAll().forEach { session ->
session.bankrollHasBeenUpdated()
}
}
realm.close()
settingsAdapterRow.refreshRow(SettingRow.CURRENCY)
}
}
}
RequestCode.SUBSCRIPTION.value -> {
settingsAdapterRow.refreshRow(SettingRow.SUBSCRIPTION)
}
}
}
override fun adapterRows(): List<RowRepresentable>? {
return rowRepresentation
}
override fun stringForRow(row: RowRepresentable): String {
return when (row) {
SettingRow.SUBSCRIPTION -> AppGuard.subscriptionStatus(requireContext())
SettingRow.VERSION -> BuildConfig.VERSION_NAME + if (BuildConfig.DEBUG) " (${BuildConfig.VERSION_CODE}) DEBUG" else ""
SettingRow.CURRENCY -> UserDefaults.currency.symbol
else -> ""
}
}
override fun onRowSelected(position: Int, row: RowRepresentable, fromAction: Boolean) {
when (row) {
SettingRow.BANKROLL_REPORT -> BankrollActivity.newInstance(requireContext())
SettingRow.TOP_10 -> Top10Activity.newInstance(requireContext())
SettingRow.SUBSCRIPTION -> {
if (!AppGuard.isProUser) {
BillingActivity.newInstanceForResult(this, false)
} else {
this.openPlaystoreAccount()
}
}
SettingRow.RATE_APP -> parentActivity?.openPlayStorePage()
SettingRow.CONTACT_US -> parentActivity?.openContactMail(R.string.contact)
SettingRow.BUG_REPORT -> parentActivity?.openContactMail(R.string.bug_report_subject, Realm.getDefaultInstance().path)
SettingRow.CURRENCY -> CurrenciesActivity.newInstanceForResult(this@SettingsFragment, RequestCode.CURRENCY.value)
SettingRow.FOLLOW_US -> {
when (position) {
0 -> parentActivity?.openUrl(URL.BLOG.value)
1 -> parentActivity?.openUrl(URL.INSTAGRAM.value)
2 -> parentActivity?.openUrl(URL.TWITTER.value)
3 -> parentActivity?.openUrl(URL.FACEBOOK.value)
}
}
SettingRow.PRIVACY_POLICY -> parentActivity?.openUrl(URL.PRIVACY_POLICY.value)
SettingRow.TERMS_OF_USE -> parentActivity?.openUrl(URL.TERMS.value)
SettingRow.GDPR -> openGDPRActivity()
}
row.relatedResultsRepresentable?.let {
DataListActivity.newInstance(requireContext(), it.ordinal)
}
}
/**
* Init UI
*/
private fun initUI() {
setToolbarTitle(getString(R.string.more))
setDisplayHomeAsUpEnabled(true)
val viewManager = LinearLayoutManager(requireContext())
settingsAdapterRow = RowRepresentableAdapter(
this, this
)
recyclerView.apply {
setHasFixedSize(true)
layoutManager = viewManager
adapter = settingsAdapterRow
}
}
/**
* Init data
*/
private fun initData() {
}
/**
* Open GDPR Activity
*/
private fun openGDPRActivity() {
val intent = Intent(requireContext(), GDPRActivity::class.java)
startActivity(intent)
}
/**
* Open Google Play account
*/
private fun openPlaystoreAccount() {
val packageName = "net.pokeranalytics.android"
val sku = IAPProducts.PRO.identifier
try {
startActivity(Intent(Intent.ACTION_VIEW, Uri.parse("https://play.google.com/store/account/subscriptions?sku=$sku&package=$packageName")))
} catch (e: ActivityNotFoundException) {
Timber.d(e)
}
}
}

@ -78,7 +78,7 @@ abstract class DeletableItemFragment : RealmFragment() {
this.dataListAdapter = dataListAdapter
// Save the delete position & create a copy of the object
// Save the delete position & buildAndShow a copy of the object
val itemPosition = items.indexOfFirst { it.id == itemId }
val itemToDelete = items.find { it.id == itemId }

@ -18,7 +18,6 @@ import net.pokeranalytics.android.ui.interfaces.FilterHandler
import net.pokeranalytics.android.ui.interfaces.FilterHandler.Companion.INTENT_FILTER_UPDATE_FILTER_UI
import net.pokeranalytics.android.ui.interfaces.FilterableType
import net.pokeranalytics.android.util.Preferences
import timber.log.Timber
/**
@ -70,7 +69,7 @@ open class FilterableFragment : RealmFragment(), FilterHandler {
return super.onCreateView(inflater, container, savedInstanceState)
}
override fun onCreateOptionsMenu(menu: Menu?, inflater: MenuInflater?) {
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
super.onCreateOptionsMenu(menu, inflater)
view?.findViewById<Toolbar>(R.id.toolbar)?.let { toolbar ->
toolbar.menu.removeItem(R.id.menu_item_filter)
@ -80,8 +79,8 @@ open class FilterableFragment : RealmFragment(), FilterHandler {
}
}
override fun onOptionsItemSelected(item: MenuItem?): Boolean {
when (item?.itemId) {
override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
R.id.menu_item_filter -> {
manageFilters(this)
}

@ -46,7 +46,7 @@ class LoaderDialogFragment: DialogFragment() {
override fun onStart() {
super.onStart()
val window = dialog.window
val window = dialog?.window
window?.setBackgroundDrawableResource(android.R.color.transparent)
}

@ -7,11 +7,12 @@ import androidx.fragment.app.Fragment
import com.crashlytics.android.Crashlytics
import net.pokeranalytics.android.R
import net.pokeranalytics.android.ui.activity.components.PokerAnalyticsActivity
import java.io.File
open class PokerAnalyticsFragment : Fragment() {
private var loaderDialogFragment: LoaderDialogFragment? = null
var parentActivity: PokerAnalyticsActivity? = null
open var parentActivity: PokerAnalyticsActivity? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@ -94,4 +95,14 @@ open class PokerAnalyticsFragment : Fragment() {
parentActivity?.supportActionBar?.setDisplayHomeAsUpEnabled(enabled)
}
/**
* Called when the user is adding new photos
*/
open fun isLoadingNewPhotos() {}
/*
* Called when the user has selected photos
*/
open fun getPhotos(files: ArrayList<File>) {}
}

@ -1,50 +0,0 @@
package net.pokeranalytics.android.ui.fragment.components.bottomsheet
import net.pokeranalytics.android.ui.view.RowRepresentable
enum class BottomSheetType {
NONE,
LIST,
LIST_STATIC,
LIST_GAME,
DOUBLE_LIST,
MULTI_SELECTION,
GRID,
EDIT_TEXT,
EDIT_TEXT_MULTI_LINES,
DOUBLE_EDIT_TEXT,
NUMERIC_TEXT,
SUM;
fun newInstance(row: RowRepresentable): BottomSheetFragment {
return when (this) {
NONE -> BottomSheetFragment(row)
LIST -> BottomSheetListFragment(row)
LIST_STATIC -> BottomSheetStaticListFragment(row)
LIST_GAME -> BottomSheetListGameFragment(row)
DOUBLE_LIST -> BottomSheetListGameFragment(row)
MULTI_SELECTION -> BottomSheetMultiSelectionFragment(row)
GRID -> BottomSheetTableSizeGridFragment(row)
EDIT_TEXT -> BottomSheetEditTextFragment(row)
EDIT_TEXT_MULTI_LINES -> BottomSheetEditTextMultiLinesFragment(row)
DOUBLE_EDIT_TEXT -> BottomSheetDoubleEditTextFragment(row)
NUMERIC_TEXT -> BottomSheetNumericTextFragment(row)
SUM -> BottomSheetSumFragment(row)
}
}
val validationRequired: Boolean
get() = when (this) {
LIST, LIST_GAME, LIST_STATIC, GRID, DOUBLE_LIST -> false
else -> true
}
val clearRequired: Boolean
get() = true
val addRequired: Boolean
get() = when (this) {
EDIT_TEXT, NUMERIC_TEXT, DOUBLE_EDIT_TEXT, EDIT_TEXT_MULTI_LINES, GRID, LIST_STATIC, SUM -> false
else -> true
}
}

@ -1,4 +1,4 @@
package net.pokeranalytics.android.ui.fragment.components.bottomsheet
package net.pokeranalytics.android.ui.fragment.components.input
import android.os.Bundle
import android.text.InputType
@ -15,7 +15,7 @@ import net.pokeranalytics.android.ui.view.rowrepresentable.SessionRow
import net.pokeranalytics.android.util.extensions.round
class BottomSheetDoubleEditTextFragment(row: RowRepresentable) : BottomSheetFragment(row) {
class InputDoubleEditTextFragment(row: RowRepresentable) : InputFragment(row) {
private val values = ArrayList<String>()
private var isEditingBlinds: Boolean = false
@ -52,9 +52,9 @@ class BottomSheetDoubleEditTextFragment(row: RowRepresentable) : BottomSheetFrag
* Init UI
*/
private fun initUI() {
val data = getData()?:throw RowRepresentableEditDescriptorException("RowRepresentableEditDescriptor not found")
val data = getData()?:throw RowRepresentableEditDescriptorException("RowEditableDescriptor not found")
if (data.size != 2) {
throw RowRepresentableEditDescriptorException("RowRepresentableEditDescriptor inconsistency")
throw RowRepresentableEditDescriptorException("RowEditableDescriptor inconsistency")
}
values.add(0, "")

@ -1,4 +1,4 @@
package net.pokeranalytics.android.ui.fragment.components.bottomsheet
package net.pokeranalytics.android.ui.fragment.components.input
import android.os.Bundle
import android.text.InputType
@ -13,7 +13,7 @@ import net.pokeranalytics.android.exceptions.RowRepresentableEditDescriptorExcep
import net.pokeranalytics.android.ui.view.RowRepresentable
class BottomSheetEditTextFragment(row: RowRepresentable) : BottomSheetFragment(row) {
class InputEditTextFragment(row: RowRepresentable) : InputFragment(row) {
private var value: String? = null
@ -51,9 +51,9 @@ class BottomSheetEditTextFragment(row: RowRepresentable) : BottomSheetFragment(r
*/
private fun initUI() {
val data = getData()?:throw RowRepresentableEditDescriptorException("RowRepresentableEditDescriptor not found")
val data = getData()?:throw RowRepresentableEditDescriptorException("RowEditableDescriptor not found")
if (data.size != 1) {
throw RowRepresentableEditDescriptorException("RowRepresentableEditDescriptor inconsistency")
throw RowRepresentableEditDescriptorException("RowEditableDescriptor inconsistency")
}
LayoutInflater.from(requireContext()).inflate(R.layout.bottom_sheet_edit_text, view?.bottomSheetContainer, true)

@ -1,4 +1,4 @@
package net.pokeranalytics.android.ui.fragment.components.bottomsheet
package net.pokeranalytics.android.ui.fragment.components.input
import android.os.Bundle
import android.text.InputType
@ -11,7 +11,7 @@ import net.pokeranalytics.android.exceptions.RowRepresentableEditDescriptorExcep
import net.pokeranalytics.android.ui.view.RowRepresentable
class BottomSheetEditTextMultiLinesFragment(row: RowRepresentable) : BottomSheetFragment(row) {
class InputEditTextMultiLinesFragment(row: RowRepresentable) : InputFragment(row) {
private var value: String? = null
@ -43,9 +43,9 @@ class BottomSheetEditTextMultiLinesFragment(row: RowRepresentable) : BottomSheet
* Init UI
*/
private fun initUI() {
val data = getData()?:throw RowRepresentableEditDescriptorException("RowRepresentableEditDescriptor not found")
val data = getData()?:throw RowRepresentableEditDescriptorException("RowEditableDescriptor not found")
if (data.size != 1) {
throw RowRepresentableEditDescriptorException("RowRepresentableEditDescriptor inconsistency")
throw RowRepresentableEditDescriptorException("RowEditableDescriptor inconsistency")
}
LayoutInflater.from(requireContext()).inflate(net.pokeranalytics.android.R.layout.bottom_sheet_edit_text_multi_lines, view?.bottomSheetContainer, true)

@ -1,4 +1,4 @@
package net.pokeranalytics.android.ui.fragment.components.bottomsheet
package net.pokeranalytics.android.ui.fragment.components.input
import android.annotation.SuppressLint
import android.app.Activity.RESULT_OK
@ -10,57 +10,63 @@ import android.view.View
import android.view.ViewGroup
import android.view.WindowManager
import androidx.appcompat.view.ContextThemeWrapper
import androidx.fragment.app.FragmentManager
import androidx.fragment.app.Fragment
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
import io.realm.RealmModel
import kotlinx.android.synthetic.main.fragment_bottom_sheet.*
import net.pokeranalytics.android.R
import net.pokeranalytics.android.exceptions.PAIllegalStateException
import net.pokeranalytics.android.exceptions.PokerAnalyticsException
import net.pokeranalytics.android.model.LiveData
import net.pokeranalytics.android.ui.activity.EditableDataActivity
import net.pokeranalytics.android.ui.activity.components.PokerAnalyticsActivity
import net.pokeranalytics.android.ui.adapter.RowRepresentableDelegate
import net.pokeranalytics.android.ui.adapter.RowEditableDelegate
import net.pokeranalytics.android.ui.helpers.DateTimePickerManager
import net.pokeranalytics.android.ui.view.RowEditableDataSource
import net.pokeranalytics.android.ui.view.RowEditableDescriptor
import net.pokeranalytics.android.ui.view.RowEditableDescriptorType
import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.RowRepresentableEditDescriptor
import net.pokeranalytics.android.ui.view.rowrepresentable.SessionRow
import net.pokeranalytics.android.ui.view.rowrepresentable.TransactionRow
import java.util.*
open class BottomSheetFragment(val row: RowRepresentable) : BottomSheetDialogFragment() {
open class InputFragment(val row: RowRepresentable) : BottomSheetDialogFragment() {
// lateinit var row: RowRepresentable
lateinit var delegate: RowRepresentableDelegate
// lateinit var row: RowRepresentable
lateinit var delegate: RowEditableDelegate
var currentCurrency: Currency? = null
var valueHasPlaceholder: Boolean = false
private var isClearable: Boolean = true
private var isDeletable: Boolean = false
private var rowRepresentableEditDescriptors: ArrayList<RowRepresentableEditDescriptor>? = null
private var rowEditableDescriptors: ArrayList<RowEditableDescriptor>? = null
companion object {
const val REQUEST_CODE_ADD_NEW_OBJECT = 100
fun create(
fragmentManager: FragmentManager?,
fun buildAndShow(
row: RowRepresentable,
delegate: RowRepresentableDelegate,
rowRepresentableEditDescriptors: ArrayList<RowRepresentableEditDescriptor>?,
isClearable: Boolean? = true,
currentCurrency: Currency? = null,
delegate: RowEditableDelegate,
dataSource: RowEditableDataSource?,
isDeletable: Boolean? = false,
valueHasPlaceholder: Boolean? = null
): BottomSheetFragment {
val bottomSheetFragment = row.bottomSheetType.newInstance(row)
bottomSheetFragment.show(fragmentManager, "bottomSheet")
// bottomSheetFragment.row = row
bottomSheetFragment.delegate = delegate
bottomSheetFragment.rowRepresentableEditDescriptors = rowRepresentableEditDescriptors
bottomSheetFragment.isClearable = isClearable ?: true
bottomSheetFragment.isDeletable = isDeletable ?: true
bottomSheetFragment.valueHasPlaceholder = valueHasPlaceholder ?: true
bottomSheetFragment.currentCurrency = currentCurrency
return bottomSheetFragment
) {
if (delegate !is Fragment) throw PokerAnalyticsException.InputFragmentException
if (dataSource?.descriptorType == RowEditableDescriptorType.DATE) {
DateTimePickerManager.buildAndShow(row, delegate, dataSource.descriptors.first())
} else {
delegate.fragmentManager?.let { fragmentManager ->
val bottomSheetFragment = row.inputFragmentType.newInstance(row)
bottomSheetFragment.show(fragmentManager, "bottomSheet")
bottomSheetFragment.delegate = delegate
bottomSheetFragment.rowEditableDescriptors = dataSource?.descriptors
bottomSheetFragment.isClearable = row.valueCanBeClearedWhenEditing
bottomSheetFragment.isDeletable = isDeletable ?: true
bottomSheetFragment.valueHasPlaceholder = valueHasPlaceholder ?: true
bottomSheetFragment.currentCurrency = dataSource?.currency
}
}
}
}
@ -93,9 +99,9 @@ open class BottomSheetFragment(val row: RowRepresentable) : BottomSheetDialogFra
}
@SuppressLint("RestrictedApi")
override fun setupDialog(dialog: Dialog?, style: Int) {
override fun setupDialog(dialog: Dialog, style: Int) {
super.setupDialog(dialog, style)
dialog?.window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE)
dialog.window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE)
}
/**
@ -108,9 +114,9 @@ open class BottomSheetFragment(val row: RowRepresentable) : BottomSheetDialogFra
bottomSheetToolbar.setOnMenuItemClickListener {
false
}
bottomSheetToolbar.menu.findItem(R.id.actionCheck).isVisible = row.bottomSheetType.validationRequired
bottomSheetToolbar.menu.findItem(R.id.actionClear).isVisible = row.bottomSheetType.clearRequired
bottomSheetToolbar.menu.findItem(R.id.actionAdd).isVisible = row.bottomSheetType.addRequired
bottomSheetToolbar.menu.findItem(R.id.actionCheck).isVisible = row.inputFragmentType.validationRequired
bottomSheetToolbar.menu.findItem(R.id.actionClear).isVisible = row.inputFragmentType.clearRequired
bottomSheetToolbar.menu.findItem(R.id.actionAdd).isVisible = row.inputFragmentType.addRequired
// Menu
bottomSheetToolbar.menu.findItem(R.id.actionClear).setOnMenuItemClickListener {
@ -158,8 +164,8 @@ open class BottomSheetFragment(val row: RowRepresentable) : BottomSheetDialogFra
/**
* Return the data list
*/
fun getData(): ArrayList<RowRepresentableEditDescriptor>? {
return this.rowRepresentableEditDescriptors
fun getData(): ArrayList<RowEditableDescriptor>? {
return this.rowEditableDescriptors
}
open fun getValue(): Any? {

@ -0,0 +1,50 @@
package net.pokeranalytics.android.ui.fragment.components.input
import net.pokeranalytics.android.ui.view.RowRepresentable
enum class InputFragmentType {
NONE,
LIST,
LIST_STATIC,
LIST_GAME,
DOUBLE_LIST,
MULTI_SELECTION,
GRID,
EDIT_TEXT,
EDIT_TEXT_MULTI_LINES,
DOUBLE_EDIT_TEXT,
NUMERIC_TEXT,
SUM;
fun newInstance(row: RowRepresentable): InputFragment {
return when (this) {
NONE -> InputFragment(row)
LIST -> InputListFragment(row)
LIST_STATIC -> InputStaticListFragment(row)
LIST_GAME -> InputListGameFragment(row)
DOUBLE_LIST -> InputListGameFragment(row)
MULTI_SELECTION -> InputMultiSelectionFragment(row)
GRID -> InputTableSizeGridFragment(row)
EDIT_TEXT -> InputEditTextFragment(row)
EDIT_TEXT_MULTI_LINES -> InputEditTextMultiLinesFragment(row)
DOUBLE_EDIT_TEXT -> InputDoubleEditTextFragment(row)
NUMERIC_TEXT -> InputNumericTextFragment(row)
SUM -> InputSumFragment(row)
}
}
val validationRequired: Boolean
get() = when (this) {
LIST, LIST_GAME, LIST_STATIC, GRID, DOUBLE_LIST -> false
else -> true
}
val clearRequired: Boolean
get() = true
val addRequired: Boolean
get() = when (this) {
EDIT_TEXT, NUMERIC_TEXT, DOUBLE_EDIT_TEXT, EDIT_TEXT_MULTI_LINES, GRID, LIST_STATIC, SUM -> false
else -> true
}
}

@ -1,4 +1,4 @@
package net.pokeranalytics.android.ui.fragment.components.bottomsheet
package net.pokeranalytics.android.ui.fragment.components.input
import android.os.Bundle
import android.view.LayoutInflater
@ -13,10 +13,11 @@ import net.pokeranalytics.android.exceptions.RowRepresentableEditDescriptorExcep
import net.pokeranalytics.android.ui.adapter.LiveRowRepresentableDataSource
import net.pokeranalytics.android.ui.adapter.RowRepresentableAdapter
import net.pokeranalytics.android.ui.adapter.RowRepresentableDelegate
import net.pokeranalytics.android.ui.view.DataRowEditableDescriptor
import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.RowViewType
open class BottomSheetListFragment(row: RowRepresentable) : BottomSheetFragment(row), LiveRowRepresentableDataSource, RowRepresentableDelegate {
open class InputListFragment(row: RowRepresentable) : InputFragment(row), LiveRowRepresentableDataSource, RowRepresentableDelegate {
lateinit var dataAdapter: RowRepresentableAdapter
var realmData: RealmResults<RowRepresentable>? = null
@ -69,14 +70,14 @@ open class BottomSheetListFragment(row: RowRepresentable) : BottomSheetFragment(
* Init data
*/
open fun initData() {
val bottomSheetData = getData()?:throw RowRepresentableEditDescriptorException("RowRepresentableEditDescriptor not found")
val bottomSheetData = getData()?:throw RowRepresentableEditDescriptorException("RowEditableDescriptor not found")
if (bottomSheetData.size != 1) {
throw RowRepresentableEditDescriptorException("RowRepresentableEditDescriptor inconsistency")
throw RowRepresentableEditDescriptorException("RowEditableDescriptor inconsistency")
}
if (bottomSheetData.first().data == null) {
throw RowRepresentableEditDescriptorException("RowRepresentableEditDescriptor inconsistency")
}
this.realmData = bottomSheetData.first().data as RealmResults<RowRepresentable>
val dataList = bottomSheetData[0]
if (dataList !is DataRowEditableDescriptor) { throw RowRepresentableEditDescriptorException("RowEditableDescriptor inconsistency") }
if (dataList.data == null) { throw RowRepresentableEditDescriptorException("RowEditableDescriptor inconsistency") }
this.realmData = dataList.data
}
/**

@ -1,4 +1,4 @@
package net.pokeranalytics.android.ui.fragment.components.bottomsheet
package net.pokeranalytics.android.ui.fragment.components.input
import android.os.Bundle
import android.view.LayoutInflater
@ -13,13 +13,14 @@ import net.pokeranalytics.android.exceptions.RowRepresentableEditDescriptorExcep
import net.pokeranalytics.android.model.Limit
import net.pokeranalytics.android.ui.adapter.RowRepresentableAdapter
import net.pokeranalytics.android.ui.extensions.px
import net.pokeranalytics.android.ui.view.DataRowEditableDescriptor
import net.pokeranalytics.android.ui.view.RowRepresentable
/**
* Bottom Sheet List Game Fragment
* Display a list of game + chips to choose the game limit
*/
class BottomSheetListGameFragment(row: RowRepresentable) : BottomSheetListFragment(row) {
class InputListGameFragment(row: RowRepresentable) : InputListFragment(row) {
private var limit: Int? = 0
private val values = ArrayList<Any?>()
@ -49,15 +50,15 @@ class BottomSheetListGameFragment(row: RowRepresentable) : BottomSheetListFragme
* Init data
*/
override fun initData() {
val bottomSheetData = getData()?:throw RowRepresentableEditDescriptorException("RowRepresentableEditDescriptor not found")
val bottomSheetData = getData()?:throw RowRepresentableEditDescriptorException("RowEditableDescriptor not found")
if (bottomSheetData.size != 2) {
throw RowRepresentableEditDescriptorException("RowRepresentableEditDescriptor inconsistency")
}
if (bottomSheetData[1].data == null) {
throw RowRepresentableEditDescriptorException("RowRepresentableEditDescriptor inconsistency")
throw RowRepresentableEditDescriptorException("RowEditableDescriptor inconsistency")
}
val dataList = bottomSheetData[1]
if (dataList !is DataRowEditableDescriptor) { throw RowRepresentableEditDescriptorException("RowEditableDescriptor inconsistency") }
if (dataList.data == null) { throw RowRepresentableEditDescriptorException("RowEditableDescriptor inconsistency") }
this.realmData = dataList.data
this.limit = bottomSheetData[0].defaultValue as Int?
this.realmData = bottomSheetData[1].data
}
/**

@ -1,4 +1,4 @@
package net.pokeranalytics.android.ui.fragment.components.bottomsheet
package net.pokeranalytics.android.ui.fragment.components.input
import android.app.Activity
import android.content.Intent
@ -14,7 +14,7 @@ import net.pokeranalytics.android.ui.view.RowViewType
/**
* Manage multiple items selection in a bottom sheet list
*/
open class BottomSheetMultiSelectionFragment(row: RowRepresentable) : BottomSheetListFragment(row) {
open class InputMultiSelectionFragment(row: RowRepresentable) : InputListFragment(row) {
private val selectedRows: ArrayList<RowRepresentable> = ArrayList()
@ -54,9 +54,9 @@ open class BottomSheetMultiSelectionFragment(row: RowRepresentable) : BottomShee
override fun initData() {
super.initData()
val bottomSheetData =
getData() ?: throw RowRepresentableEditDescriptorException("RowRepresentableEditDescriptor not found")
getData() ?: throw RowRepresentableEditDescriptorException("RowEditableDescriptor not found")
if (bottomSheetData.size != 1) {
throw RowRepresentableEditDescriptorException("RowRepresentableEditDescriptor inconsistency")
throw RowRepresentableEditDescriptorException("RowEditableDescriptor inconsistency")
}
bottomSheetData.first().defaultValue?.let {
(it as RealmList<*>).forEach { row ->

@ -1,4 +1,4 @@
package net.pokeranalytics.android.ui.fragment.components.bottomsheet
package net.pokeranalytics.android.ui.fragment.components.input
import android.os.Bundle
import android.text.InputType
@ -14,7 +14,7 @@ import net.pokeranalytics.android.ui.view.RowRepresentable
import java.text.NumberFormat
class BottomSheetNumericTextFragment(row: RowRepresentable) : BottomSheetFragment(row) {
class InputNumericTextFragment(row: RowRepresentable) : InputFragment(row) {
private var value: Double? = null
@ -43,9 +43,9 @@ class BottomSheetNumericTextFragment(row: RowRepresentable) : BottomSheetFragmen
* Init UI
*/
private fun initUI() {
val data = getData()?:throw RowRepresentableEditDescriptorException("RowRepresentableEditDescriptor not found")
val data = getData()?:throw RowRepresentableEditDescriptorException("RowEditableDescriptor not found")
if (data.size != 1) {
throw RowRepresentableEditDescriptorException("RowRepresentableEditDescriptor inconsistency")
throw RowRepresentableEditDescriptorException("RowEditableDescriptor inconsistency")
}
LayoutInflater.from(requireContext()).inflate(R.layout.bottom_sheet_edit_text, view?.bottomSheetContainer, true)

@ -1,4 +1,4 @@
package net.pokeranalytics.android.ui.fragment.components.bottomsheet
package net.pokeranalytics.android.ui.fragment.components.input
import android.os.Bundle
import android.view.LayoutInflater
@ -12,8 +12,9 @@ import net.pokeranalytics.android.ui.adapter.RowRepresentableAdapter
import net.pokeranalytics.android.ui.adapter.RowRepresentableDelegate
import net.pokeranalytics.android.ui.adapter.StaticRowRepresentableDataSource
import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.StaticDataRowEditableDescriptor
class BottomSheetStaticListFragment(row: RowRepresentable) : BottomSheetFragment(row), StaticRowRepresentableDataSource,
class InputStaticListFragment(row: RowRepresentable) : InputFragment(row), StaticRowRepresentableDataSource,
RowRepresentableDelegate {
private var staticRows: List<RowRepresentable> = emptyList()
@ -44,14 +45,14 @@ class BottomSheetStaticListFragment(row: RowRepresentable) : BottomSheetFragment
* Init data
*/
private fun initData() {
val bottomSheetData = getData()?:throw RowRepresentableEditDescriptorException("RowRepresentableEditDescriptor not found")
val bottomSheetData = getData()?:throw RowRepresentableEditDescriptorException("RowEditableDescriptor not found")
if (bottomSheetData.size != 1) {
throw RowRepresentableEditDescriptorException("RowRepresentableEditDescriptor inconsistency")
throw RowRepresentableEditDescriptorException("RowEditableDescriptor inconsistency")
}
if (bottomSheetData.first().staticData == null) {
throw RowRepresentableEditDescriptorException("RowRepresentableEditDescriptor inconsistency")
}
this.staticRows = bottomSheetData.first().staticData as List<RowRepresentable>
val dataList = bottomSheetData[0]
if (dataList !is StaticDataRowEditableDescriptor) { throw RowRepresentableEditDescriptorException("RowEditableDescriptor inconsistency") }
if (dataList.staticData == null) { throw RowRepresentableEditDescriptorException("RowEditableDescriptor inconsistency") }
this.staticRows= dataList.staticData as List<RowRepresentable>
}
/**

@ -1,4 +1,4 @@
package net.pokeranalytics.android.ui.fragment.components.bottomsheet
package net.pokeranalytics.android.ui.fragment.components.input
import android.os.Bundle
import android.text.InputType
@ -16,7 +16,7 @@ import net.pokeranalytics.android.util.extensions.toCurrency
import java.text.NumberFormat
class BottomSheetSumFragment(row: RowRepresentable) : BottomSheetFragment(row) {
class InputSumFragment(row: RowRepresentable) : InputFragment(row) {
private var value = 0.0
private var currentDefaultValue = 0.0
@ -50,9 +50,9 @@ class BottomSheetSumFragment(row: RowRepresentable) : BottomSheetFragment(row) {
* Init UI
*/
private fun initUI() {
val data = getData()?:throw RowRepresentableEditDescriptorException("RowRepresentableEditDescriptor not found")
val data = getData()?:throw RowRepresentableEditDescriptorException("RowEditableDescriptor not found")
if (data.size != 5) {
throw RowRepresentableEditDescriptorException("RowRepresentableEditDescriptor inconsistency")
throw RowRepresentableEditDescriptorException("RowEditableDescriptor inconsistency")
}
LayoutInflater.from(requireContext()).inflate(R.layout.bottom_sheet_sum, view?.bottomSheetContainer, true)

@ -1,4 +1,4 @@
package net.pokeranalytics.android.ui.fragment.components.bottomsheet
package net.pokeranalytics.android.ui.fragment.components.input
import android.os.Bundle
import android.view.LayoutInflater
@ -15,7 +15,7 @@ import net.pokeranalytics.android.ui.extensions.px
import net.pokeranalytics.android.ui.view.GridSpacingItemDecoration
import net.pokeranalytics.android.ui.view.RowRepresentable
class BottomSheetTableSizeGridFragment(row: RowRepresentable) : BottomSheetFragment(row), StaticRowRepresentableDataSource, RowRepresentableDelegate {
class InputTableSizeGridFragment(row: RowRepresentable) : InputFragment(row), StaticRowRepresentableDataSource, RowRepresentableDelegate {
private lateinit var dataAdapter: RowRepresentableAdapter
private var defaultSize: Int? = null
@ -39,9 +39,9 @@ class BottomSheetTableSizeGridFragment(row: RowRepresentable) : BottomSheetFragm
* Init data
*/
private fun initData() {
val bottomSheetData = getData()?:throw RowRepresentableEditDescriptorException("RowRepresentableEditDescriptor not found")
val bottomSheetData = getData()?:throw RowRepresentableEditDescriptorException("RowEditableDescriptor not found")
if (bottomSheetData.size != 1) {
throw RowRepresentableEditDescriptorException("RowRepresentableEditDescriptor inconsistency")
throw RowRepresentableEditDescriptorException("RowEditableDescriptor inconsistency")
}
defaultSize = bottomSheetData.first().defaultValue as Int?
}

@ -14,11 +14,9 @@ import net.pokeranalytics.android.ui.adapter.RowRepresentableDataSource
import net.pokeranalytics.android.ui.adapter.StaticRowRepresentableDataSource
import net.pokeranalytics.android.ui.fragment.CurrenciesFragment
import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.RowRepresentableEditDescriptor
import net.pokeranalytics.android.ui.view.RowViewType
import net.pokeranalytics.android.ui.view.rowrepresentable.BankrollRow
import net.pokeranalytics.android.ui.view.rowrepresentable.CustomizableRowRepresentable
import net.pokeranalytics.android.ui.view.rowrepresentable.SimpleRow
import net.pokeranalytics.android.util.NULL_TEXT
import net.pokeranalytics.android.util.UserDefaults
import net.pokeranalytics.android.util.extensions.toCurrency
@ -85,7 +83,7 @@ class BankrollDataFragment : EditableDataFragment(), StaticRowRepresentableDataS
override fun stringForRow(row: RowRepresentable): String {
return when (row) {
SimpleRow.NAME -> if (bankroll.name.isNotEmpty()) bankroll.name else NULL_TEXT
BankrollRow.NAME -> if (bankroll.name.isNotEmpty()) bankroll.name else NULL_TEXT
BankrollRow.CURRENCY -> {
bankroll.currency?.code?.let { code ->
Currency.getInstance(code).currencyCode
@ -116,20 +114,6 @@ class BankrollDataFragment : EditableDataFragment(), StaticRowRepresentableDataS
}
}
override fun editDescriptors(row: RowRepresentable): ArrayList<RowRepresentableEditDescriptor>? {
return when (row) {
SimpleRow.NAME -> row.editingDescriptors(mapOf("defaultValue" to this.bankroll.name))
BankrollRow.INITIAL_VALUE -> {
row.editingDescriptors(mapOf("defaultValue" to this.bankroll.initialValue))
}
BankrollRow.RATE -> {
val rate = this.bankroll.currency?.rate
row.editingDescriptors(mapOf("defaultValue" to rate))
}
else -> null
}
}
override fun onRowSelected(position: Int, row: RowRepresentable, fromAction: Boolean) {
when (row) {
BankrollRow.CURRENCY -> CurrenciesActivity.newInstanceForResult(this@BankrollDataFragment,
@ -174,7 +158,7 @@ class BankrollDataFragment : EditableDataFragment(), StaticRowRepresentableDataS
private fun refreshRows() {
rows.clear()
rows.add(SimpleRow.NAME)
rows.add(BankrollRow.NAME)
rows.add(BankrollRow.LIVE)
rows.add(BankrollRow.INITIAL_VALUE)
rows.add(CustomizableRowRepresentable(customViewType = RowViewType.HEADER_TITLE, resId = R.string.currency))

@ -17,11 +17,8 @@ import net.pokeranalytics.android.ui.adapter.StaticRowRepresentableDataSource
import net.pokeranalytics.android.ui.extensions.ChipGroupExtension
import net.pokeranalytics.android.ui.extensions.px
import net.pokeranalytics.android.ui.extensions.showAlertDialog
import net.pokeranalytics.android.ui.fragment.components.bottomsheet.BottomSheetFragment
import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.RowRepresentableEditDescriptor
import net.pokeranalytics.android.ui.view.rowrepresentable.CustomFieldRow
import net.pokeranalytics.android.ui.view.rowrepresentable.SimpleRow
import net.pokeranalytics.android.util.NULL_TEXT
import java.util.*
@ -122,7 +119,7 @@ class CustomFieldDataFragment : EditableDataFragment(), StaticRowRepresentableDa
override fun stringForRow(row: RowRepresentable): String {
return when (row) {
SimpleRow.NAME -> if (customField.name.isNotEmpty()) customField.name else NULL_TEXT
CustomFieldRow.NAME -> if (customField.name.isNotEmpty()) customField.name else NULL_TEXT
else -> super.stringForRow(row)
}
}
@ -142,20 +139,9 @@ class CustomFieldDataFragment : EditableDataFragment(), StaticRowRepresentableDa
}
}
override fun editDescriptors(row: RowRepresentable): ArrayList<RowRepresentableEditDescriptor>? {
return when (row) {
SimpleRow.NAME -> row.editingDescriptors(mapOf("defaultValue" to this.customField.name))
is CustomFieldEntry -> row.editingDescriptors(mapOf("defaultValue" to row.value))
else -> null
}
}
override fun onRowSelected(position: Int, row: RowRepresentable, fromAction: Boolean) {
when (row) {
is CustomFieldEntry -> {
val data = customField.editDescriptors(row)
BottomSheetFragment.create(fragmentManager, row, this, data, isClearable = false, isDeletable = true)
}
is CustomFieldEntry -> row.startEditing(null, this)
else -> super.onRowSelected(position, row, fromAction)
}
}
@ -255,7 +241,6 @@ class CustomFieldDataFragment : EditableDataFragment(), StaticRowRepresentableDa
}
}
/**
* Update UI
*/
@ -273,9 +258,7 @@ class CustomFieldDataFragment : EditableDataFragment(), StaticRowRepresentableDa
override fun onDataSaved() {
super.onDataSaved()
this.customField.cleanupEntries()
}
}

@ -18,6 +18,7 @@ import net.pokeranalytics.android.ui.activity.DataListActivity
import net.pokeranalytics.android.ui.activity.EditableDataActivity
import net.pokeranalytics.android.ui.fragment.components.RealmFragment
open class DataManagerFragment : RealmFragment() {
lateinit var item: Deletable
@ -46,9 +47,9 @@ open class DataManagerFragment : RealmFragment() {
loadItem()
}
override fun onCreateOptionsMenu(menu: Menu?, inflater: MenuInflater?) {
menu?.clear()
inflater?.inflate(R.menu.toolbar_editable_data, menu)
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
menu.clear()
inflater.inflate(R.menu.toolbar_editable_data, menu)
this.editableMenu = menu
updateMenuUI()
super.onCreateOptionsMenu(menu, inflater)
@ -62,8 +63,8 @@ open class DataManagerFragment : RealmFragment() {
editableMenu?.findItem(R.id.save)?.isVisible = this.saveButtonShouldAppear
}
override fun onOptionsItemSelected(item: MenuItem?): Boolean {
when (item!!.itemId) {
override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
R.id.save -> saveData()
R.id.delete -> deleteData()
}
@ -147,7 +148,7 @@ open class DataManagerFragment : RealmFragment() {
}
}
open fun willDeleteData() { }
open fun willDeleteData() {}
/**
* Finish the activity with a result

@ -14,8 +14,8 @@ import net.pokeranalytics.android.model.interfaces.Editable
import net.pokeranalytics.android.ui.adapter.RowRepresentableAdapter
import net.pokeranalytics.android.ui.adapter.RowRepresentableDataSource
import net.pokeranalytics.android.ui.adapter.RowRepresentableDelegate
import net.pokeranalytics.android.ui.fragment.components.bottomsheet.BottomSheetFragment
import net.pokeranalytics.android.ui.view.RowRepresentable
import java.io.File
open class EditableDataFragment : DataManagerFragment(), RowRepresentableDelegate {
@ -62,7 +62,7 @@ open class EditableDataFragment : DataManagerFragment(), RowRepresentableDelegat
}
override fun onRowSelected(position: Int, row: RowRepresentable, fromAction: Boolean) {
BottomSheetFragment.create(fragmentManager, row, this, getDataSource().editDescriptors(row))
row.startEditing(this.item, this)
}
override fun onRowValueChanged(value: Any?, row: RowRepresentable) {

@ -8,11 +8,9 @@ import net.pokeranalytics.android.model.realm.Location
import net.pokeranalytics.android.ui.adapter.RowRepresentableDataSource
import net.pokeranalytics.android.ui.adapter.StaticRowRepresentableDataSource
import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.RowRepresentableEditDescriptor
import net.pokeranalytics.android.ui.view.RowViewType
import net.pokeranalytics.android.ui.view.rowrepresentable.CustomizableRowRepresentable
import net.pokeranalytics.android.ui.view.rowrepresentable.LocationRow
import net.pokeranalytics.android.ui.view.rowrepresentable.SimpleRow
import net.pokeranalytics.android.util.NULL_TEXT
/**
@ -47,7 +45,7 @@ class LocationDataFragment : EditableDataFragment(), StaticRowRepresentableDataS
} else if (locationActivated) {
// If we create a new location, we try to locate the user by default
// If we buildAndShow a new location, we try to locate the user by default
isLookingForPlaces = true
getSuggestionsPlaces()
@ -66,7 +64,7 @@ class LocationDataFragment : EditableDataFragment(), StaticRowRepresentableDataS
override fun stringForRow(row: RowRepresentable): String {
return when (row) {
SimpleRow.NAME -> if (location.name.isNotEmpty())location.name else NULL_TEXT
LocationRow.NAME -> if (location.name.isNotEmpty())location.name else NULL_TEXT
else -> return super.stringForRow(row)
}
}
@ -78,13 +76,6 @@ class LocationDataFragment : EditableDataFragment(), StaticRowRepresentableDataS
}
}
override fun editDescriptors(row: RowRepresentable): ArrayList<RowRepresentableEditDescriptor>? {
return when (row) {
SimpleRow.NAME -> row.editingDescriptors(mapOf("defaultValue" to this.location.name))
else -> null
}
}
override fun onRowSelected(position: Int, row: RowRepresentable, fromAction: Boolean) {
// If we click on a location row, save the location (and finish activity)
placesForRows[row]?.place?.let { place ->
@ -128,7 +119,7 @@ class LocationDataFragment : EditableDataFragment(), StaticRowRepresentableDataS
*/
private fun refreshRows() {
rows.clear()
rows.add(SimpleRow.NAME)
rows.add(LocationRow.NAME)
rows.add(LocationRow.LOCATION_PERMISSION_SWITCH)
// Add info row to explain why we need the location permission
rows.add(CustomizableRowRepresentable(customViewType = RowViewType.INFO, resId = R.string.location_when_in_use_usage_description))

@ -0,0 +1,205 @@
package net.pokeranalytics.android.ui.fragment.data
import android.app.Activity.RESULT_OK
import android.content.Intent
import android.graphics.Color
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.app.AlertDialog
import kotlinx.android.synthetic.main.fragment_player.*
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import net.pokeranalytics.android.R
import net.pokeranalytics.android.model.realm.Comment
import net.pokeranalytics.android.model.realm.Player
import net.pokeranalytics.android.ui.activity.ColorPickerActivity
import net.pokeranalytics.android.ui.activity.components.MediaActivity
import net.pokeranalytics.android.ui.adapter.RowRepresentableDataSource
import net.pokeranalytics.android.ui.adapter.StaticRowRepresentableDataSource
import net.pokeranalytics.android.ui.extensions.showAlertDialog
import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.RowViewType
import net.pokeranalytics.android.ui.view.rowrepresentable.PlayerRow
import net.pokeranalytics.android.ui.view.rowrepresentable.SimpleRow
import net.pokeranalytics.android.util.NULL_TEXT
import java.io.File
/**
* Player data fragment
*/
class PlayerDataFragment : EditableDataFragment(), StaticRowRepresentableDataSource {
companion object {
const val REQUEST_CODE_PICK_COLOR = 1000
}
private val player: Player
get() {
return this.item as Player
}
private var mediaActivity: MediaActivity? = null
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
super.onCreateView(inflater, container, savedInstanceState)
shouldOpenKeyboard = false
return inflater.inflate(R.layout.fragment_player, container, false)
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == REQUEST_CODE_PICK_COLOR && resultCode == RESULT_OK && data?.hasExtra(ColorPickerActivity.INTENT_COLOR) == true) {
val color = data.getIntExtra(ColorPickerActivity.INTENT_COLOR, Color.TRANSPARENT)
player.color = if (color != Color.TRANSPARENT) color else null
rowRepresentableAdapter.refreshRow(PlayerRow.IMAGE)
}
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
initUI()
}
override fun getPhotos(files: ArrayList<File>) {
super.getPhotos(files)
files.firstOrNull()?.let { picture ->
player.updateValue(picture.absolutePath, PlayerRow.IMAGE)
rowRepresentableAdapter.refreshRow(PlayerRow.IMAGE)
}
}
override fun getDataSource(): RowRepresentableDataSource {
return this
}
override fun adapterRows(): List<RowRepresentable>? {
return player.adapterRows()
}
override fun viewTypeForPosition(position: Int): Int {
return when (position) {
0 -> RowViewType.ROW_PLAYER_IMAGE.ordinal
else -> super.viewTypeForPosition(position)
}
}
override fun rowRepresentableForPosition(position: Int): RowRepresentable? {
return when (position) {
0 -> player
else -> super.rowRepresentableForPosition(position)
}
}
override fun stringForRow(row: RowRepresentable): String {
return when (row) {
PlayerRow.NAME -> if (player.name.isNotEmpty()) player.name else NULL_TEXT
PlayerRow.SUMMARY -> if (player.summary.isNotEmpty()) player.summary else NULL_TEXT
else -> super.stringForRow(row)
}
}
override fun onRowSelected(position: Int, row: RowRepresentable, fromAction: Boolean) {
when (row) {
PlayerRow.IMAGE -> openPictureDialog()
else -> super.onRowSelected(position, row, fromAction)
}
}
override fun onRowValueChanged(value: Any?, row: RowRepresentable) {
when (row) {
is Comment -> {
row.updateValue(value, row)
player.updateRowRepresentation()
rowRepresentableAdapter.notifyDataSetChanged()
}
else -> {
super.onRowValueChanged(value, row)
if (row == PlayerRow.NAME) {
rowRepresentableAdapter.refreshRow(PlayerRow.IMAGE)
}
}
}
}
override fun onRowDeleted(row: RowRepresentable) {
super.onRowDeleted(row)
when (row) {
is Comment -> {
if (row.isValidForDelete(getRealm())) {
GlobalScope.launch(Dispatchers.Main) {
delay(300)
showAlertDialog(requireContext(), message = R.string.are_you_sure_you_want_to_delete, showCancelButton = true, positiveAction = {
player.deleteComment(row)
rowRepresentableAdapter.notifyDataSetChanged()
})
}
}
}
}
}
/**
* Init UI
*/
private fun initUI() {
mediaActivity = parentActivity as MediaActivity?
player.updateRowRepresentation()
if (!deleteButtonShouldAppear) {
onRowSelected(0, SimpleRow.NAME)
}
addComment.setOnClickListener {
val comment = player.addComment()
rowRepresentableAdapter.notifyDataSetChanged()
onRowSelected(-1, comment)
}
}
/**
* Open picture dialog
*/
private fun openPictureDialog() {
val builder = AlertDialog.Builder(requireContext())
val placesArray = ArrayList<CharSequence>()
placesArray.add(getString(R.string.take_a_picture))
placesArray.add(getString(R.string.library))
placesArray.add(getString(R.string.select_a_color))
if (player.hasPicture()) {
placesArray.add(getString(R.string.remove_picture))
}
builder.setItems(placesArray.toTypedArray()) { _, which ->
when (placesArray[which]) {
getString(R.string.take_a_picture) -> mediaActivity?.openImageCaptureIntent(false)
getString(R.string.library) -> mediaActivity?.openImageGalleryIntent(false)
getString(R.string.select_a_color) -> {
ColorPickerActivity.newInstanceForResult(this, REQUEST_CODE_PICK_COLOR)
}
getString(R.string.remove_picture) -> {
player.updateValue(null, PlayerRow.IMAGE)
rowRepresentableAdapter.refreshRow(PlayerRow.IMAGE)
}
}
}
builder.show()
}
override fun onDataSaved() {
super.onDataSaved()
player.cleanupComments()
}
}

@ -7,20 +7,14 @@ import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import net.pokeranalytics.android.calculus.bankroll.BankrollReportManager
import net.pokeranalytics.android.model.realm.Bankroll
import net.pokeranalytics.android.model.realm.Transaction
import net.pokeranalytics.android.model.realm.TransactionType
import net.pokeranalytics.android.ui.adapter.RowRepresentableDataSource
import net.pokeranalytics.android.ui.adapter.StaticRowRepresentableDataSource
import net.pokeranalytics.android.ui.helpers.DateTimePickerManager
import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.RowRepresentableEditDescriptor
import net.pokeranalytics.android.ui.view.rowrepresentable.TransactionRow
import net.pokeranalytics.android.util.NULL_TEXT
import net.pokeranalytics.android.util.extensions.round
import net.pokeranalytics.android.util.extensions.shortDate
import net.pokeranalytics.android.util.extensions.sorted
import java.util.*
/**
* Custom EditableDataFragment to manage the Transaction data
@ -57,40 +51,6 @@ class TransactionDataFragment : EditableDataFragment(), StaticRowRepresentableDa
}
}
override fun editDescriptors(row: RowRepresentable): ArrayList<RowRepresentableEditDescriptor>? {
return when (row) {
TransactionRow.BANKROLL -> row.editingDescriptors(
mapOf(
"defaultValue" to this.transaction.bankroll,
"data" to getRealm().sorted<Bankroll>()
)
)
TransactionRow.TYPE -> row.editingDescriptors(
mapOf(
"defaultValue" to this.transaction.type,
"data" to getRealm().sorted<TransactionType>()
)
)
TransactionRow.AMOUNT -> row.editingDescriptors(mapOf("defaultValue" to (if (this.transaction.amount != 0.0) this.transaction.amount.round() else "")))
TransactionRow.COMMENT -> row.editingDescriptors(mapOf("defaultValue" to this.transaction.comment))
else -> super.editDescriptors(row)
}
}
override fun onRowSelected(position: Int, row: RowRepresentable, fromAction: Boolean) {
when (row) {
TransactionRow.DATE -> DateTimePickerManager.create(
requireContext(),
row,
this,
this.transaction.date,
onlyDate = true,
isClearable = false
)
else -> super.onRowSelected(position, row, fromAction)
}
}
override fun onRowValueChanged(value: Any?, row: RowRepresentable) {
super.onRowValueChanged(value, row)
rowRepresentableAdapter.refreshRow(row)

@ -4,7 +4,6 @@ import net.pokeranalytics.android.model.realm.Transaction
import net.pokeranalytics.android.model.realm.TransactionType
import net.pokeranalytics.android.ui.adapter.RowRepresentableDataSource
import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.RowRepresentableEditDescriptor
import net.pokeranalytics.android.ui.view.rowrepresentable.SimpleRow
import net.pokeranalytics.android.ui.view.rowrepresentable.TransactionTypeRow
@ -47,10 +46,6 @@ class TransactionTypeDataFragment : EditableDataFragment(), RowRepresentableData
}
}
override fun editDescriptors(row: RowRepresentable): ArrayList<RowRepresentableEditDescriptor>? {
return row.editingDescriptors(mapOf("defaultValue" to this.transactionType.name))
}
override fun isEnabled(row: RowRepresentable): Boolean {
return when (row) {
TransactionTypeRow.TRANSACTION_ADDITIVE -> {

@ -8,9 +8,11 @@ import android.text.format.DateFormat
import android.widget.DatePicker
import android.widget.TimePicker
import android.widget.Toast
import androidx.fragment.app.Fragment
import net.pokeranalytics.android.R
import net.pokeranalytics.android.ui.adapter.RowRepresentableDelegate
import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.exceptions.PokerAnalyticsException
import net.pokeranalytics.android.ui.adapter.RowEditableDelegate
import net.pokeranalytics.android.ui.view.*
import java.util.*
class DateTimePickerManager : DatePickerDialog.OnDateSetListener,
@ -19,7 +21,7 @@ class DateTimePickerManager : DatePickerDialog.OnDateSetListener,
private var context: Context? = null
private lateinit var row: RowRepresentable
private lateinit var delegate: RowRepresentableDelegate
private lateinit var delegate: RowEditableDelegate
private lateinit var calendar: Calendar
private var minimumDate: Date? = null
private var onlyDate: Boolean = false
@ -27,39 +29,34 @@ class DateTimePickerManager : DatePickerDialog.OnDateSetListener,
private var isClearable: Boolean = true
companion object {
fun create(
context: Context,
row: RowRepresentable,
delegate: RowRepresentableDelegate,
date: Date?,
minimumDate: Date? = null,
onlyDate: Boolean? = false,
onlyTime: Boolean? = false,
isClearable: Boolean? = true
): DateTimePickerManager {
val calendar = Calendar.getInstance()
calendar.time = date ?: Date()
val dateTimePickerManager = DateTimePickerManager()
dateTimePickerManager.context = context
dateTimePickerManager.row = row
dateTimePickerManager.delegate = delegate
dateTimePickerManager.calendar = calendar
dateTimePickerManager.minimumDate = minimumDate
dateTimePickerManager.onlyDate = onlyDate ?: false
dateTimePickerManager.onlyTime = onlyTime ?: false
dateTimePickerManager.isClearable = isClearable ?: true
if (dateTimePickerManager.onlyTime) {
dateTimePickerManager.showTimePicker()
} else {
dateTimePickerManager.showDatePicker()
}
return dateTimePickerManager
}
}
fun buildAndShow(
row: RowRepresentable,
delegate: RowEditableDelegate,
dataSource: RowEditableDescriptor
) {
if (delegate !is Fragment) throw PokerAnalyticsException.InputFragmentException
if (dataSource !is DateRowEditableDescriptor) throw PokerAnalyticsException.DateTimePickerException
val calendar = Calendar.getInstance()
calendar.time = dataSource.date ?: Date()
val dateTimePickerManager = DateTimePickerManager()
dateTimePickerManager.context = delegate.context
dateTimePickerManager.row = row
dateTimePickerManager.delegate = delegate
dateTimePickerManager.calendar = calendar
dateTimePickerManager.minimumDate = dataSource.minimumDate
dateTimePickerManager.onlyDate = dataSource.onlyDate
dateTimePickerManager.onlyTime = dataSource.onlyTime
dateTimePickerManager.isClearable = row.valueCanBeClearedWhenEditing
if (dateTimePickerManager.onlyTime) {
dateTimePickerManager.showTimePicker()
} else {
dateTimePickerManager.showDatePicker()
}
}
}
override fun onDateSet(view: DatePicker?, year: Int, month: Int, dayOfMonth: Int) {
calendar.set(Calendar.YEAR, year)

@ -0,0 +1,144 @@
package net.pokeranalytics.android.ui.view
import android.content.Context
import android.graphics.Color
import android.graphics.drawable.GradientDrawable
import android.util.AttributeSet
import android.util.TypedValue
import android.view.LayoutInflater
import android.widget.FrameLayout
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.content.ContextCompat.getColor
import androidx.core.content.res.ResourcesCompat
import com.bumptech.glide.Glide
import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions.withCrossFade
import com.bumptech.glide.request.RequestOptions
import kotlinx.android.synthetic.main.view_player_image.view.*
import net.pokeranalytics.android.R
import net.pokeranalytics.android.model.realm.Player
import net.pokeranalytics.android.ui.extensions.px
/**
* Display a row session
*/
class PlayerImageView : FrameLayout {
enum class Size {
NORMAL,
SMALL;
fun getFontSize(): Float {
return when (this) {
NORMAL -> 32f
SMALL -> 16f
}
}
fun getStrokeSize() : Int {
return when (this) {
NORMAL -> 4.px
SMALL -> 2.px
}
}
}
private lateinit var playerImageView: ConstraintLayout
private var onImageClickListener: OnClickListener? = null
/**
* Constructors
*/
constructor(context: Context) : super(context) {
init()
}
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) {
init()
}
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {
init()
}
/**
* Init
*/
private fun init() {
val layoutInflater = LayoutInflater.from(context)
playerImageView = layoutInflater.inflate(R.layout.view_player_image, this, false) as ConstraintLayout
val layoutParams = LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)
addView(playerImageView, layoutParams)
}
/**
* Set the session data to the view
*/
fun setPlayer(player: Player, size: Size = Size.NORMAL, isClickable: Boolean = true) {
// Initial
val playerInitial = if (player.name.isNotEmpty()) {
val playerData = player.name.split(" ")
if (playerData.size > 1) {
playerData[0].first().toString() + playerData[1].first().toString()
} else if (player.name.length > 1) {
player.name.substring(0, 2)
} else {
player.name.substring(0, player.name.length)
}
} else {
"" //NULL_TEXT
}
// Picture
if (player.hasPicture()) {
playerImageView.playerInitial.text = ""
Glide.with(this)
.load(player.picture)
.apply(RequestOptions().circleCrop())
.transition(withCrossFade())
.into(playerImageView.playerImage)
} else {
playerImageView.playerStroke.background = ResourcesCompat.getDrawable(resources, R.drawable.circle_stroke_kaki, null)
playerImageView.playerImage.setImageDrawable(null)
playerImageView.playerInitial.text = playerInitial
playerImageView.playerInitial.setTextSize(TypedValue.COMPLEX_UNIT_SP, size.getFontSize())
}
// Player color
val color = if (player.color != null) {
player.color as Int
} else if (player.hasPicture()) {
Color.TRANSPARENT
} else {
getColor(context, R.color.kaki)
}
// Stroke & initial
val drawable = playerImageView.playerStroke.background as GradientDrawable?
drawable?.setStroke(size.getStrokeSize(), color)
playerImageView.playerInitial.setTextColor(color)
// Click listener
if (isClickable) {
playerImageView.playerImageSelection.setOnClickListener {
onImageClickListener?.onClick(it)
}
} else {
playerImageView.playerImageSelection.background = null
}
}
/**
* Set image click listener
*/
fun setOnImageClickListener(onImageClickListener: OnClickListener) {
this.onImageClickListener = onImageClickListener
}
}

@ -0,0 +1,92 @@
package net.pokeranalytics.android.ui.view
import io.realm.RealmResults
import net.pokeranalytics.android.exceptions.RowRepresentableEditDescriptorException
import net.pokeranalytics.android.util.UserDefaults
import java.util.*
import kotlin.collections.ArrayList
/**
* An container class to describe the way an field of an object will be edited
*/
enum class RowEditableDescriptorType {
DATE,
DATA,
STATIC,
DEFAULT
}
open class RowEditableDescriptor(var defaultValue: Any? = null,
var hint: Int? = null,
var inputType: Int? = null)
class DateRowEditableDescriptor(date: Date? = null,
val minimumDate: Date? = null,
var onlyDate: Boolean = false,
var onlyTime: Boolean = false): RowEditableDescriptor(defaultValue = date) {
val date: Date?
get() {
return defaultValue as Date?
}
}
class DataRowEditableDescriptor(
defaultValue: Any? = null,
hint: Int? = null,
inputType: Int? = null,
data: RealmResults<*>? = null): RowEditableDescriptor(defaultValue, hint, inputType) {
var data: RealmResults<RowRepresentable>? = null
init {
if (data != null && data.count() > 0) {
if (data.first() is RowRepresentable) {
this.data = data as RealmResults<RowRepresentable>?
}
}
}
}
class StaticDataRowEditableDescriptor(
defaultValue: Any? = null,
hint: Int? = null,
inputType: Int? = null,
var staticData: List<RowRepresentable>? = null): RowEditableDescriptor(defaultValue, hint, inputType) {
}
class RowEditableDataSource(customCurrency: Currency? = null) {
var currency: Currency = UserDefaults.currency
init {
customCurrency?.let { currency = it }
}
var descriptors = ArrayList<RowEditableDescriptor>()
fun append(defaultValue: Any? = null, hint: Int? = null, inputType: Int? = null, data: RealmResults<*>? = null, staticData: List<RowRepresentable>? = null) {
when {
data != null -> descriptors.add(DataRowEditableDescriptor(defaultValue, hint, inputType, data))
staticData != null -> descriptors.add(StaticDataRowEditableDescriptor(defaultValue, hint, inputType, staticData))
else -> descriptors.add(RowEditableDescriptor(defaultValue, hint, inputType))
}
}
fun appendDateDescriptor(date:Date?= null,
minimumDate: Date? = null,
onlyDate: Boolean = false,
onlyTime: Boolean = false) {
descriptors.add(DateRowEditableDescriptor(date, minimumDate, onlyDate, onlyTime))
}
val descriptorType: RowEditableDescriptorType
get() {
return when (descriptors.firstOrNull()) {
null -> throw RowRepresentableEditDescriptorException("RowEditableDescriptor inconsistency")
is DateRowEditableDescriptor -> RowEditableDescriptorType.DATE
is DataRowEditableDescriptor -> RowEditableDescriptorType.DATA
is StaticDataRowEditableDescriptor -> RowEditableDescriptorType.STATIC
else -> RowEditableDescriptorType.DEFAULT
}
}
}

@ -1,31 +1,26 @@
package net.pokeranalytics.android.ui.view
import android.content.Context
import androidx.fragment.app.Fragment
import net.pokeranalytics.android.model.LiveData
import net.pokeranalytics.android.ui.fragment.components.bottomsheet.BottomSheetType
import net.pokeranalytics.android.ui.fragment.components.input.InputFragmentType
import net.pokeranalytics.android.util.NULL_TEXT
/**
* An interface extending Displayable to add a way to represent an object as a String
*/
interface RowRepresentable : Displayable, EditDataSource, ImageDecorator {
interface RowRepresentable : Displayable, RowEditable, ImageDecorator {
fun getDisplayName(context: Context): String {
return NULL_TEXT
}
}
interface EditDataSource {
fun editingDescriptors(map: Map<String, Any?>): ArrayList<RowRepresentableEditDescriptor>? {
return null
}
}
interface RowEditable {
fun startEditing(dataSource:Any?, parent:Fragment?) {}
interface DefaultEditDataSource : EditDataSource, Localizable {
override fun editingDescriptors(map: Map<String, Any?>): ArrayList<RowRepresentableEditDescriptor>? {
val defaultValue: String? by map
return arrayListOf(RowRepresentableEditDescriptor(defaultValue, this.resId))
}
val valueCanBeClearedWhenEditing: Boolean
get() { return true }
}
/**
@ -62,9 +57,9 @@ interface Displayable : Localizable {
return null
}
val bottomSheetType: BottomSheetType
val inputFragmentType: InputFragmentType
get() {
return BottomSheetType.NONE
return InputFragmentType.NONE
}
val selectedChoice: Int

@ -1,14 +0,0 @@
package net.pokeranalytics.android.ui.view
import io.realm.RealmResults
/**
* An container class to describe the way an field of an object will be edited
*/
class RowRepresentableEditDescriptor(
var defaultValue: Any? = null,
var hint: Int? = null,
var inputType: Int? = null,
var data: RealmResults<RowRepresentable>? = null,
var staticData: List<RowRepresentable>? = null
)

@ -26,6 +26,7 @@ import net.pokeranalytics.android.calculus.bankroll.BankrollReportManager
import net.pokeranalytics.android.model.TableSize
import net.pokeranalytics.android.model.extensions.getFormattedGameType
import net.pokeranalytics.android.model.realm.CustomField
import net.pokeranalytics.android.model.realm.Player
import net.pokeranalytics.android.model.realm.Session
import net.pokeranalytics.android.model.realm.Transaction
import net.pokeranalytics.android.ui.adapter.RowRepresentableAdapter
@ -59,6 +60,7 @@ enum class RowViewType(private var layoutRes: Int) {
HEADER_TITLE_VALUE(R.layout.row_header_title_value),
HEADER_TITLE_AMOUNT(R.layout.row_header_title_amount),
HEADER_TITLE_AMOUNT_BIG(R.layout.row_header_title_amount_big),
HEADER_SUBTITLE(R.layout.row_header_subtitle),
LOCATION_TITLE(R.layout.row_title),
INFO(R.layout.row_info),
@ -69,8 +71,10 @@ enum class RowViewType(private var layoutRes: Int) {
TITLE_VALUE(R.layout.row_title_value),
TITLE_VALUE_ARROW(R.layout.row_title_value_arrow),
TITLE_VALUE_ACTION(R.layout.row_title_value_action),
TITLE_SUBTITLE(R.layout.row_title_subtitle),
TITLE_SWITCH(R.layout.row_title_switch),
TITLE_GRID(R.layout.row_bottom_sheet_grid_title),
CONTENT(R.layout.row_content),
DATA(R.layout.row_title),
BOTTOM_SHEET_DATA(R.layout.row_bottom_sheet_title),
TITLE_CHECK(R.layout.row_title_check),
@ -80,6 +84,8 @@ enum class RowViewType(private var layoutRes: Int) {
// Custom row
ROW_SESSION(R.layout.row_feed_session),
ROW_TRANSACTION(R.layout.row_transaction),
ROW_PLAYER(R.layout.row_player),
ROW_PLAYER_IMAGE(R.layout.row_player_image),
ROW_TOP_10(R.layout.row_top_10),
ROW_BUTTON(R.layout.row_button),
ROW_FOLLOW_US(R.layout.row_follow_us),
@ -102,10 +108,10 @@ enum class RowViewType(private var layoutRes: Int) {
return when (this) {
// Row View Holder
HEADER_TITLE, HEADER_TITLE_VALUE, HEADER_TITLE_AMOUNT, HEADER_TITLE_AMOUNT_BIG, LOCATION_TITLE,
INFO, TITLE, TITLE_ARROW, TITLE_ICON_ARROW, TITLE_VALUE, TITLE_VALUE_ARROW, TITLE_VALUE_ACTION, TITLE_GRID,
TITLE_SWITCH, TITLE_CHECK, TITLE_VALUE_CHECK,
DATA, BOTTOM_SHEET_DATA, LOADER -> RowViewHolder(layout)
HEADER_TITLE, HEADER_TITLE_VALUE, HEADER_TITLE_AMOUNT, HEADER_TITLE_AMOUNT_BIG, HEADER_SUBTITLE, LOCATION_TITLE,
INFO, TITLE, TITLE_ARROW, TITLE_ICON_ARROW, TITLE_VALUE, TITLE_VALUE_ARROW, TITLE_VALUE_ACTION, TITLE_SUBTITLE,
TITLE_GRID, TITLE_SWITCH, TITLE_CHECK, TITLE_VALUE_CHECK,
CONTENT, DATA, BOTTOM_SHEET_DATA, LOADER -> RowViewHolder(layout)
// Row Session
ROW_SESSION -> RowSessionViewHolder(layout)
@ -116,6 +122,10 @@ enum class RowViewType(private var layoutRes: Int) {
// Row Transaction
ROW_TOP_10 -> RowTop10ViewHolder(layout)
ROW_PLAYER -> RowPlayerViewHolder(layout)
ROW_PLAYER_IMAGE -> RowPlayerImageViewHolder(layout)
// Row Button
ROW_BUTTON -> RowButtonViewHolder(layout)
@ -468,7 +478,7 @@ enum class RowViewType(private var layoutRes: Int) {
val listener = View.OnClickListener {
adapter.delegate?.onRowSelected(position, row)
}
itemView.findViewById<ConstraintLayout>(R.id.container)?.setOnClickListener(listener)
itemView.findViewById<ConstraintLayout?>(R.id.container)?.setOnClickListener(listener)
}
}
@ -483,7 +493,7 @@ enum class RowViewType(private var layoutRes: Int) {
if (row is CustomFieldRow) {
itemView.findViewById<ChipGroup>(R.id.chipGroup)?.let { chipGroup ->
itemView.findViewById<ChipGroup?>(R.id.chipGroup)?.let { chipGroup ->
chipGroup.removeAllViews()
chipGroup.setOnCheckedChangeListener(null)
@ -526,9 +536,9 @@ enum class RowViewType(private var layoutRes: Int) {
*/
inner class RowButtonViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView), BindableHolder {
override fun bind(position: Int, row: RowRepresentable, adapter: RowRepresentableAdapter) {
itemView.findViewById<AppCompatTextView>(R.id.title).text = row.localizedTitle(itemView.context)
itemView.findViewById<AppCompatTextView>(R.id.title).isVisible = !adapter.dataSource.boolForRow(row)
itemView.findViewById<ContentLoadingProgressBar>(R.id.progressBar).isVisible = adapter.dataSource.boolForRow(row)
itemView.findViewById<AppCompatTextView?>(R.id.title)?.text = row.localizedTitle(itemView.context)
itemView.findViewById<AppCompatTextView?>(R.id.title)?.isVisible = !adapter.dataSource.boolForRow(row)
itemView.findViewById<ContentLoadingProgressBar?>(R.id.progressBar)?.isVisible = adapter.dataSource.boolForRow(row)
val listener = View.OnClickListener {
adapter.delegate?.onRowSelected(position, row)
}
@ -623,6 +633,47 @@ enum class RowViewType(private var layoutRes: Int) {
}
/**
* Display a player image view
*/
inner class RowPlayerViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView), BindableHolder {
override fun bind(position: Int, row: RowRepresentable, adapter: RowRepresentableAdapter) {
if (row is Player) {
itemView.findViewById<PlayerImageView?>(R.id.playerImage)?.let { playerImageView ->
playerImageView.setPlayer(row, PlayerImageView.Size.SMALL, false)
}
itemView.findViewById<AppCompatTextView?>(R.id.playerName)?.let { textView ->
textView.text = row.name
}
itemView.findViewById<AppCompatTextView?>(R.id.playerSummary)?.let { textView ->
textView.text = row.summary
textView.isVisible = row.summary.isNotEmpty()
}
val listener = View.OnClickListener {
adapter.delegate?.onRowSelected(position, row)
}
itemView.setOnClickListener(listener)
}
}
}
/**
* Display a player image view
*/
inner class RowPlayerImageViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView), BindableHolder {
override fun bind(position: Int, row: RowRepresentable, adapter: RowRepresentableAdapter) {
itemView.findViewById<PlayerImageView?>(R.id.playerImageView)?.let { playerImageView ->
val listener = View.OnClickListener {
adapter.delegate?.onRowSelected(position, PlayerRow.IMAGE)
}
playerImageView.setPlayer(row as Player)
playerImageView.setOnImageClickListener(listener)
}
}
}
/**
* Display a separator
*/

@ -1,15 +1,18 @@
package net.pokeranalytics.android.ui.view.rowrepresentable
import android.text.InputType
import androidx.fragment.app.Fragment
import net.pokeranalytics.android.R
import net.pokeranalytics.android.ui.fragment.components.bottomsheet.BottomSheetType
import net.pokeranalytics.android.ui.view.DefaultEditDataSource
import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.RowRepresentableEditDescriptor
import net.pokeranalytics.android.ui.view.RowViewType
import net.pokeranalytics.android.exceptions.PokerAnalyticsException
import net.pokeranalytics.android.model.realm.Bankroll
import net.pokeranalytics.android.ui.adapter.RowRepresentableDelegate
import net.pokeranalytics.android.ui.fragment.components.input.InputFragment
import net.pokeranalytics.android.ui.fragment.components.input.InputFragmentType
import net.pokeranalytics.android.ui.view.*
import java.util.*
enum class BankrollRow : RowRepresentable, DefaultEditDataSource {
enum class BankrollRow : RowRepresentable {
NAME,
LIVE,
INITIAL_VALUE,
CURRENCY,
@ -19,6 +22,7 @@ enum class BankrollRow : RowRepresentable, DefaultEditDataSource {
override val resId: Int?
get() {
return when (this) {
NAME -> R.string.name
LIVE -> R.string.online
INITIAL_VALUE -> R.string.initial_value
CURRENCY -> R.string.currency
@ -30,6 +34,7 @@ enum class BankrollRow : RowRepresentable, DefaultEditDataSource {
override val viewType: Int
get() {
return when (this) {
NAME -> RowViewType.TITLE_VALUE.ordinal
LIVE -> RowViewType.TITLE_SWITCH.ordinal
INITIAL_VALUE -> RowViewType.TITLE_VALUE.ordinal
CURRENCY -> RowViewType.TITLE_VALUE_ARROW.ordinal
@ -38,34 +43,32 @@ enum class BankrollRow : RowRepresentable, DefaultEditDataSource {
}
}
override val bottomSheetType: BottomSheetType
override val inputFragmentType: InputFragmentType
get() {
return when (this) {
LIVE -> BottomSheetType.NONE
INITIAL_VALUE -> BottomSheetType.NUMERIC_TEXT
CURRENCY -> BottomSheetType.NONE
RATE -> BottomSheetType.NUMERIC_TEXT
REFRESH_RATE -> BottomSheetType.NONE
NAME -> InputFragmentType.EDIT_TEXT
LIVE -> InputFragmentType.NONE
INITIAL_VALUE -> InputFragmentType.NUMERIC_TEXT
CURRENCY -> InputFragmentType.NONE
RATE -> InputFragmentType.NUMERIC_TEXT
REFRESH_RATE -> InputFragmentType.NONE
}
}
override fun editingDescriptors(map: Map<String, Any?>): ArrayList<RowRepresentableEditDescriptor>? {
return when (this) {
INITIAL_VALUE -> {
val defaultValue : Any? by map
arrayListOf(
RowRepresentableEditDescriptor(defaultValue, R.string.initial_value, InputType.TYPE_CLASS_NUMBER
or InputType.TYPE_NUMBER_FLAG_DECIMAL)
)
}
RATE -> {
val defaultValue : Any? by map
arrayListOf(
RowRepresentableEditDescriptor(defaultValue, R.string.rate, InputType.TYPE_CLASS_NUMBER
or InputType.TYPE_NUMBER_FLAG_DECIMAL)
)
}
else -> super<RowRepresentable>.editingDescriptors(map)
}
}
override fun startEditing(dataSource: Any?, parent: Fragment?) {
if (dataSource == null) return
if (dataSource !is Bankroll) return
if (parent == null) return
if (parent !is RowRepresentableDelegate) return
val bankrollCurrency: Currency? = dataSource.currency?.code?.let { Currency.getInstance(it) }
val data = RowEditableDataSource(bankrollCurrency)
when (this) {
NAME -> data.append(dataSource.name)
INITIAL_VALUE -> data.append(dataSource.initialValue, R.string.initial_value, InputType.TYPE_CLASS_NUMBER or InputType.TYPE_NUMBER_FLAG_DECIMAL)
RATE -> data.append(dataSource.currency?.rate, R.string.rate, InputType.TYPE_CLASS_NUMBER or InputType.TYPE_NUMBER_FLAG_DECIMAL)
else -> PokerAnalyticsException.InputFragmentException
}
InputFragment.buildAndShow(this, parent, data)
}
}

@ -1,19 +1,25 @@
package net.pokeranalytics.android.ui.view.rowrepresentable
import androidx.fragment.app.Fragment
import net.pokeranalytics.android.R
import net.pokeranalytics.android.exceptions.PokerAnalyticsException
import net.pokeranalytics.android.model.realm.CustomField
import net.pokeranalytics.android.ui.fragment.components.bottomsheet.BottomSheetType
import net.pokeranalytics.android.ui.view.DefaultEditDataSource
import net.pokeranalytics.android.ui.adapter.RowRepresentableDelegate
import net.pokeranalytics.android.ui.fragment.components.input.InputFragment
import net.pokeranalytics.android.ui.fragment.components.input.InputFragmentType
import net.pokeranalytics.android.ui.view.RowEditableDataSource
import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.RowViewType
enum class CustomFieldRow : RowRepresentable, DefaultEditDataSource {
enum class CustomFieldRow : RowRepresentable {
NAME,
TYPE,
COPY_ON_DUPLICATE;
override val resId: Int?
get() {
return when (this) {
NAME -> R.string.name
COPY_ON_DUPLICATE -> R.string.copy_on_duplicate
else -> null
}
@ -22,16 +28,18 @@ enum class CustomFieldRow : RowRepresentable, DefaultEditDataSource {
override val viewType: Int
get() {
return when (this) {
NAME -> RowViewType.TITLE_VALUE.ordinal
TYPE -> RowViewType.LIST.ordinal
COPY_ON_DUPLICATE -> RowViewType.TITLE_SWITCH.ordinal
}
}
override val bottomSheetType: BottomSheetType
override val inputFragmentType: InputFragmentType
get() {
return when (this) {
TYPE -> BottomSheetType.NONE
COPY_ON_DUPLICATE -> BottomSheetType.NONE
NAME -> InputFragmentType.EDIT_TEXT
TYPE -> InputFragmentType.NONE
COPY_ON_DUPLICATE -> InputFragmentType.NONE
}
}
@ -55,4 +63,17 @@ enum class CustomFieldRow : RowRepresentable, DefaultEditDataSource {
}
return list
}
override fun startEditing(dataSource: Any?, parent: Fragment?) {
if (dataSource == null) return
if (dataSource !is CustomField) return
if (parent == null) return
if (parent !is RowRepresentableDelegate) return
val data = RowEditableDataSource()
when (this) {
NAME -> data.append(dataSource.name)
else -> PokerAnalyticsException.InputFragmentException
}
InputFragment.buildAndShow(this, parent, data)
}
}

@ -1,27 +1,37 @@
package net.pokeranalytics.android.ui.view.rowrepresentable
import android.text.InputType
import androidx.fragment.app.Fragment
import net.pokeranalytics.android.R
import net.pokeranalytics.android.model.filter.QueryCondition
import net.pokeranalytics.android.ui.fragment.components.bottomsheet.BottomSheetType
import net.pokeranalytics.android.ui.adapter.RowRepresentableDelegate
import net.pokeranalytics.android.ui.fragment.components.input.InputFragment
import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.RowRepresentableEditDescriptor
import net.pokeranalytics.android.ui.view.RowViewType
import java.util.*
import net.pokeranalytics.android.ui.view.RowEditableDataSource
interface FilterElementRow : RowRepresentable {
override fun editingDescriptors(map: Map<String, Any?>): ArrayList<RowRepresentableEditDescriptor>? {
return when (this) {
override fun startEditing(dataSource: Any?, parent: Fragment?) {
if (parent == null) return
if (parent !is RowRepresentableDelegate) return
val data = RowEditableDataSource()
when (this) {
is QueryCondition.DateQuery -> data.appendDateDescriptor(this.singleValue, onlyDate = !this.showTime, onlyTime = this.showTime)
is QueryCondition.Duration -> {
val hours: String? by map
val minutes: String? by map
arrayListOf(
RowRepresentableEditDescriptor(hours, R.string.hour, inputType = InputType.TYPE_CLASS_NUMBER),
RowRepresentableEditDescriptor(minutes, R.string.minute, inputType = InputType.TYPE_CLASS_NUMBER)
)
var hours: String? = null
var minutes: String? = null
this.minutes?.let {
hours = if (it / 60 > 0) (it / 60).toString() else null
minutes = if (it % 60 > 0) (it % 60).toString() else null
}
data.append(hours, R.string.hour, inputType = InputType.TYPE_CLASS_NUMBER)
data.append(minutes, R.string.minute, inputType = InputType.TYPE_CLASS_NUMBER)
}
is QueryCondition.ListOfValues<*> -> {
val valueAsString: String? by map
var valueAsString: String? = null
this.listOfValues.firstOrNull()?.let {
valueAsString = this.listOfValues.firstOrNull()?.toString()
}
val hint = when (this.operator) {
QueryCondition.Operator.MORE, QueryCondition.Operator.LESS -> {
when (this) {
@ -32,13 +42,11 @@ interface FilterElementRow : RowRepresentable {
}
else -> this.resId
}
arrayListOf(
RowRepresentableEditDescriptor(valueAsString, hint, inputType = InputType.TYPE_CLASS_NUMBER)
)
data.append(valueAsString, hint, inputType = InputType.TYPE_CLASS_NUMBER)
}
else -> super.editingDescriptors(map)
}
InputFragment.buildAndShow(this, parent, data)
}
var filterSectionRow: FilterSectionRow

@ -1,17 +1,23 @@
package net.pokeranalytics.android.ui.view.rowrepresentable
import androidx.fragment.app.Fragment
import net.pokeranalytics.android.R
import net.pokeranalytics.android.ui.fragment.components.bottomsheet.BottomSheetType
import net.pokeranalytics.android.ui.view.DefaultEditDataSource
import net.pokeranalytics.android.model.realm.Game
import net.pokeranalytics.android.ui.adapter.RowRepresentableDelegate
import net.pokeranalytics.android.ui.fragment.components.input.InputFragment
import net.pokeranalytics.android.ui.fragment.components.input.InputFragmentType
import net.pokeranalytics.android.ui.view.RowEditableDataSource
import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.RowViewType
enum class GameRow : RowRepresentable, DefaultEditDataSource {
enum class GameRow : RowRepresentable {
NAME,
SHORT_NAME;
override val resId: Int?
get() {
return when (this) {
NAME -> R.string.name
SHORT_NAME -> R.string.short_name
}
}
@ -19,15 +25,30 @@ enum class GameRow : RowRepresentable, DefaultEditDataSource {
override val viewType: Int
get() {
return when (this) {
NAME -> RowViewType.TITLE_VALUE.ordinal
SHORT_NAME -> RowViewType.TITLE_VALUE.ordinal
}
}
override val bottomSheetType: BottomSheetType
override val inputFragmentType: InputFragmentType
get() {
return when (this) {
SHORT_NAME -> BottomSheetType.EDIT_TEXT
NAME -> InputFragmentType.EDIT_TEXT
SHORT_NAME -> InputFragmentType.EDIT_TEXT
}
}
override fun startEditing(dataSource: Any?, parent: Fragment?) {
if (dataSource == null) return
if (dataSource !is Game) return
if (parent == null) return
if (parent !is RowRepresentableDelegate) return
val data = RowEditableDataSource()
when (this) {
NAME -> data.append(dataSource.name)
SHORT_NAME -> data.append(dataSource.shortName)
}
InputFragment.buildAndShow(this, parent, data)
}
}

@ -1,19 +1,26 @@
package net.pokeranalytics.android.ui.view.rowrepresentable
import androidx.fragment.app.Fragment
import net.pokeranalytics.android.R
import net.pokeranalytics.android.ui.fragment.components.bottomsheet.BottomSheetType
import net.pokeranalytics.android.ui.view.DefaultEditDataSource
import net.pokeranalytics.android.exceptions.PokerAnalyticsException
import net.pokeranalytics.android.model.realm.Location
import net.pokeranalytics.android.ui.adapter.RowRepresentableDelegate
import net.pokeranalytics.android.ui.fragment.components.input.InputFragment
import net.pokeranalytics.android.ui.fragment.components.input.InputFragmentType
import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.RowEditableDataSource
import net.pokeranalytics.android.ui.view.RowViewType
enum class LocationRow : RowRepresentable, DefaultEditDataSource {
enum class LocationRow : RowRepresentable {
NAME,
LOCATION_PERMISSION_SWITCH,
LOCATION_LOADER;
override val resId: Int?
get() {
return when (this) {
NAME -> R.string.name
LOCATION_PERMISSION_SWITCH -> R.string.geo_locate
LOCATION_LOADER -> null
}
@ -22,17 +29,32 @@ enum class LocationRow : RowRepresentable, DefaultEditDataSource {
override val viewType: Int
get() {
return when (this) {
NAME -> RowViewType.TITLE_VALUE.ordinal
LOCATION_PERMISSION_SWITCH -> RowViewType.TITLE_SWITCH.ordinal
LOCATION_LOADER -> RowViewType.LOADER.ordinal
}
}
override val bottomSheetType: BottomSheetType
override val inputFragmentType: InputFragmentType
get() {
return when (this) {
LOCATION_PERMISSION_SWITCH -> BottomSheetType.NONE
LOCATION_LOADER -> BottomSheetType.NONE
NAME -> InputFragmentType.EDIT_TEXT
LOCATION_PERMISSION_SWITCH -> InputFragmentType.NONE
LOCATION_LOADER -> InputFragmentType.NONE
}
}
override fun startEditing(dataSource: Any?, parent: Fragment?) {
if (dataSource == null) return
if (dataSource !is Location) return
if (parent == null) return
if (parent !is RowRepresentableDelegate) return
val data = RowEditableDataSource()
when (this) {
NAME -> data.append(dataSource.name)
else -> PokerAnalyticsException.InputFragmentException
}
InputFragment.buildAndShow(this, parent, data)
}
}

@ -1,34 +0,0 @@
package net.pokeranalytics.android.ui.view.rowrepresentable
import net.pokeranalytics.android.R
import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.RowViewType
/**
* An enum managing the rows in the more tabs
*/
enum class MoreTabRow : RowRepresentable {
BANKROLL,
TOP_10,
SETTINGS;
override val resId: Int?
get() {
return when(this) {
BANKROLL -> R.string.bankroll
TOP_10 -> R.string.top_10
SETTINGS -> R.string.services
}
}
override val imageRes: Int?
get() {
return when(this) {
BANKROLL -> R.drawable.ic_outline_lock
TOP_10 -> R.drawable.ic_outline_star
SETTINGS -> R.drawable.ic_outline_settings
}
}
override val viewType: Int = RowViewType.TITLE_ICON_ARROW.ordinal
}

@ -0,0 +1,63 @@
package net.pokeranalytics.android.ui.view.rowrepresentable
import androidx.fragment.app.Fragment
import net.pokeranalytics.android.R
import net.pokeranalytics.android.exceptions.PokerAnalyticsException
import net.pokeranalytics.android.model.realm.Player
import net.pokeranalytics.android.ui.adapter.RowRepresentableDelegate
import net.pokeranalytics.android.ui.fragment.components.input.InputFragment
import net.pokeranalytics.android.ui.fragment.components.input.InputFragmentType
import net.pokeranalytics.android.ui.view.RowEditableDataSource
import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.RowViewType
/**
* An enum managing the player rows
*/
enum class PlayerRow : RowRepresentable {
IMAGE,
NAME,
SUMMARY;
override val resId: Int?
get() {
return when (this) {
IMAGE -> null
NAME -> R.string.name
SUMMARY -> R.string.summary
}
}
override val viewType: Int
get() {
return when (this) {
IMAGE -> RowViewType.ROW_PLAYER_IMAGE.ordinal
NAME -> RowViewType.TITLE_SUBTITLE.ordinal
SUMMARY -> RowViewType.TITLE_SUBTITLE.ordinal
}
}
override val inputFragmentType: InputFragmentType
get() {
return when (this) {
IMAGE -> InputFragmentType.NONE
NAME -> InputFragmentType.EDIT_TEXT
SUMMARY -> InputFragmentType.EDIT_TEXT_MULTI_LINES
}
}
override fun startEditing(dataSource: Any?, parent: Fragment?) {
if (dataSource == null) return
if (dataSource !is Player) return
if (parent == null) return
if (parent !is RowRepresentableDelegate) return
val data = RowEditableDataSource()
when (this) {
NAME -> data.append(dataSource.name)
SUMMARY -> data.append(dataSource.summary)
else -> PokerAnalyticsException.InputFragmentException
}
InputFragment.buildAndShow(this, parent, data)
}
}

@ -1,315 +1,286 @@
package net.pokeranalytics.android.ui.view.rowrepresentable
import android.text.InputType
import io.realm.RealmResults
import android.widget.Toast
import androidx.fragment.app.Fragment
import net.pokeranalytics.android.R
import net.pokeranalytics.android.model.TournamentType
import net.pokeranalytics.android.model.extensions.SessionState
import net.pokeranalytics.android.model.extensions.getState
import net.pokeranalytics.android.model.realm.Session
import net.pokeranalytics.android.ui.fragment.components.bottomsheet.BottomSheetType
import net.pokeranalytics.android.model.realm.*
import net.pokeranalytics.android.ui.adapter.RowRepresentableDelegate
import net.pokeranalytics.android.ui.fragment.components.input.InputFragment
import net.pokeranalytics.android.ui.fragment.components.input.InputFragmentType
import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.RowRepresentableEditDescriptor
import net.pokeranalytics.android.ui.view.RowEditableDataSource
import net.pokeranalytics.android.ui.view.RowViewType
import net.pokeranalytics.android.util.extensions.round
import net.pokeranalytics.android.util.extensions.sorted
import java.util.*
enum class SessionRow : RowRepresentable {
PRIZE,
CASHED_OUT,
NET_RESULT,
INITIAL_BUY_IN,
BUY_IN,
POSITION,
PLAYERS,
TIPS,
PRIZE,
CASHED_OUT,
NET_RESULT,
INITIAL_BUY_IN,
BUY_IN,
POSITION,
PLAYERS,
TIPS,
GAME,
BLINDS,
LOCATION,
BANKROLL,
TABLE_SIZE,
TOURNAMENT_TYPE,
TOURNAMENT_NAME,
TOURNAMENT_FEATURE,
START_DATE,
END_DATE,
GAME,
BLINDS,
LOCATION,
BANKROLL,
TABLE_SIZE,
TOURNAMENT_TYPE,
TOURNAMENT_NAME,
TOURNAMENT_FEATURE,
START_DATE,
END_DATE,
BREAK_TIME,
COMMENT;
BREAK_TIME,
COMMENT;
companion object {
/**
* Return the rows to display for the current session state
*/
fun getRows(session: Session): List<RowRepresentable> {
when (session.type) {
Session.Type.TOURNAMENT.ordinal -> {
return when (session.getState()) {
SessionState.PENDING, SessionState.PLANNED -> {
arrayListOf(
GAME,
INITIAL_BUY_IN,
LOCATION,
BANKROLL,
TABLE_SIZE,
TOURNAMENT_TYPE,
TOURNAMENT_NAME,
TOURNAMENT_FEATURE,
START_DATE,
END_DATE
)
}
SessionState.STARTED, SessionState.PAUSED, SessionState.FINISHED -> {
arrayListOf(
PRIZE,
BUY_IN,
POSITION,
PLAYERS,
TIPS,
COMMENT,
SeparatorRow(),
GAME,
INITIAL_BUY_IN,
LOCATION,
BANKROLL,
TABLE_SIZE,
TOURNAMENT_TYPE,
TOURNAMENT_NAME,
TOURNAMENT_FEATURE,
SeparatorRow(),
START_DATE,
END_DATE,
BREAK_TIME
)
}
}
}
Session.Type.CASH_GAME.ordinal -> {
when (session.getState()) {
SessionState.PENDING, SessionState.PLANNED -> {
return arrayListOf(GAME, BLINDS, LOCATION, BANKROLL, TABLE_SIZE, START_DATE, END_DATE)
}
SessionState.STARTED, SessionState.PAUSED, SessionState.FINISHED -> {
companion object {
/**
* Return the rows to display for the current session state
*/
fun getRows(session: Session): List<RowRepresentable> {
when (session.type) {
Session.Type.TOURNAMENT.ordinal -> {
return when (session.getState()) {
SessionState.PENDING, SessionState.PLANNED -> {
arrayListOf(
GAME,
INITIAL_BUY_IN,
LOCATION,
BANKROLL,
TABLE_SIZE,
TOURNAMENT_TYPE,
TOURNAMENT_NAME,
TOURNAMENT_FEATURE,
START_DATE,
END_DATE
)
}
SessionState.STARTED, SessionState.PAUSED, SessionState.FINISHED -> {
arrayListOf(
PRIZE,
BUY_IN,
POSITION,
PLAYERS,
TIPS,
COMMENT,
SeparatorRow(),
GAME,
INITIAL_BUY_IN,
LOCATION,
BANKROLL,
TABLE_SIZE,
TOURNAMENT_TYPE,
TOURNAMENT_NAME,
TOURNAMENT_FEATURE,
SeparatorRow(),
START_DATE,
END_DATE,
BREAK_TIME
)
}
}
}
Session.Type.CASH_GAME.ordinal -> {
when (session.getState()) {
SessionState.PENDING, SessionState.PLANNED -> {
return arrayListOf(GAME, BLINDS, LOCATION, BANKROLL, TABLE_SIZE, START_DATE, END_DATE)
}
SessionState.STARTED, SessionState.PAUSED, SessionState.FINISHED -> {
val fields = mutableListOf<RowRepresentable>()
when {
session.hasBuyin -> fields.addAll(listOf(CASHED_OUT, BUY_IN, TIPS))
session.hasNetResult -> fields.add(NET_RESULT)
session.isLive -> fields.addAll(listOf(CASHED_OUT, BUY_IN, TIPS))
else -> fields.add(NET_RESULT)
}
fields.add(COMMENT)
fields.add(SeparatorRow())
fields.addAll(listOf(
GAME,
BLINDS,
LOCATION,
BANKROLL,
TABLE_SIZE,
START_DATE,
END_DATE,
BREAK_TIME
val fields = mutableListOf<RowRepresentable>()
when {
session.hasBuyin -> fields.addAll(listOf(CASHED_OUT, BUY_IN, TIPS))
session.hasNetResult -> fields.add(NET_RESULT)
session.isLive -> fields.addAll(listOf(CASHED_OUT, BUY_IN, TIPS))
else -> fields.add(NET_RESULT)
}
fields.add(COMMENT)
fields.add(SeparatorRow())
fields.addAll(
listOf(
GAME,
BLINDS,
LOCATION,
BANKROLL,
TABLE_SIZE,
START_DATE,
END_DATE,
BREAK_TIME
)
)
return fields
}
}
}
}
return arrayListOf()
}
}
)
)
return fields
}
}
}
}
return arrayListOf()
}
}
override val resId: Int?
get() {
return when (this) {
NET_RESULT -> R.string.net_result
PRIZE -> R.string.prize
POSITION -> R.string.position
PLAYERS -> R.string.players
CASHED_OUT -> R.string.cashed_out
INITIAL_BUY_IN -> R.string.initial_stack
BUY_IN -> R.string.buyin
TIPS -> R.string.tips
GAME -> R.string.game
BLINDS -> R.string.blinds
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
START_DATE -> R.string.start_date
END_DATE -> R.string.end_date
BREAK_TIME -> R.string.break_time
COMMENT -> R.string.comment
}
}
override val resId: Int?
get() {
return when (this) {
NET_RESULT -> R.string.net_result
PRIZE -> R.string.prize
POSITION -> R.string.position
PLAYERS -> R.string.players
CASHED_OUT -> R.string.cashed_out
INITIAL_BUY_IN -> R.string.initial_stack
BUY_IN -> R.string.buyin
TIPS -> R.string.tips
GAME -> R.string.game
BLINDS -> R.string.blinds
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
START_DATE -> R.string.start_date
END_DATE -> R.string.end_date
BREAK_TIME -> R.string.break_time
COMMENT -> R.string.comment
}
}
override val viewType: Int
get() {
return when (this) {
NET_RESULT, PRIZE, POSITION, PLAYERS, CASHED_OUT, INITIAL_BUY_IN, BUY_IN, TIPS,
GAME, BLINDS, LOCATION, BANKROLL, TABLE_SIZE, COMMENT,
TOURNAMENT_TYPE, TOURNAMENT_NAME, TOURNAMENT_FEATURE, START_DATE, END_DATE, BREAK_TIME -> RowViewType.TITLE_VALUE.ordinal
}
}
override val viewType: Int
get() {
return when (this) {
NET_RESULT, PRIZE, POSITION, PLAYERS, CASHED_OUT, INITIAL_BUY_IN, BUY_IN, TIPS,
GAME, BLINDS, LOCATION, BANKROLL, TABLE_SIZE, COMMENT,
TOURNAMENT_TYPE, TOURNAMENT_NAME, TOURNAMENT_FEATURE, START_DATE, END_DATE, BREAK_TIME -> RowViewType.TITLE_VALUE.ordinal
}
}
override val bottomSheetType: BottomSheetType
get() {
return when (this) {
NET_RESULT, CASHED_OUT, INITIAL_BUY_IN, BREAK_TIME, POSITION, PLAYERS, PRIZE -> BottomSheetType.NUMERIC_TEXT
BUY_IN, TIPS -> BottomSheetType.SUM
BLINDS -> BottomSheetType.DOUBLE_EDIT_TEXT
GAME -> BottomSheetType.LIST_GAME
TOURNAMENT_TYPE -> BottomSheetType.LIST_STATIC
LOCATION, BANKROLL, TOURNAMENT_NAME -> BottomSheetType.LIST
TOURNAMENT_FEATURE -> BottomSheetType.MULTI_SELECTION
TABLE_SIZE -> BottomSheetType.GRID
COMMENT -> BottomSheetType.EDIT_TEXT_MULTI_LINES
else -> BottomSheetType.NONE
}
}
override val inputFragmentType: InputFragmentType
get() {
return when (this) {
NET_RESULT, CASHED_OUT, INITIAL_BUY_IN, BREAK_TIME, POSITION, PLAYERS, PRIZE -> InputFragmentType.NUMERIC_TEXT
BUY_IN, TIPS -> InputFragmentType.SUM
BLINDS -> InputFragmentType.DOUBLE_EDIT_TEXT
GAME -> InputFragmentType.LIST_GAME
TOURNAMENT_TYPE -> InputFragmentType.LIST_STATIC
LOCATION, BANKROLL, TOURNAMENT_NAME -> InputFragmentType.LIST
TOURNAMENT_FEATURE -> InputFragmentType.MULTI_SELECTION
TABLE_SIZE -> InputFragmentType.GRID
COMMENT -> InputFragmentType.EDIT_TEXT_MULTI_LINES
else -> InputFragmentType.NONE
}
}
override fun editingDescriptors(map: Map<String, Any?>): ArrayList<RowRepresentableEditDescriptor>? {
return when (this) {
BLINDS -> {
val sb: String? by map
val bb: String? by map
arrayListOf(
RowRepresentableEditDescriptor(
sb, R.string.smallblind, 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
)
)
}
BUY_IN -> {
val bb: Double? by map
val fee: Double? by map
val ratedBuyin: Double? by map
val data = arrayListOf<RowRepresentableEditDescriptor>()
if (bb != null) {
data.add(RowRepresentableEditDescriptor(100.0 * (bb ?: 0.0)))
data.add(RowRepresentableEditDescriptor(200.0 * (bb ?: 0.0)))
} else if (fee != null) {
data.add(RowRepresentableEditDescriptor((fee ?: 0.0) * 1.0))
data.add(RowRepresentableEditDescriptor((fee ?: 0.0) * 2.0))
} else {
data.add(RowRepresentableEditDescriptor(0))
data.add(RowRepresentableEditDescriptor(0))
}
override fun startEditing(dataSource: Any?, parent: Fragment?) {
if (dataSource == null) return
if (dataSource !is Session) return
if (parent == null) return
if (parent !is RowRepresentableDelegate) return
data.add(RowRepresentableEditDescriptor(ratedBuyin))
data.add(
RowRepresentableEditDescriptor(
inputType = InputType.TYPE_CLASS_NUMBER or InputType.TYPE_NUMBER_FLAG_DECIMAL
)
)
data.add(
RowRepresentableEditDescriptor(
inputType = InputType.TYPE_CLASS_NUMBER or InputType.TYPE_NUMBER_FLAG_DECIMAL
)
)
data
}
CASHED_OUT, PRIZE, NET_RESULT -> {
val defaultValue: Double? by map
arrayListOf(
RowRepresentableEditDescriptor(
defaultValue,
inputType = InputType.TYPE_CLASS_NUMBER
or InputType.TYPE_NUMBER_FLAG_DECIMAL
or InputType.TYPE_NUMBER_FLAG_SIGNED
)
)
}
COMMENT -> {
val defaultValue: String? by map
arrayListOf(RowRepresentableEditDescriptor(defaultValue, R.string.comment))
}
BREAK_TIME -> {
arrayListOf(
RowRepresentableEditDescriptor(
hint = R.string.in_minutes, inputType = InputType.TYPE_CLASS_NUMBER
)
)
}
GAME -> {
val limit: Int? by map
val defaultValue: Any? by map
val data: RealmResults<RowRepresentable>? by map
arrayListOf(
RowRepresentableEditDescriptor(limit),
RowRepresentableEditDescriptor(defaultValue, data = data)
)
}
INITIAL_BUY_IN -> {
val defaultValue: Double? by map
arrayListOf(
RowRepresentableEditDescriptor(defaultValue?.round(), inputType = InputType.TYPE_CLASS_NUMBER)
)
}
BANKROLL, LOCATION, TOURNAMENT_FEATURE, TOURNAMENT_NAME -> {
val defaultValue: Any? by map
val data: RealmResults<RowRepresentable>? by map
arrayListOf(
RowRepresentableEditDescriptor(defaultValue, data = data)
)
}
PLAYERS -> {
val defaultValue: Int? by map
arrayListOf(
RowRepresentableEditDescriptor(
defaultValue?.toString(),
inputType = InputType.TYPE_CLASS_NUMBER
)
)
}
POSITION -> {
val defaultValue: Int? by map
arrayListOf(
RowRepresentableEditDescriptor(
defaultValue,
inputType = InputType.TYPE_CLASS_NUMBER
)
)
}
TABLE_SIZE -> {
val defaultValue: Int? by map
arrayListOf(RowRepresentableEditDescriptor(defaultValue))
}
TIPS -> {
val sb: String? by map
val bb: String? by map
val tips: Double? by map
val session: Session = dataSource
// Disable the buttons with value = 0, add current value & set the 2 edit texts
arrayListOf(
RowRepresentableEditDescriptor(sb ?: 0.0),
RowRepresentableEditDescriptor(bb ?: 0.0),
RowRepresentableEditDescriptor(tips ?: 0.0),
RowRepresentableEditDescriptor("", inputType = InputType.TYPE_CLASS_NUMBER),
RowRepresentableEditDescriptor("", inputType = InputType.TYPE_CLASS_NUMBER)
)
}
TOURNAMENT_TYPE -> {
val defaultValue: Any? by map
arrayListOf(
RowRepresentableEditDescriptor(defaultValue, staticData = TournamentType.values().map {
it
})
)
}
else -> null
}
}
val data = RowEditableDataSource(session.currency)
when (this) {
START_DATE -> {
data.appendDateDescriptor(session.startDate)
}
END_DATE -> {
if (session.startDate == null) {
Toast.makeText(parent.context, R.string.session_missing_start_date, Toast.LENGTH_SHORT).show()
return
} else {
data.appendDateDescriptor(session.endDate ?: session.startDate ?: Date(), session.startDate)
}
}
BANKROLL -> data.append(session.bankroll, data = session.realm.sorted<Bankroll>())
CASHED_OUT, PRIZE -> data.append(
session.result?.cashout,
inputType = InputType.TYPE_CLASS_NUMBER or InputType.TYPE_NUMBER_FLAG_DECIMAL or InputType.TYPE_NUMBER_FLAG_SIGNED
)
NET_RESULT -> data.append(
session.result?.netResult,
inputType = InputType.TYPE_CLASS_NUMBER or InputType.TYPE_NUMBER_FLAG_DECIMAL or InputType.TYPE_NUMBER_FLAG_SIGNED
)
INITIAL_BUY_IN -> data.append(session.tournamentEntryFee?.round(), inputType = InputType.TYPE_CLASS_NUMBER)
BUY_IN -> {
val bb: Double? = session.cgBigBlind
val fee: Double? = session.tournamentEntryFee
val ratedBuyin: Double? = session.result?.buyin
if (bb != null) {
data.append(100.0 * bb)
data.append(200.0 * bb)
} else if (fee != null) {
data.append(fee)
data.append(fee * 2.0)
} else {
data.append(0)
data.append(0)
}
data.append(ratedBuyin)
data.append(inputType = InputType.TYPE_CLASS_NUMBER or InputType.TYPE_NUMBER_FLAG_DECIMAL)
data.append(inputType = InputType.TYPE_CLASS_NUMBER or InputType.TYPE_NUMBER_FLAG_DECIMAL)
}
POSITION -> data.append(session.result?.tournamentFinalPosition, inputType = InputType.TYPE_CLASS_NUMBER)
PLAYERS -> data.append(
session.tournamentNumberOfPlayers.toString(),
inputType = InputType.TYPE_CLASS_NUMBER
)
TIPS -> {
val sb: String? = session.cgSmallBlind?.round()
val bb: String? = session.cgBigBlind?.round()
val tips: Double? = session.result?.tips
data.append(sb ?: 0.0)
data.append(bb ?: 0.0)
data.append(tips ?: 0.0)
data.append("", inputType = InputType.TYPE_CLASS_NUMBER)
data.append("", inputType = InputType.TYPE_CLASS_NUMBER)
}
GAME -> {
data.append(session.limit)
data.append(session.game, data = session.realm.sorted<Game>())
}
BLINDS -> {
data.append(
session.cgSmallBlind?.round(),
R.string.smallblind,
InputType.TYPE_CLASS_NUMBER or InputType.TYPE_NUMBER_FLAG_DECIMAL
)
data.append(
session.cgBigBlind?.round(),
R.string.bigblind,
InputType.TYPE_CLASS_NUMBER or InputType.TYPE_NUMBER_FLAG_DECIMAL
)
}
LOCATION -> data.append(session.location, data = session.realm.sorted<Location>())
TABLE_SIZE -> data.append(session.tableSize)
TOURNAMENT_TYPE -> data.append(session.tournamentType, staticData = TournamentType.values().map { it })
TOURNAMENT_NAME -> data.append(session.tournamentName, data = session.realm.sorted<TournamentName>())
TOURNAMENT_FEATURE -> data.append(
session.tournamentFeatures,
data = session.realm.sorted<TournamentFeature>()
)
BREAK_TIME -> data.append(hint = R.string.in_minutes, inputType = InputType.TYPE_CLASS_NUMBER)
COMMENT -> data.append(session.comment, R.string.comment)
}
InputFragment.buildAndShow(this, parent, data)
}
override val valueCanBeClearedWhenEditing: Boolean
get() {
return when (this) {
BANKROLL -> false
else -> true
}
}
}

@ -11,6 +11,7 @@ enum class SettingRow : RowRepresentable {
// More
BANKROLL_REPORT,
TOP_10,
PLAYERS,
// About
SUBSCRIPTION,
@ -50,7 +51,7 @@ enum class SettingRow : RowRepresentable {
val rows = ArrayList<RowRepresentable>()
rows.add(CustomizableRowRepresentable(customViewType = RowViewType.HEADER_TITLE, resId = R.string.reports))
rows.addAll(arrayListOf(BANKROLL_REPORT, TOP_10))
rows.addAll(arrayListOf(BANKROLL_REPORT, TOP_10, PLAYERS))
rows.add(CustomizableRowRepresentable(customViewType = RowViewType.HEADER_TITLE, resId = R.string.information))
// rows.addAll(arrayListOf(VERSION, RATE_APP, CONTACT_US, BUG_REPORT))
@ -86,6 +87,7 @@ enum class SettingRow : RowRepresentable {
return when (this) {
BANKROLL_REPORT -> R.string.bankroll
TOP_10 -> R.string.top_10
PLAYERS -> R.string.players
SUBSCRIPTION -> R.string.subscription
VERSION -> R.string.version
RATE_APP -> R.string.releasenote_rating
@ -106,7 +108,7 @@ enum class SettingRow : RowRepresentable {
override val viewType: Int
get() {
return when (this) {
BANKROLL_REPORT, TOP_10 -> RowViewType.TITLE_ICON_ARROW.ordinal
BANKROLL_REPORT, TOP_10, PLAYERS -> RowViewType.TITLE_ICON_ARROW.ordinal
VERSION, SUBSCRIPTION -> RowViewType.TITLE_VALUE.ordinal
LANGUAGE, CURRENCY -> RowViewType.TITLE_VALUE_ARROW.ordinal
FOLLOW_US -> RowViewType.ROW_FOLLOW_US.ordinal
@ -119,6 +121,7 @@ enum class SettingRow : RowRepresentable {
return when(this) {
BANKROLL_REPORT -> R.drawable.ic_outline_lock
TOP_10 -> R.drawable.ic_outline_star
PLAYERS -> R.drawable.ic_outline_people
else -> null
}
}

@ -1,16 +1,15 @@
package net.pokeranalytics.android.ui.view.rowrepresentable
import net.pokeranalytics.android.R
import net.pokeranalytics.android.ui.fragment.components.bottomsheet.BottomSheetType
import net.pokeranalytics.android.ui.view.DefaultEditDataSource
import net.pokeranalytics.android.ui.fragment.components.input.InputFragmentType
import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.RowViewType
enum class SimpleRow : RowRepresentable, DefaultEditDataSource {
enum class SimpleRow : RowRepresentable {
NAME;
override val resId: Int? = R.string.name
override val viewType: Int = RowViewType.TITLE_VALUE.ordinal
override val bottomSheetType: BottomSheetType = BottomSheetType.EDIT_TEXT
override val inputFragmentType: InputFragmentType = InputFragmentType.EDIT_TEXT
}

@ -1,6 +1,49 @@
package net.pokeranalytics.android.ui.view.rowrepresentable
import net.pokeranalytics.android.ui.view.DefaultEditDataSource
import androidx.fragment.app.Fragment
import net.pokeranalytics.android.R
import net.pokeranalytics.android.model.realm.TournamentFeature
import net.pokeranalytics.android.ui.adapter.RowRepresentableDelegate
import net.pokeranalytics.android.ui.fragment.components.input.InputFragment
import net.pokeranalytics.android.ui.fragment.components.input.InputFragmentType
import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.RowEditableDataSource
import net.pokeranalytics.android.ui.view.RowViewType
enum class TournamentFeatureRow : RowRepresentable, DefaultEditDataSource
enum class TournamentFeatureRow : RowRepresentable {
NAME;
override val resId: Int?
get() {
return when (this) {
NAME -> R.string.name
}
}
override val viewType: Int
get() {
return when (this) {
NAME -> RowViewType.TITLE_VALUE.ordinal
}
}
override val inputFragmentType: InputFragmentType
get() {
return when (this) {
NAME -> InputFragmentType.EDIT_TEXT
}
}
override fun startEditing(dataSource: Any?, parent: Fragment?) {
if (dataSource == null) return
if (dataSource !is TournamentFeature) return
if (parent == null) return
if (parent !is RowRepresentableDelegate) return
val data = RowEditableDataSource()
when (this) {
NAME -> data.append(dataSource.name)
}
InputFragment.buildAndShow(this, parent, data)
}
}

@ -1,6 +1,49 @@
package net.pokeranalytics.android.ui.view.rowrepresentable
import net.pokeranalytics.android.ui.view.DefaultEditDataSource
import androidx.fragment.app.Fragment
import net.pokeranalytics.android.R
import net.pokeranalytics.android.model.realm.TournamentName
import net.pokeranalytics.android.ui.adapter.RowRepresentableDelegate
import net.pokeranalytics.android.ui.fragment.components.input.InputFragment
import net.pokeranalytics.android.ui.fragment.components.input.InputFragmentType
import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.RowEditableDataSource
import net.pokeranalytics.android.ui.view.RowViewType
enum class TournamentNameRow : RowRepresentable, DefaultEditDataSource
enum class TournamentNameRow : RowRepresentable {
NAME;
override val resId: Int?
get() {
return when (this) {
NAME -> R.string.name
}
}
override val viewType: Int
get() {
return when (this) {
NAME -> RowViewType.TITLE_VALUE.ordinal
}
}
override val inputFragmentType: InputFragmentType
get() {
return when (this) {
NAME -> InputFragmentType.EDIT_TEXT
}
}
override fun startEditing(dataSource: Any?, parent: Fragment?) {
if (dataSource == null) return
if (dataSource !is TournamentName) return
if (parent == null) return
if (parent !is RowRepresentableDelegate) return
val data = RowEditableDataSource()
when (this) {
NAME -> data.append(dataSource.name)
}
InputFragment.buildAndShow(this, parent, data)
}
}

@ -1,16 +1,21 @@
package net.pokeranalytics.android.ui.view.rowrepresentable
import android.text.InputType
import io.realm.RealmResults
import androidx.fragment.app.Fragment
import io.realm.Realm
import net.pokeranalytics.android.R
import net.pokeranalytics.android.ui.fragment.components.bottomsheet.BottomSheetType
import net.pokeranalytics.android.ui.view.DefaultEditDataSource
import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.RowRepresentableEditDescriptor
import net.pokeranalytics.android.ui.view.RowViewType
import net.pokeranalytics.android.model.realm.Bankroll
import net.pokeranalytics.android.model.realm.Transaction
import net.pokeranalytics.android.model.realm.TransactionType
import net.pokeranalytics.android.ui.adapter.RowEditableDelegate
import net.pokeranalytics.android.ui.fragment.components.input.InputFragment
import net.pokeranalytics.android.ui.fragment.components.input.InputFragmentType
import net.pokeranalytics.android.ui.view.*
import net.pokeranalytics.android.util.extensions.round
import net.pokeranalytics.android.util.extensions.sorted
enum class TransactionRow : RowRepresentable, DefaultEditDataSource {
enum class TransactionRow : RowRepresentable {
BANKROLL,
TYPE,
AMOUNT,
@ -39,48 +44,50 @@ enum class TransactionRow : RowRepresentable, DefaultEditDataSource {
}
}
override val bottomSheetType: BottomSheetType
override val inputFragmentType: InputFragmentType
get() {
return when (this) {
BANKROLL -> BottomSheetType.LIST
TYPE -> BottomSheetType.LIST
AMOUNT -> BottomSheetType.EDIT_TEXT
COMMENT -> BottomSheetType.EDIT_TEXT_MULTI_LINES
DATE -> BottomSheetType.NONE
BANKROLL -> InputFragmentType.LIST
TYPE -> InputFragmentType.LIST
AMOUNT -> InputFragmentType.EDIT_TEXT
COMMENT -> InputFragmentType.EDIT_TEXT_MULTI_LINES
DATE -> InputFragmentType.NONE
}
}
override fun editingDescriptors(map: Map<String, Any?>): ArrayList<RowRepresentableEditDescriptor>? {
return when (this) {
BANKROLL -> {
val defaultValue : Any? by map
val data : RealmResults<RowRepresentable>? by map
arrayListOf(
RowRepresentableEditDescriptor(defaultValue, data = data)
)
}
TYPE -> {
val defaultValue : Any? by map
val data : RealmResults<RowRepresentable>? by map
arrayListOf(
RowRepresentableEditDescriptor(defaultValue, data = data)
)
}
AMOUNT -> {
val defaultValue: String? by map
arrayListOf(
RowRepresentableEditDescriptor(
defaultValue,
inputType = InputType.TYPE_CLASS_NUMBER
or InputType.TYPE_NUMBER_FLAG_DECIMAL
or InputType.TYPE_NUMBER_FLAG_SIGNED
))
}
COMMENT -> {
val defaultValue : String? by map
arrayListOf(RowRepresentableEditDescriptor(defaultValue, R.string.comment))
}
else -> super<RowRepresentable>.editingDescriptors(map)
}
}
override val valueCanBeClearedWhenEditing: Boolean
get() {
return when (this) {
DATE -> false
else -> true
}
}
override fun startEditing(dataSource: Any?, parent: Fragment?) {
if (dataSource == null) return
if (dataSource !is Transaction) return
if (parent == null) return
if (parent !is RowEditableDelegate) return
val data = RowEditableDataSource()
val realm = dataSource.realm?.let { it } ?: run { Realm.getDefaultInstance() }
when (this) {
DATE -> {
data.appendDateDescriptor(dataSource.date, onlyDate = true)
}
BANKROLL -> data.append(
dataSource.bankroll,
data = realm.sorted<Bankroll>()
)
TYPE -> data.append(
dataSource.type,
data = realm.sorted<TransactionType>()
)
AMOUNT -> data.append(
(if (dataSource.amount != 0.0) dataSource.amount.round() else ""),
inputType = InputType.TYPE_CLASS_NUMBER or InputType.TYPE_NUMBER_FLAG_DECIMAL or InputType.TYPE_NUMBER_FLAG_SIGNED
)
COMMENT -> data.append(dataSource.comment, R.string.comment)
}
InputFragment.buildAndShow(this, parent, data)
}
}

@ -1,17 +1,24 @@
package net.pokeranalytics.android.ui.view.rowrepresentable
import androidx.fragment.app.Fragment
import net.pokeranalytics.android.R
import net.pokeranalytics.android.ui.fragment.components.bottomsheet.BottomSheetType
import net.pokeranalytics.android.ui.view.DefaultEditDataSource
import net.pokeranalytics.android.exceptions.PokerAnalyticsException
import net.pokeranalytics.android.model.realm.TransactionType
import net.pokeranalytics.android.ui.adapter.RowRepresentableDelegate
import net.pokeranalytics.android.ui.fragment.components.input.InputFragment
import net.pokeranalytics.android.ui.fragment.components.input.InputFragmentType
import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.RowEditableDataSource
import net.pokeranalytics.android.ui.view.RowViewType
enum class TransactionTypeRow : RowRepresentable, DefaultEditDataSource {
enum class TransactionTypeRow : RowRepresentable {
NAME,
TRANSACTION_ADDITIVE;
override val resId: Int?
get() {
return when (this) {
NAME -> R.string.name
TRANSACTION_ADDITIVE -> R.string.additive
}
}
@ -19,17 +26,32 @@ enum class TransactionTypeRow : RowRepresentable, DefaultEditDataSource {
override val viewType: Int
get() {
return when (this) {
NAME -> RowViewType.TITLE_VALUE.ordinal
TRANSACTION_ADDITIVE -> RowViewType.TITLE_SWITCH.ordinal
}
}
override val bottomSheetType: BottomSheetType
override val inputFragmentType: InputFragmentType
get() {
return when (this) {
TRANSACTION_ADDITIVE -> BottomSheetType.NONE
NAME -> InputFragmentType.EDIT_TEXT
TRANSACTION_ADDITIVE -> InputFragmentType.NONE
}
}
override fun startEditing(dataSource: Any?, parent: Fragment?) {
if (dataSource == null) return
if (dataSource !is TransactionType) return
if (parent == null) return
if (parent !is RowRepresentableDelegate) return
val data = RowEditableDataSource()
when (this) {
NAME -> data.append(dataSource.name)
else -> PokerAnalyticsException.InputFragmentException
}
InputFragment.buildAndShow(this, parent, data)
}
}

@ -3,10 +3,7 @@ package net.pokeranalytics.android.util
import io.realm.Realm
import io.realm.kotlin.where
import net.pokeranalytics.android.model.Limit
import net.pokeranalytics.android.model.realm.Bankroll
import net.pokeranalytics.android.model.realm.Game
import net.pokeranalytics.android.model.realm.Location
import net.pokeranalytics.android.model.realm.Session
import net.pokeranalytics.android.model.realm.*
import net.pokeranalytics.android.util.extensions.getOrCreate
import timber.log.Timber
import java.util.*
@ -33,8 +30,9 @@ class FakeDataManager {
val games = realm.where<Game>().findAll()
val bankroll = realm.where<Bankroll>().findAll().firstOrNull()
val locations = realm.where<Location>().findAll()
val players = realm.where<Player>().findAll()
if (locations.size == 0) {
if (locations.isEmpty()) {
realm.executeTransaction {
listOf("Bellagio", "Aria", "Borgata").map {
realm.getOrCreate<Location>(it)
@ -42,6 +40,20 @@ class FakeDataManager {
}
}
if (players.isEmpty()) {
val playersName = listOf("Candice Cole", "Owen Barnes", "Ramona Harper", "Julie Grant", "Zoey Wood", "Hugh Nelson", "Christi Adams", "Keith Shaw")
val playersSummary = listOf("", "Be careful of this boy", "😄", "", "- Creepy\n- Hard to play", "", "", "👍👍")
realm.executeTransaction {
playersName.forEachIndexed { index, name ->
val player = Player()
player.name = name
player.summary = playersSummary[index]
realm.copyToRealm(player)
}
}
}
// Test endedSessions
Timber.d("*** Start creating ${numberOfSessions} fake computables...")

@ -0,0 +1,377 @@
package net.pokeranalytics.android.util
import android.app.Activity
import android.content.Context
import android.content.Intent
import android.graphics.*
import android.graphics.Paint.FILTER_BITMAP_FLAG
import android.media.ExifInterface
import android.net.Uri
import android.os.Environment
import androidx.core.content.ContextCompat
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import net.pokeranalytics.android.R
import timber.log.Timber
import java.io.File
import java.io.FileOutputStream
import java.io.IOException
import java.io.InputStream
import java.text.SimpleDateFormat
import java.util.*
object ImageUtils {
/**
* Rotate a bitmap if it's necessary (depending of the EXIF data)
* Some devices don't rotate the picture but instead add the orientation
* value in the EXIF data.
* That's why we need sometimes to rotate by ourselves the bitmap
*
* @param src The file to check (for getting the Exif data)
* @param bitmap The bitmap to modify (if necessary)
* @return The bitmap in the correct orientation
*/
fun rotateBitmap(src: String, bitmap: Bitmap, updateFile: Boolean): Bitmap {
try {
val orientation = getExifOrientation(src)
if (orientation == ExifInterface.ORIENTATION_NORMAL) {
return bitmap
}
val matrix = Matrix()
when (orientation) {
ExifInterface.ORIENTATION_FLIP_HORIZONTAL -> matrix.setScale(-1f, 1f)
ExifInterface.ORIENTATION_ROTATE_180 -> matrix.setRotate(180f)
ExifInterface.ORIENTATION_FLIP_VERTICAL -> {
matrix.setRotate(180f)
matrix.postScale(-1f, 1f)
}
ExifInterface.ORIENTATION_TRANSPOSE -> {
matrix.setRotate(90f)
matrix.postScale(-1f, 1f)
}
ExifInterface.ORIENTATION_ROTATE_90 -> matrix.setRotate(90f)
ExifInterface.ORIENTATION_TRANSVERSE -> {
matrix.setRotate(-90f)
matrix.postScale(-1f, 1f)
}
ExifInterface.ORIENTATION_ROTATE_270 -> matrix.setRotate(-90f)
else -> return bitmap
}
try {
val oriented = Bitmap.createBitmap(bitmap, 0, 0, bitmap.width, bitmap.height, matrix, true)
bitmap.recycle()
if (updateFile) {
updateFile(src, oriented)
}
return oriented
} catch (e: OutOfMemoryError) {
e.printStackTrace()
return bitmap
}
} catch (e: IOException) {
e.printStackTrace()
}
return bitmap
}
/**
* Get the Exif orientation value
*
* @param filePath The path of the file
* @return the orientation value
* @throws IOException
*/
@Throws(IOException::class)
private fun getExifOrientation(filePath: String): Int {
val exifInterface = ExifInterface(filePath)
return exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL)
}
/**
* Save a bitmap into a file (& apply 90% compression)
*
* @param filePath Path of the file
* @param bitmap Bitmap to save
*/
fun updateFile(filePath: String, bitmap: Bitmap) {
var out: FileOutputStream? = null
try {
out = FileOutputStream(filePath)
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, out)
} catch (e: Exception) {
e.printStackTrace()
} finally {
try {
out?.close()
} catch (e: IOException) {
e.printStackTrace()
}
}
}
/**
* Resize a file with the given maximum width or height (and keep the ratio!)
* @param filePath String: File path
* @param bitmap Bitmap: Image
* @param maxWidth int: Max width
* @param maxHeight int: Max height
*/
fun resizeFile(filePath: String, bitmap: Bitmap, maxWidth: Int, maxHeight: Int) {
var bitmap = bitmap
val options = BitmapFactory.Options()
options.inJustDecodeBounds = true
BitmapFactory.decodeFile(filePath, options)
val imageWidth = options.outWidth
val imageHeight = options.outHeight
var newWidth: Int
var newHeight: Int
if (imageWidth > imageHeight) {
newWidth = maxWidth
newHeight = imageHeight * maxWidth / imageWidth
if (newHeight > maxHeight) {
newHeight = maxHeight
newWidth = imageWidth * maxHeight / imageHeight
}
} else {
newHeight = maxHeight
newWidth = imageWidth * maxHeight / imageHeight
if (newWidth > maxWidth) {
newWidth = maxWidth
newHeight = imageHeight * maxWidth / imageWidth
}
}
bitmap = Bitmap.createScaledBitmap(bitmap, newWidth, newHeight, true)
updateFile(filePath, bitmap)
}
/**
* Create a unique temp image file name
*
* @return
* @throws IOException
*/
@Throws(IOException::class)
fun createTempImageFile(context: Context): File {
// Create an image file name
val timeStamp = SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(Date())
val imageFileName = "JPEG_" + timeStamp + "_"
val storageDir = context.cacheDir
return File.createTempFile(imageFileName, ".jpg", storageDir)
}
/**
* Create a unique image file name
*
* @return
* @throws IOException
*/
@Throws(IOException::class)
fun createImageFile(context: Context): File {
// Create an image file name
val timeStamp = SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(Date())
val imageFileName = "JPEG_" + timeStamp + "_"
val storage = ContextCompat.getExternalFilesDirs(context, Environment.DIRECTORY_PICTURES)
val storageDir = if (storage.isNotEmpty()) storage.first() else Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES)
val appStorageDir = File(storageDir.path + "/" + context.getString(R.string.app_name))
if (!appStorageDir.exists()) {
appStorageDir.mkdirs()
}
return File.createTempFile(imageFileName, ".jpg", appStorageDir)
}
/**
* Decode sample Bitmap
*
* @param filePath The bitmap file path
* @param reqWidth Max width required
* @param reqHeight Max height required
* @return The sampled bitmap
*/
fun decodeSampledBitmapFromFile(filePath: String, reqWidth: Int, reqHeight: Int): Bitmap {
// First decode with inJustDecodeBounds=true to check dimensions
val options = BitmapFactory.Options()
options.inJustDecodeBounds = true
BitmapFactory.decodeFile(filePath, options)
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight)
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false
return BitmapFactory.decodeFile(filePath, options)
}
/**
* Calculate the sample size
*/
fun calculateInSampleSize(options: BitmapFactory.Options, reqWidth: Int,
reqHeight: Int): Int {
// Raw height and width of image
val height = options.outHeight
val width = options.outWidth
var inSampleSize = 1
if (height > reqHeight || width > reqWidth) {
val halfHeight = height / 2
val halfWidth = width / 2
// Calculate the largest inSampleSize value that is a power of 2 and keeps both
// height and width larger than the requested height and width.
while (halfHeight / inSampleSize > reqHeight && halfWidth / inSampleSize > reqWidth) {
inSampleSize *= 2
}
}
return inSampleSize
}
/**
* Copy an input stream inside a file
*
* @param in Input Stream
* @param file Destination file
*/
fun copyInputStreamToFile(inputStream: InputStream, file: File) {
try {
val out = FileOutputStream(file)
val buf = ByteArray(4096)
var len = 0
while ({ len = inputStream.read(buf); len }() > 0) {
out.write(buf, 0, len)
}
out.close()
inputStream.close()
} catch (e: Exception) {
e.printStackTrace()
}
}
/**
* Update the gallery with the current file
*
* @param context Context
* @param filePath The file to add
*/
fun updateGallery(context: Context, filePath: String) {
val mediaScanIntent = Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE)
val f = File(filePath)
val contentUri = Uri.fromFile(f)
mediaScanIntent.data = contentUri
context.sendBroadcast(mediaScanIntent)
}
/**
* Save the bitmap in a file
*/
fun saveBitmapInFile(context: Context, bitmap: Bitmap, filename: String, action: (filePath: String) -> Unit) {
GlobalScope.launch {
val outputFile = File(context.filesDir, filename)
var out: FileOutputStream? = null
try {
out = FileOutputStream(outputFile.absolutePath)
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, out) // bmp is your Bitmap instance
} catch (e: Exception) {
e.printStackTrace()
} finally {
try {
if (out != null) {
out.close()
}
} catch (e: IOException) {
e.printStackTrace()
}
}
GlobalScope.launch(Dispatchers.Main) {
Timber.d("Save file here: ${outputFile.absolutePath}")
action(outputFile.absolutePath)
}
}
}
/**
* Bitmap resizer
*/
fun bitmapResizer(bitmap: Bitmap, newWidth: Int, newHeight: Int): Bitmap {
val scaledBitmap = Bitmap.createBitmap(newWidth, newHeight, Bitmap.Config.ARGB_8888)
val ratioX = newWidth / bitmap.width.toFloat()
val ratioY = newHeight / bitmap.height.toFloat()
val middleX = newWidth / 2.0f
val middleY = newHeight / 2.0f
val scaleMatrix = Matrix()
scaleMatrix.setScale(ratioX, ratioY, middleX, middleY)
val canvas = Canvas(scaledBitmap)
canvas.matrix = scaleMatrix
canvas.drawBitmap(bitmap, middleX - bitmap.width / 2, middleY - bitmap.height / 2, Paint(FILTER_BITMAP_FLAG))
return scaledBitmap
}
/**
* Export a bitmap
*/
private fun exportFile(context: Activity, bitmap: Bitmap) {
/*
val outputFile = File.createTempFile("test_export", ".jpg", context.cacheDir)
var out: FileOutputStream? = null
try {
out = FileOutputStream(outputFile.absolutePath)
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, out)
} catch (e: Exception) {
e.printStackTrace()
} finally {
try {
if (out != null) {
out.close()
}
} catch (e: IOException) {
e.printStackTrace()
}
}
val uri = FileProvider.getUriForFile(context,
context.packageName + ".provider", outputFile)
val shareIntent = ShareCompat.IntentBuilder.from(context)
.setType("image/jpg")
.setSubject(context.getString(R.string.share_file_name))
.setStream(uri)
.setChooserTitle(context.getString(R.string.share_title))
.createChooserIntent()
.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
context.startActivity(shareIntent)
*/
}
}

@ -1,36 +0,0 @@
package net.pokeranalytics.android.util
import android.content.Context
import java.util.*
class LocaleUtils {
companion object {
/**
* Return the current locale
*/
fun getCurrentLocale(context: Context) : Locale {
val defaultLocaleCode = Preferences.getString(Preferences.Keys.LOCALE_CODE, context)
var locale = Locale.getDefault()
if (defaultLocaleCode != null) {
locale = Locale(defaultLocaleCode)
Locale.setDefault(locale)
}
return locale
}
/**
*
*/
fun setCurrentLocale(context: Context, language: String) {
Preferences.setString(Preferences.Keys.LOCALE_CODE, language, context)
}
}
}

@ -38,7 +38,7 @@ class LocationManager(private var context: Context) {
// Use fields to define the data types to return.
val placeFields = Arrays.asList(Place.Field.NAME, Place.Field.ADDRESS, Place.Field.LAT_LNG)
// Use the builder to create a FindCurrentPlaceRequest.
// Use the builder to buildAndShow a FindCurrentPlaceRequest.
val request = FindCurrentPlaceRequest.builder(placeFields).build()
// Call findCurrentPlace and handle the response (first check that the user has granted permission).

@ -1,16 +1,10 @@
package net.pokeranalytics.android.util.extensions
import io.realm.Realm
import io.realm.RealmModel
import io.realm.RealmResults
import io.realm.Sort
import io.realm.*
import net.pokeranalytics.android.model.interfaces.CountableUsage
import net.pokeranalytics.android.model.interfaces.Identifiable
import net.pokeranalytics.android.model.interfaces.NameManageable
import net.pokeranalytics.android.model.realm.Filter
import net.pokeranalytics.android.model.realm.TournamentFeature
import net.pokeranalytics.android.model.realm.Transaction
import net.pokeranalytics.android.model.realm.TransactionType
import net.pokeranalytics.android.model.realm.*
fun <T : RealmModel>Realm.count(clazz: Class<T>) : Long {
return this.where(clazz).count()
@ -106,5 +100,22 @@ fun <T : RealmModel>Realm.updateUsageCount(clazz: Class<T>) {
countable.useCount = count
}
}
}
/**
* Returns all entities of the [clazz] which contain the given search content
*/
fun < T : RealmModel> Realm.find(clazz: Class<T>, searchContent: String?) : RealmResults<T> {
val query = this.where(clazz)
when (clazz.kotlin) {
Player::class -> {
query.contains("name", searchContent ?: "", Case.INSENSITIVE).or()
query.contains("summary", searchContent ?: "", Case.INSENSITIVE)
}
}
val items = query.findAll()
val sortField = arrayOf("name")
val resultSort = arrayOf(Sort.ASCENDING)
return items.sort(sortField, resultSort)
}

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<solid android:color="@color/player_color_1" />
<stroke
android:color="@color/gray"
android:width="1dp" />
<size
android:width="48dp"
android:height="48dp" />
</shape>

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<solid android:color="@color/player_color_2" />
<size
android:width="48dp"
android:height="48dp" />
</shape>

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<solid android:color="@color/player_color_3" />
<size
android:width="48dp"
android:height="48dp" />
</shape>

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<solid android:color="@color/player_color_4" />
<size
android:width="48dp"
android:height="48dp" />
</shape>

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<solid android:color="@color/player_color_5" />
<size
android:width="48dp"
android:height="48dp" />
</shape>

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<solid android:color="@color/player_color_6" />
<size
android:width="48dp"
android:height="48dp" />
</shape>

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<solid android:color="@color/player_color_7" />
<size
android:width="48dp"
android:height="48dp" />
</shape>

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<solid android:color="@color/player_color_8" />
<size
android:width="48dp"
android:height="48dp" />
</shape>

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<solid android:color="@color/player_color_9" />
<size
android:width="48dp"
android:height="48dp" />
</shape>

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save