Merge branch 'master' of gitlab.com:stax-river/poker-analytics

kmm
Laurent 5 years ago
commit 777d4826ba
  1. 5
      app/build.gradle
  2. 18
      app/src/androidTest/java/net/pokeranalytics/android/unitTests/filter/BlindFilterInstrumentedTest.kt
  3. 37
      app/src/androidTest/java/net/pokeranalytics/android/unitTests/filter/DateFilterInstrumentedUnitTest.kt
  4. 6
      app/src/androidTest/java/net/pokeranalytics/android/unitTests/filter/RealmFilterInstrumentedUnitTest.kt
  5. 64
      app/src/androidTest/java/net/pokeranalytics/android/unitTests/filter/SessionFilterInstrumentedUnitTest.kt
  6. 8
      app/src/main/java/net/pokeranalytics/android/calculus/bankroll/BankrollReport.kt
  7. 18
      app/src/main/java/net/pokeranalytics/android/exceptions/Exceptions.kt
  8. 16
      app/src/main/java/net/pokeranalytics/android/model/filter/Query.kt
  9. 287
      app/src/main/java/net/pokeranalytics/android/model/filter/QueryCondition.kt
  10. 32
      app/src/main/java/net/pokeranalytics/android/model/realm/Filter.kt
  11. 24
      app/src/main/java/net/pokeranalytics/android/model/realm/FilterCondition.kt
  12. 22
      app/src/main/java/net/pokeranalytics/android/ui/fragment/SettingsFragment.kt
  13. 17
      app/src/main/java/net/pokeranalytics/android/ui/fragment/SubscriptionFragment.kt
  14. 2
      app/src/main/java/net/pokeranalytics/android/ui/fragment/components/BaseFragment.kt
  15. 2
      app/src/main/java/net/pokeranalytics/android/ui/fragment/components/bottomsheet/BottomSheetEditTextFragment.kt
  16. 2
      app/src/main/java/net/pokeranalytics/android/ui/fragment/components/bottomsheet/BottomSheetFragment.kt
  17. 4
      app/src/main/java/net/pokeranalytics/android/ui/modules/calendar/CalendarDetailsActivity.kt
  18. 33
      app/src/main/java/net/pokeranalytics/android/ui/modules/feed/FeedFragment.kt
  19. 189
      app/src/main/java/net/pokeranalytics/android/ui/modules/filter/FilterDetailsFragment.kt
  20. 96
      app/src/main/java/net/pokeranalytics/android/ui/modules/filter/FilterDetailsViewModel.kt
  21. 5
      app/src/main/java/net/pokeranalytics/android/ui/modules/filter/FilterHandler.kt
  22. 10
      app/src/main/java/net/pokeranalytics/android/ui/modules/filter/FilterViewModel.kt
  23. 12
      app/src/main/java/net/pokeranalytics/android/ui/modules/filter/FiltersActivity.kt
  24. 25
      app/src/main/java/net/pokeranalytics/android/ui/modules/filter/FiltersFragment.kt
  25. 11
      app/src/main/java/net/pokeranalytics/android/ui/modules/filter/FiltersListActivity.kt
  26. 8
      app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/FilterCategoryRow.kt
  27. 61
      app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/FilterElementRow.kt
  28. 197
      app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/FilterItemRow.kt
  29. 86
      app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/FilterSectionRow.kt
  30. 44
      app/src/main/java/net/pokeranalytics/android/util/billing/AppGuard.kt
  31. 66
      app/src/main/res/layout/fragment_filter_details.xml
  32. 27
      app/src/test/java/net/pokeranalytics/android/InstantiationTest.kt

