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

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

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

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

@ -21,6 +21,8 @@ sealed class PokerAnalyticsException(message: String) : Exception(message) {
object QueryTypeUnhandled: PokerAnalyticsException(message = "queryWith type not handled") object QueryTypeUnhandled: PokerAnalyticsException(message = "queryWith type not handled")
object QueryValueMapUnexpectedValue: PokerAnalyticsException(message = "valueMap null not expected") object QueryValueMapUnexpectedValue: PokerAnalyticsException(message = "valueMap null not expected")
object FilterElementExpectedValueMissing : PokerAnalyticsException(message = "queryWith is empty or null") 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 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 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") data class UnknownQueryTypeForRow(val filterElementRow: FilterElementRow) : PokerAnalyticsException(message = "no queryWith type for $filterElementRow")

@ -20,6 +20,7 @@ enum class LiveData : Localizable {
TRANSACTION, TRANSACTION,
TRANSACTION_TYPE, TRANSACTION_TYPE,
FILTER, FILTER,
PLAYER,
CUSTOM_FIELD, CUSTOM_FIELD,
REPORT_SETUP; REPORT_SETUP;
@ -36,6 +37,7 @@ enum class LiveData : Localizable {
TRANSACTION -> Transaction::class.java TRANSACTION -> Transaction::class.java
TRANSACTION_TYPE -> TransactionType::class.java TRANSACTION_TYPE -> TransactionType::class.java
FILTER -> Filter::class.java FILTER -> Filter::class.java
PLAYER -> Player::class.java
CUSTOM_FIELD -> CustomField::class.java CUSTOM_FIELD -> CustomField::class.java
REPORT_SETUP -> ReportSetup::class.java REPORT_SETUP -> ReportSetup::class.java
} }
@ -76,6 +78,7 @@ enum class LiveData : Localizable {
TRANSACTION -> R.string.operation TRANSACTION -> R.string.operation
TRANSACTION_TYPE -> R.string.operation_type TRANSACTION_TYPE -> R.string.operation_type
FILTER -> R.string.filter FILTER -> R.string.filter
PLAYER -> R.string.player
CUSTOM_FIELD -> R.string.custom_field CUSTOM_FIELD -> R.string.custom_field
REPORT_SETUP -> R.string.custom REPORT_SETUP -> R.string.custom
} }
@ -92,6 +95,7 @@ enum class LiveData : Localizable {
TRANSACTION -> R.string.operations TRANSACTION -> R.string.operations
TRANSACTION_TYPE -> R.string.operation_types TRANSACTION_TYPE -> R.string.operation_types
FILTER -> R.string.filters FILTER -> R.string.filters
PLAYER -> R.string.players
CUSTOM_FIELD -> R.string.custom_fields CUSTOM_FIELD -> R.string.custom_fields
REPORT_SETUP -> R.string.custom REPORT_SETUP -> R.string.custom
} }
@ -108,6 +112,7 @@ enum class LiveData : Localizable {
TRANSACTION -> R.string.new_operation TRANSACTION -> R.string.new_operation
TRANSACTION_TYPE -> R.string.new_operation_type TRANSACTION_TYPE -> R.string.new_operation_type
FILTER -> R.string.new_filter FILTER -> R.string.new_filter
PLAYER -> R.string.new_friend
CUSTOM_FIELD -> R.string.new_custom_field CUSTOM_FIELD -> R.string.new_custom_field
REPORT_SETUP -> R.string.new_report 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.Identifiable
import net.pokeranalytics.android.model.interfaces.NameManageable import net.pokeranalytics.android.model.interfaces.NameManageable
import net.pokeranalytics.android.model.realm.* import net.pokeranalytics.android.model.realm.*
import net.pokeranalytics.android.ui.fragment.components.bottomsheet.BottomSheetType import net.pokeranalytics.android.ui.fragment.components.input.InputFragmentType
import net.pokeranalytics.android.ui.view.RowViewType import net.pokeranalytics.android.ui.view.RowViewType
import net.pokeranalytics.android.ui.view.rowrepresentable.FilterElementRow import net.pokeranalytics.android.ui.view.rowrepresentable.FilterElementRow
import net.pokeranalytics.android.ui.view.rowrepresentable.FilterSectionRow 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 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 { override fun labelForValue(value: Int, context: Context): String {
return value.toMinutes(context) return value.toMinutes(context)
@ -952,15 +952,15 @@ sealed class QueryCondition : FilterElementRow {
} }
} }
override val bottomSheetType: BottomSheetType override val inputFragmentType: InputFragmentType
get() { get() {
return when (this) { return when (this) {
is PastDay -> BottomSheetType.EDIT_TEXT is PastDay -> InputFragmentType.EDIT_TEXT
else -> { else -> {
when (this.operator) { when (this.operator) {
Operator.MORE -> BottomSheetType.EDIT_TEXT Operator.MORE -> InputFragmentType.EDIT_TEXT
Operator.LESS -> BottomSheetType.EDIT_TEXT Operator.LESS -> InputFragmentType.EDIT_TEXT
else -> BottomSheetType.NONE else -> InputFragmentType.NONE
} }
} }
} }

@ -2,156 +2,176 @@ package net.pokeranalytics.android.model.migrations
import io.realm.DynamicRealm import io.realm.DynamicRealm
import io.realm.RealmMigration import io.realm.RealmMigration
import net.pokeranalytics.android.model.realm.Comment
import timber.log.Timber import timber.log.Timber
import java.util.*
class PokerAnalyticsMigration : RealmMigration { class PokerAnalyticsMigration : RealmMigration {
override fun migrate(realm: DynamicRealm, oldVersion: Long, newVersion: Long) { override fun migrate(realm: DynamicRealm, oldVersion: Long, newVersion: Long) {
// DynamicRealm exposes an editable schema // DynamicRealm exposes an editable schema
val schema = realm.schema val schema = realm.schema
var currentVersion = oldVersion.toInt() var currentVersion = oldVersion.toInt()
Timber.d("*** migrate from $oldVersion to $newVersion") Timber.d("*** migrate from $oldVersion to $newVersion")
// Migrate to version 1 // Migrate to version 1
if (currentVersion == 0) { if (currentVersion == 0) {
Timber.d("*** Running migration 1") Timber.d("*** Running migration 1")
schema.get("Filter")?.addField("entityType", Int::class.java)?.setNullable("entityType", true) schema.get("Filter")?.addField("entityType", Int::class.java)?.setNullable("entityType", true)
schema.get("FilterElement")?.let { schema.get("FilterElement")?.let {
it.setNullable("filterName", true) it.setNullable("filterName", true)
it.setNullable("sectionName", true) it.setNullable("sectionName", true)
} }
schema.get("FilterElementBlind")?.renameField("code", "currencyCode") schema.get("FilterElementBlind")?.renameField("code", "currencyCode")
currentVersion++ currentVersion++
} }
// Migrate to version 2 // Migrate to version 2
if (currentVersion == 1) { if (currentVersion == 1) {
Timber.d("*** Running migration ${currentVersion + 1}") Timber.d("*** Running migration ${currentVersion + 1}")
schema.rename("FilterElement", "FilterCondition") schema.rename("FilterElement", "FilterCondition")
schema.get("Filter")?.renameField("filterElements", "filterConditions") schema.get("Filter")?.renameField("filterElements", "filterConditions")
schema.get("SessionSet")?.let { schema.get("SessionSet")?.let {
it.addField("id", String::class.java).setRequired("id", true) it.addField("id", String::class.java).setRequired("id", true)
it.addPrimaryKey("id") it.addPrimaryKey("id")
} }
currentVersion++ currentVersion++
} }
// Migrate to version 3 // Migrate to version 3
if (currentVersion == 2) { if (currentVersion == 2) {
Timber.d("*** Running migration ${currentVersion + 1}") Timber.d("*** Running migration ${currentVersion + 1}")
schema.rename("Report", "ReportSetup") schema.rename("Report", "ReportSetup")
schema.get("Filter")?.removeField("entityType") schema.get("Filter")?.removeField("entityType")
schema.get("Session")?.let { schema.get("Session")?.let {
it.addField("blinds", String::class.java).transform { it.addField("blinds", String::class.java).transform {
} }
} }
schema.get("FilterCondition")?.let { schema.get("FilterCondition")?.let {
it.removeField("blindValues") it.removeField("blindValues")
it.removeField("numericValues") it.removeField("numericValues")
it.addField("operator", Integer::class.java) it.addField("operator", Integer::class.java)
it.addField("intValue", Integer::class.java) it.addField("intValue", Integer::class.java)
it.addRealmListField("intValues", Integer::class.java) it.addRealmListField("intValues", Integer::class.java)
it.addField("doubleValue", Double::class.java).setNullable("doubleValue", true) it.addField("doubleValue", Double::class.java).setNullable("doubleValue", true)
it.addRealmListField("doubleValues", Double::class.java) it.addRealmListField("doubleValues", Double::class.java)
if (it.isRequired("doubleValues")) { if (it.isRequired("doubleValues")) {
it.setRequired("doubleValues", false) it.setRequired("doubleValues", false)
} }
it.addField("stringValue", String::class.java) it.addField("stringValue", String::class.java)
} }
schema.get("ComputableResult")?.removeField("sessionSet") schema.get("ComputableResult")?.removeField("sessionSet")
schema.get("Bankroll")?.addField("initialValue", Double::class.java) schema.get("Bankroll")?.addField("initialValue", Double::class.java)
currentVersion++ currentVersion++
} }
// Migrate to version 4 // Migrate to version 4
if (currentVersion == 3) { if (currentVersion == 3) {
Timber.d("*** Running migration ${currentVersion + 1}") Timber.d("*** Running migration ${currentVersion + 1}")
schema.get("Result")?.addField("numberOfRebuy", Double::class.java)?.setNullable("numberOfRebuy", true) schema.get("Result")?.addField("numberOfRebuy", Double::class.java)?.setNullable("numberOfRebuy", true)
currentVersion++ currentVersion++
} }
// Migrate to version 5 // Migrate to version 5
if (currentVersion == 4) { if (currentVersion == 4) {
Timber.d("*** Running migration ${currentVersion + 1}") Timber.d("*** Running migration ${currentVersion + 1}")
schema.get("Bankroll")?.removeField("transactions") schema.get("Bankroll")?.removeField("transactions")
currentVersion++ currentVersion++
} }
// Migrate to version 6 // Migrate to version 6
if (currentVersion == 5) { if (currentVersion == 5) {
Timber.d("*** Running migration ${currentVersion + 1}") Timber.d("*** Running migration ${currentVersion + 1}")
schema.get("Transaction")?.let { schema.get("Transaction")?.let {
it.addField("dayOfWeek", Integer::class.java) it.addField("dayOfWeek", Integer::class.java)
it.addField("month", Integer::class.java) it.addField("month", Integer::class.java)
it.addField("year", Integer::class.java) it.addField("year", Integer::class.java)
it.addField("dayOfMonth", Integer::class.java) it.addField("dayOfMonth", Integer::class.java)
} }
val cfEntry = schema.create("CustomFieldEntry")?.let { val cfEntry = schema.create("CustomFieldEntry")?.let {
it.addField("id", String::class.java).setRequired("id", true) it.addField("id", String::class.java).setRequired("id", true)
it.addPrimaryKey("id") it.addPrimaryKey("id")
it.addField("value", String::class.java).setNullable("value", false) it.addField("value", String::class.java).setNullable("value", false)
it.addField("order", Integer::class.java).setNullable("order", false) it.addField("order", Integer::class.java).setNullable("order", false)
// it.addRealmObjectField("customField", it).setNullable("customField", false) // it.addRealmObjectField("customField", it).setNullable("customField", false)
it.addField("numericValue", Double::class.java).setNullable("numericValue", true) it.addField("numericValue", Double::class.java).setNullable("numericValue", true)
} }
cfEntry?.let { customFieldEntrySchema -> cfEntry?.let { customFieldEntrySchema ->
schema.get("CustomField")?.let { schema.get("CustomField")?.let {
it.addField("type", Integer::class.java).setNullable("type", false) it.addField("type", Integer::class.java).setNullable("type", false)
it.addField("duplicateValue", Boolean::class.java) it.addField("duplicateValue", Boolean::class.java)
it.addField("sortCondition", Integer::class.java).setRequired("sortCondition", true) it.addField("sortCondition", Integer::class.java).setRequired("sortCondition", true)
it.addRealmListField("entries", customFieldEntrySchema) it.addRealmListField("entries", customFieldEntrySchema)
} }
schema.get("Session")?.let { schema.get("Session")?.let {
it.addField("startDateHourMinuteComponent", Double::class.java) it.addField("startDateHourMinuteComponent", Double::class.java)
.setNullable("startDateHourMinuteComponent", true) .setNullable("startDateHourMinuteComponent", true)
it.addField("endDateHourMinuteComponent", Double::class.java) it.addField("endDateHourMinuteComponent", Double::class.java)
.setNullable("endDateHourMinuteComponent", true) .setNullable("endDateHourMinuteComponent", true)
it.addRealmListField("customFieldEntries", customFieldEntrySchema) it.addRealmListField("customFieldEntries", customFieldEntrySchema)
} }
} }
schema.get("ReportSetup")?.let { schema.get("ReportSetup")?.let {
it.addRealmListField("statIds", Int::class.java).setNullable("statIds", true) it.addRealmListField("statIds", Int::class.java).setNullable("statIds", true)
it.addRealmListField("criteriaCustomFieldIds", String::class.java) it.addRealmListField("criteriaCustomFieldIds", String::class.java)
it.addRealmListField("criteriaIds", Int::class.java).setNullable("criteriaIds", true) it.addRealmListField("criteriaIds", Int::class.java).setNullable("criteriaIds", true)
it.removeField("filters") it.removeField("filters")
schema.get("Filter")?.let { filterSchema -> schema.get("Filter")?.let { filterSchema ->
it.addRealmObjectField("filter", filterSchema) it.addRealmObjectField("filter", filterSchema)
} }
} }
schema.get("Filter")?.addField("filterableTypeUniqueIdentifier", Integer::class.java) schema.get("Filter")?.addField("filterableTypeUniqueIdentifier", Integer::class.java)
schema.get("Filter")?.addField("useCount", Int::class.java) schema.get("Filter")?.addField("useCount", Int::class.java)
schema.get("Filter")?.removeField("usageCount") schema.get("Filter")?.removeField("usageCount")
currentVersion++
} currentVersion++
}
// Migrate to version 7
if (currentVersion == 6) { // Migrate to version 7
Timber.d("*** Running migration ${currentVersion + 1}") if (currentVersion == 6) {
schema.get("TransactionType")?.addField("useCount", Int::class.java) Timber.d("*** Running migration ${currentVersion + 1}")
currentVersion++ 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 { override fun equals(other: Any?): Boolean {
return other is RealmMigration 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.model.interfaces.SaveValidityStatus
import net.pokeranalytics.android.ui.view.RowRepresentable import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.rowrepresentable.BankrollRow import net.pokeranalytics.android.ui.view.rowrepresentable.BankrollRow
import net.pokeranalytics.android.ui.view.rowrepresentable.SimpleRow
import net.pokeranalytics.android.util.UserDefaults import net.pokeranalytics.android.util.UserDefaults
import java.util.* import java.util.*
@ -46,13 +45,22 @@ open class Bankroll : RealmObject(), NameManageable, RowRepresentable {
return this.currency?.rate ?: Currency.DEFAULT_RATE 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 { override fun getDisplayName(context: Context): String {
return this.name return this.name
} }
override fun updateValue(value: Any?, row: RowRepresentable) { override fun updateValue(value: Any?, row: RowRepresentable) {
when (row) { when (row) {
SimpleRow.NAME -> this.name = value as String? ?: "" BankrollRow.NAME -> this.name = value as String? ?: ""
BankrollRow.LIVE -> { BankrollRow.LIVE -> {
this.live = if (value is Boolean) !value else false 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.content.Context
import android.text.InputType import android.text.InputType
import androidx.fragment.app.Fragment
import io.realm.Realm import io.realm.Realm
import io.realm.RealmList import io.realm.RealmList
import io.realm.RealmObject 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.Identifiable
import net.pokeranalytics.android.model.interfaces.NameManageable import net.pokeranalytics.android.model.interfaces.NameManageable
import net.pokeranalytics.android.model.interfaces.SaveValidityStatus 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.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.RowRepresentable
import net.pokeranalytics.android.ui.view.RowRepresentableEditDescriptor
import net.pokeranalytics.android.ui.view.RowViewType import net.pokeranalytics.android.ui.view.RowViewType
import net.pokeranalytics.android.ui.view.rowrepresentable.CustomFieldRow import net.pokeranalytics.android.ui.view.rowrepresentable.CustomFieldRow
import net.pokeranalytics.android.ui.view.rowrepresentable.CustomizableRowRepresentable import net.pokeranalytics.android.ui.view.rowrepresentable.CustomizableRowRepresentable
import net.pokeranalytics.android.ui.view.rowrepresentable.SimpleRow
import net.pokeranalytics.android.util.enumerations.IntIdentifiable import net.pokeranalytics.android.util.enumerations.IntIdentifiable
import java.util.* import java.util.*
import kotlin.collections.ArrayList import kotlin.collections.ArrayList
@ -125,9 +127,23 @@ open class CustomField : RealmObject(), NameManageable, StaticRowRepresentableDa
return rowRepresentation 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) { override fun updateValue(value: Any?, row: RowRepresentable) {
when (row) { 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.TYPE -> this.type = (value as Type?)?.uniqueIdentifier ?: Type.LIST.uniqueIdentifier
CustomFieldRow.COPY_ON_DUPLICATE -> this.duplicateValue = value as Boolean? ?: false 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 return R.string.cf_entry_delete_popup_message
} }
override val bottomSheetType: BottomSheetType override val inputFragmentType: InputFragmentType
get() { get() {
return when (type) { return when (type) {
Type.LIST.uniqueIdentifier -> BottomSheetType.LIST_STATIC Type.LIST.uniqueIdentifier -> InputFragmentType.LIST_STATIC
else -> BottomSheetType.NUMERIC_TEXT 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 * Update the row representation
*/ */
private fun updatedRowRepresentationForCurrentState(): List<RowRepresentable> { private fun updatedRowRepresentationForCurrentState(): List<RowRepresentable> {
val rows = ArrayList<RowRepresentable>() val rows = ArrayList<RowRepresentable>()
rows.add(SimpleRow.NAME) rows.add(CustomFieldRow.NAME)
rows.add(CustomFieldRow.TYPE) rows.add(CustomFieldRow.TYPE)
if (type == Type.LIST.uniqueIdentifier && entries.size >= 0) { if (type == Type.LIST.uniqueIdentifier && entries.size >= 0) {
@ -270,10 +253,11 @@ open class CustomField : RealmObject(), NameManageable, StaticRowRepresentableDa
updateRowRepresentation() updateRowRepresentation()
} }
/**
* Cleanup deleted entries
*/
fun cleanupEntries() { // called when saving the custom field fun cleanupEntries() { // called when saving the custom field
val realm = Realm.getDefaultInstance() val realm = Realm.getDefaultInstance()
realm.executeTransaction { realm.executeTransaction {
this.entriesToDelete.forEach { // entries are out of realm this.entriesToDelete.forEach { // entries are out of realm
realm.where<CustomFieldEntry>().equalTo("id", it.id).findFirst()?.deleteFromRealm() 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.content.Context
import android.text.InputType import android.text.InputType
import androidx.fragment.app.Fragment
import io.realm.Realm import io.realm.Realm
import io.realm.RealmObject import io.realm.RealmObject
import io.realm.RealmResults 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.Identifiable
import net.pokeranalytics.android.model.interfaces.NameManageable import net.pokeranalytics.android.model.interfaces.NameManageable
import net.pokeranalytics.android.model.interfaces.SaveValidityStatus 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.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.ui.view.RowViewType
import net.pokeranalytics.android.util.NULL_TEXT import net.pokeranalytics.android.util.NULL_TEXT
import net.pokeranalytics.android.util.extensions.toCurrency import net.pokeranalytics.android.util.extensions.toCurrency
@ -81,7 +84,7 @@ open class CustomFieldEntry : RealmObject(), NameManageable, RowRepresentable {
} }
@Ignore @Ignore
override val bottomSheetType: BottomSheetType = BottomSheetType.EDIT_TEXT override val inputFragmentType: InputFragmentType = InputFragmentType.EDIT_TEXT
override fun localizedTitle(context: Context): String { override fun localizedTitle(context: Context): String {
return context.getString(R.string.value) return context.getString(R.string.value)
@ -91,12 +94,16 @@ open class CustomFieldEntry : RealmObject(), NameManageable, RowRepresentable {
return if (value.isNotEmpty()) value else NULL_TEXT return if (value.isNotEmpty()) value else NULL_TEXT
} }
override fun editingDescriptors(map: Map<String, Any?>): ArrayList<RowRepresentableEditDescriptor>? { override fun startEditing(dataSource: Any?, parent: Fragment?) {
val defaultValue: Any? by map if (parent == null) return
return arrayListOf( if (parent !is RowRepresentableDelegate) return
RowRepresentableEditDescriptor(defaultValue, R.string.value, InputType.TYPE_CLASS_TEXT) 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 { override fun isValidForSave(): Boolean {
return true return true

@ -1,6 +1,7 @@
package net.pokeranalytics.android.model.realm package net.pokeranalytics.android.model.realm
import android.content.Context import android.content.Context
import androidx.fragment.app.Fragment
import io.realm.* import io.realm.*
import io.realm.annotations.Ignore import io.realm.annotations.Ignore
import io.realm.annotations.PrimaryKey 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.Query
import net.pokeranalytics.android.model.filter.QueryCondition import net.pokeranalytics.android.model.filter.QueryCondition
import net.pokeranalytics.android.model.interfaces.* import net.pokeranalytics.android.model.interfaces.*
import net.pokeranalytics.android.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.interfaces.FilterableType
import net.pokeranalytics.android.ui.view.ImageDecorator import net.pokeranalytics.android.ui.view.*
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.FilterCategoryRow import net.pokeranalytics.android.ui.view.rowrepresentable.FilterCategoryRow
import timber.log.Timber import timber.log.Timber
import java.util.* import java.util.*
@ -193,20 +193,15 @@ open class Filter : RealmObject(), RowRepresentable, Editable, Deletable, Counta
return R.string.relationship_error return R.string.relationship_error
} }
override val bottomSheetType: BottomSheetType override val inputFragmentType: InputFragmentType
get() { get() {
return BottomSheetType.EDIT_TEXT return InputFragmentType.EDIT_TEXT
} }
override fun localizedTitle(context: Context): String { override fun localizedTitle(context: Context): String {
return context.getString(R.string.name) 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) { override fun updateValue(value: Any?, row: RowRepresentable) {
realm.executeTransaction { realm.executeTransaction {
val newName = value as String? ?: "" 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.model.interfaces.SaveValidityStatus
import net.pokeranalytics.android.ui.adapter.StaticRowRepresentableDataSource import net.pokeranalytics.android.ui.adapter.StaticRowRepresentableDataSource
import net.pokeranalytics.android.ui.view.RowRepresentable import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.RowRepresentableEditDescriptor
import net.pokeranalytics.android.ui.view.rowrepresentable.GameRow import net.pokeranalytics.android.ui.view.rowrepresentable.GameRow
import net.pokeranalytics.android.ui.view.rowrepresentable.SimpleRow
import net.pokeranalytics.android.util.NULL_TEXT import net.pokeranalytics.android.util.NULL_TEXT
import java.util.* import java.util.*
import kotlin.collections.ArrayList import kotlin.collections.ArrayList
@ -29,7 +27,7 @@ open class Game : RealmObject(), NameManageable, StaticRowRepresentableDataSourc
companion object { companion object {
val rowRepresentation : List<RowRepresentable> by lazy { val rowRepresentation : List<RowRepresentable> by lazy {
val rows = ArrayList<RowRepresentable>() val rows = ArrayList<RowRepresentable>()
rows.add(SimpleRow.NAME) rows.add(GameRow.NAME)
// rows.addAll(GameRow.values()) // rows.addAll(GameRow.values())
rows rows
} }
@ -62,28 +60,20 @@ open class Game : RealmObject(), NameManageable, StaticRowRepresentableDataSourc
} }
override fun adapterRows(): List<RowRepresentable>? { override fun adapterRows(): List<RowRepresentable>? {
return Game.rowRepresentation return rowRepresentation
} }
override fun stringForRow(row: RowRepresentable): String { override fun stringForRow(row: RowRepresentable): String {
return when (row) { 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 GameRow.SHORT_NAME -> this.shortName ?: NULL_TEXT
else -> return super.stringForRow(row) 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) { override fun updateValue(value: Any?, row: RowRepresentable) {
when (row) { when (row) {
SimpleRow.NAME -> this.name = value as String? ?: "" GameRow.NAME -> this.name = value as String? ?: ""
GameRow.SHORT_NAME -> this.shortName = value as String? ?: "" GameRow.SHORT_NAME -> this.shortName = value as String? ?: ""
} }
} }

@ -1,15 +1,175 @@
package net.pokeranalytics.android.model.realm 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.RealmObject
import io.realm.annotations.Ignore
import io.realm.annotations.PrimaryKey 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.* import java.util.*
open class Player : RealmObject() { open class Player : RealmObject(), NameManageable, Deletable, StaticRowRepresentableDataSource, RowRepresentable {
@PrimaryKey @PrimaryKey
var id = UUID.randomUUID().toString() override var id = UUID.randomUUID().toString()
// The name of the player // The name of the player
var name: String = "" 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) { override fun updateValue(value: Any?, row: RowRepresentable) {
realm.executeTransaction { realm.executeTransaction {

@ -233,7 +233,7 @@
// //
// /** // /**
// * Multiple session sets update: // * 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>) { // 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.model.interfaces.SaveValidityStatus
import net.pokeranalytics.android.ui.adapter.StaticRowRepresentableDataSource import net.pokeranalytics.android.ui.adapter.StaticRowRepresentableDataSource
import net.pokeranalytics.android.ui.view.RowRepresentable import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.RowRepresentableEditDescriptor
import net.pokeranalytics.android.ui.view.rowrepresentable.SimpleRow
import net.pokeranalytics.android.ui.view.rowrepresentable.TournamentFeatureRow import net.pokeranalytics.android.ui.view.rowrepresentable.TournamentFeatureRow
import net.pokeranalytics.android.util.NULL_TEXT import net.pokeranalytics.android.util.NULL_TEXT
import java.util.* import java.util.*
@ -27,7 +25,6 @@ open class TournamentFeature : RealmObject(), NameManageable, StaticRowRepresent
companion object { companion object {
val rowRepresentation : List<RowRepresentable> by lazy { val rowRepresentation : List<RowRepresentable> by lazy {
val rows = ArrayList<RowRepresentable>() val rows = ArrayList<RowRepresentable>()
rows.add(SimpleRow.NAME)
rows.addAll(TournamentFeatureRow.values()) rows.addAll(TournamentFeatureRow.values())
rows rows
} }
@ -53,24 +50,19 @@ open class TournamentFeature : RealmObject(), NameManageable, StaticRowRepresent
} }
override fun adapterRows(): List<RowRepresentable>? { override fun adapterRows(): List<RowRepresentable>? {
return TournamentFeature.rowRepresentation return rowRepresentation
} }
override fun stringForRow(row: RowRepresentable): String { override fun stringForRow(row: RowRepresentable): String {
return when (row) { 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) 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) { override fun updateValue(value: Any?, row: RowRepresentable) {
when (row) { 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.model.interfaces.SaveValidityStatus
import net.pokeranalytics.android.ui.adapter.StaticRowRepresentableDataSource import net.pokeranalytics.android.ui.adapter.StaticRowRepresentableDataSource
import net.pokeranalytics.android.ui.view.RowRepresentable import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.RowRepresentableEditDescriptor
import net.pokeranalytics.android.ui.view.rowrepresentable.SimpleRow
import net.pokeranalytics.android.ui.view.rowrepresentable.TournamentNameRow import net.pokeranalytics.android.ui.view.rowrepresentable.TournamentNameRow
import net.pokeranalytics.android.util.NULL_TEXT import net.pokeranalytics.android.util.NULL_TEXT
import java.util.* import java.util.*
@ -24,7 +22,6 @@ open class TournamentName : RealmObject(), NameManageable, StaticRowRepresentabl
companion object { companion object {
val rowRepresentation : List<RowRepresentable> by lazy { val rowRepresentation : List<RowRepresentable> by lazy {
val rows = ArrayList<RowRepresentable>() val rows = ArrayList<RowRepresentable>()
rows.add(SimpleRow.NAME)
rows.addAll(TournamentNameRow.values()) rows.addAll(TournamentNameRow.values())
rows rows
} }
@ -45,25 +42,21 @@ open class TournamentName : RealmObject(), NameManageable, StaticRowRepresentabl
override fun updateValue(value: Any?, row: RowRepresentable) { override fun updateValue(value: Any?, row: RowRepresentable) {
when (row) { when (row) {
SimpleRow.NAME -> this.name = value as String? ?: "" TournamentNameRow.NAME -> this.name = value as String? ?: ""
} }
} }
override fun adapterRows(): List<RowRepresentable>? { override fun adapterRows(): List<RowRepresentable>? {
return TournamentName.rowRepresentation return rowRepresentation
} }
override fun stringForRow(row: RowRepresentable): String { override fun stringForRow(row: RowRepresentable): String {
return when (row) { 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) 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 { override fun getFailedSaveMessage(status: SaveValidityStatus): Int {
return when (status) { return when (status) {
SaveValidityStatus.DATA_INVALID -> R.string.tournament_name_empty_field_error 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.adapter.StaticRowRepresentableDataSource
import net.pokeranalytics.android.ui.view.Localizable import net.pokeranalytics.android.ui.view.Localizable
import net.pokeranalytics.android.ui.view.RowRepresentable import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.RowRepresentableEditDescriptor
import net.pokeranalytics.android.ui.view.rowrepresentable.SimpleRow
import net.pokeranalytics.android.ui.view.rowrepresentable.TransactionTypeRow import net.pokeranalytics.android.ui.view.rowrepresentable.TransactionTypeRow
import net.pokeranalytics.android.util.enumerations.IntIdentifiable import net.pokeranalytics.android.util.enumerations.IntIdentifiable
import net.pokeranalytics.android.util.enumerations.IntSearchable import net.pokeranalytics.android.util.enumerations.IntSearchable
@ -55,7 +53,6 @@ open class TransactionType : RealmObject(), NameManageable, StaticRowRepresentab
companion object { companion object {
val rowRepresentation: List<RowRepresentable> by lazy { val rowRepresentation: List<RowRepresentable> by lazy {
val rows = ArrayList<RowRepresentable>() val rows = ArrayList<RowRepresentable>()
rows.add(SimpleRow.NAME)
rows.addAll(TransactionTypeRow.values()) rows.addAll(TransactionTypeRow.values())
rows rows
} }
@ -108,7 +105,7 @@ open class TransactionType : RealmObject(), NameManageable, StaticRowRepresentab
override fun stringForRow(row: RowRepresentable): String { override fun stringForRow(row: RowRepresentable): String {
return when (row) { return when (row) {
SimpleRow.NAME -> this.name TransactionTypeRow.NAME -> this.name
else -> return super.stringForRow(row) 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) { override fun updateValue(value: Any?, row: RowRepresentable) {
when (row) { 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 TransactionTypeRow.TRANSACTION_ADDITIVE -> this.additive = value as Boolean? ?: false
} }
} }

@ -97,7 +97,7 @@ class SessionSetManager {
/** /**
* Multiple session sets update: * 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>) { 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 androidx.fragment.app.Fragment
import net.pokeranalytics.android.R import net.pokeranalytics.android.R
import net.pokeranalytics.android.model.LiveData 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 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) { enum class IntentKey(val keyName: String) {
DATA_TYPE("DATA_TYPE"), DATA_TYPE("DATA_TYPE"),
@ -43,6 +45,8 @@ class EditableDataActivity : PokerAnalyticsActivity() {
} }
private var currentFragment: EditableDataFragment? = null
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setContentView(R.layout.activity_editable_data) setContentView(R.layout.activity_editable_data)
@ -57,20 +61,35 @@ class EditableDataActivity : PokerAnalyticsActivity() {
val dataType = intent.getIntExtra(IntentKey.DATA_TYPE.keyName, 0) val dataType = intent.getIntExtra(IntentKey.DATA_TYPE.keyName, 0)
val primaryKey = intent.getStringExtra(IntentKey.PRIMARY_KEY.keyName) val primaryKey = intent.getStringExtra(IntentKey.PRIMARY_KEY.keyName)
val fragmentManager = supportFragmentManager currentFragment = when (dataType) {
val fragmentTransaction = fragmentManager.beginTransaction()
val fragment: EditableDataFragment = when (dataType) {
LiveData.BANKROLL.ordinal -> BankrollDataFragment() LiveData.BANKROLL.ordinal -> BankrollDataFragment()
LiveData.LOCATION.ordinal -> LocationDataFragment() LiveData.LOCATION.ordinal -> LocationDataFragment()
LiveData.TRANSACTION.ordinal -> TransactionDataFragment() LiveData.TRANSACTION.ordinal -> TransactionDataFragment()
LiveData.CUSTOM_FIELD.ordinal -> CustomFieldDataFragment() LiveData.CUSTOM_FIELD.ordinal -> CustomFieldDataFragment()
LiveData.TRANSACTION_TYPE.ordinal -> TransactionTypeDataFragment() LiveData.TRANSACTION_TYPE.ordinal -> TransactionTypeDataFragment()
LiveData.PLAYER.ordinal -> PlayerDataFragment()
else -> EditableDataFragment() else -> EditableDataFragment()
} }
fragment.setData(dataType, primaryKey)
fragmentTransaction.add(R.id.container, fragment) currentFragment?.let { fragment ->
fragmentTransaction.commit() 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 { item?.let {
if (it.itemId == android.R.id.home) { if (it.itemId == android.R.id.home) {
onBackPressed() onBackPressed()

@ -21,7 +21,7 @@ class HomePagerAdapter(fragmentManager: FragmentManager) : FragmentStatePagerAda
1 -> StatisticsFragment.newInstance() 1 -> StatisticsFragment.newInstance()
2 -> CalendarFragment.newInstance() 2 -> CalendarFragment.newInstance()
3 -> ReportsFragment.newInstance() 3 -> ReportsFragment.newInstance()
4 -> SettingsFragment.newInstance() 4 -> MoreFragment.newInstance()
else -> FeedFragment.newInstance() else -> FeedFragment.newInstance()
} }
} }
@ -47,7 +47,7 @@ class HomePagerAdapter(fragmentManager: FragmentManager) : FragmentStatePagerAda
StatisticsFragment::class.java -> 1 StatisticsFragment::class.java -> 1
CalendarFragment::class.java -> 2 CalendarFragment::class.java -> 2
ReportsFragment::class.java -> 3 ReportsFragment::class.java -> 3
SettingsFragment::class.java -> 4 MoreFragment::class.java -> 4
else -> -1 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.RowRepresentable
import net.pokeranalytics.android.ui.view.RowViewType import net.pokeranalytics.android.ui.view.RowViewType
interface RowRepresentableDelegate { interface RowRepresentableDelegate: RowEditableDelegate {
fun onRowSelected(position: Int, row: RowRepresentable, fromAction: Boolean = false) {} 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 android.content.Context
import net.pokeranalytics.android.exceptions.PAIllegalStateException import net.pokeranalytics.android.exceptions.PAIllegalStateException
import net.pokeranalytics.android.ui.view.RowRepresentable import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.RowRepresentableEditDescriptor
import net.pokeranalytics.android.util.TextFormat import net.pokeranalytics.android.util.TextFormat
/** /**
* Base Interface to provide the RowRepresentable to the adapter * Base Interface to provide the RowRepresentable to the adapter
*/ */
interface RowRepresentableDataSource: EditableDataSource, DisplayableDataSource, SelectableDataSource { interface RowRepresentableDataSource: DisplayableDataSource, SelectableDataSource {
/** /**
* Returns a prebuild list of rows * 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 * An interface providing a way to select a row

@ -7,9 +7,11 @@ import android.content.res.Resources
import android.net.Uri import android.net.Uri
import android.util.TypedValue import android.util.TypedValue
import android.view.View import android.view.View
import android.widget.LinearLayout
import android.widget.Toast import android.widget.Toast
import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AlertDialog
import androidx.appcompat.widget.AppCompatTextView import androidx.appcompat.widget.AppCompatTextView
import androidx.appcompat.widget.SearchView
import androidx.browser.customtabs.CustomTabsIntent import androidx.browser.customtabs.CustomTabsIntent
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.core.content.FileProvider import androidx.core.content.FileProvider
@ -94,7 +96,7 @@ fun PokerAnalyticsActivity.openContactMail(subjectStringRes: Int, filePath: Stri
// Open custom tab // Open custom tab
fun PokerAnalyticsActivity.openUrl(url: String) { fun PokerAnalyticsActivity.openUrl(url: String) {
val builder: CustomTabsIntent.Builder = CustomTabsIntent.Builder() 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() val customTabsIntent = builder.build()
customTabsIntent.launchUrl(this, Uri.parse(url)) customTabsIntent.launchUrl(this, Uri.parse(url))
} }
@ -124,7 +126,7 @@ fun showAlertDialog(
message?.let { message?.let {
builder.setMessage(message) builder.setMessage(message)
} }
builder.setPositiveButton(net.pokeranalytics.android.R.string.ok) { _, _ -> builder.setPositiveButton(R.string.ok) { _, _ ->
positiveAction?.invoke() positiveAction?.invoke()
} }
@ -160,4 +162,12 @@ fun View.showWithAnimation() {
fun View.addCircleRipple() = with(TypedValue()) { fun View.addCircleRipple() = with(TypedValue()) {
context.theme.resolveAttribute(android.R.attr.selectableItemBackgroundBorderless, this, true) context.theme.resolveAttribute(android.R.attr.selectableItemBackgroundBorderless, this, true)
setBackgroundResource(resourceId) 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?) { override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
menu?.clear() menu.clear()
inflater?.inflate(R.menu.toolbar_comparison_chart, menu) // TODO R.menu.toolbar_comparison_chart? inflater.inflate(R.menu.toolbar_comparison_chart, menu) // TODO R.menu.toolbar_comparison_chart?
this.bankrollDetailsMenu = menu this.bankrollDetailsMenu = menu
updateMenuUI() updateMenuUI()
super.onCreateOptionsMenu(menu, inflater) super.onCreateOptionsMenu(menu, inflater)
@ -197,8 +197,8 @@ class BankrollDetailsFragment : RealmFragment(), StaticRowRepresentableDataSourc
} }
override fun onOptionsItemSelected(item: MenuItem?): Boolean { override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item?.itemId) { when (item.itemId) {
R.id.settings -> editBankroll() R.id.settings -> editBankroll()
} }
return true 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.app.Activity
import android.content.Intent import android.content.Intent
import android.os.Bundle import android.os.Bundle
import android.view.LayoutInflater import android.view.*
import android.view.View import androidx.appcompat.widget.SearchView
import android.view.ViewGroup
import androidx.core.view.isVisible import androidx.core.view.isVisible
import androidx.recyclerview.widget.ItemTouchHelper import androidx.recyclerview.widget.ItemTouchHelper
import androidx.recyclerview.widget.LinearLayoutManager 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.LiveRowRepresentableDataSource
import net.pokeranalytics.android.ui.adapter.RowRepresentableAdapter import net.pokeranalytics.android.ui.adapter.RowRepresentableAdapter
import net.pokeranalytics.android.ui.adapter.RowRepresentableDelegate import net.pokeranalytics.android.ui.adapter.RowRepresentableDelegate
import net.pokeranalytics.android.ui.extensions.removeMargins
import net.pokeranalytics.android.ui.fragment.components.DeletableItemFragment import net.pokeranalytics.android.ui.fragment.components.DeletableItemFragment
import net.pokeranalytics.android.ui.helpers.SwipeToDeleteCallback import net.pokeranalytics.android.ui.helpers.SwipeToDeleteCallback
import net.pokeranalytics.android.ui.view.RowRepresentable import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.RowViewType import net.pokeranalytics.android.ui.view.RowViewType
import net.pokeranalytics.android.util.extensions.find
import net.pokeranalytics.android.util.extensions.sorted import net.pokeranalytics.android.util.extensions.sorted
@ -40,6 +41,16 @@ open class DataListFragment : DeletableItemFragment(), LiveRowRepresentableDataS
private lateinit var dataType: LiveData private lateinit var dataType: LiveData
private lateinit var items: RealmResults<out Deletable> 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 * Set fragment data
@ -51,13 +62,19 @@ open class DataListFragment : DeletableItemFragment(), LiveRowRepresentableDataS
setToolbarTitle(this.dataType.pluralLocalizedTitle(requireContext())) setToolbarTitle(this.dataType.pluralLocalizedTitle(requireContext()))
this.items = this.retrieveItems(getRealm()) 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> { 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 return this.items
} }
@ -71,44 +88,32 @@ open class DataListFragment : DeletableItemFragment(), LiveRowRepresentableDataS
initUI() initUI()
} }
/** override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
* Init UI
*/
private fun initUI() {
setDisplayHomeAsUpEnabled(true) menu.clear()
inflater.inflate(R.menu.toolbar_data_list, menu)
this.dataListMenu = menu
val viewManager = LinearLayoutManager(requireContext()) val searchMenuItem = menu.findItem(R.id.action_search)
dataListAdapter = RowRepresentableAdapter(this, this) searchMenuItem.isVisible = isSearchable
val swipeToDelete = SwipeToDeleteCallback(dataListAdapter) { position -> searchView = searchMenuItem.actionView as SearchView?
val item = this.items[position] searchView?.removeMargins()
if (item != null) { searchView?.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
val itemId = item.id override fun onQueryTextSubmit(query: String?): Boolean {
deleteItem(dataListAdapter, items, itemId) return false
} else {
throw PAIllegalStateException("Item with position $position not found")
} }
}
val itemTouchHelper = ItemTouchHelper(swipeToDelete)
recyclerView.apply { override fun onQueryTextChange(newText: String?): Boolean {
setHasFixedSize(true) filterItemsWithSearch(newText)
layoutManager = viewManager return false
adapter = dataListAdapter }
itemTouchHelper.attachToRecyclerView(this) })
}
this.addButton.setOnClickListener { super.onCreateOptionsMenu(menu, inflater)
EditableDataActivity.newInstance(
requireContext(),
dataType = this.dataType.ordinal,
primaryKey = null
)
}
} }
override fun onResume() { override fun onResume() {
super.onResume() super.onResume()
this.recyclerView?.adapter?.notifyDataSetChanged() this.recyclerView?.adapter?.notifyDataSetChanged()
@ -128,6 +133,7 @@ open class DataListFragment : DeletableItemFragment(), LiveRowRepresentableDataS
} }
override fun onRowSelected(position: Int, row: RowRepresentable, fromAction: Boolean) { override fun onRowSelected(position: Int, row: RowRepresentable, fromAction: Boolean) {
searchView?.clearFocus()
when (this.dataType) { when (this.dataType) {
LiveData.FILTER -> { 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 * Update UI
*/ */

@ -4,7 +4,6 @@ import android.app.Activity.RESULT_OK
import android.content.Intent import android.content.Intent
import android.os.Bundle import android.os.Bundle
import android.view.* import android.view.*
import android.widget.Toast
import androidx.core.app.ActivityOptionsCompat import androidx.core.app.ActivityOptionsCompat
import androidx.core.view.isVisible import androidx.core.view.isVisible
import androidx.interpolator.view.animation.FastOutSlowInInterpolator import androidx.interpolator.view.animation.FastOutSlowInInterpolator
@ -92,18 +91,15 @@ class FeedFragment : FilterableFragment(), RowRepresentableDelegate {
return inflater.inflate(R.layout.fragment_feed, container, false) 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) 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) activity?.menuInflater?.inflate(R.menu.menu_session, menu)
} }
} }
override fun onContextItemSelected(item: MenuItem?): Boolean { override fun onContextItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
when (item?.itemId) {
R.id.duplicate -> { R.id.duplicate -> {
val info = item.menuInfo as ContextMenuRecyclerView.RecyclerViewContextMenuInfo val info = item.menuInfo as ContextMenuRecyclerView.RecyclerViewContextMenuInfo
val sessionId = this.feedSessionAdapter.sessionIdForPosition(info.position) val sessionId = this.feedSessionAdapter.sessionIdForPosition(info.position)
@ -336,6 +332,8 @@ class FeedFragment : FilterableFragment(), RowRepresentableDelegate {
* Show end of beta message * Show end of beta message
* Keep for possible future uses * Keep for possible future uses
*/ */
//TODO: Delete
/*
private fun showEndOfBetaMessage() { private fun showEndOfBetaMessage() {
Toast.makeText( Toast.makeText(
context, context,
@ -343,6 +341,7 @@ class FeedFragment : FilterableFragment(), RowRepresentableDelegate {
Toast.LENGTH_LONG Toast.LENGTH_LONG
).show() ).show()
} }
*/
// Filter Handler // 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.RowRepresentableDelegate
import net.pokeranalytics.android.ui.adapter.StaticRowRepresentableDataSource import net.pokeranalytics.android.ui.adapter.StaticRowRepresentableDataSource
import net.pokeranalytics.android.ui.fragment.components.RealmFragment 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.RowRepresentable
import net.pokeranalytics.android.ui.view.RowViewType import net.pokeranalytics.android.ui.view.RowViewType
import net.pokeranalytics.android.ui.view.rowrepresentable.FilterCategoryRow import net.pokeranalytics.android.ui.view.rowrepresentable.FilterCategoryRow
@ -65,35 +63,7 @@ open class FilterDetailsFragment : RealmFragment(), StaticRowRepresentableDataSo
updateRowsSelection(row) updateRowsSelection(row)
return return
} }
row.startEditing(null, this)
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)
}
}
} }
override fun stringForRow(row: RowRepresentable, context: Context): String { override fun stringForRow(row: RowRepresentable, context: Context): String {

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

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

@ -1,94 +1,198 @@
package net.pokeranalytics.android.ui.fragment 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.os.Bundle
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import io.realm.Realm
import kotlinx.android.synthetic.main.fragment_more.* import kotlinx.android.synthetic.main.fragment_more.*
import net.pokeranalytics.android.BuildConfig
import net.pokeranalytics.android.R import net.pokeranalytics.android.R
import net.pokeranalytics.android.ui.activity.BankrollActivity import net.pokeranalytics.android.model.LiveData
import net.pokeranalytics.android.ui.activity.SettingsActivity import net.pokeranalytics.android.model.realm.Currency
import net.pokeranalytics.android.ui.activity.Top10Activity 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.RowRepresentableAdapter
import net.pokeranalytics.android.ui.adapter.RowRepresentableDelegate import net.pokeranalytics.android.ui.adapter.RowRepresentableDelegate
import net.pokeranalytics.android.ui.adapter.StaticRowRepresentableDataSource 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.fragment.components.PokerAnalyticsFragment
import net.pokeranalytics.android.ui.view.RowRepresentable 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 { companion object {
val rows = ArrayList<RowRepresentable>()
rows.addAll(MoreTabRow.values())
rows
}
} /**
* 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? { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
return inflater.inflate(R.layout.fragment_more, container, false) super.onViewCreated(view, savedInstanceState)
} initData()
initUI()
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onViewCreated(view, savedInstanceState)
initData() when (requestCode) {
initUI() 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>? { override fun adapterRows(): List<RowRepresentable>? {
return rowRepresentation return rowRepresentation
} }
override fun onRowSelected(position: Int, row: RowRepresentable, fromAction: Boolean) { override fun stringForRow(row: RowRepresentable): String {
super.onRowSelected(position, row, fromAction) return when (row) {
when(row) { SettingRow.SUBSCRIPTION -> AppGuard.subscriptionStatus(requireContext())
MoreTabRow.BANKROLL -> BankrollActivity.newInstance(requireContext()) SettingRow.VERSION -> BuildConfig.VERSION_NAME + if (BuildConfig.DEBUG) " (${BuildConfig.VERSION_CODE}) DEBUG" else ""
MoreTabRow.TOP_10 -> Top10Activity.newInstance(requireContext()) SettingRow.CURRENCY -> UserDefaults.currency.symbol
MoreTabRow.SETTINGS -> SettingsActivity.newInstance(requireContext()) 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()
}
/** row.relatedResultsRepresentable?.let {
* Init data DataListActivity.newInstance(requireContext(), it.ordinal)
*/ }
private fun initData() { }
}
/** /**
* Init UI * Init UI
*/ */
private fun initUI() { private fun initUI() {
moreAdapter = RowRepresentableAdapter(this, this) setToolbarTitle(getString(R.string.more))
val viewManager = LinearLayoutManager(requireContext()) val viewManager = LinearLayoutManager(requireContext())
settingsAdapterRow = RowRepresentableAdapter(
this, this
)
recyclerView.apply { recyclerView.apply {
setHasFixedSize(true) setHasFixedSize(true)
layoutManager = viewManager 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) super.onCreateOptionsMenu(menu, inflater)
menu?.clear() menu.clear()
inflater?.inflate(R.menu.toolbar_report_creation, menu) inflater.inflate(R.menu.toolbar_report_creation, menu)
menu?.findItem(R.id.add)?.isVisible = false menu.findItem(R.id.add)?.isVisible = false
reportCreationMenu = menu reportCreationMenu = menu
} }
override fun onOptionsItemSelected(item: MenuItem?): Boolean { override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item?.itemId) { when (item.itemId) {
R.id.add -> { R.id.add -> {
if (this.assistant.step == Assistant.Step.FILTER) { if (this.assistant.step == Assistant.Step.FILTER) {
FiltersActivity.newInstanceForResult( FiltersActivity.newInstanceForResult(
@ -174,7 +174,7 @@ class ReportCreationFragment : RealmFragment(), RowRepresentableDataSource, RowR
0 -> RowViewType.HEADER_TITLE.ordinal 0 -> RowViewType.HEADER_TITLE.ordinal
else -> { else -> {
val row = this.currentRows[position] val row = this.currentRows[position]
when (row) { when (this.currentRows[position]) {
is SeparatorRow -> row.viewType is SeparatorRow -> row.viewType
else -> RowViewType.TITLE_CHECK.ordinal 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.RowRepresentableAdapter
import net.pokeranalytics.android.ui.adapter.RowRepresentableDelegate import net.pokeranalytics.android.ui.adapter.RowRepresentableDelegate
import net.pokeranalytics.android.ui.fragment.components.RealmFragment 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.RowRepresentable
import net.pokeranalytics.android.ui.view.RowRepresentableDiffCallback import net.pokeranalytics.android.ui.view.RowRepresentableDiffCallback
import net.pokeranalytics.android.ui.view.SmoothScrollLinearLayoutManager import net.pokeranalytics.android.ui.view.SmoothScrollLinearLayoutManager
@ -82,7 +80,7 @@ class SessionFragment : RealmFragment(), RowRepresentableDelegate {
} else { } else {
throw PAIllegalStateException("Session cannot be null here, session id = $sessionId") throw PAIllegalStateException("Session cannot be null here, session id = $sessionId")
} }
} else { // create new session } else { // buildAndShow new session
realm.executeTransaction { executeRealm -> realm.executeTransaction { executeRealm ->
currentSession = Session.newInstance(executeRealm, isTournament) currentSession = Session.newInstance(executeRealm, isTournament)
FavoriteSessionFinder.copyParametersFromFavoriteSession(currentSession, null, requireContext()) FavoriteSessionFinder.copyParametersFromFavoriteSession(currentSession, null, requireContext())
@ -135,16 +133,16 @@ class SessionFragment : RealmFragment(), RowRepresentableDelegate {
handler.removeCallbacksAndMessages(null) handler.removeCallbacksAndMessages(null)
} }
override fun onCreateOptionsMenu(menu: Menu?, inflater: MenuInflater?) { override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
menu?.clear() menu.clear()
inflater?.inflate(R.menu.toolbar_session, menu) inflater.inflate(R.menu.toolbar_session, menu)
this.sessionMenu = menu this.sessionMenu = menu
updateMenuUI() updateMenuUI()
super.onCreateOptionsMenu(menu, inflater) super.onCreateOptionsMenu(menu, inflater)
} }
override fun onOptionsItemSelected(item: MenuItem?): Boolean { override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item!!.itemId) { when (item.itemId) {
R.id.stop -> stopSession() R.id.stop -> stopSession()
R.id.newCustomField -> addNewCustomField() R.id.newCustomField -> addNewCustomField()
R.id.restart -> restartTimer() R.id.restart -> restartTimer()
@ -158,30 +156,7 @@ class SessionFragment : RealmFragment(), RowRepresentableDelegate {
Toast.makeText(requireContext(), "Action for row: $row", Toast.LENGTH_SHORT).show() Toast.makeText(requireContext(), "Action for row: $row", Toast.LENGTH_SHORT).show()
return return
} }
row.startEditing(currentSession, this)
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)
}
} }
override fun onRowValueChanged(value: Any?, row: RowRepresentable) { override fun onRowValueChanged(value: Any?, row: RowRepresentable) {
@ -237,8 +212,7 @@ class SessionFragment : RealmFragment(), RowRepresentableDelegate {
val animationDuration = if (firstDisplay) 0L else 300L val animationDuration = if (firstDisplay) 0L else 300L
val state = currentSession.getState() when (currentSession.getState()) {
when (state) {
SessionState.PENDING, SessionState.PLANNED -> { SessionState.PENDING, SessionState.PLANNED -> {
sessionMenu?.findItem(R.id.restart)?.isVisible = false sessionMenu?.findItem(R.id.restart)?.isVisible = false
floatingActionButton.setImageResource(R.drawable.ic_outline_play) 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 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 itemPosition = items.indexOfFirst { it.id == itemId }
val itemToDelete = items.find { 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.FilterHandler.Companion.INTENT_FILTER_UPDATE_FILTER_UI
import net.pokeranalytics.android.ui.interfaces.FilterableType import net.pokeranalytics.android.ui.interfaces.FilterableType
import net.pokeranalytics.android.util.Preferences 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) return super.onCreateView(inflater, container, savedInstanceState)
} }
override fun onCreateOptionsMenu(menu: Menu?, inflater: MenuInflater?) { override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
super.onCreateOptionsMenu(menu, inflater) super.onCreateOptionsMenu(menu, inflater)
view?.findViewById<Toolbar>(R.id.toolbar)?.let { toolbar -> view?.findViewById<Toolbar>(R.id.toolbar)?.let { toolbar ->
toolbar.menu.removeItem(R.id.menu_item_filter) toolbar.menu.removeItem(R.id.menu_item_filter)
@ -80,8 +79,8 @@ open class FilterableFragment : RealmFragment(), FilterHandler {
} }
} }
override fun onOptionsItemSelected(item: MenuItem?): Boolean { override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item?.itemId) { when (item.itemId) {
R.id.menu_item_filter -> { R.id.menu_item_filter -> {
manageFilters(this) manageFilters(this)
} }

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

@ -7,11 +7,12 @@ import androidx.fragment.app.Fragment
import com.crashlytics.android.Crashlytics import com.crashlytics.android.Crashlytics
import net.pokeranalytics.android.R import net.pokeranalytics.android.R
import net.pokeranalytics.android.ui.activity.components.PokerAnalyticsActivity import net.pokeranalytics.android.ui.activity.components.PokerAnalyticsActivity
import java.io.File
open class PokerAnalyticsFragment : Fragment() { open class PokerAnalyticsFragment : Fragment() {
private var loaderDialogFragment: LoaderDialogFragment? = null private var loaderDialogFragment: LoaderDialogFragment? = null
var parentActivity: PokerAnalyticsActivity? = null open var parentActivity: PokerAnalyticsActivity? = null
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
@ -94,4 +95,14 @@ open class PokerAnalyticsFragment : Fragment() {
parentActivity?.supportActionBar?.setDisplayHomeAsUpEnabled(enabled) 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.os.Bundle
import android.text.InputType import android.text.InputType
@ -15,7 +15,7 @@ import net.pokeranalytics.android.ui.view.rowrepresentable.SessionRow
import net.pokeranalytics.android.util.extensions.round 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 val values = ArrayList<String>()
private var isEditingBlinds: Boolean = false private var isEditingBlinds: Boolean = false
@ -52,9 +52,9 @@ class BottomSheetDoubleEditTextFragment(row: RowRepresentable) : BottomSheetFrag
* Init UI * Init UI
*/ */
private fun initUI() { private fun initUI() {
val data = getData()?:throw RowRepresentableEditDescriptorException("RowRepresentableEditDescriptor not found") val data = getData()?:throw RowRepresentableEditDescriptorException("RowEditableDescriptor not found")
if (data.size != 2) { if (data.size != 2) {
throw RowRepresentableEditDescriptorException("RowRepresentableEditDescriptor inconsistency") throw RowRepresentableEditDescriptorException("RowEditableDescriptor inconsistency")
} }
values.add(0, "") 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.os.Bundle
import android.text.InputType import android.text.InputType
@ -13,7 +13,7 @@ import net.pokeranalytics.android.exceptions.RowRepresentableEditDescriptorExcep
import net.pokeranalytics.android.ui.view.RowRepresentable import net.pokeranalytics.android.ui.view.RowRepresentable
class BottomSheetEditTextFragment(row: RowRepresentable) : BottomSheetFragment(row) { class InputEditTextFragment(row: RowRepresentable) : InputFragment(row) {
private var value: String? = null private var value: String? = null
@ -51,9 +51,9 @@ class BottomSheetEditTextFragment(row: RowRepresentable) : BottomSheetFragment(r
*/ */
private fun initUI() { private fun initUI() {
val data = getData()?:throw RowRepresentableEditDescriptorException("RowRepresentableEditDescriptor not found") val data = getData()?:throw RowRepresentableEditDescriptorException("RowEditableDescriptor not found")
if (data.size != 1) { 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) 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.os.Bundle
import android.text.InputType import android.text.InputType
@ -11,7 +11,7 @@ import net.pokeranalytics.android.exceptions.RowRepresentableEditDescriptorExcep
import net.pokeranalytics.android.ui.view.RowRepresentable import net.pokeranalytics.android.ui.view.RowRepresentable
class BottomSheetEditTextMultiLinesFragment(row: RowRepresentable) : BottomSheetFragment(row) { class InputEditTextMultiLinesFragment(row: RowRepresentable) : InputFragment(row) {
private var value: String? = null private var value: String? = null
@ -43,9 +43,9 @@ class BottomSheetEditTextMultiLinesFragment(row: RowRepresentable) : BottomSheet
* Init UI * Init UI
*/ */
private fun initUI() { private fun initUI() {
val data = getData()?:throw RowRepresentableEditDescriptorException("RowRepresentableEditDescriptor not found") val data = getData()?:throw RowRepresentableEditDescriptorException("RowEditableDescriptor not found")
if (data.size != 1) { 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) 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.annotation.SuppressLint
import android.app.Activity.RESULT_OK import android.app.Activity.RESULT_OK
@ -10,57 +10,63 @@ import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.view.WindowManager import android.view.WindowManager
import androidx.appcompat.view.ContextThemeWrapper import androidx.appcompat.view.ContextThemeWrapper
import androidx.fragment.app.FragmentManager import androidx.fragment.app.Fragment
import com.google.android.material.bottomsheet.BottomSheetDialogFragment import com.google.android.material.bottomsheet.BottomSheetDialogFragment
import io.realm.RealmModel import io.realm.RealmModel
import kotlinx.android.synthetic.main.fragment_bottom_sheet.* import kotlinx.android.synthetic.main.fragment_bottom_sheet.*
import net.pokeranalytics.android.R import net.pokeranalytics.android.R
import net.pokeranalytics.android.exceptions.PAIllegalStateException import net.pokeranalytics.android.exceptions.PAIllegalStateException
import net.pokeranalytics.android.exceptions.PokerAnalyticsException
import net.pokeranalytics.android.model.LiveData import net.pokeranalytics.android.model.LiveData
import net.pokeranalytics.android.ui.activity.EditableDataActivity import net.pokeranalytics.android.ui.activity.EditableDataActivity
import net.pokeranalytics.android.ui.activity.components.PokerAnalyticsActivity import net.pokeranalytics.android.ui.activity.components.PokerAnalyticsActivity
import net.pokeranalytics.android.ui.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.RowRepresentable
import net.pokeranalytics.android.ui.view.RowRepresentableEditDescriptor
import net.pokeranalytics.android.ui.view.rowrepresentable.SessionRow import net.pokeranalytics.android.ui.view.rowrepresentable.SessionRow
import net.pokeranalytics.android.ui.view.rowrepresentable.TransactionRow import net.pokeranalytics.android.ui.view.rowrepresentable.TransactionRow
import java.util.* import java.util.*
open class BottomSheetFragment(val row: RowRepresentable) : BottomSheetDialogFragment() { open class InputFragment(val row: RowRepresentable) : BottomSheetDialogFragment() {
// lateinit var row: RowRepresentable // lateinit var row: RowRepresentable
lateinit var delegate: RowRepresentableDelegate lateinit var delegate: RowEditableDelegate
var currentCurrency: Currency? = null var currentCurrency: Currency? = null
var valueHasPlaceholder: Boolean = false var valueHasPlaceholder: Boolean = false
private var isClearable: Boolean = true private var isClearable: Boolean = true
private var isDeletable: Boolean = false private var isDeletable: Boolean = false
private var rowRepresentableEditDescriptors: ArrayList<RowRepresentableEditDescriptor>? = null private var rowEditableDescriptors: ArrayList<RowEditableDescriptor>? = null
companion object { companion object {
const val REQUEST_CODE_ADD_NEW_OBJECT = 100 const val REQUEST_CODE_ADD_NEW_OBJECT = 100
fun create( fun buildAndShow(
fragmentManager: FragmentManager?,
row: RowRepresentable, row: RowRepresentable,
delegate: RowRepresentableDelegate, delegate: RowEditableDelegate,
rowRepresentableEditDescriptors: ArrayList<RowRepresentableEditDescriptor>?, dataSource: RowEditableDataSource?,
isClearable: Boolean? = true,
currentCurrency: Currency? = null,
isDeletable: Boolean? = false, isDeletable: Boolean? = false,
valueHasPlaceholder: Boolean? = null valueHasPlaceholder: Boolean? = null
): BottomSheetFragment { ) {
val bottomSheetFragment = row.bottomSheetType.newInstance(row) if (delegate !is Fragment) throw PokerAnalyticsException.InputFragmentException
bottomSheetFragment.show(fragmentManager, "bottomSheet") if (dataSource?.descriptorType == RowEditableDescriptorType.DATE) {
// bottomSheetFragment.row = row DateTimePickerManager.buildAndShow(row, delegate, dataSource.descriptors.first())
bottomSheetFragment.delegate = delegate } else {
bottomSheetFragment.rowRepresentableEditDescriptors = rowRepresentableEditDescriptors delegate.fragmentManager?.let { fragmentManager ->
bottomSheetFragment.isClearable = isClearable ?: true val bottomSheetFragment = row.inputFragmentType.newInstance(row)
bottomSheetFragment.isDeletable = isDeletable ?: true bottomSheetFragment.show(fragmentManager, "bottomSheet")
bottomSheetFragment.valueHasPlaceholder = valueHasPlaceholder ?: true bottomSheetFragment.delegate = delegate
bottomSheetFragment.currentCurrency = currentCurrency bottomSheetFragment.rowEditableDescriptors = dataSource?.descriptors
return bottomSheetFragment 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") @SuppressLint("RestrictedApi")
override fun setupDialog(dialog: Dialog?, style: Int) { override fun setupDialog(dialog: Dialog, style: Int) {
super.setupDialog(dialog, style) 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 { bottomSheetToolbar.setOnMenuItemClickListener {
false false
} }
bottomSheetToolbar.menu.findItem(R.id.actionCheck).isVisible = row.bottomSheetType.validationRequired bottomSheetToolbar.menu.findItem(R.id.actionCheck).isVisible = row.inputFragmentType.validationRequired
bottomSheetToolbar.menu.findItem(R.id.actionClear).isVisible = row.bottomSheetType.clearRequired bottomSheetToolbar.menu.findItem(R.id.actionClear).isVisible = row.inputFragmentType.clearRequired
bottomSheetToolbar.menu.findItem(R.id.actionAdd).isVisible = row.bottomSheetType.addRequired bottomSheetToolbar.menu.findItem(R.id.actionAdd).isVisible = row.inputFragmentType.addRequired
// Menu // Menu
bottomSheetToolbar.menu.findItem(R.id.actionClear).setOnMenuItemClickListener { bottomSheetToolbar.menu.findItem(R.id.actionClear).setOnMenuItemClickListener {
@ -158,8 +164,8 @@ open class BottomSheetFragment(val row: RowRepresentable) : BottomSheetDialogFra
/** /**
* Return the data list * Return the data list
*/ */
fun getData(): ArrayList<RowRepresentableEditDescriptor>? { fun getData(): ArrayList<RowEditableDescriptor>? {
return this.rowRepresentableEditDescriptors return this.rowEditableDescriptors
} }
open fun getValue(): Any? { 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.os.Bundle
import android.view.LayoutInflater 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.LiveRowRepresentableDataSource
import net.pokeranalytics.android.ui.adapter.RowRepresentableAdapter import net.pokeranalytics.android.ui.adapter.RowRepresentableAdapter
import net.pokeranalytics.android.ui.adapter.RowRepresentableDelegate import net.pokeranalytics.android.ui.adapter.RowRepresentableDelegate
import net.pokeranalytics.android.ui.view.DataRowEditableDescriptor
import net.pokeranalytics.android.ui.view.RowRepresentable import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.RowViewType import net.pokeranalytics.android.ui.view.RowViewType
open class BottomSheetListFragment(row: RowRepresentable) : BottomSheetFragment(row), LiveRowRepresentableDataSource, RowRepresentableDelegate { open class InputListFragment(row: RowRepresentable) : InputFragment(row), LiveRowRepresentableDataSource, RowRepresentableDelegate {
lateinit var dataAdapter: RowRepresentableAdapter lateinit var dataAdapter: RowRepresentableAdapter
var realmData: RealmResults<RowRepresentable>? = null var realmData: RealmResults<RowRepresentable>? = null
@ -69,14 +70,14 @@ open class BottomSheetListFragment(row: RowRepresentable) : BottomSheetFragment(
* Init data * Init data
*/ */
open fun initData() { open fun initData() {
val bottomSheetData = getData()?:throw RowRepresentableEditDescriptorException("RowRepresentableEditDescriptor not found") val bottomSheetData = getData()?:throw RowRepresentableEditDescriptorException("RowEditableDescriptor not found")
if (bottomSheetData.size != 1) { if (bottomSheetData.size != 1) {
throw RowRepresentableEditDescriptorException("RowRepresentableEditDescriptor inconsistency") throw RowRepresentableEditDescriptorException("RowEditableDescriptor inconsistency")
} }
if (bottomSheetData.first().data == null) { val dataList = bottomSheetData[0]
throw RowRepresentableEditDescriptorException("RowRepresentableEditDescriptor inconsistency") if (dataList !is DataRowEditableDescriptor) { throw RowRepresentableEditDescriptorException("RowEditableDescriptor inconsistency") }
} if (dataList.data == null) { throw RowRepresentableEditDescriptorException("RowEditableDescriptor inconsistency") }
this.realmData = bottomSheetData.first().data as RealmResults<RowRepresentable> 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.os.Bundle
import android.view.LayoutInflater import android.view.LayoutInflater
@ -13,13 +13,14 @@ import net.pokeranalytics.android.exceptions.RowRepresentableEditDescriptorExcep
import net.pokeranalytics.android.model.Limit import net.pokeranalytics.android.model.Limit
import net.pokeranalytics.android.ui.adapter.RowRepresentableAdapter import net.pokeranalytics.android.ui.adapter.RowRepresentableAdapter
import net.pokeranalytics.android.ui.extensions.px import net.pokeranalytics.android.ui.extensions.px
import net.pokeranalytics.android.ui.view.DataRowEditableDescriptor
import net.pokeranalytics.android.ui.view.RowRepresentable import net.pokeranalytics.android.ui.view.RowRepresentable
/** /**
* Bottom Sheet List Game Fragment * Bottom Sheet List Game Fragment
* Display a list of game + chips to choose the game limit * 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 var limit: Int? = 0
private val values = ArrayList<Any?>() private val values = ArrayList<Any?>()
@ -49,15 +50,15 @@ class BottomSheetListGameFragment(row: RowRepresentable) : BottomSheetListFragme
* Init data * Init data
*/ */
override fun initData() { override fun initData() {
val bottomSheetData = getData()?:throw RowRepresentableEditDescriptorException("RowRepresentableEditDescriptor not found") val bottomSheetData = getData()?:throw RowRepresentableEditDescriptorException("RowEditableDescriptor not found")
if (bottomSheetData.size != 2) { if (bottomSheetData.size != 2) {
throw RowRepresentableEditDescriptorException("RowRepresentableEditDescriptor inconsistency") throw RowRepresentableEditDescriptorException("RowEditableDescriptor inconsistency")
}
if (bottomSheetData[1].data == null) {
throw RowRepresentableEditDescriptorException("RowRepresentableEditDescriptor 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.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.app.Activity
import android.content.Intent import android.content.Intent
@ -14,7 +14,7 @@ import net.pokeranalytics.android.ui.view.RowViewType
/** /**
* Manage multiple items selection in a bottom sheet list * 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() private val selectedRows: ArrayList<RowRepresentable> = ArrayList()
@ -54,9 +54,9 @@ open class BottomSheetMultiSelectionFragment(row: RowRepresentable) : BottomShee
override fun initData() { override fun initData() {
super.initData() super.initData()
val bottomSheetData = val bottomSheetData =
getData() ?: throw RowRepresentableEditDescriptorException("RowRepresentableEditDescriptor not found") getData() ?: throw RowRepresentableEditDescriptorException("RowEditableDescriptor not found")
if (bottomSheetData.size != 1) { if (bottomSheetData.size != 1) {
throw RowRepresentableEditDescriptorException("RowRepresentableEditDescriptor inconsistency") throw RowRepresentableEditDescriptorException("RowEditableDescriptor inconsistency")
} }
bottomSheetData.first().defaultValue?.let { bottomSheetData.first().defaultValue?.let {
(it as RealmList<*>).forEach { row -> (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.os.Bundle
import android.text.InputType import android.text.InputType
@ -14,7 +14,7 @@ import net.pokeranalytics.android.ui.view.RowRepresentable
import java.text.NumberFormat import java.text.NumberFormat
class BottomSheetNumericTextFragment(row: RowRepresentable) : BottomSheetFragment(row) { class InputNumericTextFragment(row: RowRepresentable) : InputFragment(row) {
private var value: Double? = null private var value: Double? = null
@ -43,9 +43,9 @@ class BottomSheetNumericTextFragment(row: RowRepresentable) : BottomSheetFragmen
* Init UI * Init UI
*/ */
private fun initUI() { private fun initUI() {
val data = getData()?:throw RowRepresentableEditDescriptorException("RowRepresentableEditDescriptor not found") val data = getData()?:throw RowRepresentableEditDescriptorException("RowEditableDescriptor not found")
if (data.size != 1) { 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) 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.os.Bundle
import android.view.LayoutInflater 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.RowRepresentableDelegate
import net.pokeranalytics.android.ui.adapter.StaticRowRepresentableDataSource import net.pokeranalytics.android.ui.adapter.StaticRowRepresentableDataSource
import net.pokeranalytics.android.ui.view.RowRepresentable 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 { RowRepresentableDelegate {
private var staticRows: List<RowRepresentable> = emptyList() private var staticRows: List<RowRepresentable> = emptyList()
@ -44,14 +45,14 @@ class BottomSheetStaticListFragment(row: RowRepresentable) : BottomSheetFragment
* Init data * Init data
*/ */
private fun initData() { private fun initData() {
val bottomSheetData = getData()?:throw RowRepresentableEditDescriptorException("RowRepresentableEditDescriptor not found") val bottomSheetData = getData()?:throw RowRepresentableEditDescriptorException("RowEditableDescriptor not found")
if (bottomSheetData.size != 1) { if (bottomSheetData.size != 1) {
throw RowRepresentableEditDescriptorException("RowRepresentableEditDescriptor inconsistency") throw RowRepresentableEditDescriptorException("RowEditableDescriptor inconsistency")
} }
if (bottomSheetData.first().staticData == null) { val dataList = bottomSheetData[0]
throw RowRepresentableEditDescriptorException("RowRepresentableEditDescriptor inconsistency") if (dataList !is StaticDataRowEditableDescriptor) { throw RowRepresentableEditDescriptorException("RowEditableDescriptor inconsistency") }
} if (dataList.staticData == null) { throw RowRepresentableEditDescriptorException("RowEditableDescriptor inconsistency") }
this.staticRows = bottomSheetData.first().staticData as List<RowRepresentable> 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.os.Bundle
import android.text.InputType import android.text.InputType
@ -16,7 +16,7 @@ import net.pokeranalytics.android.util.extensions.toCurrency
import java.text.NumberFormat import java.text.NumberFormat
class BottomSheetSumFragment(row: RowRepresentable) : BottomSheetFragment(row) { class InputSumFragment(row: RowRepresentable) : InputFragment(row) {
private var value = 0.0 private var value = 0.0
private var currentDefaultValue = 0.0 private var currentDefaultValue = 0.0
@ -50,9 +50,9 @@ class BottomSheetSumFragment(row: RowRepresentable) : BottomSheetFragment(row) {
* Init UI * Init UI
*/ */
private fun initUI() { private fun initUI() {
val data = getData()?:throw RowRepresentableEditDescriptorException("RowRepresentableEditDescriptor not found") val data = getData()?:throw RowRepresentableEditDescriptorException("RowEditableDescriptor not found")
if (data.size != 5) { if (data.size != 5) {
throw RowRepresentableEditDescriptorException("RowRepresentableEditDescriptor inconsistency") throw RowRepresentableEditDescriptorException("RowEditableDescriptor inconsistency")
} }
LayoutInflater.from(requireContext()).inflate(R.layout.bottom_sheet_sum, view?.bottomSheetContainer, true) 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.os.Bundle
import android.view.LayoutInflater 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.GridSpacingItemDecoration
import net.pokeranalytics.android.ui.view.RowRepresentable 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 lateinit var dataAdapter: RowRepresentableAdapter
private var defaultSize: Int? = null private var defaultSize: Int? = null
@ -39,9 +39,9 @@ class BottomSheetTableSizeGridFragment(row: RowRepresentable) : BottomSheetFragm
* Init data * Init data
*/ */
private fun initData() { private fun initData() {
val bottomSheetData = getData()?:throw RowRepresentableEditDescriptorException("RowRepresentableEditDescriptor not found") val bottomSheetData = getData()?:throw RowRepresentableEditDescriptorException("RowEditableDescriptor not found")
if (bottomSheetData.size != 1) { if (bottomSheetData.size != 1) {
throw RowRepresentableEditDescriptorException("RowRepresentableEditDescriptor inconsistency") throw RowRepresentableEditDescriptorException("RowEditableDescriptor inconsistency")
} }
defaultSize = bottomSheetData.first().defaultValue as Int? 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.adapter.StaticRowRepresentableDataSource
import net.pokeranalytics.android.ui.fragment.CurrenciesFragment import net.pokeranalytics.android.ui.fragment.CurrenciesFragment
import net.pokeranalytics.android.ui.view.RowRepresentable import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.RowRepresentableEditDescriptor
import net.pokeranalytics.android.ui.view.RowViewType import net.pokeranalytics.android.ui.view.RowViewType
import net.pokeranalytics.android.ui.view.rowrepresentable.BankrollRow import net.pokeranalytics.android.ui.view.rowrepresentable.BankrollRow
import net.pokeranalytics.android.ui.view.rowrepresentable.CustomizableRowRepresentable import net.pokeranalytics.android.ui.view.rowrepresentable.CustomizableRowRepresentable
import net.pokeranalytics.android.ui.view.rowrepresentable.SimpleRow
import net.pokeranalytics.android.util.NULL_TEXT import net.pokeranalytics.android.util.NULL_TEXT
import net.pokeranalytics.android.util.UserDefaults import net.pokeranalytics.android.util.UserDefaults
import net.pokeranalytics.android.util.extensions.toCurrency import net.pokeranalytics.android.util.extensions.toCurrency
@ -85,7 +83,7 @@ class BankrollDataFragment : EditableDataFragment(), StaticRowRepresentableDataS
override fun stringForRow(row: RowRepresentable): String { override fun stringForRow(row: RowRepresentable): String {
return when (row) { 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 -> { BankrollRow.CURRENCY -> {
bankroll.currency?.code?.let { code -> bankroll.currency?.code?.let { code ->
Currency.getInstance(code).currencyCode 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) { override fun onRowSelected(position: Int, row: RowRepresentable, fromAction: Boolean) {
when (row) { when (row) {
BankrollRow.CURRENCY -> CurrenciesActivity.newInstanceForResult(this@BankrollDataFragment, BankrollRow.CURRENCY -> CurrenciesActivity.newInstanceForResult(this@BankrollDataFragment,
@ -174,7 +158,7 @@ class BankrollDataFragment : EditableDataFragment(), StaticRowRepresentableDataS
private fun refreshRows() { private fun refreshRows() {
rows.clear() rows.clear()
rows.add(SimpleRow.NAME) rows.add(BankrollRow.NAME)
rows.add(BankrollRow.LIVE) rows.add(BankrollRow.LIVE)
rows.add(BankrollRow.INITIAL_VALUE) rows.add(BankrollRow.INITIAL_VALUE)
rows.add(CustomizableRowRepresentable(customViewType = RowViewType.HEADER_TITLE, resId = R.string.currency)) 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.ChipGroupExtension
import net.pokeranalytics.android.ui.extensions.px import net.pokeranalytics.android.ui.extensions.px
import net.pokeranalytics.android.ui.extensions.showAlertDialog 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.RowRepresentable
import net.pokeranalytics.android.ui.view.RowRepresentableEditDescriptor
import net.pokeranalytics.android.ui.view.rowrepresentable.CustomFieldRow import net.pokeranalytics.android.ui.view.rowrepresentable.CustomFieldRow
import net.pokeranalytics.android.ui.view.rowrepresentable.SimpleRow
import net.pokeranalytics.android.util.NULL_TEXT import net.pokeranalytics.android.util.NULL_TEXT
import java.util.* import java.util.*
@ -122,7 +119,7 @@ class CustomFieldDataFragment : EditableDataFragment(), StaticRowRepresentableDa
override fun stringForRow(row: RowRepresentable): String { override fun stringForRow(row: RowRepresentable): String {
return when (row) { 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) 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) { override fun onRowSelected(position: Int, row: RowRepresentable, fromAction: Boolean) {
when (row) { when (row) {
is CustomFieldEntry -> { is CustomFieldEntry -> row.startEditing(null, this)
val data = customField.editDescriptors(row)
BottomSheetFragment.create(fragmentManager, row, this, data, isClearable = false, isDeletable = true)
}
else -> super.onRowSelected(position, row, fromAction) else -> super.onRowSelected(position, row, fromAction)
} }
} }
@ -255,7 +241,6 @@ class CustomFieldDataFragment : EditableDataFragment(), StaticRowRepresentableDa
} }
} }
/** /**
* Update UI * Update UI
*/ */
@ -273,9 +258,7 @@ class CustomFieldDataFragment : EditableDataFragment(), StaticRowRepresentableDa
override fun onDataSaved() { override fun onDataSaved() {
super.onDataSaved() super.onDataSaved()
this.customField.cleanupEntries() 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.activity.EditableDataActivity
import net.pokeranalytics.android.ui.fragment.components.RealmFragment import net.pokeranalytics.android.ui.fragment.components.RealmFragment
open class DataManagerFragment : RealmFragment() { open class DataManagerFragment : RealmFragment() {
lateinit var item: Deletable lateinit var item: Deletable
@ -46,9 +47,9 @@ open class DataManagerFragment : RealmFragment() {
loadItem() loadItem()
} }
override fun onCreateOptionsMenu(menu: Menu?, inflater: MenuInflater?) { override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
menu?.clear() menu.clear()
inflater?.inflate(R.menu.toolbar_editable_data, menu) inflater.inflate(R.menu.toolbar_editable_data, menu)
this.editableMenu = menu this.editableMenu = menu
updateMenuUI() updateMenuUI()
super.onCreateOptionsMenu(menu, inflater) super.onCreateOptionsMenu(menu, inflater)
@ -62,8 +63,8 @@ open class DataManagerFragment : RealmFragment() {
editableMenu?.findItem(R.id.save)?.isVisible = this.saveButtonShouldAppear editableMenu?.findItem(R.id.save)?.isVisible = this.saveButtonShouldAppear
} }
override fun onOptionsItemSelected(item: MenuItem?): Boolean { override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item!!.itemId) { when (item.itemId) {
R.id.save -> saveData() R.id.save -> saveData()
R.id.delete -> deleteData() R.id.delete -> deleteData()
} }
@ -147,7 +148,7 @@ open class DataManagerFragment : RealmFragment() {
} }
} }
open fun willDeleteData() { } open fun willDeleteData() {}
/** /**
* Finish the activity with a result * 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.RowRepresentableAdapter
import net.pokeranalytics.android.ui.adapter.RowRepresentableDataSource import net.pokeranalytics.android.ui.adapter.RowRepresentableDataSource
import net.pokeranalytics.android.ui.adapter.RowRepresentableDelegate import net.pokeranalytics.android.ui.adapter.RowRepresentableDelegate
import net.pokeranalytics.android.ui.fragment.components.bottomsheet.BottomSheetFragment
import net.pokeranalytics.android.ui.view.RowRepresentable import net.pokeranalytics.android.ui.view.RowRepresentable
import java.io.File
open class EditableDataFragment : DataManagerFragment(), RowRepresentableDelegate { open class EditableDataFragment : DataManagerFragment(), RowRepresentableDelegate {
@ -62,7 +62,7 @@ open class EditableDataFragment : DataManagerFragment(), RowRepresentableDelegat
} }
override fun onRowSelected(position: Int, row: RowRepresentable, fromAction: Boolean) { 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) { 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.RowRepresentableDataSource
import net.pokeranalytics.android.ui.adapter.StaticRowRepresentableDataSource import net.pokeranalytics.android.ui.adapter.StaticRowRepresentableDataSource
import net.pokeranalytics.android.ui.view.RowRepresentable import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.RowRepresentableEditDescriptor
import net.pokeranalytics.android.ui.view.RowViewType import net.pokeranalytics.android.ui.view.RowViewType
import net.pokeranalytics.android.ui.view.rowrepresentable.CustomizableRowRepresentable import net.pokeranalytics.android.ui.view.rowrepresentable.CustomizableRowRepresentable
import net.pokeranalytics.android.ui.view.rowrepresentable.LocationRow import net.pokeranalytics.android.ui.view.rowrepresentable.LocationRow
import net.pokeranalytics.android.ui.view.rowrepresentable.SimpleRow
import net.pokeranalytics.android.util.NULL_TEXT import net.pokeranalytics.android.util.NULL_TEXT
/** /**
@ -47,7 +45,7 @@ class LocationDataFragment : EditableDataFragment(), StaticRowRepresentableDataS
} else if (locationActivated) { } 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 isLookingForPlaces = true
getSuggestionsPlaces() getSuggestionsPlaces()
@ -66,7 +64,7 @@ class LocationDataFragment : EditableDataFragment(), StaticRowRepresentableDataS
override fun stringForRow(row: RowRepresentable): String { override fun stringForRow(row: RowRepresentable): String {
return when (row) { 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) 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) { override fun onRowSelected(position: Int, row: RowRepresentable, fromAction: Boolean) {
// If we click on a location row, save the location (and finish activity) // If we click on a location row, save the location (and finish activity)
placesForRows[row]?.place?.let { place -> placesForRows[row]?.place?.let { place ->
@ -128,7 +119,7 @@ class LocationDataFragment : EditableDataFragment(), StaticRowRepresentableDataS
*/ */
private fun refreshRows() { private fun refreshRows() {
rows.clear() rows.clear()
rows.add(SimpleRow.NAME) rows.add(LocationRow.NAME)
rows.add(LocationRow.LOCATION_PERMISSION_SWITCH) rows.add(LocationRow.LOCATION_PERMISSION_SWITCH)
// Add info row to explain why we need the location permission // 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)) 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.delay
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import net.pokeranalytics.android.calculus.bankroll.BankrollReportManager 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.Transaction
import net.pokeranalytics.android.model.realm.TransactionType
import net.pokeranalytics.android.ui.adapter.RowRepresentableDataSource import net.pokeranalytics.android.ui.adapter.RowRepresentableDataSource
import net.pokeranalytics.android.ui.adapter.StaticRowRepresentableDataSource import net.pokeranalytics.android.ui.adapter.StaticRowRepresentableDataSource
import net.pokeranalytics.android.ui.helpers.DateTimePickerManager
import net.pokeranalytics.android.ui.view.RowRepresentable import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.RowRepresentableEditDescriptor
import net.pokeranalytics.android.ui.view.rowrepresentable.TransactionRow import net.pokeranalytics.android.ui.view.rowrepresentable.TransactionRow
import net.pokeranalytics.android.util.NULL_TEXT import net.pokeranalytics.android.util.NULL_TEXT
import net.pokeranalytics.android.util.extensions.round import net.pokeranalytics.android.util.extensions.round
import net.pokeranalytics.android.util.extensions.shortDate import net.pokeranalytics.android.util.extensions.shortDate
import net.pokeranalytics.android.util.extensions.sorted
import java.util.*
/** /**
* Custom EditableDataFragment to manage the Transaction data * 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) { override fun onRowValueChanged(value: Any?, row: RowRepresentable) {
super.onRowValueChanged(value, row) super.onRowValueChanged(value, row)
rowRepresentableAdapter.refreshRow(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.model.realm.TransactionType
import net.pokeranalytics.android.ui.adapter.RowRepresentableDataSource import net.pokeranalytics.android.ui.adapter.RowRepresentableDataSource
import net.pokeranalytics.android.ui.view.RowRepresentable import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.RowRepresentableEditDescriptor
import net.pokeranalytics.android.ui.view.rowrepresentable.SimpleRow import net.pokeranalytics.android.ui.view.rowrepresentable.SimpleRow
import net.pokeranalytics.android.ui.view.rowrepresentable.TransactionTypeRow 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 { override fun isEnabled(row: RowRepresentable): Boolean {
return when (row) { return when (row) {
TransactionTypeRow.TRANSACTION_ADDITIVE -> { TransactionTypeRow.TRANSACTION_ADDITIVE -> {

@ -8,9 +8,11 @@ import android.text.format.DateFormat
import android.widget.DatePicker import android.widget.DatePicker
import android.widget.TimePicker import android.widget.TimePicker
import android.widget.Toast import android.widget.Toast
import androidx.fragment.app.Fragment
import net.pokeranalytics.android.R import net.pokeranalytics.android.R
import net.pokeranalytics.android.ui.adapter.RowRepresentableDelegate import net.pokeranalytics.android.exceptions.PokerAnalyticsException
import net.pokeranalytics.android.ui.view.RowRepresentable import net.pokeranalytics.android.ui.adapter.RowEditableDelegate
import net.pokeranalytics.android.ui.view.*
import java.util.* import java.util.*
class DateTimePickerManager : DatePickerDialog.OnDateSetListener, class DateTimePickerManager : DatePickerDialog.OnDateSetListener,
@ -19,7 +21,7 @@ class DateTimePickerManager : DatePickerDialog.OnDateSetListener,
private var context: Context? = null private var context: Context? = null
private lateinit var row: RowRepresentable private lateinit var row: RowRepresentable
private lateinit var delegate: RowRepresentableDelegate private lateinit var delegate: RowEditableDelegate
private lateinit var calendar: Calendar private lateinit var calendar: Calendar
private var minimumDate: Date? = null private var minimumDate: Date? = null
private var onlyDate: Boolean = false private var onlyDate: Boolean = false
@ -27,39 +29,34 @@ class DateTimePickerManager : DatePickerDialog.OnDateSetListener,
private var isClearable: Boolean = true private var isClearable: Boolean = true
companion object { companion object {
fun create( fun buildAndShow(
context: Context, row: RowRepresentable,
row: RowRepresentable, delegate: RowEditableDelegate,
delegate: RowRepresentableDelegate, dataSource: RowEditableDescriptor
date: Date?, ) {
minimumDate: Date? = null,
onlyDate: Boolean? = false, if (delegate !is Fragment) throw PokerAnalyticsException.InputFragmentException
onlyTime: Boolean? = false, if (dataSource !is DateRowEditableDescriptor) throw PokerAnalyticsException.DateTimePickerException
isClearable: Boolean? = true val calendar = Calendar.getInstance()
): DateTimePickerManager { calendar.time = dataSource.date ?: Date()
val calendar = Calendar.getInstance() val dateTimePickerManager = DateTimePickerManager()
calendar.time = date ?: Date() dateTimePickerManager.context = delegate.context
dateTimePickerManager.row = row
val dateTimePickerManager = DateTimePickerManager() dateTimePickerManager.delegate = delegate
dateTimePickerManager.context = context dateTimePickerManager.calendar = calendar
dateTimePickerManager.row = row dateTimePickerManager.minimumDate = dataSource.minimumDate
dateTimePickerManager.delegate = delegate dateTimePickerManager.onlyDate = dataSource.onlyDate
dateTimePickerManager.calendar = calendar dateTimePickerManager.onlyTime = dataSource.onlyTime
dateTimePickerManager.minimumDate = minimumDate dateTimePickerManager.isClearable = row.valueCanBeClearedWhenEditing
dateTimePickerManager.onlyDate = onlyDate ?: false
dateTimePickerManager.onlyTime = onlyTime ?: false if (dateTimePickerManager.onlyTime) {
dateTimePickerManager.isClearable = isClearable ?: true dateTimePickerManager.showTimePicker()
} else {
if (dateTimePickerManager.onlyTime) { dateTimePickerManager.showDatePicker()
dateTimePickerManager.showTimePicker() }
} else { }
dateTimePickerManager.showDatePicker() }
}
return dateTimePickerManager
}
}
override fun onDateSet(view: DatePicker?, year: Int, month: Int, dayOfMonth: Int) { override fun onDateSet(view: DatePicker?, year: Int, month: Int, dayOfMonth: Int) {
calendar.set(Calendar.YEAR, year) 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 package net.pokeranalytics.android.ui.view
import android.content.Context import android.content.Context
import androidx.fragment.app.Fragment
import net.pokeranalytics.android.model.LiveData 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 import net.pokeranalytics.android.util.NULL_TEXT
/** /**
* An interface extending Displayable to add a way to represent an object as a String * 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 { fun getDisplayName(context: Context): String {
return NULL_TEXT return NULL_TEXT
} }
} }
interface EditDataSource { interface RowEditable {
fun editingDescriptors(map: Map<String, Any?>): ArrayList<RowRepresentableEditDescriptor>? { fun startEditing(dataSource:Any?, parent:Fragment?) {}
return null
}
}
interface DefaultEditDataSource : EditDataSource, Localizable { val valueCanBeClearedWhenEditing: Boolean
override fun editingDescriptors(map: Map<String, Any?>): ArrayList<RowRepresentableEditDescriptor>? { get() { return true }
val defaultValue: String? by map
return arrayListOf(RowRepresentableEditDescriptor(defaultValue, this.resId))
}
} }
/** /**
@ -62,9 +57,9 @@ interface Displayable : Localizable {
return null return null
} }
val bottomSheetType: BottomSheetType val inputFragmentType: InputFragmentType
get() { get() {
return BottomSheetType.NONE return InputFragmentType.NONE
} }
val selectedChoice: Int 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.TableSize
import net.pokeranalytics.android.model.extensions.getFormattedGameType import net.pokeranalytics.android.model.extensions.getFormattedGameType
import net.pokeranalytics.android.model.realm.CustomField 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.Session
import net.pokeranalytics.android.model.realm.Transaction import net.pokeranalytics.android.model.realm.Transaction
import net.pokeranalytics.android.ui.adapter.RowRepresentableAdapter import net.pokeranalytics.android.ui.adapter.RowRepresentableAdapter
@ -59,6 +60,7 @@ enum class RowViewType(private var layoutRes: Int) {
HEADER_TITLE_VALUE(R.layout.row_header_title_value), HEADER_TITLE_VALUE(R.layout.row_header_title_value),
HEADER_TITLE_AMOUNT(R.layout.row_header_title_amount), HEADER_TITLE_AMOUNT(R.layout.row_header_title_amount),
HEADER_TITLE_AMOUNT_BIG(R.layout.row_header_title_amount_big), HEADER_TITLE_AMOUNT_BIG(R.layout.row_header_title_amount_big),
HEADER_SUBTITLE(R.layout.row_header_subtitle),
LOCATION_TITLE(R.layout.row_title), LOCATION_TITLE(R.layout.row_title),
INFO(R.layout.row_info), 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(R.layout.row_title_value),
TITLE_VALUE_ARROW(R.layout.row_title_value_arrow), TITLE_VALUE_ARROW(R.layout.row_title_value_arrow),
TITLE_VALUE_ACTION(R.layout.row_title_value_action), TITLE_VALUE_ACTION(R.layout.row_title_value_action),
TITLE_SUBTITLE(R.layout.row_title_subtitle),
TITLE_SWITCH(R.layout.row_title_switch), TITLE_SWITCH(R.layout.row_title_switch),
TITLE_GRID(R.layout.row_bottom_sheet_grid_title), TITLE_GRID(R.layout.row_bottom_sheet_grid_title),
CONTENT(R.layout.row_content),
DATA(R.layout.row_title), DATA(R.layout.row_title),
BOTTOM_SHEET_DATA(R.layout.row_bottom_sheet_title), BOTTOM_SHEET_DATA(R.layout.row_bottom_sheet_title),
TITLE_CHECK(R.layout.row_title_check), TITLE_CHECK(R.layout.row_title_check),
@ -80,6 +84,8 @@ enum class RowViewType(private var layoutRes: Int) {
// Custom row // Custom row
ROW_SESSION(R.layout.row_feed_session), ROW_SESSION(R.layout.row_feed_session),
ROW_TRANSACTION(R.layout.row_transaction), 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_TOP_10(R.layout.row_top_10),
ROW_BUTTON(R.layout.row_button), ROW_BUTTON(R.layout.row_button),
ROW_FOLLOW_US(R.layout.row_follow_us), ROW_FOLLOW_US(R.layout.row_follow_us),
@ -102,10 +108,10 @@ enum class RowViewType(private var layoutRes: Int) {
return when (this) { return when (this) {
// Row View Holder // Row View Holder
HEADER_TITLE, HEADER_TITLE_VALUE, HEADER_TITLE_AMOUNT, HEADER_TITLE_AMOUNT_BIG, LOCATION_TITLE, 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_GRID, INFO, TITLE, TITLE_ARROW, TITLE_ICON_ARROW, TITLE_VALUE, TITLE_VALUE_ARROW, TITLE_VALUE_ACTION, TITLE_SUBTITLE,
TITLE_SWITCH, TITLE_CHECK, TITLE_VALUE_CHECK, TITLE_GRID, TITLE_SWITCH, TITLE_CHECK, TITLE_VALUE_CHECK,
DATA, BOTTOM_SHEET_DATA, LOADER -> RowViewHolder(layout) CONTENT, DATA, BOTTOM_SHEET_DATA, LOADER -> RowViewHolder(layout)
// Row Session // Row Session
ROW_SESSION -> RowSessionViewHolder(layout) ROW_SESSION -> RowSessionViewHolder(layout)
@ -116,6 +122,10 @@ enum class RowViewType(private var layoutRes: Int) {
// Row Transaction // Row Transaction
ROW_TOP_10 -> RowTop10ViewHolder(layout) ROW_TOP_10 -> RowTop10ViewHolder(layout)
ROW_PLAYER -> RowPlayerViewHolder(layout)
ROW_PLAYER_IMAGE -> RowPlayerImageViewHolder(layout)
// Row Button // Row Button
ROW_BUTTON -> RowButtonViewHolder(layout) ROW_BUTTON -> RowButtonViewHolder(layout)
@ -468,7 +478,7 @@ enum class RowViewType(private var layoutRes: Int) {
val listener = View.OnClickListener { val listener = View.OnClickListener {
adapter.delegate?.onRowSelected(position, row) 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) { if (row is CustomFieldRow) {
itemView.findViewById<ChipGroup>(R.id.chipGroup)?.let { chipGroup -> itemView.findViewById<ChipGroup?>(R.id.chipGroup)?.let { chipGroup ->
chipGroup.removeAllViews() chipGroup.removeAllViews()
chipGroup.setOnCheckedChangeListener(null) chipGroup.setOnCheckedChangeListener(null)
@ -526,9 +536,9 @@ enum class RowViewType(private var layoutRes: Int) {
*/ */
inner class RowButtonViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView), BindableHolder { inner class RowButtonViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView), BindableHolder {
override fun bind(position: Int, row: RowRepresentable, adapter: RowRepresentableAdapter) { 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)?.text = row.localizedTitle(itemView.context)
itemView.findViewById<AppCompatTextView>(R.id.title).isVisible = !adapter.dataSource.boolForRow(row) itemView.findViewById<AppCompatTextView?>(R.id.title)?.isVisible = !adapter.dataSource.boolForRow(row)
itemView.findViewById<ContentLoadingProgressBar>(R.id.progressBar).isVisible = adapter.dataSource.boolForRow(row) itemView.findViewById<ContentLoadingProgressBar?>(R.id.progressBar)?.isVisible = adapter.dataSource.boolForRow(row)
val listener = View.OnClickListener { val listener = View.OnClickListener {
adapter.delegate?.onRowSelected(position, row) 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 * Display a separator
*/ */

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

@ -1,19 +1,25 @@
package net.pokeranalytics.android.ui.view.rowrepresentable package net.pokeranalytics.android.ui.view.rowrepresentable
import androidx.fragment.app.Fragment
import net.pokeranalytics.android.R import net.pokeranalytics.android.R
import net.pokeranalytics.android.exceptions.PokerAnalyticsException
import net.pokeranalytics.android.model.realm.CustomField import net.pokeranalytics.android.model.realm.CustomField
import net.pokeranalytics.android.ui.fragment.components.bottomsheet.BottomSheetType import net.pokeranalytics.android.ui.adapter.RowRepresentableDelegate
import net.pokeranalytics.android.ui.view.DefaultEditDataSource 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.RowRepresentable
import net.pokeranalytics.android.ui.view.RowViewType import net.pokeranalytics.android.ui.view.RowViewType
enum class CustomFieldRow : RowRepresentable, DefaultEditDataSource { enum class CustomFieldRow : RowRepresentable {
NAME,
TYPE, TYPE,
COPY_ON_DUPLICATE; COPY_ON_DUPLICATE;
override val resId: Int? override val resId: Int?
get() { get() {
return when (this) { return when (this) {
NAME -> R.string.name
COPY_ON_DUPLICATE -> R.string.copy_on_duplicate COPY_ON_DUPLICATE -> R.string.copy_on_duplicate
else -> null else -> null
} }
@ -22,16 +28,18 @@ enum class CustomFieldRow : RowRepresentable, DefaultEditDataSource {
override val viewType: Int override val viewType: Int
get() { get() {
return when (this) { return when (this) {
NAME -> RowViewType.TITLE_VALUE.ordinal
TYPE -> RowViewType.LIST.ordinal TYPE -> RowViewType.LIST.ordinal
COPY_ON_DUPLICATE -> RowViewType.TITLE_SWITCH.ordinal COPY_ON_DUPLICATE -> RowViewType.TITLE_SWITCH.ordinal
} }
} }
override val bottomSheetType: BottomSheetType override val inputFragmentType: InputFragmentType
get() { get() {
return when (this) { return when (this) {
TYPE -> BottomSheetType.NONE NAME -> InputFragmentType.EDIT_TEXT
COPY_ON_DUPLICATE -> BottomSheetType.NONE TYPE -> InputFragmentType.NONE
COPY_ON_DUPLICATE -> InputFragmentType.NONE
} }
} }
@ -55,4 +63,17 @@ enum class CustomFieldRow : RowRepresentable, DefaultEditDataSource {
} }
return list 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 package net.pokeranalytics.android.ui.view.rowrepresentable
import android.text.InputType import android.text.InputType
import androidx.fragment.app.Fragment
import net.pokeranalytics.android.R import net.pokeranalytics.android.R
import net.pokeranalytics.android.model.filter.QueryCondition 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.RowRepresentable
import net.pokeranalytics.android.ui.view.RowRepresentableEditDescriptor import net.pokeranalytics.android.ui.view.RowEditableDataSource
import net.pokeranalytics.android.ui.view.RowViewType
import java.util.*
interface FilterElementRow : RowRepresentable { 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 -> { is QueryCondition.Duration -> {
val hours: String? by map var hours: String? = null
val minutes: String? by map var minutes: String? = null
arrayListOf( this.minutes?.let {
RowRepresentableEditDescriptor(hours, R.string.hour, inputType = InputType.TYPE_CLASS_NUMBER), hours = if (it / 60 > 0) (it / 60).toString() else null
RowRepresentableEditDescriptor(minutes, R.string.minute, inputType = InputType.TYPE_CLASS_NUMBER) 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<*> -> { 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) { val hint = when (this.operator) {
QueryCondition.Operator.MORE, QueryCondition.Operator.LESS -> { QueryCondition.Operator.MORE, QueryCondition.Operator.LESS -> {
when (this) { when (this) {
@ -32,13 +42,11 @@ interface FilterElementRow : RowRepresentable {
} }
else -> this.resId else -> this.resId
} }
data.append(valueAsString, hint, inputType = InputType.TYPE_CLASS_NUMBER)
arrayListOf(
RowRepresentableEditDescriptor(valueAsString, hint, inputType = InputType.TYPE_CLASS_NUMBER)
)
} }
else -> super.editingDescriptors(map)
} }
InputFragment.buildAndShow(this, parent, data)
} }
var filterSectionRow: FilterSectionRow var filterSectionRow: FilterSectionRow

@ -1,17 +1,23 @@
package net.pokeranalytics.android.ui.view.rowrepresentable package net.pokeranalytics.android.ui.view.rowrepresentable
import androidx.fragment.app.Fragment
import net.pokeranalytics.android.R import net.pokeranalytics.android.R
import net.pokeranalytics.android.ui.fragment.components.bottomsheet.BottomSheetType import net.pokeranalytics.android.model.realm.Game
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.RowRepresentable
import net.pokeranalytics.android.ui.view.RowViewType import net.pokeranalytics.android.ui.view.RowViewType
enum class GameRow : RowRepresentable, DefaultEditDataSource { enum class GameRow : RowRepresentable {
NAME,
SHORT_NAME; SHORT_NAME;
override val resId: Int? override val resId: Int?
get() { get() {
return when (this) { return when (this) {
NAME -> R.string.name
SHORT_NAME -> R.string.short_name SHORT_NAME -> R.string.short_name
} }
} }
@ -19,15 +25,30 @@ enum class GameRow : RowRepresentable, DefaultEditDataSource {
override val viewType: Int override val viewType: Int
get() { get() {
return when (this) { return when (this) {
NAME -> RowViewType.TITLE_VALUE.ordinal
SHORT_NAME -> RowViewType.TITLE_VALUE.ordinal SHORT_NAME -> RowViewType.TITLE_VALUE.ordinal
} }
} }
override val bottomSheetType: BottomSheetType override val inputFragmentType: InputFragmentType
get() { get() {
return when (this) { 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 package net.pokeranalytics.android.ui.view.rowrepresentable
import androidx.fragment.app.Fragment
import net.pokeranalytics.android.R import net.pokeranalytics.android.R
import net.pokeranalytics.android.ui.fragment.components.bottomsheet.BottomSheetType import net.pokeranalytics.android.exceptions.PokerAnalyticsException
import net.pokeranalytics.android.ui.view.DefaultEditDataSource 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.RowRepresentable
import net.pokeranalytics.android.ui.view.RowEditableDataSource
import net.pokeranalytics.android.ui.view.RowViewType import net.pokeranalytics.android.ui.view.RowViewType
enum class LocationRow : RowRepresentable, DefaultEditDataSource { enum class LocationRow : RowRepresentable {
NAME,
LOCATION_PERMISSION_SWITCH, LOCATION_PERMISSION_SWITCH,
LOCATION_LOADER; LOCATION_LOADER;
override val resId: Int? override val resId: Int?
get() { get() {
return when (this) { return when (this) {
NAME -> R.string.name
LOCATION_PERMISSION_SWITCH -> R.string.geo_locate LOCATION_PERMISSION_SWITCH -> R.string.geo_locate
LOCATION_LOADER -> null LOCATION_LOADER -> null
} }
@ -22,17 +29,32 @@ enum class LocationRow : RowRepresentable, DefaultEditDataSource {
override val viewType: Int override val viewType: Int
get() { get() {
return when (this) { return when (this) {
NAME -> RowViewType.TITLE_VALUE.ordinal
LOCATION_PERMISSION_SWITCH -> RowViewType.TITLE_SWITCH.ordinal LOCATION_PERMISSION_SWITCH -> RowViewType.TITLE_SWITCH.ordinal
LOCATION_LOADER -> RowViewType.LOADER.ordinal LOCATION_LOADER -> RowViewType.LOADER.ordinal
} }
} }
override val bottomSheetType: BottomSheetType override val inputFragmentType: InputFragmentType
get() { get() {
return when (this) { return when (this) {
LOCATION_PERMISSION_SWITCH -> BottomSheetType.NONE NAME -> InputFragmentType.EDIT_TEXT
LOCATION_LOADER -> BottomSheetType.NONE 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 package net.pokeranalytics.android.ui.view.rowrepresentable
import android.text.InputType 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.R
import net.pokeranalytics.android.model.TournamentType import net.pokeranalytics.android.model.TournamentType
import net.pokeranalytics.android.model.extensions.SessionState import net.pokeranalytics.android.model.extensions.SessionState
import net.pokeranalytics.android.model.extensions.getState import net.pokeranalytics.android.model.extensions.getState
import net.pokeranalytics.android.model.realm.Session import net.pokeranalytics.android.model.realm.*
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.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.ui.view.RowViewType
import net.pokeranalytics.android.util.extensions.round import net.pokeranalytics.android.util.extensions.round
import net.pokeranalytics.android.util.extensions.sorted
import java.util.*
enum class SessionRow : RowRepresentable { enum class SessionRow : RowRepresentable {
PRIZE, PRIZE,
CASHED_OUT, CASHED_OUT,
NET_RESULT, NET_RESULT,
INITIAL_BUY_IN, INITIAL_BUY_IN,
BUY_IN, BUY_IN,
POSITION, POSITION,
PLAYERS, PLAYERS,
TIPS, TIPS,
GAME, GAME,
BLINDS, BLINDS,
LOCATION, LOCATION,
BANKROLL, BANKROLL,
TABLE_SIZE, TABLE_SIZE,
TOURNAMENT_TYPE, TOURNAMENT_TYPE,
TOURNAMENT_NAME, TOURNAMENT_NAME,
TOURNAMENT_FEATURE, TOURNAMENT_FEATURE,
START_DATE, START_DATE,
END_DATE, END_DATE,
BREAK_TIME, BREAK_TIME,
COMMENT; COMMENT;
companion object { companion object {
/** /**
* Return the rows to display for the current session state * Return the rows to display for the current session state
*/ */
fun getRows(session: Session): List<RowRepresentable> { fun getRows(session: Session): List<RowRepresentable> {
when (session.type) { when (session.type) {
Session.Type.TOURNAMENT.ordinal -> { Session.Type.TOURNAMENT.ordinal -> {
return when (session.getState()) { return when (session.getState()) {
SessionState.PENDING, SessionState.PLANNED -> { SessionState.PENDING, SessionState.PLANNED -> {
arrayListOf( arrayListOf(
GAME, GAME,
INITIAL_BUY_IN, INITIAL_BUY_IN,
LOCATION, LOCATION,
BANKROLL, BANKROLL,
TABLE_SIZE, TABLE_SIZE,
TOURNAMENT_TYPE, TOURNAMENT_TYPE,
TOURNAMENT_NAME, TOURNAMENT_NAME,
TOURNAMENT_FEATURE, TOURNAMENT_FEATURE,
START_DATE, START_DATE,
END_DATE END_DATE
) )
} }
SessionState.STARTED, SessionState.PAUSED, SessionState.FINISHED -> { SessionState.STARTED, SessionState.PAUSED, SessionState.FINISHED -> {
arrayListOf( arrayListOf(
PRIZE, PRIZE,
BUY_IN, BUY_IN,
POSITION, POSITION,
PLAYERS, PLAYERS,
TIPS, TIPS,
COMMENT, COMMENT,
SeparatorRow(), SeparatorRow(),
GAME, GAME,
INITIAL_BUY_IN, INITIAL_BUY_IN,
LOCATION, LOCATION,
BANKROLL, BANKROLL,
TABLE_SIZE, TABLE_SIZE,
TOURNAMENT_TYPE, TOURNAMENT_TYPE,
TOURNAMENT_NAME, TOURNAMENT_NAME,
TOURNAMENT_FEATURE, TOURNAMENT_FEATURE,
SeparatorRow(), SeparatorRow(),
START_DATE, START_DATE,
END_DATE, END_DATE,
BREAK_TIME BREAK_TIME
) )
} }
} }
} }
Session.Type.CASH_GAME.ordinal -> { Session.Type.CASH_GAME.ordinal -> {
when (session.getState()) { when (session.getState()) {
SessionState.PENDING, SessionState.PLANNED -> { SessionState.PENDING, SessionState.PLANNED -> {
return arrayListOf(GAME, BLINDS, LOCATION, BANKROLL, TABLE_SIZE, START_DATE, END_DATE) return arrayListOf(GAME, BLINDS, LOCATION, BANKROLL, TABLE_SIZE, START_DATE, END_DATE)
} }
SessionState.STARTED, SessionState.PAUSED, SessionState.FINISHED -> { SessionState.STARTED, SessionState.PAUSED, SessionState.FINISHED -> {
val fields = mutableListOf<RowRepresentable>() val fields = mutableListOf<RowRepresentable>()
when { when {
session.hasBuyin -> fields.addAll(listOf(CASHED_OUT, BUY_IN, TIPS)) session.hasBuyin -> fields.addAll(listOf(CASHED_OUT, BUY_IN, TIPS))
session.hasNetResult -> fields.add(NET_RESULT) session.hasNetResult -> fields.add(NET_RESULT)
session.isLive -> fields.addAll(listOf(CASHED_OUT, BUY_IN, TIPS)) session.isLive -> fields.addAll(listOf(CASHED_OUT, BUY_IN, TIPS))
else -> fields.add(NET_RESULT) else -> fields.add(NET_RESULT)
} }
fields.add(COMMENT) fields.add(COMMENT)
fields.add(SeparatorRow()) fields.add(SeparatorRow())
fields.addAll(listOf( fields.addAll(
GAME, listOf(
BLINDS, GAME,
LOCATION, BLINDS,
BANKROLL, LOCATION,
TABLE_SIZE, BANKROLL,
START_DATE, TABLE_SIZE,
END_DATE, START_DATE,
BREAK_TIME END_DATE,
BREAK_TIME
) )
) )
return fields return fields
} }
} }
} }
} }
return arrayListOf() return arrayListOf()
} }
} }
override val resId: Int? override val resId: Int?
get() { get() {
return when (this) { return when (this) {
NET_RESULT -> R.string.net_result NET_RESULT -> R.string.net_result
PRIZE -> R.string.prize PRIZE -> R.string.prize
POSITION -> R.string.position POSITION -> R.string.position
PLAYERS -> R.string.players PLAYERS -> R.string.players
CASHED_OUT -> R.string.cashed_out CASHED_OUT -> R.string.cashed_out
INITIAL_BUY_IN -> R.string.initial_stack INITIAL_BUY_IN -> R.string.initial_stack
BUY_IN -> R.string.buyin BUY_IN -> R.string.buyin
TIPS -> R.string.tips TIPS -> R.string.tips
GAME -> R.string.game GAME -> R.string.game
BLINDS -> R.string.blinds BLINDS -> R.string.blinds
LOCATION -> R.string.location LOCATION -> R.string.location
BANKROLL -> R.string.bankroll BANKROLL -> R.string.bankroll
TABLE_SIZE -> R.string.table_size TABLE_SIZE -> R.string.table_size
TOURNAMENT_TYPE -> R.string.tournament_type TOURNAMENT_TYPE -> R.string.tournament_type
TOURNAMENT_NAME -> R.string.tournament_name TOURNAMENT_NAME -> R.string.tournament_name
TOURNAMENT_FEATURE -> R.string.tournament_feature TOURNAMENT_FEATURE -> R.string.tournament_feature
START_DATE -> R.string.start_date START_DATE -> R.string.start_date
END_DATE -> R.string.end_date END_DATE -> R.string.end_date
BREAK_TIME -> R.string.break_time BREAK_TIME -> R.string.break_time
COMMENT -> R.string.comment COMMENT -> R.string.comment
} }
} }
override val viewType: Int override val viewType: Int
get() { get() {
return when (this) { return when (this) {
NET_RESULT, PRIZE, POSITION, PLAYERS, CASHED_OUT, INITIAL_BUY_IN, BUY_IN, TIPS, NET_RESULT, PRIZE, POSITION, PLAYERS, CASHED_OUT, INITIAL_BUY_IN, BUY_IN, TIPS,
GAME, BLINDS, LOCATION, BANKROLL, TABLE_SIZE, COMMENT, GAME, BLINDS, LOCATION, BANKROLL, TABLE_SIZE, COMMENT,
TOURNAMENT_TYPE, TOURNAMENT_NAME, TOURNAMENT_FEATURE, START_DATE, END_DATE, BREAK_TIME -> RowViewType.TITLE_VALUE.ordinal TOURNAMENT_TYPE, TOURNAMENT_NAME, TOURNAMENT_FEATURE, START_DATE, END_DATE, BREAK_TIME -> RowViewType.TITLE_VALUE.ordinal
} }
} }
override val bottomSheetType: BottomSheetType override val inputFragmentType: InputFragmentType
get() { get() {
return when (this) { return when (this) {
NET_RESULT, CASHED_OUT, INITIAL_BUY_IN, BREAK_TIME, POSITION, PLAYERS, PRIZE -> BottomSheetType.NUMERIC_TEXT NET_RESULT, CASHED_OUT, INITIAL_BUY_IN, BREAK_TIME, POSITION, PLAYERS, PRIZE -> InputFragmentType.NUMERIC_TEXT
BUY_IN, TIPS -> BottomSheetType.SUM BUY_IN, TIPS -> InputFragmentType.SUM
BLINDS -> BottomSheetType.DOUBLE_EDIT_TEXT BLINDS -> InputFragmentType.DOUBLE_EDIT_TEXT
GAME -> BottomSheetType.LIST_GAME GAME -> InputFragmentType.LIST_GAME
TOURNAMENT_TYPE -> BottomSheetType.LIST_STATIC TOURNAMENT_TYPE -> InputFragmentType.LIST_STATIC
LOCATION, BANKROLL, TOURNAMENT_NAME -> BottomSheetType.LIST LOCATION, BANKROLL, TOURNAMENT_NAME -> InputFragmentType.LIST
TOURNAMENT_FEATURE -> BottomSheetType.MULTI_SELECTION TOURNAMENT_FEATURE -> InputFragmentType.MULTI_SELECTION
TABLE_SIZE -> BottomSheetType.GRID TABLE_SIZE -> InputFragmentType.GRID
COMMENT -> BottomSheetType.EDIT_TEXT_MULTI_LINES COMMENT -> InputFragmentType.EDIT_TEXT_MULTI_LINES
else -> BottomSheetType.NONE else -> InputFragmentType.NONE
} }
} }
override fun editingDescriptors(map: Map<String, Any?>): ArrayList<RowRepresentableEditDescriptor>? { override fun startEditing(dataSource: Any?, parent: Fragment?) {
return when (this) { if (dataSource == null) return
BLINDS -> { if (dataSource !is Session) return
val sb: String? by map if (parent == null) return
val bb: String? by map if (parent !is RowRepresentableDelegate) return
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))
}
data.add(RowRepresentableEditDescriptor(ratedBuyin)) val session: Session = dataSource
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
// Disable the buttons with value = 0, add current value & set the 2 edit texts val data = RowEditableDataSource(session.currency)
arrayListOf( when (this) {
RowRepresentableEditDescriptor(sb ?: 0.0), START_DATE -> {
RowRepresentableEditDescriptor(bb ?: 0.0), data.appendDateDescriptor(session.startDate)
RowRepresentableEditDescriptor(tips ?: 0.0), }
RowRepresentableEditDescriptor("", inputType = InputType.TYPE_CLASS_NUMBER), END_DATE -> {
RowRepresentableEditDescriptor("", inputType = InputType.TYPE_CLASS_NUMBER) if (session.startDate == null) {
) Toast.makeText(parent.context, R.string.session_missing_start_date, Toast.LENGTH_SHORT).show()
} return
TOURNAMENT_TYPE -> { } else {
val defaultValue: Any? by map data.appendDateDescriptor(session.endDate ?: session.startDate ?: Date(), session.startDate)
arrayListOf( }
RowRepresentableEditDescriptor(defaultValue, staticData = TournamentType.values().map { }
it
})
)
}
else -> null
}
}
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 // More
BANKROLL_REPORT, BANKROLL_REPORT,
TOP_10, TOP_10,
PLAYERS,
// About // About
SUBSCRIPTION, SUBSCRIPTION,
@ -50,7 +51,7 @@ enum class SettingRow : RowRepresentable {
val rows = ArrayList<RowRepresentable>() val rows = ArrayList<RowRepresentable>()
rows.add(CustomizableRowRepresentable(customViewType = RowViewType.HEADER_TITLE, resId = R.string.reports)) 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.add(CustomizableRowRepresentable(customViewType = RowViewType.HEADER_TITLE, resId = R.string.information))
// rows.addAll(arrayListOf(VERSION, RATE_APP, CONTACT_US, BUG_REPORT)) // rows.addAll(arrayListOf(VERSION, RATE_APP, CONTACT_US, BUG_REPORT))
@ -86,6 +87,7 @@ enum class SettingRow : RowRepresentable {
return when (this) { return when (this) {
BANKROLL_REPORT -> R.string.bankroll BANKROLL_REPORT -> R.string.bankroll
TOP_10 -> R.string.top_10 TOP_10 -> R.string.top_10
PLAYERS -> R.string.players
SUBSCRIPTION -> R.string.subscription SUBSCRIPTION -> R.string.subscription
VERSION -> R.string.version VERSION -> R.string.version
RATE_APP -> R.string.releasenote_rating RATE_APP -> R.string.releasenote_rating
@ -106,7 +108,7 @@ enum class SettingRow : RowRepresentable {
override val viewType: Int override val viewType: Int
get() { get() {
return when (this) { 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 VERSION, SUBSCRIPTION -> RowViewType.TITLE_VALUE.ordinal
LANGUAGE, CURRENCY -> RowViewType.TITLE_VALUE_ARROW.ordinal LANGUAGE, CURRENCY -> RowViewType.TITLE_VALUE_ARROW.ordinal
FOLLOW_US -> RowViewType.ROW_FOLLOW_US.ordinal FOLLOW_US -> RowViewType.ROW_FOLLOW_US.ordinal
@ -119,6 +121,7 @@ enum class SettingRow : RowRepresentable {
return when(this) { return when(this) {
BANKROLL_REPORT -> R.drawable.ic_outline_lock BANKROLL_REPORT -> R.drawable.ic_outline_lock
TOP_10 -> R.drawable.ic_outline_star TOP_10 -> R.drawable.ic_outline_star
PLAYERS -> R.drawable.ic_outline_people
else -> null else -> null
} }
} }

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

@ -1,17 +1,24 @@
package net.pokeranalytics.android.ui.view.rowrepresentable package net.pokeranalytics.android.ui.view.rowrepresentable
import androidx.fragment.app.Fragment
import net.pokeranalytics.android.R import net.pokeranalytics.android.R
import net.pokeranalytics.android.ui.fragment.components.bottomsheet.BottomSheetType import net.pokeranalytics.android.exceptions.PokerAnalyticsException
import net.pokeranalytics.android.ui.view.DefaultEditDataSource 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.RowRepresentable
import net.pokeranalytics.android.ui.view.RowEditableDataSource
import net.pokeranalytics.android.ui.view.RowViewType import net.pokeranalytics.android.ui.view.RowViewType
enum class TransactionTypeRow : RowRepresentable, DefaultEditDataSource { enum class TransactionTypeRow : RowRepresentable {
NAME,
TRANSACTION_ADDITIVE; TRANSACTION_ADDITIVE;
override val resId: Int? override val resId: Int?
get() { get() {
return when (this) { return when (this) {
NAME -> R.string.name
TRANSACTION_ADDITIVE -> R.string.additive TRANSACTION_ADDITIVE -> R.string.additive
} }
} }
@ -19,17 +26,32 @@ enum class TransactionTypeRow : RowRepresentable, DefaultEditDataSource {
override val viewType: Int override val viewType: Int
get() { get() {
return when (this) { return when (this) {
NAME -> RowViewType.TITLE_VALUE.ordinal
TRANSACTION_ADDITIVE -> RowViewType.TITLE_SWITCH.ordinal TRANSACTION_ADDITIVE -> RowViewType.TITLE_SWITCH.ordinal
} }
} }
override val bottomSheetType: BottomSheetType override val inputFragmentType: InputFragmentType
get() { get() {
return when (this) { 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.Realm
import io.realm.kotlin.where import io.realm.kotlin.where
import net.pokeranalytics.android.model.Limit import net.pokeranalytics.android.model.Limit
import net.pokeranalytics.android.model.realm.Bankroll import net.pokeranalytics.android.model.realm.*
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.util.extensions.getOrCreate import net.pokeranalytics.android.util.extensions.getOrCreate
import timber.log.Timber import timber.log.Timber
import java.util.* import java.util.*
@ -33,8 +30,9 @@ class FakeDataManager {
val games = realm.where<Game>().findAll() val games = realm.where<Game>().findAll()
val bankroll = realm.where<Bankroll>().findAll().firstOrNull() val bankroll = realm.where<Bankroll>().findAll().firstOrNull()
val locations = realm.where<Location>().findAll() val locations = realm.where<Location>().findAll()
val players = realm.where<Player>().findAll()
if (locations.size == 0) { if (locations.isEmpty()) {
realm.executeTransaction { realm.executeTransaction {
listOf("Bellagio", "Aria", "Borgata").map { listOf("Bellagio", "Aria", "Borgata").map {
realm.getOrCreate<Location>(it) 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 // Test endedSessions
Timber.d("*** Start creating ${numberOfSessions} fake computables...") 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. // Use fields to define the data types to return.
val placeFields = Arrays.asList(Place.Field.NAME, Place.Field.ADDRESS, Place.Field.LAT_LNG) 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() val request = FindCurrentPlaceRequest.builder(placeFields).build()
// Call findCurrentPlace and handle the response (first check that the user has granted permission). // Call findCurrentPlace and handle the response (first check that the user has granted permission).

@ -1,16 +1,10 @@
package net.pokeranalytics.android.util.extensions package net.pokeranalytics.android.util.extensions
import io.realm.Realm import io.realm.*
import io.realm.RealmModel
import io.realm.RealmResults
import io.realm.Sort
import net.pokeranalytics.android.model.interfaces.CountableUsage import net.pokeranalytics.android.model.interfaces.CountableUsage
import net.pokeranalytics.android.model.interfaces.Identifiable import net.pokeranalytics.android.model.interfaces.Identifiable
import net.pokeranalytics.android.model.interfaces.NameManageable import net.pokeranalytics.android.model.interfaces.NameManageable
import net.pokeranalytics.android.model.realm.Filter import net.pokeranalytics.android.model.realm.*
import net.pokeranalytics.android.model.realm.TournamentFeature
import net.pokeranalytics.android.model.realm.Transaction
import net.pokeranalytics.android.model.realm.TransactionType
fun <T : RealmModel>Realm.count(clazz: Class<T>) : Long { fun <T : RealmModel>Realm.count(clazz: Class<T>) : Long {
return this.where(clazz).count() return this.where(clazz).count()
@ -106,5 +100,22 @@ fun <T : RealmModel>Realm.updateUsageCount(clazz: Class<T>) {
countable.useCount = count 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