@ -79,6 +79,11 @@ android {
versionNameSuffix = '_nov2020'
versionCode = 52110 + android.defaultConfig.versionCode
}
oct2021 {
dimension = 'endOfUse'
versionNameSuffix = '_oct2021'
versionCode = 52120 + android.defaultConfig.versionCode
}
}
configurations {

@ -47,9 +47,9 @@ class BlindFilterInstrumentedTest : BaseFilterInstrumentedUnitTest() {
listOfValues = arrayListOf(s1.blinds!!)
}
blind.filterSectionRow = FilterSectionRow.Blind
// blind.filterSectionRow = FilterSectionRow.Blind
val filterElement = FilterCondition(filterElementRows = arrayListOf(blind))
val filterElement = FilterCondition(arrayListOf(blind), FilterSectionRow.Blind)
filter.updateValueBy(filterElement)
val sessions = Filter.queryOn<Session>(realm, Query(filter))
@ -97,10 +97,7 @@ class BlindFilterInstrumentedTest : BaseFilterInstrumentedUnitTest() {
listOfValues = arrayListOf(s2.blinds!!)
}
blind1.filterSectionRow = FilterSectionRow.Blind
blind2.filterSectionRow = FilterSectionRow.Blind
val filterElements = FilterCondition(filterElementRows = arrayListOf(blind1, blind2))
val filterElements = FilterCondition(arrayListOf(blind1, blind2), FilterSectionRow.Blind)
filter.updateValueBy(filterElements)
val sessions = Filter.queryOn<Session>(realm, Query(filter))
@ -146,9 +143,7 @@ class BlindFilterInstrumentedTest : BaseFilterInstrumentedUnitTest() {
listOfValues = arrayListOf(s3.blinds!!)
}
blind.filterSectionRow = FilterSectionRow.Blind
val filterElement = FilterCondition(filterElementRows = arrayListOf(blind))
val filterElement = FilterCondition(arrayListOf(blind), FilterSectionRow.Blind)
filter.updateValueBy(filterElement)
val sessions = Filter.queryOn<Session>(realm, Query(filter))
@ -196,10 +191,7 @@ class BlindFilterInstrumentedTest : BaseFilterInstrumentedUnitTest() {
listOfValues = arrayListOf(s2.blinds!!)
}
blind1.filterSectionRow = FilterSectionRow.Blind
blind2.filterSectionRow = FilterSectionRow.Blind
val filterElement = FilterCondition(filterElementRows = arrayListOf(blind1, blind2))
val filterElement = FilterCondition(arrayListOf(blind1, blind2), FilterSectionRow.Blind)
filter.updateValueBy(filterElement)
val sessions = Filter.queryOn<Session>(realm, Query(filter))

@ -35,8 +35,7 @@ class DateFilterInstrumentedUnitTest : BaseFilterInstrumentedUnitTest() {
cal.time = s1.startDate
val filterElementRow = QueryCondition.AnyDayOfWeek().apply { listOfValues = arrayListOf(cal.get(Calendar.DAY_OF_WEEK)) }
filterElementRow.filterSectionRow = FilterSectionRow.DynamicDate
val filterElement = FilterCondition(arrayListOf(filterElementRow))
val filterElement = FilterCondition(arrayListOf(filterElementRow), FilterSectionRow.DynamicDate)
filter.updateValueBy(filterElement)
val sessions = Filter.queryOn<Session>(realm, Query(filter))
@ -64,8 +63,7 @@ class DateFilterInstrumentedUnitTest : BaseFilterInstrumentedUnitTest() {
cal.time = s1.startDate
val filterElementRow = QueryCondition.AnyMonthOfYear().apply { listOfValues = arrayListOf(cal.get(Calendar.MONTH)) }
filterElementRow.filterSectionRow = FilterSectionRow.DynamicDate
val filterElement = FilterCondition(arrayListOf(filterElementRow))
val filterElement = FilterCondition(arrayListOf(filterElementRow), FilterSectionRow.DynamicDate)
filter.updateValueBy(filterElement)
val sessions = Filter.queryOn<Session>(realm, Query(filter))
@ -92,8 +90,7 @@ class DateFilterInstrumentedUnitTest : BaseFilterInstrumentedUnitTest() {
val filter = QueryCondition.AnyYear()
cal.time = s1.startDate
val filterElementRow = QueryCondition.AnyYear().apply { listOfValues = arrayListOf(cal.get(Calendar.YEAR)) }
filterElementRow.filterSectionRow = FilterSectionRow.DynamicDate
val filterElement = FilterCondition(arrayListOf(filterElementRow))
val filterElement = FilterCondition(arrayListOf(filterElementRow), FilterSectionRow.DynamicDate)
filter.updateValueBy(filterElement)
val sessions = Filter.queryOn<Session>(realm, Query(filter))
@ -384,10 +381,9 @@ class DateFilterInstrumentedUnitTest : BaseFilterInstrumentedUnitTest() {
val s2 = Session.testInstance(100.0, true, cal.time, 1)
realm.commitTransaction()
val filter = QueryCondition.StartedFromDate()
val filterElementRow = QueryCondition.StartedFromDate().apply { singleValue = s2.startDate!!}
filterElementRow.filterSectionRow = FilterSectionRow.FixedDate
filter.updateValueBy(FilterCondition(arrayListOf(filterElementRow)))
val filter = QueryCondition.StartedFromDate(Date())
val filterElementRow = QueryCondition.StartedFromDate(Date()).apply { singleValue = s2.startDate!!}
filter.updateValueBy(FilterCondition(arrayListOf(filterElementRow), FilterSectionRow.FixedDate))
val sessions = Filter.queryOn<Session>(realm, Query(filter))
@ -412,10 +408,9 @@ class DateFilterInstrumentedUnitTest : BaseFilterInstrumentedUnitTest() {
realm.commitTransaction()
val filter = QueryCondition.StartedToDate()
val filterElementRow = QueryCondition.StartedToDate().apply { singleValue = s1.startDate!! }
filterElementRow.filterSectionRow = FilterSectionRow.FixedDate
filter.updateValueBy(FilterCondition(arrayListOf(filterElementRow)))
val filter = QueryCondition.StartedToDate(Date())
val filterElementRow = QueryCondition.StartedToDate(Date()).apply { singleValue = s1.startDate!! }
filter.updateValueBy(FilterCondition(arrayListOf(filterElementRow), FilterSectionRow.FixedDate))
val sessions = Filter.queryOn<Session>(realm, Query(filter))
@ -441,10 +436,9 @@ class DateFilterInstrumentedUnitTest : BaseFilterInstrumentedUnitTest() {
realm.commitTransaction()
val filter = QueryCondition.EndedFromDate()
val filterElementRow = QueryCondition.EndedFromDate().apply { singleValue = s2.endDate() }
filterElementRow.filterSectionRow = FilterSectionRow.FixedDate
filter.updateValueBy(FilterCondition(arrayListOf(filterElementRow)))
val filter = QueryCondition.EndedFromDate(Date())
val filterElementRow = QueryCondition.EndedFromDate(Date()).apply { singleValue = s2.endDate() }
filter.updateValueBy(FilterCondition(arrayListOf(filterElementRow), FilterSectionRow.FixedDate))
val sessions = Filter.queryOn<Session>(realm, Query(filter))
@ -470,10 +464,9 @@ class DateFilterInstrumentedUnitTest : BaseFilterInstrumentedUnitTest() {
realm.commitTransaction()
val filter = QueryCondition.EndedToDate()
val filterElementRow = QueryCondition.EndedToDate().apply { singleValue = s1.endDate() }
filterElementRow.filterSectionRow = FilterSectionRow.FixedDate
filter.updateValueBy(FilterCondition(arrayListOf(filterElementRow)))
val filter = QueryCondition.EndedToDate(Date())
val filterElementRow = QueryCondition.EndedToDate(Date()).apply { singleValue = s1.endDate() }
filter.updateValueBy(FilterCondition(arrayListOf(filterElementRow), FilterSectionRow.FixedDate))
val sessions = Filter.queryOn<Session>(realm, Query(filter))

@ -5,6 +5,7 @@ import net.pokeranalytics.android.components.BaseFilterInstrumentedUnitTest
import net.pokeranalytics.android.model.filter.QueryCondition
import net.pokeranalytics.android.model.realm.Filter
import net.pokeranalytics.android.model.realm.Session
import net.pokeranalytics.android.ui.view.rowrepresentable.FixedValueFilterItemRow
import net.pokeranalytics.android.ui.view.rowrepresentable.FilterCategoryRow
import net.pokeranalytics.android.ui.view.rowrepresentable.FilterSectionRow
import org.junit.Assert
@ -24,8 +25,9 @@ class RealmFilterInstrumentedUnitTest : BaseFilterInstrumentedUnitTest() {
filter.name = "testSaveLoadCashFilter"
val filterElement = QueryCondition.IsCash
filterElement.filterSectionRow = FilterSectionRow.CashOrTournament
filter.createOrUpdateFilterConditions(arrayListOf(filterElement))
val filterItemRow = FixedValueFilterItemRow(filterElement, FilterSectionRow.CashOrTournament)
filter.createOrUpdateFilterConditions(arrayListOf(filterItemRow))
val useCount = filter.countBy(FilterCategoryRow.GENERAL)
Assert.assertEquals(1, useCount)

@ -110,8 +110,7 @@ class SessionFilterInstrumentedUnitTest : BaseFilterInstrumentedUnitTest() {
val filter = QueryCondition.AnyBankroll()
val filterElementRow = QueryCondition.AnyBankroll().apply { setObject(b1) }
filterElementRow.filterSectionRow = FilterSectionRow.Bankroll
filter.updateValueBy(FilterCondition(filterElementRows = arrayListOf(filterElementRow)))
filter.updateValueBy(FilterCondition(arrayListOf(filterElementRow), FilterSectionRow.Bankroll))
val sessions = Filter.queryOn<Session>(realm, Query(filter))
@ -141,11 +140,9 @@ class SessionFilterInstrumentedUnitTest : BaseFilterInstrumentedUnitTest() {
val filter = QueryCondition.AnyBankroll()
val filterElementRow = QueryCondition.AnyBankroll().apply { setObject(b1) }
filterElementRow.filterSectionRow = FilterSectionRow.Bankroll
val filterElementRow2 = QueryCondition.AnyBankroll().apply { setObject(b2) }
filterElementRow2.filterSectionRow = FilterSectionRow.Bankroll
filter.updateValueBy(FilterCondition(filterElementRows = arrayListOf(filterElementRow, filterElementRow2)))
filter.updateValueBy(FilterCondition(arrayListOf(filterElementRow, filterElementRow2), FilterSectionRow.Bankroll))
val sessions = Filter.queryOn<Session>(realm, Query(filter))
@ -169,7 +166,7 @@ class SessionFilterInstrumentedUnitTest : BaseFilterInstrumentedUnitTest() {
realm.commitTransaction()
val anyGame = QueryCondition.AnyGame(g2)
val fc = FilterCondition(filterElementRows = arrayListOf(anyGame))
val fc = FilterCondition(arrayListOf(anyGame), FilterSectionRow.Game)
val sessions = Filter.queryOn<Session>(realm, Query(fc.queryCondition))
Assert.assertEquals(1, sessions.size)
@ -197,10 +194,10 @@ class SessionFilterInstrumentedUnitTest : BaseFilterInstrumentedUnitTest() {
realm.commitTransaction()
val filterElementRow = QueryCondition.AnyGame().apply { setObject(g2) }
filterElementRow.filterSectionRow = FilterSectionRow.Game
val filterElementRow2 = QueryCondition.AnyGame().apply { setObject(g3) }
filterElementRow2.filterSectionRow = FilterSectionRow.Game
val filterCondition = FilterCondition(filterElementRows = arrayListOf(filterElementRow, filterElementRow2))
val filterCondition = FilterCondition(arrayListOf(filterElementRow, filterElementRow2), FilterSectionRow.Game)
val queryCondition = filterCondition.queryCondition
val sessions = Filter.queryOn<Session>(realm, Query(queryCondition))
@ -225,8 +222,7 @@ class SessionFilterInstrumentedUnitTest : BaseFilterInstrumentedUnitTest() {
val filter = QueryCondition.AnyLocation()
val filterElementRow = QueryCondition.AnyLocation().apply { setObject(l1) }
filterElementRow.filterSectionRow = FilterSectionRow.Location
filter.updateValueBy(FilterCondition(filterElementRows = arrayListOf(filterElementRow)))
filter.updateValueBy(FilterCondition(arrayListOf(filterElementRow), FilterSectionRow.Location))
val sessions = Filter.queryOn<Session>(realm, Query(filter))
@ -257,11 +253,9 @@ class SessionFilterInstrumentedUnitTest : BaseFilterInstrumentedUnitTest() {
val filter = QueryCondition.AnyLocation()
val filterElementRow = QueryCondition.AnyLocation().apply { setObject(l1) }
filterElementRow.filterSectionRow = FilterSectionRow.Location
val filterElementRow2 = QueryCondition.AnyLocation().apply { setObject(l3) }
filterElementRow2.filterSectionRow = FilterSectionRow.Location
filter.updateValueBy(FilterCondition(filterElementRows = arrayListOf(filterElementRow, filterElementRow2)))
filter.updateValueBy(FilterCondition(arrayListOf(filterElementRow, filterElementRow2), FilterSectionRow.Location))
val sessions = Filter.queryOn<Session>(realm, Query(filter))
@ -287,8 +281,7 @@ class SessionFilterInstrumentedUnitTest : BaseFilterInstrumentedUnitTest() {
val filter = QueryCondition.AnyTournamentName()
val filterElementRow = QueryCondition.AnyTournamentName().apply { setObject(t1) }
filterElementRow.filterSectionRow = FilterSectionRow.TournamentName
filter.updateValueBy(FilterCondition(filterElementRows = arrayListOf(filterElementRow)))
filter.updateValueBy(FilterCondition(arrayListOf(filterElementRow), FilterSectionRow.TournamentName))
val sessions = Filter.queryOn<Session>(realm, Query(filter))
@ -318,10 +311,8 @@ class SessionFilterInstrumentedUnitTest : BaseFilterInstrumentedUnitTest() {
val filter = QueryCondition.AnyTournamentName()
val filterElementRow = QueryCondition.AnyTournamentName().apply { setObject(t1) }
filterElementRow.filterSectionRow = FilterSectionRow.TournamentName
val filterElementRow2 = QueryCondition.AnyTournamentName().apply { setObject(t2) }
filterElementRow.filterSectionRow = FilterSectionRow.TournamentName
filter.updateValueBy(FilterCondition(filterElementRows = arrayListOf(filterElementRow, filterElementRow2)))
filter.updateValueBy(FilterCondition(arrayListOf(filterElementRow, filterElementRow2), FilterSectionRow.TournamentName))
val sessions = Filter.queryOn<Session>(realm, Query(filter))
@ -354,12 +345,10 @@ class SessionFilterInstrumentedUnitTest : BaseFilterInstrumentedUnitTest() {
val filter = QueryCondition.AllTournamentFeature()
val filterElementRow = QueryCondition.AllTournamentFeature().apply { setObject(t1) }
filterElementRow.filterSectionRow = FilterSectionRow.TournamentFeature
val filterElementRow2 = QueryCondition.AllTournamentFeature().apply { setObject(t2) }
filterElementRow2.filterSectionRow = FilterSectionRow.TournamentFeature
val filterElementRow3 = QueryCondition.AllTournamentFeature().apply { setObject(t4) }
filterElementRow3.filterSectionRow = FilterSectionRow.TournamentFeature
filter.updateValueBy(FilterCondition(filterElementRows = arrayListOf(filterElementRow, filterElementRow2, filterElementRow3)))
filter.updateValueBy(FilterCondition(arrayListOf(filterElementRow, filterElementRow2, filterElementRow3), FilterSectionRow.TournamentFeature))
val sessions = Filter.queryOn<Session>(realm, Query(filter))
@ -389,14 +378,11 @@ class SessionFilterInstrumentedUnitTest : BaseFilterInstrumentedUnitTest() {
val filter = QueryCondition.AnyTournamentFeature()
val filterElementRow = QueryCondition.AnyTournamentFeature().apply { setObject(t1) }
filterElementRow.filterSectionRow = FilterSectionRow.TournamentFeature
val filterElementRow2 = QueryCondition.AnyTournamentFeature().apply { setObject(t2) }
filterElementRow2.filterSectionRow = FilterSectionRow.TournamentFeature
val filterElementRow3 = QueryCondition.AnyTournamentFeature().apply { setObject(t3) }
filterElementRow3.filterSectionRow = FilterSectionRow.TournamentFeature
val filterElementRow4 = QueryCondition.AnyTournamentFeature().apply { setObject(t4) }
filterElementRow4.filterSectionRow = FilterSectionRow.TournamentFeature
filter.updateValueBy(FilterCondition(filterElementRows = arrayListOf(filterElementRow, filterElementRow2, filterElementRow3, filterElementRow4)))
filter.updateValueBy(FilterCondition(arrayListOf(filterElementRow, filterElementRow2, filterElementRow3, filterElementRow4), FilterSectionRow.TournamentFeature))
val sessions = Filter.queryOn<Session>(realm, Query(filter))
@ -423,8 +409,7 @@ class SessionFilterInstrumentedUnitTest : BaseFilterInstrumentedUnitTest() {
val filter = QueryCondition.AnyTournamentFeature()
val filterElementRow = QueryCondition.AnyTournamentFeature().apply { setObject(t2) }
filterElementRow.filterSectionRow = FilterSectionRow.TournamentFeature
filter.updateValueBy(FilterCondition(filterElementRows = arrayListOf(filterElementRow)))
filter.updateValueBy(FilterCondition(arrayListOf(filterElementRow), FilterSectionRow.TournamentFeature))
val sessions = Filter.queryOn<Session>(realm, Query(filter))
@ -448,10 +433,9 @@ class SessionFilterInstrumentedUnitTest : BaseFilterInstrumentedUnitTest() {
val filter = QueryCondition.AnyTableSize()
val filterElementRow = QueryCondition.AnyTableSize().apply { listOfValues = arrayListOf(2) }
filterElementRow.filterSectionRow = FilterSectionRow.TableSize
val filterElementRow2 = QueryCondition.AnyTableSize().apply { listOfValues = arrayListOf(4) }
filterElementRow.filterSectionRow = FilterSectionRow.TableSize
filter.updateValueBy(FilterCondition(filterElementRows = arrayListOf(filterElementRow, filterElementRow2)))
filter.updateValueBy(FilterCondition(arrayListOf(filterElementRow, filterElementRow2), FilterSectionRow.TableSize))
val sessions = Filter.queryOn<Session>(realm, Query(filter))
@ -475,8 +459,7 @@ class SessionFilterInstrumentedUnitTest : BaseFilterInstrumentedUnitTest() {
val filter = QueryCondition.NetAmountWon()
val filterElementRow = QueryCondition.more<QueryCondition.NetAmountWon>().apply { listOfValues = arrayListOf(204.0) }
filterElementRow.filterSectionRow = FilterSectionRow.Value
filter.updateValueBy(FilterCondition(arrayListOf(filterElementRow)))
filter.updateValueBy(FilterCondition(arrayListOf(filterElementRow), FilterSectionRow.Value))
val sessions = Filter.queryOn<Session>(realm, Query(filterElementRow))
@ -500,8 +483,7 @@ class SessionFilterInstrumentedUnitTest : BaseFilterInstrumentedUnitTest() {
val filter = QueryCondition.NetAmountWon()
val filterElementRow = QueryCondition.less<QueryCondition.NetAmountWon>().apply { listOfValues = arrayListOf(540.0) }
filterElementRow.filterSectionRow = FilterSectionRow.Value
filter.updateValueBy(FilterCondition(arrayListOf(filterElementRow)))
filter.updateValueBy(FilterCondition(arrayListOf(filterElementRow), FilterSectionRow.Value))
val sessions = Filter.queryOn<Session>(realm, Query(filter))
@ -525,13 +507,11 @@ class SessionFilterInstrumentedUnitTest : BaseFilterInstrumentedUnitTest() {
val filterMore = QueryCondition.NetAmountWon()
val filterElementRow = QueryCondition.more<QueryCondition.NetAmountWon>().apply { listOfValues = arrayListOf(199.0) }
filterElementRow.filterSectionRow = FilterSectionRow.Value
filterMore.updateValueBy(FilterCondition(arrayListOf(filterElementRow)))
filterMore.updateValueBy(FilterCondition(arrayListOf(filterElementRow), FilterSectionRow.Value))
val filterLess = QueryCondition.NetAmountWon()
val filterElementRow2 = QueryCondition.less<QueryCondition.NetAmountWon>().apply { listOfValues = arrayListOf(400.0) }
filterElementRow2.filterSectionRow = FilterSectionRow.Value
filterLess.updateValueBy(FilterCondition(arrayListOf(filterElementRow2)))
filterLess.updateValueBy(FilterCondition(arrayListOf(filterElementRow2), FilterSectionRow.Value))
val sessions = Filter.queryOn<Session>(realm, Query(filterMore, filterLess))

@ -220,14 +220,10 @@ class BankrollReportSetup(val bankrollId: String? = null, val from: Date? = null
query.add(bankrollCondition)
}
this.from?.let {
val fromCondition = QueryCondition.StartedFromDate()
fromCondition.singleValue = it
query.add(fromCondition)
query.add(QueryCondition.StartedFromDate(it))
}
this.to?.let {
val toCondition = QueryCondition.StartedToDate()
toCondition.singleValue = it
query.add(toCondition)
query.add(QueryCondition.StartedToDate(it))
}
return query
}

@ -1,7 +1,5 @@
package net.pokeranalytics.android.exceptions
import net.pokeranalytics.android.ui.view.rowrepresentable.FilterElementRow
class ModelException(message: String) : Exception(message)
class FormattingException(message: String) : Exception(message)
class RowRepresentableEditDescriptorException(message: String) : Exception(message)
@ -14,16 +12,16 @@ class PAIllegalStateException(message: String) : Exception(message)
sealed class PokerAnalyticsException(message: String) : Exception(message) {
object FilterElementUnknownName : PokerAnalyticsException(message = "No filterElement name was found to identify the queryCondition")
object FilterElementUnknownSectionName: PokerAnalyticsException(message = "No filterElement section name was found to identify the queryCondition")
object FilterMissingEntity: PokerAnalyticsException(message = "This queryWith has no entity initialized")
object FilterUnhandledEntity : PokerAnalyticsException(message = "This entity is not filterable")
// object FilterElementUnknownSectionName: PokerAnalyticsException(message = "No filterElement section name was found to identify the queryCondition")
// object FilterMissingEntity: PokerAnalyticsException(message = "This queryWith has no entity initialized")
// object FilterUnhandledEntity : PokerAnalyticsException(message = "This entity is not filterable")
object QueryValueMapUnknown: PokerAnalyticsException(message = "fieldName is missing")
object QueryTypeUnhandled: PokerAnalyticsException(message = "queryWith type not handled")
object QueryValueMapUnexpectedValue: PokerAnalyticsException(message = "valueMap null not expected")
object FilterElementExpectedValueMissing : PokerAnalyticsException(message = "queryWith is empty or null")
data class FilterElementTypeMissing(val filterElementRow: FilterElementRow) : PokerAnalyticsException(message = "queryWith element '$filterElementRow' type is missing")
data class QueryValueMapMissingKeys(val missingKeys: List<String>) : PokerAnalyticsException(message = "valueMap does not contain $missingKeys")
data class UnknownQueryTypeForRow(val filterElementRow: FilterElementRow) : PokerAnalyticsException(message = "no queryWith type for $filterElementRow")
data class MissingFieldNameForQueryCondition(val name: String) : PokerAnalyticsException(message = "Missing fieldname for QueryCondition ${name}")
object InputFragmentException : PokerAnalyticsException(message = "RowEditableDelegate must be a Fragment")
// data class FilterElementTypeMissing(val filterElementRow: FilterElementRow) : PokerAnalyticsException(message = "queryWith element '$filterElementRow' type is missing")
// data class QueryValueMapMissingKeys(val missingKeys: List<String>) : PokerAnalyticsException(message = "valueMap does not contain $missingKeys")
// data class UnknownQueryTypeForRow(val filterElementRow: FilterElementRow) : PokerAnalyticsException(message = "no queryWith type for $filterElementRow")
// data class MissingFieldNameForQueryCondition(val name: String) : PokerAnalyticsException(message = "Missing fieldname for QueryCondition ${name}")
// object InputFragmentException : PokerAnalyticsException(message = "RowEditableDelegate must be a Fragment")
}

@ -84,14 +84,14 @@ class Query {
}
// println("<<<<<< ${realmQuery.description}")
val queryLast = this.conditions.firstOrNull {
it is QueryCondition.Last
}
queryLast?.let {qc ->
(qc as QueryCondition.Last).singleValue?.let {
return realmQuery.limit(it.toLong())
}
}
// val queryLast = this.conditions.firstOrNull {
// it is QueryCondition.Last
// }
// queryLast?.let {qc ->
// (qc as QueryCondition.Last).singleValue?.let {
// return realmQuery.limit(it.toLong())
// }
// }
return realmQuery
}

@ -16,31 +16,49 @@ import net.pokeranalytics.android.model.interfaces.Identifiable
import net.pokeranalytics.android.model.interfaces.NameManageable
import net.pokeranalytics.android.model.realm.*
import net.pokeranalytics.android.ui.fragment.components.bottomsheet.BottomSheetType
import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.RowViewType
import net.pokeranalytics.android.ui.view.rowrepresentable.FilterElementRow
import net.pokeranalytics.android.ui.view.rowrepresentable.FilterSectionRow
import net.pokeranalytics.android.util.NULL_TEXT
import net.pokeranalytics.android.util.UserDefaults
import net.pokeranalytics.android.util.extensions.*
import java.text.DateFormatSymbols
import java.text.NumberFormat
import java.util.*
import kotlin.collections.ArrayList
import kotlin.reflect.KClass
/**
* Enum describing the way a query should be handled
* Some queries requires a value to be checked upon through equals, in, more, less, between
*/
sealed class QueryCondition : FilterElementRow {
sealed class QueryCondition : RowRepresentable {
companion object {
fun <T: Any> newInstance(kClass: KClass<T>): T {
return try {
kClass.objectInstance ?: kClass.java.newInstance()
} catch (e: Exception) {
// some object instance can fail due to: java.lang.Class has no zero argument constructor
// We should have just one constructor with a single parameter
val primaryConstructor = kClass.java.declaredConstructors.first()
val paramClass = primaryConstructor.parameterTypes.first()
val param = when (paramClass) {
Int::class.java -> 0
Double::class.java -> 0.0
else -> paramClass.newInstance()
}
val constructor = kClass.java.getDeclaredConstructor(paramClass)
constructor.newInstance(param)
}
}
inline fun <reified T : QueryCondition> more(): T {
return T::class.java.newInstance().apply { this.operator = Operator.MORE }
return newInstance(T::class).apply { this.operator = Operator.MORE }
}
inline fun <reified T : QueryCondition> less(): T {
return T::class.java.newInstance().apply { this.operator = Operator.LESS }
return newInstance(T::class).apply { this.operator = Operator.LESS }
}
inline fun <reified T : QueryCondition> moreOrLess(): ArrayList<T> {
@ -49,8 +67,7 @@ sealed class QueryCondition : FilterElementRow {
fun <T : QueryCondition> valueOf(name: String): T {
val kClass = Class.forName("${QueryCondition::class.qualifiedName}$$name").kotlin
val instance = kClass.objectInstance ?: kClass.java.newInstance()
return instance as T
return newInstance(kClass) as T
}
inline fun <reified T : Identifiable> getInstance(): QueryCondition {
@ -125,23 +142,27 @@ sealed class QueryCondition : FilterElementRow {
abstract class ListOfValues<T> : QueryCondition(), Comparable<ListOfValues<T>> where T : Comparable<T> {
abstract var listOfValues: ArrayList<T>
abstract var listOfValues: MutableList<T>
abstract fun labelForValue(value: T, context: Context): String
open fun entityName(context: Context): String {
return getDisplayName(context)
}
override fun getDisplayName(context: Context): String {
fun getDisplayName(context: Context, values: List<T>): String {
val prefix = this.resId?.let {
context.getString(it) + " "
} ?: ""
return when (listOfValues.size) {
return when (values.size) {
0 -> return NULL_TEXT
1, 2 -> prefix + listOfValues.map { labelForValue(it, context) }.joinToString(", ")
else -> "${listOfValues.size} $prefix ${entityName(context)}"
1, 2 -> prefix + values.joinToString(", ") { labelForValue(it, context) }
else -> "${values.size} $prefix ${entityName(context)}"
}
}
override fun getDisplayName(context: Context): String {
return getDisplayName(context, this.listOfValues)
}
override fun compareTo(other: ListOfValues<T>): Int {
@ -151,17 +172,32 @@ sealed class QueryCondition : FilterElementRow {
fun firstValue(context: Context): String? {
return this.listOfValues.firstOrNull()?.let { this.labelForValue(it, context) }
}
}
abstract class SingleValue<T>(value: T) : QueryCondition() where T : Comparable<T> {
// override var listOfValues = mutableListOf<T>()
var singleValue: T = value
abstract fun labelForValue(value: T, context: Context): String
override fun getDisplayName(context: Context): String {
return getDisplayName(context, singleValue)
}
fun getDisplayName(context: Context, value: T): String {
val prefix = this.resId?.let {
context.getString(it) + " "
} ?: ""
return prefix + labelForValue(value, context)
}
abstract class SingleValue<T> : ListOfValues<T>() where T : Comparable<T> {
override var listOfValues = ArrayList<T>()
abstract var singleValue: T?
}
abstract class ListOfDouble : ListOfValues<Double>() {
open var sign: Int = 1
override var operator: Operator = Operator.ANY
override var listOfValues: ArrayList<Double> = arrayListOf()
override var listOfValues = mutableListOf<Double>()
override fun updateValueBy(filterCondition: FilterCondition) {
super.updateValueBy(filterCondition)
listOfValues = filterCondition.getValues()
@ -174,7 +210,7 @@ sealed class QueryCondition : FilterElementRow {
abstract class ListOfInt : ListOfValues<Int>() {
override var operator: Operator = Operator.ANY
override var listOfValues: ArrayList<Int> = arrayListOf()
override var listOfValues = mutableListOf<Int>()
override fun updateValueBy(filterCondition: FilterCondition) {
super.updateValueBy(filterCondition)
listOfValues = filterCondition.getValues()
@ -187,7 +223,7 @@ sealed class QueryCondition : FilterElementRow {
abstract class ListOfString : ListOfValues<String>() {
override var operator: Operator = Operator.ANY
override var listOfValues = ArrayList<String>()
override var listOfValues = mutableListOf<String>()
override fun labelForValue(value: String, context: Context): String {
return value
}
@ -198,46 +234,30 @@ sealed class QueryCondition : FilterElementRow {
}
}
abstract class SingleDate : SingleValue<Date>() {
abstract class SingleDate(date: Date) : SingleValue<Date>(date) {
override fun labelForValue(value: Date, context: Context): String {
return value.shortDate()
}
override var listOfValues = ArrayList<Date>()
override var singleValue: Date?
get() {
return listOfValues.firstOrNull()
}
set(value) {
listOfValues.removeAll(this.listOfValues)
value?.let { listOfValues.add(it) }
}
// override var listOfValues = mutableListOf<Date>()
override fun updateValueBy(filterCondition: FilterCondition) {
super.updateValueBy(filterCondition)
singleValue = filterCondition.getValue()
}
}
abstract class SingleInt : SingleValue<Int>() {
abstract class SingleInt(value: Int) : SingleValue<Int>(value) {
override fun labelForValue(value: Int, context: Context): String {
return value.toString()
}
override var singleValue: Int?
get() {
return listOfValues.firstOrNull()
}
set(value) {
listOfValues.removeAll(this.listOfValues)
value?.let { listOfValues.add(it) }
}
override fun updateValueBy(filterCondition: FilterCondition) {
super.updateValueBy(filterCondition)
singleValue = filterCondition.getValue()
}
}
override fun getDisplayName(context: Context): String {
@ -247,7 +267,7 @@ sealed class QueryCondition : FilterElementRow {
return baseId
}
override var filterSectionRow: FilterSectionRow = FilterSectionRow.CashOrTournament
// override var filterSectionRow: FilterSectionRow = FilterSectionRow.CashOrTournament
abstract class QueryDataCondition<T : NameManageable> : ListOfString() {
fun setObject(dataObject: T) {
@ -263,7 +283,7 @@ sealed class QueryCondition : FilterElementRow {
val completeLabel = when (listOfValues.size) {
0 -> NULL_TEXT
1, 2 -> {
listOfValues.map { labelForValue(realm, it) }.joinToString(", ")
listOfValues.joinToString(", ") { labelForValue(realm, it) }
}
else -> "${listOfValues.size} $entityName"
}
@ -281,26 +301,23 @@ sealed class QueryCondition : FilterElementRow {
}
}
interface DateTime {
val showTime: Boolean
}
abstract class DateQuery : SingleDate(), DateTime {
abstract class DateQuery(date: Date) : SingleDate(date), DateTime {
override val showTime: Boolean = false
override fun labelForValue(value: Date, context: Context): String {
return singleValue?.let {
if (showTime) {
it.shortTime()
return if (showTime) {
singleValue.shortTime()
} else {
it.shortDate()
singleValue.shortDate()
}
} ?: NULL_TEXT
}
}
abstract class TimeQuery : DateQuery() {
abstract class TimeQuery(date: Date) : DateQuery(date) {
override val showTime: Boolean = true
}
@ -343,50 +360,34 @@ sealed class QueryCondition : FilterElementRow {
}
}
class AnyTournamentName() : QueryDataCondition<TournamentName>() {
class AnyTournamentName : QueryDataCondition<TournamentName>() {
override val entity: Class<TournamentName> = TournamentName::class.java
constructor(tournamentName: TournamentName) : this() {
this.setObject(tournamentName)
}
override fun entityName(context: Context): String {
return context.getString(R.string.tournament_names)
}
}
class AnyTournamentFeature() : QueryDataCondition<TournamentFeature>() {
class AnyTournamentFeature : QueryDataCondition<TournamentFeature>() {
override val entity: Class<TournamentFeature> = TournamentFeature::class.java
constructor(tournamentFeature: TournamentFeature) : this() {
this.setObject(tournamentFeature)
}
override fun entityName(context: Context): String {
return context.getString(R.string.tournament_features)
}
}
class AllTournamentFeature() : QueryDataCondition<TournamentFeature>() {
class AllTournamentFeature : QueryDataCondition<TournamentFeature>() {
override var operator = Operator.ALL
override val entity: Class<TournamentFeature> = TournamentFeature::class.java
constructor(tournamentFeature: TournamentFeature) : this() {
this.setObject(tournamentFeature)
}
override fun entityName(context: Context): String {
return context.getString(R.string.tournament_features)
}
}
class AnyLocation() : QueryDataCondition<Location>() {
class AnyLocation : QueryDataCondition<Location>() {
override val entity: Class<Location> = Location::class.java
constructor(location: Location) : this() {
this.setObject(location)
}
override fun entityName(context: Context): String {
return context.getString(R.string.locations)
}
@ -440,14 +441,6 @@ sealed class QueryCondition : FilterElementRow {
}
}
object Last : SingleInt() {
override var operator = Operator.EQUALS
override fun getDisplayName(context: Context): String {
//TODO update string "last %i"
return "${context.getString(R.string.last_i_records)} $singleValue"
}
}
class NumberOfTable : ListOfInt() {
override fun labelForValue(value: Int, context: Context): String {
return value.toString() + " " + context.getString(R.string.tables)
@ -476,13 +469,13 @@ sealed class QueryCondition : FilterElementRow {
}
override fun labelForValue(value: Int, context: Context): String {
val suffix = when (value%10) {
val suffix = when (value % 10) {
1 -> context.getString(R.string.ordinal_suffix_first)
2 -> context.getString(R.string.ordinal_suffix_second)
3 -> context.getString(R.string.ordinal_suffix_third)
else -> context.getString(R.string.ordinal_suffix_default)
}
return "$value$suffix "+context.getString(R.string.position)
return "$value$suffix " + context.getString(R.string.position)
}
override fun entityName(context: Context): String {
@ -507,19 +500,19 @@ sealed class QueryCondition : FilterElementRow {
}
}
class StartedFromDate : DateQuery() {
class StartedFromDate(date: Date) : DateQuery(date) {
override var operator = Operator.MORE
}
class StartedToDate : DateQuery() {
class StartedToDate(date: Date) : DateQuery(date) {
override var operator = Operator.LESS
}
class EndedFromDate : DateQuery() {
class EndedFromDate(date: Date) : DateQuery(date) {
override var operator = Operator.MORE
}
class EndedToDate : DateQuery() {
class EndedToDate(date: Date) : DateQuery(date) {
override var operator = Operator.LESS
}
@ -530,23 +523,23 @@ sealed class QueryCondition : FilterElementRow {
}
class AnyMonthOfYear() : ListOfInt() {
override fun labelForValue(value: Int, context: Context): String {
return DateFormatSymbols.getInstance(Locale.getDefault()).months[value].capitalize()
}
constructor(month: Int) : this() {
listOfValues = arrayListOf(month)
}
}
class AnyYear() : ListOfInt() {
override fun labelForValue(value: Int, context: Context): String {
return "$value"
return DateFormatSymbols.getInstance(Locale.getDefault()).months[value].capitalize()
}
}
class AnyYear() : ListOfInt() {
constructor(year: Int) : this() {
listOfValues = arrayListOf(year)
}
override fun labelForValue(value: Int, context: Context): String {
return "$value"
}
}
object IsWeekDay : TrueQueryCondition()
@ -564,7 +557,7 @@ sealed class QueryCondition : FilterElementRow {
}
}
class PastDay : SingleInt() {
class PastDay(value: Int) : SingleInt(value) {
override var operator = Operator.EQUALS
override val viewType: Int = RowViewType.TITLE_VALUE_CHECK.ordinal
@ -572,16 +565,17 @@ sealed class QueryCondition : FilterElementRow {
return value.toString()
}
override fun entityName(context: Context): String {
return this.resId?.let {
" " + context.getString(it)
} ?: ""
}
// override fun entityName(context: Context): String {
// return this.resId?.let {
// " " + context.getString(it)
// } ?: ""
// }
}
class Duration : SingleInt() {
class Duration(value: Int) : SingleInt(value) {
override var operator = Operator.EQUALS
var minutes: Int?
var minutes: Int
get() {
return singleValue
}
@ -589,12 +583,9 @@ sealed class QueryCondition : FilterElementRow {
singleValue = value
}
val netDuration: Long?
val netDuration: Long
get() {
minutes?.let {
return (it * 60 * 1000).toLong()
}
return null
return (singleValue * 60 * 1000).toLong()
}
override val viewType: Int = RowViewType.TITLE_VALUE_CHECK.ordinal
@ -609,22 +600,12 @@ sealed class QueryCondition : FilterElementRow {
object EndDateNotNull : NotNullQueryCondition()
object BigBlindNotNull : NotNullQueryCondition()
class StartedFromTime() : TimeQuery() {
class StartedFromTime(date: Date) : TimeQuery(date) {
override var operator = Operator.MORE
constructor(date: Date) : this() {
singleValue = date
}
}
class EndedToTime() : TimeQuery() {
class EndedToTime(date: Date) : TimeQuery(date) {
override var operator = Operator.LESS
constructor(date: Date) : this() {
singleValue = date
}
}
interface CustomFieldRelated {
@ -639,12 +620,8 @@ sealed class QueryCondition : FilterElementRow {
}
}
class CustomFieldQuery() : QueryDataCondition<CustomField>() {
class CustomFieldQuery : QueryDataCondition<CustomField>() {
override var entity: Class<CustomField> = CustomField::class.java
constructor(customField: CustomField) : this() {
this.setObject(customField)
}
}
open class CustomFieldNumberQuery() : ListOfDouble(), CustomFieldRelated {
@ -666,7 +643,9 @@ sealed class QueryCondition : FilterElementRow {
val completeLabel = when (listOfValues.size) {
0 -> return NULL_TEXT
1, 2 -> {
return name + prefix + listOfValues.map { labelForValue(it, context) }.joinToString(", ")
return name + prefix + listOfValues.joinToString(", ") {
labelForValue(it, context)
}
}
else -> "${listOfValues.size} $prefix $name"
}
@ -762,16 +741,13 @@ sealed class QueryCondition : FilterElementRow {
.lessThanOrEqualTo(fieldName, calendar.time.endOfDay())
}
is PastDay -> {
singleValue?.let {
val startDate = Date()
val calendar = Calendar.getInstance()
calendar.time = startDate
calendar.add(Calendar.DAY_OF_YEAR, -it)
calendar.add(Calendar.DAY_OF_YEAR, -singleValue)
return realmQuery.greaterThanOrEqualTo(fieldName, calendar.time.startOfDay()).and()
.lessThanOrEqualTo(fieldName, startDate.endOfDay())
}
return realmQuery
}
is DuringThisWeek -> {
val calendar = Calendar.getInstance()
calendar.set(Calendar.HOUR_OF_DAY, 0)
@ -800,30 +776,22 @@ sealed class QueryCondition : FilterElementRow {
}
is StartedFromTime -> {
val calendar = Calendar.getInstance()
singleValue?.let {
calendar.time = it
calendar.time = singleValue
realmQuery.greaterThanOrEqualTo(fieldName, calendar.hourMinute())
if (otherQueryCondition is EndedToTime) {
otherQueryCondition.singleValue?.let { endTime ->
calendar.time = endTime
calendar.time = otherQueryCondition.singleValue
realmQuery.lessThanOrEqualTo(fieldName, calendar.hourMinute())
}
}
}
return realmQuery
}
is EndedToTime -> {
val calendar = Calendar.getInstance()
singleValue?.let { date ->
calendar.time = date
calendar.time = singleValue
realmQuery.lessThanOrEqualTo(fieldName, calendar.hourMinute())
if (otherQueryCondition is StartedFromTime) {
otherQueryCondition.singleValue?.let { startTime ->
calendar.time = startTime
calendar.time = otherQueryCondition.singleValue
realmQuery.greaterThanOrEqualTo(fieldName, calendar.hourMinute())
}
}
}
return realmQuery
}
}
@ -846,14 +814,8 @@ sealed class QueryCondition : FilterElementRow {
return when (operator) {
Operator.EQUALS -> {
when (this) {
is SingleDate -> realmQuery.equalTo(
fieldName,
singleValue ?: throw PokerAnalyticsException.FilterElementExpectedValueMissing
)
is SingleInt -> realmQuery.equalTo(
fieldName,
singleValue ?: throw PokerAnalyticsException.FilterElementExpectedValueMissing
)
is SingleDate -> realmQuery.equalTo(fieldName, singleValue)
is SingleInt -> realmQuery.equalTo(fieldName, singleValue)
is ListOfInt -> realmQuery.equalTo(fieldName, listOfValues.first())
is ListOfDouble -> realmQuery.equalTo(fieldName, listOfValues.first() * sign)
is ListOfString -> realmQuery.equalTo(fieldName, listOfValues.first())
@ -862,20 +824,11 @@ sealed class QueryCondition : FilterElementRow {
}
Operator.MORE -> {
when (this) {
is SingleDate -> realmQuery.greaterThanOrEqualTo(
fieldName,
singleValue?.startOfDay() ?: throw PokerAnalyticsException.FilterElementExpectedValueMissing
)
is Duration -> realmQuery.greaterThan(
fieldName,
netDuration ?: throw PokerAnalyticsException.FilterElementExpectedValueMissing
)
is SingleDate -> realmQuery.greaterThanOrEqualTo(fieldName, singleValue.startOfDay())
is Duration -> realmQuery.greaterThan(fieldName, netDuration)
is TournamentFinalPosition -> realmQuery.greaterThanOrEqualTo(fieldName, listOfValues.first())
is TournamentNumberOfPlayer -> realmQuery.greaterThanOrEqualTo(fieldName, listOfValues.first())
is SingleInt -> realmQuery.greaterThan(
fieldName,
singleValue ?: throw PokerAnalyticsException.FilterElementExpectedValueMissing
)
is SingleInt -> realmQuery.greaterThan(fieldName, singleValue)
is ListOfInt -> realmQuery.greaterThan(fieldName, listOfValues.first())
is NetAmountLost -> realmQuery.lessThan(fieldName, listOfValues.first() * -1)
is ListOfDouble -> realmQuery.greaterThan(fieldName, listOfValues.first() * sign)
@ -884,20 +837,11 @@ sealed class QueryCondition : FilterElementRow {
}
Operator.LESS -> {
when (this) {
is SingleDate -> realmQuery.lessThanOrEqualTo(
fieldName,
singleValue?.endOfDay() ?: throw PokerAnalyticsException.FilterElementExpectedValueMissing
)
is Duration -> realmQuery.lessThan(
fieldName,
netDuration ?: throw PokerAnalyticsException.FilterElementExpectedValueMissing
)
is SingleDate -> realmQuery.lessThanOrEqualTo(fieldName, singleValue.endOfDay())
is Duration -> realmQuery.lessThan(fieldName, netDuration)
is TournamentFinalPosition -> realmQuery.lessThanOrEqualTo(fieldName, listOfValues.first())
is TournamentNumberOfPlayer -> realmQuery.lessThanOrEqualTo(fieldName, listOfValues.first())
is SingleInt -> realmQuery.lessThan(
fieldName,
singleValue ?: throw PokerAnalyticsException.FilterElementExpectedValueMissing
)
is SingleInt -> realmQuery.lessThan(fieldName, singleValue)
is ListOfInt -> realmQuery.lessThan(fieldName, listOfValues.first())
is NetAmountLost -> {
realmQuery.greaterThan(fieldName, listOfValues.first() * -1)
@ -947,6 +891,7 @@ sealed class QueryCondition : FilterElementRow {
}
}
override val viewType: Int
get() {
return when (this) {

@ -17,6 +17,7 @@ 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.FilterItemRow
import timber.log.Timber
import java.util.*
@ -89,22 +90,25 @@ open class Filter : RealmObject(), RowRepresentable, Editable, Deletable, Counta
return FilterableType.ALL
}
fun createOrUpdateFilterConditions(filterConditionRows: ArrayList<QueryCondition>) {
Timber.d("list of querys saving: ${filterConditionRows.map { it.id }}")
fun createOrUpdateFilterConditions(filterConditionRows: List<FilterItemRow>) {
Timber.d("list of querys saving: ${filterConditionRows.map { it.queryCondition?.id }}")
Timber.d("list of querys previous: ${this.filterConditions.map { it.queryCondition.id }}")
filterConditionRows
.map {
it.groupId
.mapNotNull {
it.queryCondition?.groupId
}
.distinct()
.forEach { groupId ->
filterConditionRows
.filter {
it.groupId == groupId
it.queryCondition?.groupId == groupId
}
.apply {
Timber.d("list of querys: ${this.map { it.id }}")
val newFilterCondition = FilterCondition(this)
val conditions = this.mapNotNull { it.queryCondition }
Timber.d("list of querys: ${conditions.map { it.id }}")
val newFilterCondition = FilterCondition(conditions, this.first().filterSectionRow)
val previousCondition = filterConditions.filter {
it.filterName == newFilterCondition.filterName && it.operator == newFilterCondition.operator
}
@ -132,19 +136,13 @@ open class Filter : RealmObject(), RowRepresentable, Editable, Deletable, Counta
Timber.d("list of saved queries ${filterConditions.map { it.queryCondition.id }}")
Timber.d("list of contains ${filterElementRow.id}")
val contained = filterConditions.flatMap { it.queryCondition.id }.contains(filterElementRow.id.first())
Timber.d("list of : $contained")
Timber.d("is contained: $contained")
return contained
}
/**
* Get the saved value for the given [filterElementRow]
*/
fun loadValueForElement(filterElementRow: QueryCondition) {
val filtered = filterConditions.filter {
it.queryCondition.id == filterElementRow.id
}
if (filtered.isNotEmpty()) {
return filterElementRow.updateValueBy(filtered.first())
fun filterCondition(filterElementRow: QueryCondition): FilterCondition? {
return filterConditions.firstOrNull {
it.queryCondition.id.contains(filterElementRow.id.first())
}
}

@ -4,17 +4,18 @@ import io.realm.RealmList
import io.realm.RealmObject
import net.pokeranalytics.android.exceptions.PokerAnalyticsException
import net.pokeranalytics.android.model.filter.QueryCondition
import net.pokeranalytics.android.ui.view.rowrepresentable.FilterSectionRow
import java.util.*
import kotlin.collections.ArrayList
open class FilterCondition() : RealmObject() {
private constructor(filterName:String, sectionName:String) : this() {
private constructor(filterName: String, sectionName: String) : this() {
this.filterName = filterName
this.sectionName = sectionName
}
constructor(filterElementRows: List<QueryCondition>) : this(filterElementRows.first().baseId, filterElementRows.first().filterSectionRow.name) {
constructor(filterElementRows: List<QueryCondition>, section: FilterSectionRow) : this(filterElementRows.first().baseId, section.name) {
val row = filterElementRows.first()
this.filterName ?: throw PokerAnalyticsException.FilterElementUnknownName
this.operator = row.operator.ordinal
@ -22,8 +23,8 @@ open class FilterCondition() : RealmObject() {
this.stringValue = row.customFieldId
}
when (row) {
is QueryCondition.SingleInt -> this.setValue(row.singleValue?:throw PokerAnalyticsException.FilterElementExpectedValueMissing)
is QueryCondition.SingleDate -> this.setValue(row.singleValue?:throw PokerAnalyticsException.FilterElementExpectedValueMissing)
is QueryCondition.SingleInt -> this.setValue(row.singleValue)
is QueryCondition.SingleDate -> this.setValue(row.singleValue)
is QueryCondition.ListOfDouble -> this.setValues(filterElementRows.flatMap { (it as QueryCondition.ListOfDouble).listOfValues })
is QueryCondition.ListOfInt -> this.setValues(filterElementRows.flatMap { (it as QueryCondition.ListOfInt).listOfValues })
is QueryCondition.ListOfString -> this.setValues(filterElementRows.flatMap { (it as QueryCondition.ListOfString).listOfValues })
@ -48,7 +49,7 @@ open class FilterCondition() : RealmObject() {
var stringValue: String? = null
var operator: Int? = null
inline fun <reified T:Any > getValues(): ArrayList < T > {
inline fun <reified T> getValues(): ArrayList <T> {
return when (T::class) {
Int::class -> ArrayList<T>().apply { intValues?.map { add(it as T) } }
Double::class -> ArrayList<T>().apply { doubleValues?.map { add(it as T) } }
@ -57,7 +58,17 @@ open class FilterCondition() : RealmObject() {
}
}
inline fun <reified T:Any > getValue(): T {
fun <T> getv(clazz: Class<T>) : T {
return when (clazz) {
Int::class -> intValue ?: 0
Double::class -> doubleValue?: 0.0
Date::class -> dateValue ?: Date()
String::class -> stringValue ?: ""
else -> throw PokerAnalyticsException.QueryValueMapUnexpectedValue
} as T
}
inline fun <reified T> getValue(): T {
return when (T::class) {
Int::class -> intValue ?: 0
Double::class -> doubleValue?: 0.0
@ -91,4 +102,5 @@ open class FilterCondition() : RealmObject() {
fun setValue(value:String) {
stringValue = value
}
}

@ -12,6 +12,7 @@ import android.view.ViewGroup
import android.widget.Toast
import androidx.core.content.FileProvider
import androidx.recyclerview.widget.LinearLayoutManager
import com.android.billingclient.api.Purchase
import com.google.android.play.core.review.ReviewManagerFactory
import io.realm.Realm
import kotlinx.android.synthetic.main.fragment_settings.*
@ -37,6 +38,7 @@ import net.pokeranalytics.android.ui.view.rowrepresentable.SettingRow
import net.pokeranalytics.android.util.*
import net.pokeranalytics.android.util.billing.AppGuard
import net.pokeranalytics.android.util.billing.IAPProducts
import net.pokeranalytics.android.util.billing.PurchaseListener
import net.pokeranalytics.android.util.csv.ProductCSVDescriptors
import net.pokeranalytics.android.util.extensions.dateTimeFileFormatted
import timber.log.Timber
@ -45,7 +47,7 @@ import java.io.IOException
import java.util.*
class SettingsFragment : RealmFragment(), RowRepresentableDelegate, StaticRowRepresentableDataSource {
class SettingsFragment : RealmFragment(), RowRepresentableDelegate, StaticRowRepresentableDataSource, PurchaseListener {
companion object {
@ -69,6 +71,16 @@ class SettingsFragment : RealmFragment(), RowRepresentableDelegate, StaticRowRep
private lateinit var settingsAdapterRow: RowRepresentableAdapter
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
AppGuard.registerListener(this)
}
override fun onDestroy() {
super.onDestroy()
AppGuard.unregisterListener(this)
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
super.onCreateView(inflater, container, savedInstanceState)
return inflater.inflate(R.layout.fragment_settings, container, false)
@ -299,4 +311,12 @@ class SettingsFragment : RealmFragment(), RowRepresentableDelegate, StaticRowRep
}
override fun purchaseDidSucceed(purchase: Purchase) {
this.settingsAdapterRow.refreshRow(SettingRow.SUBSCRIPTION)
}
override fun noPurchaseRetrieved() {
}
}

@ -32,12 +32,12 @@ import net.pokeranalytics.android.ui.fragment.components.ScreenSlidePageFragment
import net.pokeranalytics.android.util.Preferences
import net.pokeranalytics.android.util.billing.AppGuard
import net.pokeranalytics.android.util.billing.IAPProducts
import net.pokeranalytics.android.util.billing.PurchaseDelegate
import net.pokeranalytics.android.util.billing.PurchaseListener
import java.lang.ref.WeakReference
import java.time.Period
import java.time.format.DateTimeParseException
class SubscriptionFragment : BaseFragment(), SkuDetailsResponseListener, PurchaseDelegate, ViewPager.OnPageChangeListener {
class SubscriptionFragment : BaseFragment(), SkuDetailsResponseListener, PurchaseListener, ViewPager.OnPageChangeListener {
companion object {
val parallax: Float = 64f.px
@ -67,6 +67,8 @@ class SubscriptionFragment : BaseFragment(), SkuDetailsResponseListener, Purchas
return
}
AppGuard.registerListener(this)
this.showLoader(R.string.loading_please_wait)
if (!AppGuard.requestProducts(this)) {
this.hideLoader()
@ -86,6 +88,11 @@ class SubscriptionFragment : BaseFragment(), SkuDetailsResponseListener, Purchas
initUI()
}
override fun onDestroy() {
super.onDestroy()
AppGuard.unregisterListener(this)
}
private fun initData() {
this.showSessionMessage = arguments?.getBoolean(BundleKey.SHOW_MESSAGE.value) ?: false
}
@ -133,7 +140,7 @@ class SubscriptionFragment : BaseFragment(), SkuDetailsResponseListener, Purchas
this.purchase.setOnClickListener {
this.selectedProduct?.let {
AppGuard.initiatePurchase(this.requireActivity(), it, this)
AppGuard.initiatePurchase(this.requireActivity(), it)
} ?: run {
throw PAIllegalStateException("Attempt to initiate purchase while no product has been chosen")
}
@ -236,6 +243,10 @@ class SubscriptionFragment : BaseFragment(), SkuDetailsResponseListener, Purchas
this.activity?.finish()
}
override fun noPurchaseRetrieved() {
}
// OnPageChangeListener
override fun onPageScrollStateChanged(state: Int) {}

@ -144,7 +144,7 @@ abstract class BaseFragment : Fragment() {
isClearable: Boolean? = true,
currentCurrency: Currency? = null,
isDeletable: Boolean? = false,
valueHasPlaceholder: Boolean? = null,
valueHasPlaceholder: Boolean? = true,
alternativeLabels: Boolean = false) {
BottomSheetFragment.create(activity as BaseActivity,

@ -29,7 +29,7 @@ class BottomSheetEditTextFragment : BottomSheetFragment() {
*/
private fun initUI() {
val data = getDescriptors() ?: throw RowRepresentableEditDescriptorException("RowRepresentableEditDescriptor not found")
val data = getDescriptors() ?: throw RowRepresentableEditDescriptorException("RowRepresentableEditDescriptor not found for $this")
if (data.size != 1) {
throw RowRepresentableEditDescriptorException("RowRepresentableEditDescriptor inconsistency")
}

@ -60,7 +60,7 @@ open class BottomSheetFragment : BottomSheetDialogFragment() {
isClearable: Boolean? = true,
currentCurrency: Currency? = null,
isDeletable: Boolean? = false,
valueHasPlaceholder: Boolean? = null,
valueHasPlaceholder: Boolean? = true,
alternativeLabels: Boolean = false
): BottomSheetFragment {
val bottomSheetFragment = newInstance(row.bottomSheetType)

@ -3,7 +3,7 @@ package net.pokeranalytics.android.ui.modules.calendar
import android.content.Context
import android.content.Intent
import android.os.Bundle
import androidx.lifecycle.ViewModelProviders
import androidx.lifecycle.ViewModelProvider
import net.pokeranalytics.android.R
import net.pokeranalytics.android.calculus.ComputedResults
import net.pokeranalytics.android.model.filter.QueryCondition
@ -13,7 +13,7 @@ import net.pokeranalytics.android.ui.activity.components.BaseActivity
class CalendarDetailsActivity : BaseActivity() {
private val model: CalendarDetailsViewModel by lazy {
ViewModelProviders.of(this).get(CalendarDetailsViewModel::class.java)
ViewModelProvider(this).get(CalendarDetailsViewModel::class.java)
}
companion object {

@ -8,6 +8,7 @@ import android.widget.Toast
import androidx.core.app.ActivityOptionsCompat
import androidx.core.view.isVisible
import androidx.interpolator.view.animation.FastOutSlowInInterpolator
import com.android.billingclient.api.Purchase
import com.google.android.material.tabs.TabLayout
import io.realm.RealmModel
import io.realm.RealmResults
@ -37,11 +38,12 @@ import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.SmoothScrollLinearLayoutManager
import net.pokeranalytics.android.util.Preferences
import net.pokeranalytics.android.util.billing.AppGuard
import net.pokeranalytics.android.util.billing.PurchaseListener
import net.pokeranalytics.android.util.extensions.count
import timber.log.Timber
import java.util.*
class FeedFragment : FilterableFragment(), RowRepresentableDelegate {
class FeedFragment : FilterableFragment(), RowRepresentableDelegate, PurchaseListener {
private enum class Tab {
SESSIONS,
@ -104,6 +106,11 @@ class FeedFragment : FilterableFragment(), RowRepresentableDelegate {
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
AppGuard.registerListener(this)
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
@ -205,6 +212,11 @@ class FeedFragment : FilterableFragment(), RowRepresentableDelegate {
}
override fun onDestroy() {
AppGuard.unregisterListener(this)
super.onDestroy()
}
override fun onDestroyView() {
super.onDestroyView()
realmTransactions.removeAllChangeListeners()
@ -313,7 +325,6 @@ class FeedFragment : FilterableFragment(), RowRepresentableDelegate {
this.showSubscriptionButton()
}
}
this.showSubscriptionButton()
}
@ -419,11 +430,7 @@ class FeedFragment : FilterableFragment(), RowRepresentableDelegate {
/**
* Create a new cash game
*/
private fun createNewSession(
isTournament: Boolean,
sessionId: String? = null,
duplicate: Boolean = false
) {
private fun createNewSession(isTournament: Boolean, sessionId: String? = null, duplicate: Boolean = false) {
val sessionCount = getRealm().count(Session::class.java)
if (!AppGuard.isProUser && sessionCount >= AppGuard.MAX_SESSIONS_BEFORE_REQUESTING_SUBSCRIPTION) { // && !BuildConfig.DEBUG
@ -473,10 +480,6 @@ class FeedFragment : FilterableFragment(), RowRepresentableDelegate {
*/
private fun createNewHandHistory() {
// val intent = Intent(requireContext(), TestActivity::class.java)
// startActivity(intent)
// return
AppGuard.endOfUse?.let { endDate ->
if (Date().after(endDate)) {
this.showEndOfUseMessage()
@ -577,4 +580,12 @@ class FeedFragment : FilterableFragment(), RowRepresentableDelegate {
this.sessionAdapter.notifyDataSetChanged() // refreshes session durations
}
override fun purchaseDidSucceed(purchase: Purchase) {
this.showSubscriptionButton()
}
override fun noPurchaseRetrieved() {
this.showSubscriptionButton()
}
}

@ -1,6 +1,5 @@
package net.pokeranalytics.android.ui.modules.filter
import android.content.Context
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
@ -10,34 +9,38 @@ import androidx.recyclerview.widget.LinearLayoutManager
import kotlinx.android.synthetic.main.fragment_filter_details.*
import kotlinx.android.synthetic.main.fragment_filter_details.view.*
import net.pokeranalytics.android.R
import net.pokeranalytics.android.exceptions.PAIllegalStateException
import net.pokeranalytics.android.model.filter.QueryCondition
import net.pokeranalytics.android.ui.adapter.RowRepresentableAdapter
import net.pokeranalytics.android.ui.adapter.RowRepresentableDelegate
import net.pokeranalytics.android.ui.adapter.StaticRowRepresentableDataSource
import net.pokeranalytics.android.ui.fragment.components.RealmFragment
import net.pokeranalytics.android.ui.helpers.DateTimePickerManager
import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.RowViewType
import net.pokeranalytics.android.ui.view.rowrepresentable.FilterElementRow
import net.pokeranalytics.android.ui.view.rowrepresentable.FilterSectionRow
import net.pokeranalytics.android.util.NULL_TEXT
import net.pokeranalytics.android.ui.view.rowrepresentable.*
import timber.log.Timber
import java.util.*
import kotlin.collections.ArrayList
open class FilterDetailsFragment : RealmFragment(), StaticRowRepresentableDataSource, RowRepresentableDelegate {
open class FilterDetailsFragment : RealmFragment(), RowRepresentableDelegate {
val model: FilterViewModel by lazy {
private val activityModel: FilterViewModel by lazy {
ViewModelProvider(requireActivity()).get(FilterViewModel::class.java)
}
private lateinit var model: FilterDetailsViewModel
private lateinit var rowRepresentableAdapter: RowRepresentableAdapter
// private var currentFilter: Filter? = null
private var rows: ArrayList<RowRepresentable> = ArrayList()
private var rowsForFilterSubcategoryRow: HashMap<FilterSectionRow, ArrayList<RowRepresentable>> = HashMap()
companion object {
private val selectedRows = ArrayList<QueryCondition>()
fun newInstance(categoryRow: FilterCategoryRow): FilterDetailsFragment {
val fragment = FilterDetailsFragment()
val bundle = Bundle()
bundle.putInt(BundleKey.DATA_TYPE.value, categoryRow.ordinal)
fragment.arguments = bundle
return fragment
}
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
super.onCreateView(inflater, container, savedInstanceState)
@ -53,11 +56,8 @@ open class FilterDetailsFragment : RealmFragment(), StaticRowRepresentableDataSo
override fun onBackPressed() {
super.onBackPressed()
saveData()
// requireFragmentManager().popBackStackImmediate("f1", 0)
// requireFragmentManager().popBackStackImmediate()
}
/**
* Init UI
*/
@ -80,39 +80,24 @@ open class FilterDetailsFragment : RealmFragment(), StaticRowRepresentableDataSo
*/
private fun initData() {
// this.arguments?.let { bundle ->
//
// bundle.getString(BundleKey.PRIMARY_KEY.value)?.let { filterId ->
// this.currentFilter = getRealm().findById(filterId)
// }
//
// val category = bundle.getInt(BundleKey.DATA_TYPE.value)
// this.filterCategoryRow = FilterCategoryRow.values()[category]
//
// } ?: throw PAIllegalStateException("Missing bundle")
//currentFilter = Filter.getFilterBydId(getRealm(), primaryKey)
// currentFilter = FiltersFragment.currentFilter
this.arguments?.let { bundle ->
Timber.d(">> Filter = ${this.model.currentFilter}")
Timber.d("selectedRow = ${this.model.selectedCategoryRow}")
val filter = this.activityModel.currentFilter ?: throw PAIllegalStateException("Filter is null")
val category = bundle.getInt(BundleKey.DATA_TYPE.value)
val categoryRow = FilterCategoryRow.values()[category]
Timber.d("Category row = $categoryRow")
val filterCategoryRow = this.model.filterCategoryRow
val factory = FilterDetailsViewModelFactory(filter, categoryRow)
this.model = ViewModelProvider(this, factory).get(FilterDetailsViewModel::class.java)
this.appBar.toolbar.title = filterCategoryRow.localizedTitle(requireContext())
} ?: throw PAIllegalStateException("Missing bundle")
this.rows.clear()
this.rowsForFilterSubcategoryRow.clear()
this.rows.addAll(filterCategoryRow.filterElements)
Timber.d(">> Filter = ${this.activityModel.currentFilter}")
Timber.d("selectedRow = ${this.activityModel.selectedCategoryRow}")
this.rows.forEach { element ->
if (element is QueryCondition && this.model.currentFilter?.contains(element) == true) {
this.model.currentFilter?.loadValueForElement(element)
this.selectedRows.add(element)
}
}
this.appBar.toolbar.title = this.activityModel.selectedCategoryRow?.localizedTitle(requireContext())
this.rowRepresentableAdapter = RowRepresentableAdapter(this, this)
this.rowRepresentableAdapter = RowRepresentableAdapter(this.model, this)
this.recyclerView.adapter = rowRepresentableAdapter
}
@ -124,49 +109,31 @@ open class FilterDetailsFragment : RealmFragment(), StaticRowRepresentableDataSo
return
}
when (row) {
(row as? FixedValueFilterItemRow)?.let {
when (val condition = it.rawCondition) {
is QueryCondition.DateQuery -> DateTimePickerManager.create(
requireContext(),
row,
this,
row.singleValue,
onlyDate = !row.showTime,
onlyTime = row.showTime
(row as DateFilterItemRow).value,
onlyDate = !condition.showTime,
onlyTime = condition.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 hours = (condition.minutes / 60).toString()
val minutes = (condition.minutes % 60).toString()
val data = row.editingDescriptors(mapOf("hours" to hours, "minutes" to minutes))
showBottomSheet(row, this, data, true)
}
is QueryCondition.ListOfValues<*> -> {
var valueAsString: String? = null
row.listOfValues.firstOrNull()?.let {
valueAsString = row.listOfValues.firstOrNull()?.toString()
}
is QueryCondition.SingleValue<*>, is QueryCondition.ListOfValues<*> -> {
val valueAsString = (row as FilterItemRow).singleValue?.toString()
val data = row.editingDescriptors(mapOf("valueAsString" to valueAsString))
showBottomSheet(row, this, data, true)
showBottomSheet(row, this, data, true, valueHasPlaceholder = true)
}
else -> { }
}
}
override fun charSequenceForRow(row: RowRepresentable, context: Context): CharSequence {
return when (row) {
is QueryCondition.ListOfValues<*> -> row.firstValue(context)
else -> super.charSequenceForRow(row, context, 0)
} ?: NULL_TEXT
}
override fun isSelected(
position: Int,
row: RowRepresentable,
tag: Int
): Boolean {
return selectedRows.contains(row)
}
override fun onRowValueChanged(value: Any?, row: RowRepresentable) {
@ -174,9 +141,15 @@ open class FilterDetailsFragment : RealmFragment(), StaticRowRepresentableDataSo
Timber.d("onRowValueChanged: $row $value")
when (row) {
is QueryCondition.DateQuery -> row.singleValue = if (value != null && value is Date) value else null
is QueryCondition.Duration -> {
if (value is ArrayList<*>) {
is DateFilterItemRow -> {
row.value = value as? Date
}
is IntFilterItemRow -> {
when (value) {
is String -> {
row.value = value.toInt()
}
is ArrayList<*> -> {
val hours: Int? = try {
(value[0] as String?)?.toInt()
} catch (e: Exception) {
@ -188,66 +161,41 @@ open class FilterDetailsFragment : RealmFragment(), StaticRowRepresentableDataSo
null
}
if (hours != null && minutes != null) {
row.minutes = hours * 60 + minutes
row.value = hours * 60 + minutes
} else if (hours != null) {
row.minutes = hours * 60
row.value = hours * 60
} else if (minutes != null) {
row.minutes = minutes
row.value = minutes
}
}
} else {
row.minutes = null
else -> { row.value = null }
}
}
is QueryCondition.SingleInt -> row.singleValue = if (value != null && value is String) value.toInt() else null
is QueryCondition.ListOfDouble -> row.listOfValues = arrayListOf<Double>().apply {
if (value != null && value is String) this.add(value.toDouble())
is DoubleValueListFilterItemRow -> {
val string = value as String
row.add(string.toDouble())
}
is QueryCondition.ListOfInt -> row.listOfValues = arrayListOf<Int>().apply {
if (value != null && value is String) this.add(value.toInt())
is IntValueListFilterItemRow -> {
val string = value as String
row.add(string.toInt())
}
is QueryCondition.ListOfString -> row.listOfValues = arrayListOf<String>().apply {
if (value != null && value is String) this.add(value)
is StringValueListFilterItemRow -> {
row.add(value as String)
}
}
// Remove the row before updating the selected rows list
selectedRows.remove(row as FilterElementRow)
this.model.selectedRows.remove(row as FilterItemRow)
updateRowsSelection(row, value == null)
}
override fun adapterRows(): List<RowRepresentable>? {
return rows
}
override fun viewTypeForPosition(position: Int): Int {
val rowViewType = rowRepresentableForPosition(position)?.viewType ?: -1
return if (rowViewType != -1) rowViewType else RowViewType.TITLE_CHECK.ordinal
}
/**
* Update rows selection
*/
private fun updateRowsSelection(row: RowRepresentable, forceDeselection: Boolean = false) {
if (selectedRows.contains(row) || forceDeselection) {
selectedRows.remove(row)
} else {
if (row is FilterElementRow) {
row.sectionToExclude?.let { filterSectionToExclude ->
val excludedFilters = selectedRows.filter {
filterSectionToExclude.contains(it.filterSectionRow)
}
excludedFilters.forEach {
selectedRows.remove(it)
rowRepresentableAdapter.refreshRow(it)
}
}
selectedRows.add(row as QueryCondition)
}
}
println("list of selected rows : $selectedRows")
this.model.updateRowsSelection(this.rowRepresentableAdapter, row, forceDeselection)
// Update UI
this.rowRepresentableAdapter.refreshRow(row)
@ -258,18 +206,23 @@ open class FilterDetailsFragment : RealmFragment(), StaticRowRepresentableDataSo
*/
private fun saveData() {
val currentFilter = this.model.currentFilter
val currentFilter = this.activityModel.currentFilter
//TODO: Save currentFilter details data
Timber.d("Save data for queryWith: ${currentFilter?.id}")
this.selectedRows.forEach {
this.model.selectedRows.forEach {
Timber.d("Selected rows: $it")
}
this.activityModel.selectedCategoryRow?.let { category ->
getRealm().executeTransaction {
currentFilter?.remove(this.model.filterCategoryRow)
currentFilter?.createOrUpdateFilterConditions(this.selectedRows)
currentFilter?.remove(category)
val validConditions = this.model.selectedRows.filter { it.queryCondition != null }
currentFilter?.createOrUpdateFilterConditions(validConditions)
}
}
currentFilter?.filterConditions?.forEach {
Timber.d("Condition: $it")
}

@ -0,0 +1,96 @@
package net.pokeranalytics.android.ui.modules.filter
import android.content.Context
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import net.pokeranalytics.android.model.realm.Filter
import net.pokeranalytics.android.ui.adapter.RowRepresentableAdapter
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.FilterCategoryRow
import net.pokeranalytics.android.ui.view.rowrepresentable.FilterItemRow
import net.pokeranalytics.android.util.NULL_TEXT
import timber.log.Timber
class FilterDetailsViewModelFactory(var filter: Filter, private var categoryRow: FilterCategoryRow): ViewModelProvider.Factory {
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
return FilterDetailsViewModel(categoryRow, filter) as T
}
}
class FilterDetailsViewModel(categoryRow: FilterCategoryRow, var filter: Filter) : ViewModel(), StaticRowRepresentableDataSource {
private var rows: ArrayList<RowRepresentable> = ArrayList()
val selectedRows = ArrayList<FilterItemRow>()
init {
this.rows.addAll(categoryRow.filterElements)
this.defineSelectedItems()
}
override fun adapterRows(): List<RowRepresentable>? {
return this.rows
}
override fun charSequenceForRow(row: RowRepresentable, context: Context): CharSequence {
return when (row) {
is FilterItemRow -> {
row.valueFormatted(context)
}
else -> super.charSequenceForRow(row, context, 0)
} ?: NULL_TEXT
}
override fun isSelected(position: Int, row: RowRepresentable, tag: Int): Boolean {
return this.selectedRows.contains(row)
}
override fun viewTypeForPosition(position: Int): Int {
val rowRepresentable = rowRepresentableForPosition(position)
val rowViewType = rowRepresentable?.viewType ?: -1
// Timber.d("found viewtype = $rowViewType, rr = $rowRepresentable")
return if (rowViewType != -1) rowViewType else RowViewType.TITLE_CHECK.ordinal
}
private fun defineSelectedItems() {
this.rows.filterIsInstance<FilterItemRow>().forEach { item ->
val condition = item.rawCondition
Timber.d("condition id: ${condition.id}")
this.filter.filterCondition(condition)?.let {
item.updateValue(it)
this.selectedRows.add(item)
}
}
}
fun updateRowsSelection(adapter: RowRepresentableAdapter, row: RowRepresentable, forceDeselection: Boolean = false) {
if (this.selectedRows.contains(row) || forceDeselection) {
this.selectedRows.remove(row)
} else {
if (row is FilterItemRow) {
row.sectionToExclude?.let { filterSectionToExclude ->
val excludedFilters = this.selectedRows.filter {
filterSectionToExclude.contains(it.filterSectionRow)
}
excludedFilters.forEach {
this.selectedRows.remove(it)
adapter.refreshRow(it)
}
}
this.selectedRows.add(row)
}
}
}
}

@ -34,6 +34,7 @@ enum class FilterableType(override var uniqueIdentifier: Int) : IntIdentifiable
}
interface FilterHandler {
companion object {
const val INTENT_FILTER_UPDATE_FILTER_UI = "net.pokeranalytics.android.UPDATE_FILTER_UI"
}
@ -55,8 +56,7 @@ interface FilterHandler {
// Send broadcast
val intent = Intent()
intent.action =
INTENT_FILTER_UPDATE_FILTER_UI
intent.action = INTENT_FILTER_UPDATE_FILTER_UI
context.sendBroadcast(intent)
}
@ -70,7 +70,6 @@ interface FilterHandler {
var currentFilterable: FilterableType
/**
* Manage filters
*/

@ -20,14 +20,10 @@ class FilterViewModel : ViewModel(), StaticRowRepresentableDataSource {
var filterCopy: Filter? = null
private var categoryRows: ArrayList<RowRepresentable> = ArrayList()
var primaryKey: String? = null
var selectedCategoryRow: RowRepresentable? = null
var isUpdating = false
// Details
val filterCategoryRow: FilterCategoryRow
get() {
return this.selectedCategoryRow as FilterCategoryRow
}
var selectedCategoryRow: FilterCategoryRow? = null
var isUpdating = false
fun init(realm: Realm) {

@ -6,8 +6,10 @@ import android.os.Bundle
import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModelProvider
import net.pokeranalytics.android.R
import net.pokeranalytics.android.model.realm.Filter
import net.pokeranalytics.android.ui.activity.components.BaseActivity
import net.pokeranalytics.android.ui.fragment.components.BaseFragment
import net.pokeranalytics.android.ui.view.rowrepresentable.FilterCategoryRow
class FiltersActivity : BaseActivity() {
@ -88,23 +90,17 @@ class FiltersActivity : BaseActivity() {
this.model.filterableType = FilterableType.valueByIdentifier(uniqueIdentifier)
val filtersFragment = FiltersFragment()
// val bundle = Bundle()
// bundle.putString(BaseFragment.BundleKey.PRIMARY_KEY.value, filterId)
// bundle.putInt(BaseFragment.BundleKey.DATA_TYPE.value, uniqueIdentifier)
// fragment.arguments = bundle
// fragment.setData(filterId, filterableType)
val fragmentTransaction = this.supportFragmentManager.beginTransaction()
fragmentTransaction.add(R.id.container, filtersFragment, Tag.CATEGORIES.identifier)
// fragmentTransaction.addToBackStack(null)
fragmentTransaction.commit()
filtersFragment.updateMostUsedFiltersVisibility(!hideMostUsedFilters)
}
fun showDetailsFragment() {
fun showDetailsFragment(categoryRow: FilterCategoryRow) {
val detailsFragment = FilterDetailsFragment()
val detailsFragment = FilterDetailsFragment.newInstance(categoryRow)
val fragmentTransaction = this.supportFragmentManager.beginTransaction()
fragmentTransaction.replace(R.id.container, detailsFragment)

@ -21,6 +21,7 @@ import net.pokeranalytics.android.ui.adapter.RowRepresentableDelegate
import net.pokeranalytics.android.ui.extensions.px
import net.pokeranalytics.android.ui.fragment.components.RealmFragment
import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.rowrepresentable.FilterCategoryRow
import net.pokeranalytics.android.util.Preferences
import net.pokeranalytics.android.util.extensions.sorted
import timber.log.Timber
@ -78,9 +79,6 @@ open class FiltersFragment : RealmFragment(), RowRepresentableDelegate {
this.model.selectedCategoryRow?.let {
rowRepresentableAdapter.refreshRow(it)
}
// this.rowRepresentableAdapter.notifyDataSetChanged()
}
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
@ -132,12 +130,6 @@ open class FiltersFragment : RealmFragment(), RowRepresentableDelegate {
*/
private fun initData() {
// this.arguments?.let { bundle ->
// this.model.primaryKey = bundle.getString(BundleKey.PRIMARY_KEY.value)
// val type = bundle.getInt(BundleKey.DATA_TYPE.value)
// this.model.filterableType = FilterableType.valueByIdentifier(type)
// } ?: throw PAIllegalStateException("Missing bundle")
this.model.init(getRealm())
this.rowRepresentableAdapter = RowRepresentableAdapter(this.model, this)
@ -148,17 +140,10 @@ open class FiltersFragment : RealmFragment(), RowRepresentableDelegate {
override fun onRowSelected(position: Int, row: RowRepresentable, tag: Int) {
super.onRowSelected(position, row, tag)
this.model.selectedCategoryRow = row
this.model.currentFilter?.id?.let { _ ->
(activity as FiltersActivity).showDetailsFragment()
// this.model.filterCategoryRow = row as FilterCategoryRow
// FilterDetailsActivity.newInstanceForResult(
// this, filterId, (row as FilterCategoryRow).ordinal,
// REQUEST_CODE_FILTER_DETAILS
// )
val categoryRow = row as FilterCategoryRow
this.model.selectedCategoryRow = categoryRow
this.model.currentFilter?.let { _ ->
(activity as FiltersActivity).showDetailsFragment(categoryRow)
}
}

@ -24,15 +24,6 @@ class FiltersListActivity : BaseActivity() {
companion object {
// fun newInstance(context: Context, dataType: Int) {
// context.startActivity(
// getIntent(
// context,
// dataType
// )
// )
// }
fun newSelectInstance(fragment: Fragment, showAddButton: Boolean = true) {
val context = fragment.requireContext()
fragment.startActivityForResult(
@ -74,8 +65,6 @@ class FiltersListActivity : BaseActivity() {
this.model.showAddButton = showAddButton
// fragment.setData(dataType)
// fragment.updateUI(showAddButton)
}
}

@ -63,7 +63,13 @@ enum class FilterCategoryRow(override val resId: Int?, override val viewType: In
val filterElements: List<RowRepresentable>
get() {
return filterSectionRows.flatMap {
it.filterElements
val items = it.filterItems
val list = mutableListOf<RowRepresentable>()
if (items.isNotEmpty()) {
list.add(it)
list.addAll(it.filterItems)
}
list
}
}

@ -1,61 +0,0 @@
package net.pokeranalytics.android.ui.view.rowrepresentable
import android.text.InputType
import net.pokeranalytics.android.R
import net.pokeranalytics.android.model.filter.QueryCondition
import net.pokeranalytics.android.ui.fragment.components.bottomsheet.BottomSheetType
import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.RowRepresentableEditDescriptor
import net.pokeranalytics.android.ui.view.RowViewType
import java.util.*
interface FilterElementRow : RowRepresentable {
override fun editingDescriptors(map: Map<String, Any?>): ArrayList<RowRepresentableEditDescriptor>? {
return when (this) {
is QueryCondition.Duration -> {
val hours: String? by map
val minutes: String? by map
arrayListOf(
RowRepresentableEditDescriptor(hours, R.string.hour, inputType = InputType.TYPE_CLASS_NUMBER),
RowRepresentableEditDescriptor(minutes, R.string.minute, inputType = InputType.TYPE_CLASS_NUMBER)
)
}
is QueryCondition.ListOfValues<*> -> {
val valueAsString: String? by map
val hint = when (this.operator) {
QueryCondition.Operator.MORE, QueryCondition.Operator.LESS -> {
when (this) {
is QueryCondition.CustomFieldNumberQuery -> R.string.value
is QueryCondition.CustomFieldAmountQuery -> R.string.amount
else -> this.filterSectionRow.resId
}
}
else -> this.resId
}
arrayListOf(
RowRepresentableEditDescriptor(valueAsString, hint, inputType = InputType.TYPE_CLASS_NUMBER)
)
}
else -> super.editingDescriptors(map)
}
}
var filterSectionRow: FilterSectionRow
val sectionToExclude: List<FilterSectionRow>?
get() {
val excluded = arrayListOf<FilterSectionRow>()
if (!this.filterSectionRow.allowMultiSelection) {
excluded.add(this.filterSectionRow)
}
this.filterSectionRow.exclusiveWith?.let { exclusives ->
excluded.addAll(exclusives)
}
if (excluded.size > 0) {
return excluded
}
return null
}
}

@ -0,0 +1,197 @@
package net.pokeranalytics.android.ui.view.rowrepresentable
import android.content.Context
import android.text.InputType
import net.pokeranalytics.android.R
import net.pokeranalytics.android.exceptions.PAIllegalStateException
import net.pokeranalytics.android.model.filter.QueryCondition
import net.pokeranalytics.android.model.realm.FilterCondition
import net.pokeranalytics.android.ui.fragment.components.bottomsheet.BottomSheetType
import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.RowRepresentableEditDescriptor
import net.pokeranalytics.android.util.NULL_TEXT
import java.util.*
interface FilterItemRow : RowRepresentable {
val rawCondition: QueryCondition
val queryCondition: QueryCondition?
var filterSectionRow: FilterSectionRow
fun updateValue(fc: FilterCondition) { }
/***
* The formatted value at the right of the table cell
*/
fun valueFormatted(context: Context): CharSequence?
/***
* The value at the right of the table cell
*/
val singleValue: Any?
val sectionToExclude: List<FilterSectionRow>?
get() {
val excluded = arrayListOf<FilterSectionRow>()
if (!this.filterSectionRow.allowMultiSelection) {
excluded.add(this.filterSectionRow)
}
this.filterSectionRow.exclusiveWith?.let { exclusives ->
excluded.addAll(exclusives)
}
if (excluded.size > 0) {
return excluded
}
return null
}
// Row Representable
override fun getDisplayName(context: Context): String {
return this.rawCondition.getDisplayName(context)
}
override val resId: Int?
get() { return this.rawCondition.resId }
override val viewType: Int
get() { return this.rawCondition.viewType }
override val bottomSheetType: BottomSheetType
get() { return this.rawCondition.bottomSheetType }
override fun editingDescriptors(map: Map<String, Any?>): ArrayList<RowRepresentableEditDescriptor>? {
return when (this.rawCondition) {
is QueryCondition.Duration -> {
val hours: String? by map
val minutes: String? by map
arrayListOf(
RowRepresentableEditDescriptor(hours, R.string.hour, inputType = InputType.TYPE_CLASS_NUMBER),
RowRepresentableEditDescriptor(minutes, R.string.minute, inputType = InputType.TYPE_CLASS_NUMBER)
)
}
is QueryCondition.SingleValue<*>, is QueryCondition.ListOfValues<*> -> {
val valueAsString: String? by map
val hint = when (this.queryCondition?.operator) {
QueryCondition.Operator.MORE, QueryCondition.Operator.LESS -> {
when (this.queryCondition) {
is QueryCondition.CustomFieldNumberQuery -> R.string.value
is QueryCondition.CustomFieldAmountQuery -> R.string.amount
else -> this.filterSectionRow.resId
}
}
else -> this.resId
}
arrayListOf(
RowRepresentableEditDescriptor(valueAsString, hint, inputType = InputType.TYPE_CLASS_NUMBER)
)
}
else -> super.editingDescriptors(map)
}
}
}
open class FixedValueFilterItemRow(queryCondition: QueryCondition,
override var filterSectionRow: FilterSectionRow) : FilterItemRow {
override val rawCondition: QueryCondition = queryCondition
override val queryCondition: QueryCondition?
get() { return rawCondition }
override fun valueFormatted(context: Context): CharSequence? {
throw PAIllegalStateException("Not applicable for $rawCondition")
}
override val singleValue: Any?
get() { throw PAIllegalStateException("Not applicable for $rawCondition") }
}
abstract class ValueFilterItemRow<T: Comparable<T>>(queryCondition: QueryCondition.SingleValue<T>, filterSectionRow: FilterSectionRow): FixedValueFilterItemRow(queryCondition, filterSectionRow) {
private var valueCondition: QueryCondition.SingleValue<T> = queryCondition
var value: T? = null
override val queryCondition: QueryCondition?
get() {
value?.let {
valueCondition.singleValue = it
return valueCondition
}
return null
}
override fun valueFormatted(context: Context): CharSequence? {
(this.queryCondition as? QueryCondition.SingleValue<T>)?.let {
return it.labelForValue(it.singleValue, context)
}
return NULL_TEXT
}
override val singleValue: Any?
get() {
return this.value
}
override fun updateValue(fc: FilterCondition) {
val queryCondition = fc.queryCondition as QueryCondition.SingleValue<T>
this.value = queryCondition.singleValue
}
}
abstract class ValueListFilterItemRow<T: Comparable<T>>(queryCondition: QueryCondition.ListOfValues<T>, filterSectionRow: FilterSectionRow)
: FixedValueFilterItemRow(queryCondition, filterSectionRow) {
private var listCondition: QueryCondition.ListOfValues<T> = queryCondition
var list: MutableList<T> = mutableListOf()
private set
fun add(value: T) {
this.list.add(value)
}
override val queryCondition: QueryCondition?
get() {
return if (list.isNotEmpty()) {
listCondition.listOfValues = list
listCondition
} else {
null
}
}
override fun valueFormatted(context: Context): CharSequence? {
(this.queryCondition as? QueryCondition.ListOfValues<T>)?.let {
return it.labelForValue(this.list.first(), context)
}
return NULL_TEXT
}
override val singleValue: Any?
get() {
return this.list.firstOrNull()
}
override fun updateValue(fc: FilterCondition) {
val queryCondition = fc.queryCondition as QueryCondition.ListOfValues<T>
this.list = queryCondition.listOfValues
}
}
class DateFilterItemRow(queryCondition: QueryCondition.SingleDate, filterSectionRow: FilterSectionRow): ValueFilterItemRow<Date>(queryCondition, filterSectionRow)
class IntFilterItemRow(queryCondition: QueryCondition.SingleInt, filterSectionRow: FilterSectionRow): ValueFilterItemRow<Int>(queryCondition, filterSectionRow)
class IntValueListFilterItemRow(queryCondition: QueryCondition.ListOfInt, filterSectionRow: FilterSectionRow): ValueListFilterItemRow<Int>(queryCondition, filterSectionRow)
class DoubleValueListFilterItemRow(queryCondition: QueryCondition.ListOfDouble, filterSectionRow: FilterSectionRow): ValueListFilterItemRow<Double>(queryCondition, filterSectionRow)
class StringValueListFilterItemRow(queryCondition: QueryCondition.ListOfString, filterSectionRow: FilterSectionRow): ValueListFilterItemRow<String>(queryCondition, filterSectionRow)

@ -8,6 +8,7 @@ import net.pokeranalytics.android.model.filter.QueryCondition
import net.pokeranalytics.android.model.filter.mapFirstCondition
import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.RowViewType
import java.util.*
sealed class FilterSectionRow(override val resId: Int?) : RowRepresentable {
object CashOrTournament: FilterSectionRow(R.string.cash_or_tournament)
@ -69,13 +70,38 @@ sealed class FilterSectionRow(override val resId: Int?) : RowRepresentable {
val allowMultiSelection: Boolean
get() = (this.selectionType == SelectionType.MULTIPLE)
val filterElements: List<RowRepresentable>
val filterItems: List<FilterItemRow>
get() {
val data = arrayListOf<RowRepresentable>().apply {
this.addAll(
when (this@FilterSectionRow) {
return this.queryConditions.map {
rowWrapper(it, this@FilterSectionRow)
// it.toRowWrapper(this@FilterSectionRow)
}
}
private fun rowWrapper(queryCondition: QueryCondition, section: FilterSectionRow): FilterItemRow {
return when (queryCondition) {
// Int List
is QueryCondition.TournamentFinalPosition -> IntValueListFilterItemRow(queryCondition, section)
is QueryCondition.TournamentNumberOfPlayer -> IntValueListFilterItemRow(queryCondition, section)
// Double List
is QueryCondition.NumberOfRebuy -> DoubleValueListFilterItemRow(queryCondition, section)
is QueryCondition.NetAmount -> DoubleValueListFilterItemRow(queryCondition, section)
// Int
is QueryCondition.PastDay -> IntFilterItemRow(queryCondition, section)
is QueryCondition.Duration -> IntFilterItemRow(queryCondition, section)
// Dates
is QueryCondition.StartedFromDate -> DateFilterItemRow(queryCondition, section)
is QueryCondition.StartedFromTime -> DateFilterItemRow(queryCondition, section)
is QueryCondition.StartedToDate -> DateFilterItemRow(queryCondition, section)
is QueryCondition.EndedToDate -> DateFilterItemRow(queryCondition, section)
is QueryCondition.EndedToTime -> DateFilterItemRow(queryCondition, section)
else -> FixedValueFilterItemRow(queryCondition, section)
}
}
private val queryConditions: List<QueryCondition>
get() {
return when (this@FilterSectionRow) {
// General
CashOrTournament -> Criteria.SessionTypes.queryConditions.mapFirstCondition()
LiveOrOnline -> Criteria.BankrollTypes.queryConditions.mapFirstCondition()
@ -91,8 +117,6 @@ sealed class FilterSectionRow(override val resId: Int?) : RowRepresentable {
QueryCondition.DuringThisMonth,
QueryCondition.DuringThisYear
)
FixedDate -> arrayListOf(QueryCondition.StartedFromDate(), QueryCondition.EndedToDate())
Duration -> arrayListOf(QueryCondition.PastDay())
WeekdayOrWeekend -> arrayListOf(QueryCondition.IsWeekDay, QueryCondition.IsWeekEnd)
Year -> Criteria.Years.queryConditions.mapFirstCondition()
DayOfWeek -> Criteria.DaysOfWeek.queryConditions.mapFirstCondition()
@ -100,7 +124,10 @@ sealed class FilterSectionRow(override val resId: Int?) : RowRepresentable {
// Duration
SessionDuration -> QueryCondition.moreOrLess<QueryCondition.Duration>()
TimeFrameRange -> arrayListOf(QueryCondition.StartedFromTime(), QueryCondition.EndedToTime())
FixedDate -> arrayListOf(QueryCondition.StartedFromDate(Date()), QueryCondition.EndedToDate(Date())) // dummy constructor values
Duration -> arrayListOf(QueryCondition.PastDay(0)) // dummy constructor values
TimeFrameRange -> arrayListOf(QueryCondition.StartedFromTime(Date()), QueryCondition.EndedToTime(Date())) // dummy constructor values
// Sessions
//Sessions -> arrayListOf(QueryCondition.LastGame(), QueryCondition.LastSession())
@ -132,15 +159,18 @@ sealed class FilterSectionRow(override val resId: Int?) : RowRepresentable {
TransactionType -> Criteria.TransactionTypes.queryConditions.mapFirstCondition()
is CustomField -> {
val cf = this@FilterSectionRow.customField
if (cf.isListType) {
when {
cf.isListType -> {
Criteria.ListCustomFields(cf.id).queryConditions.mapFirstCondition()
} else if (cf.isAmountType) {
}
cf.isAmountType -> {
QueryCondition.moreOrLess<QueryCondition.CustomFieldAmountQuery>().apply {
this.forEach {
it.customFieldId = cf.id
}
}
} else {
}
else -> {
QueryCondition.moreOrLess<QueryCondition.CustomFieldNumberQuery>().apply {
this.forEach {
it.customFieldId = cf.id
@ -148,22 +178,32 @@ sealed class FilterSectionRow(override val resId: Int?) : RowRepresentable {
}
}
}
else -> arrayListOf()
}.apply {
this.forEach {
it.filterSectionRow = this@FilterSectionRow
}
else -> arrayListOf()
}
)
}
// Add the section row only if we have data for this section
if (data.isNotEmpty()) {
data.add(0, this@FilterSectionRow)
}
return data
}
// val filterElements: List<RowRepresentable>
// get() {
//
// val data = arrayListOf<RowRepresentable>().apply {
// this.addAll(
// filterItems.apply {
// this.forEach {
// it.filterSectionRow = this@FilterSectionRow
// }
// }
// )
// }
//
// // Add the section row only if we have data for this section
// if (data.isNotEmpty()) {
// data.add(0, this@FilterSectionRow)
// }
//
// return data
// }
private val selectionType: SelectionType
get() {

@ -18,8 +18,9 @@ enum class IAPProducts(var identifier: String) {
PRO("unlimited")
}
interface PurchaseDelegate {
interface PurchaseListener {
fun purchaseDidSucceed(purchase: Purchase)
fun noPurchaseRetrieved()
}
/**
@ -61,7 +62,6 @@ object AppGuard : PurchasesUpdatedListener {
*/
val isProUser: Boolean
get() {
if (this.endOfUse != null) return true
return if (BuildConfig.DEBUG) {
@ -78,6 +78,7 @@ object AppGuard : PurchasesUpdatedListener {
"august2020" -> "01/8/2020"
"april2021" -> "09/4/2021"
"nov2020" -> "08/11/2020"
"oct2021" -> "01/10/2021"
else -> null
}
@ -92,7 +93,7 @@ object AppGuard : PurchasesUpdatedListener {
/**
* A delegate to notify when the purchase has succeeded
*/
private var purchaseDelegate: PurchaseDelegate? = null
private var purchaseListeners: MutableList<PurchaseListener> = mutableListOf()
/**
* Initialization of AppGuard
@ -205,9 +206,7 @@ object AppGuard : PurchasesUpdatedListener {
/**
* Initiates purchase with the product [skuDetails]
*/
fun initiatePurchase(activity: Activity, skuDetails: SkuDetails, delegate: PurchaseDelegate) {
this.purchaseDelegate = delegate
fun initiatePurchase(activity: Activity, skuDetails: SkuDetails) {
val flowParams = BillingFlowParams.newBuilder()
.setSkuDetails(skuDetails)
@ -224,10 +223,14 @@ object AppGuard : PurchasesUpdatedListener {
override fun onPurchasesUpdated(result: BillingResult, purchases: MutableList<Purchase>?) {
if (result.responseCode == BillingResponseCode.OK && purchases != null) {
if (result.responseCode == BillingResponseCode.OK) {
if (purchases != null && purchases.isNotEmpty()) {
for (purchase in purchases) {
handlePurchase(purchase)
}
} else {
sendNoPurchaseRetrievedEvent()
}
} else if (result.responseCode == BillingResponseCode.USER_CANCELED) {
Timber.d("purchase cancel message: ${result.debugMessage}")
// Handle an error caused by a user cancelling the purchase flow.
@ -239,6 +242,12 @@ object AppGuard : PurchasesUpdatedListener {
}
private fun sendNoPurchaseRetrievedEvent() {
this.purchaseListeners.forEach { listener ->
listener.noPurchaseRetrieved()
}
}
// /**
// * Purchase callback
// */
@ -279,12 +288,13 @@ object AppGuard : PurchasesUpdatedListener {
}
this._isProUser = true
this.purchaseDelegate?.let {
this.purchaseListeners.forEach { listener ->
Handler(Looper.getMainLooper()).post {
it.purchaseDidSucceed(purchase)
listener.purchaseDidSucceed(purchase)
}
this.purchaseDelegate = null
}
}
}
@ -317,4 +327,18 @@ object AppGuard : PurchasesUpdatedListener {
return context.getString(resId)
}
/***
* Removes a listener
*/
fun registerListener(listener: PurchaseListener) {
this.purchaseListeners.add(listener)
}
/***
* Removes a listener
*/
fun unregisterListener(listener: PurchaseListener) {
this.purchaseListeners.remove(listener)
}
}

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

@ -0,0 +1,27 @@
package net.pokeranalytics.android
import org.junit.Assert
import org.junit.Test
class IntHolder(var value: Int)
class StringHolder(var value: String)
class InstantiationTest : RealmUnitTest() {
@Test
fun testIntInstance() {
Assert.assertEquals(0, 0)
val c = IntHolder::class.java
val constructor = c.declaredConstructors.first()
val type = constructor.parameterTypes.first()
when (type) {
Int::class.java -> {
// good
}
else -> Assert.fail()
}
}
}
Loading…
Cancel
Save