Changed QueryCondition single values from optional to mandatory + Details ViewModel creation and refactoring

filterfix
Laurent 5 years ago
parent 1322952b47
commit 7924e19fe3
  1. 4
      app/src/androidTest/java/net/pokeranalytics/android/unitTests/filter/RealmFilterInstrumentedUnitTest.kt
  2. 8
      app/src/main/java/net/pokeranalytics/android/calculus/bankroll/BankrollReport.kt
  3. 18
      app/src/main/java/net/pokeranalytics/android/exceptions/Exceptions.kt
  4. 16
      app/src/main/java/net/pokeranalytics/android/model/filter/Query.kt
  5. 277
      app/src/main/java/net/pokeranalytics/android/model/filter/QueryCondition.kt
  6. 40
      app/src/main/java/net/pokeranalytics/android/model/realm/Filter.kt
  7. 10
      app/src/main/java/net/pokeranalytics/android/model/realm/FilterCondition.kt
  8. 302
      app/src/main/java/net/pokeranalytics/android/ui/modules/filter/FilterDetailsFragment.kt
  9. 116
      app/src/main/java/net/pokeranalytics/android/ui/modules/filter/FilterDetailsViewModel.kt
  10. 14
      app/src/main/java/net/pokeranalytics/android/ui/modules/filter/FilterViewModel.kt
  11. 6
      app/src/main/java/net/pokeranalytics/android/ui/modules/filter/FiltersActivity.kt
  12. 8
      app/src/main/java/net/pokeranalytics/android/ui/modules/filter/FiltersFragment.kt
  13. 8
      app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/FilterCategoryRow.kt
  14. 112
      app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/FilterElementRow.kt
  15. 182
      app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/FilterSectionRow.kt

@ -24,8 +24,8 @@ class RealmFilterInstrumentedUnitTest : BaseFilterInstrumentedUnitTest() {
filter.name = "testSaveLoadCashFilter"
val filterElement = QueryCondition.IsCash
filterElement.filterSectionRow = FilterSectionRow.CashOrTournament
filter.createOrUpdateFilterConditions(arrayListOf(filterElement))
// filterElement.filterSectionRow = FilterSectionRow.CashOrTournament
filter.createOrUpdateFilterConditions(arrayListOf(filterElement), FilterSectionRow.CashOrTournament)
val useCount = filter.countBy(FilterCategoryRow.GENERAL)
Assert.assertEquals(1, useCount)

@ -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,23 +16,25 @@ 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.ui.view.rowrepresentable.*
import net.pokeranalytics.android.util.NULL_TEXT
import net.pokeranalytics.android.util.UserDefaults
import net.pokeranalytics.android.util.extensions.*
import java.lang.Exception
import java.text.DateFormatSymbols
import java.text.NumberFormat
import java.util.*
import kotlin.collections.ArrayList
import kotlin.reflect.full.primaryConstructor
/**
* 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 {
inline fun <reified T : QueryCondition> more(): T {
@ -49,7 +51,15 @@ 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()
val instance = 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 param = primaryConstructor.parameterTypes.first()
primaryConstructor.newInstance(param.newInstance())
}
return instance as T
}
@ -125,25 +135,29 @@ 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 {
return listOfValues.sorted().first().compareTo(other.listOfValues.sorted().first())
}
@ -151,17 +165,18 @@ sealed class QueryCondition : FilterElementRow {
fun firstValue(context: Context): String? {
return this.listOfValues.firstOrNull()?.let { this.labelForValue(it, context) }
}
}
abstract class SingleValue<T> : ListOfValues<T>() where T : Comparable<T> {
override var listOfValues = ArrayList<T>()
abstract var singleValue: T?
abstract class SingleValue<T>(value: T) : ListOfValues<T>() where T : Comparable<T> {
override var listOfValues = mutableListOf<T>()
var singleValue: T = value
}
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()
@ -170,11 +185,15 @@ sealed class QueryCondition : FilterElementRow {
override fun labelForValue(value: Double, context: Context): String {
return value.toCurrency(UserDefaults.currency)
}
override fun toRowWrapper(filterSectionRow: FilterSectionRow): FilterItemRow {
return DoubleValueListFilterItemRow(this, filterSectionRow)
}
}
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()
@ -183,11 +202,15 @@ sealed class QueryCondition : FilterElementRow {
override fun labelForValue(value: Int, context: Context): String {
return value.toString()
}
override fun toRowWrapper(filterSectionRow: FilterSectionRow): FilterItemRow {
return IntValueListFilterItemRow(this, filterSectionRow)
}
}
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
}
@ -196,48 +219,42 @@ sealed class QueryCondition : FilterElementRow {
super.updateValueBy(filterCondition)
listOfValues = filterCondition.getValues()
}
override fun toRowWrapper(filterSectionRow: FilterSectionRow): FilterItemRow {
return StringValueListFilterItemRow(this, filterSectionRow)
}
}
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()
}
override fun toRowWrapper(filterSectionRow: FilterSectionRow): FilterItemRow {
return DateFilterItemRow(this, filterSectionRow)
}
}
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 toRowWrapper(filterSectionRow: FilterSectionRow): FilterItemRow {
return IntFilterItemRow(this, filterSectionRow)
}
}
override fun getDisplayName(context: Context): String {
@ -247,7 +264,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 +280,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"
}
@ -286,21 +303,19 @@ sealed class QueryCondition : FilterElementRow {
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()
} else {
it.shortDate()
}
} ?: NULL_TEXT
return if (showTime) {
singleValue.shortTime()
} else {
singleValue.shortDate()
}
}
}
abstract class TimeQuery : DateQuery() {
abstract class TimeQuery(date: Date) : DateQuery(date) {
override val showTime: Boolean = true
}
@ -343,50 +358,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,13 +439,13 @@ 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"
}
}
// 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 {
@ -507,19 +506,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
}
@ -564,7 +563,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
@ -579,9 +578,10 @@ sealed class QueryCondition : FilterElementRow {
}
}
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 +589,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,21 +606,21 @@ 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
}
// 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
}
// constructor(date: Date) : this() {
// singleValue = date
// }
}
@ -641,10 +638,6 @@ sealed class QueryCondition : FilterElementRow {
class CustomFieldQuery() : QueryDataCondition<CustomField>() {
override var entity: Class<CustomField> = CustomField::class.java
constructor(customField: CustomField) : this() {
this.setObject(customField)
}
}
open class CustomFieldNumberQuery() : ListOfDouble(), CustomFieldRelated {
@ -712,6 +705,10 @@ sealed class QueryCondition : FilterElementRow {
}
}
open fun toRowWrapper(filterSectionRow: FilterSectionRow): FilterItemRow {
return BaseFilterItemRow(this, filterSectionRow)
}
/**
* main method of the enum
* providing a base RealmQuery [realmQuery], the method is able to attached the corresponding query and returns the newly formed [RealmQuery]
@ -762,15 +759,12 @@ 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)
return realmQuery.greaterThanOrEqualTo(fieldName, calendar.time.startOfDay()).and()
.lessThanOrEqualTo(fieldName, startDate.endOfDay())
}
return realmQuery
val startDate = Date()
val calendar = Calendar.getInstance()
calendar.time = startDate
calendar.add(Calendar.DAY_OF_YEAR, -singleValue)
return realmQuery.greaterThanOrEqualTo(fieldName, calendar.time.startOfDay()).and()
.lessThanOrEqualTo(fieldName, startDate.endOfDay())
}
is DuringThisWeek -> {
val calendar = Calendar.getInstance()
@ -800,29 +794,21 @@ sealed class QueryCondition : FilterElementRow {
}
is StartedFromTime -> {
val calendar = Calendar.getInstance()
singleValue?.let {
calendar.time = it
realmQuery.greaterThanOrEqualTo(fieldName, calendar.hourMinute())
if (otherQueryCondition is EndedToTime) {
otherQueryCondition.singleValue?.let { endTime ->
calendar.time = endTime
realmQuery.lessThanOrEqualTo(fieldName, calendar.hourMinute())
}
}
calendar.time = singleValue
realmQuery.greaterThanOrEqualTo(fieldName, calendar.hourMinute())
if (otherQueryCondition is EndedToTime) {
calendar.time = otherQueryCondition.singleValue
realmQuery.lessThanOrEqualTo(fieldName, calendar.hourMinute())
}
return realmQuery
}
is EndedToTime -> {
val calendar = Calendar.getInstance()
singleValue?.let { date ->
calendar.time = date
realmQuery.lessThanOrEqualTo(fieldName, calendar.hourMinute())
if (otherQueryCondition is StartedFromTime) {
otherQueryCondition.singleValue?.let { startTime ->
calendar.time = startTime
realmQuery.greaterThanOrEqualTo(fieldName, calendar.hourMinute())
}
}
calendar.time = singleValue
realmQuery.lessThanOrEqualTo(fieldName, calendar.hourMinute())
if (otherQueryCondition is StartedFromTime) {
calendar.time = otherQueryCondition.singleValue
realmQuery.greaterThanOrEqualTo(fieldName, calendar.hourMinute())
}
return realmQuery
}
@ -846,14 +832,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 +842,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 +855,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 +909,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
}
@ -136,17 +140,17 @@ open class Filter : RealmObject(), RowRepresentable, Editable, Deletable, Counta
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())
}
}
// /**
// * 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())
// }
// }
inline fun <reified T : Filterable> query(firstField: String? = null, vararg remainingFields: String): RealmQuery<T> {
val realmQuery = realm.where<T>()

@ -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 })
@ -91,4 +92,5 @@ open class FilterCondition() : RealmObject() {
fun setValue(value:String) {
stringValue = value
}
}

@ -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)
@ -57,7 +60,6 @@ open class FilterDetailsFragment : RealmFragment(), StaticRowRepresentableDataSo
// requireFragmentManager().popBackStackImmediate()
}
/**
* Init UI
*/
@ -80,39 +82,27 @@ 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")
this.arguments?.let { bundle ->
//currentFilter = Filter.getFilterBydId(getRealm(), primaryKey)
// currentFilter = FiltersFragment.currentFilter
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")
Timber.d(">> Filter = ${this.model.currentFilter}")
Timber.d("selectedRow = ${this.model.selectedCategoryRow}")
val factory = FilterDetailsViewModelFactory(filter, categoryRow)
this.model = ViewModelProvider(this, factory).get(FilterDetailsViewModel::class.java)
val filterCategoryRow = this.model.filterCategoryRow
} ?: throw PAIllegalStateException("Missing bundle")
this.appBar.toolbar.title = filterCategoryRow.localizedTitle(requireContext())
//currentFilter = Filter.getFilterBydId(getRealm(), primaryKey)
// currentFilter = FiltersFragment.currentFilter
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
}
@ -125,48 +115,78 @@ open class FilterDetailsFragment : RealmFragment(), StaticRowRepresentableDataSo
}
when (row) {
is QueryCondition.DateQuery -> DateTimePickerManager.create(
requireContext(),
row,
this,
row.singleValue,
onlyDate = !row.showTime,
onlyTime = row.showTime
)
is QueryCondition.Duration -> {
var hours: String? = null
var minutes: String? = null
row.minutes?.let {
hours = if (it / 60 > 0) (it / 60).toString() else null
minutes = if (it % 60 > 0) (it % 60).toString() else null
is DateFilterItemRow -> {
when (val condition = row.rawCondition) {
is QueryCondition.DateQuery -> DateTimePickerManager.create(
requireContext(),
row,
this,
row.value,
onlyDate = !condition.showTime,
onlyTime = condition.showTime
)
}
}
is IntFilterItemRow -> {
when (val condition = row.rawCondition) {
is QueryCondition.Duration -> {
val hours: String? = (condition.minutes / 60).toString()
val minutes: String? = (condition.minutes % 60).toString()
val data = row.editingDescriptors(mapOf("hours" to hours, "minutes" to minutes))
showBottomSheet(row, this, data, true)
}
}
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 ValueListFilterItemRow<*> -> {
when (row.rawCondition) {
is QueryCondition.ListOfValues<*> -> {
var valueAsString: String? = null
row.list.firstOrNull()?.let {
valueAsString = row.list.firstOrNull()?.toString()
}
val data = row.editingDescriptors(mapOf("valueAsString" to valueAsString))
showBottomSheet(row, this, data, true)
}
}
val data = row.editingDescriptors(mapOf("valueAsString" to valueAsString))
showBottomSheet(row, this, data, true)
}
}
}
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)
// (row as? BaseFilterItemRow)?.let { filterItemRow ->
// val rawCondition = filterItemRow.rawCondition
// when (rawCondition) {
// is QueryCondition.DateQuery -> DateTimePickerManager.create(
// requireContext(),
// row,
// this,
// filterItemRow.value,
// onlyDate = !row.showTime,
// onlyTime = row.showTime
// )
// is QueryCondition.Duration -> {
// val hours: String? = (row.minutes / 60).toString()
// val minutes: String? = (row.minutes % 60).toString()
//// row.minutes?.let {
//// hours = if (it / 60 > 0) (it / 60).toString() else null
//// minutes = if (it % 60 > 0) (it % 60).toString() else null
//// }
// val data = row.editingDescriptors(mapOf("hours" to hours, "minutes" to minutes))
// showBottomSheet(row, this, data, true)
// }
// is QueryCondition.ListOfValues<*> -> {
// var valueAsString: String? = null
// row.listOfValues.firstOrNull()?.let {
// valueAsString = row.listOfValues.firstOrNull()?.toString()
// }
// val data = row.editingDescriptors(mapOf("valueAsString" to valueAsString))
// showBottomSheet(row, this, data, true)
// }
// else -> { }
// }
//
// }
}
override fun onRowValueChanged(value: Any?, row: RowRepresentable) {
@ -174,80 +194,89 @@ 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<*>) {
val hours: Int? = try {
(value[0] as String?)?.toInt()
} catch (e: Exception) {
null
}
val minutes = try {
(value[1] as String?)?.toInt()
} catch (e: Exception) {
null
is DateFilterItemRow -> {
row.value = value as Date
}
is IntFilterItemRow -> {
when (value) {
is Int -> {
row.value = value
}
if (hours != null && minutes != null) {
row.minutes = hours * 60 + minutes
} else if (hours != null) {
row.minutes = hours * 60
} else if (minutes != null) {
row.minutes = minutes
is ArrayList<*> -> {
val hours: Int? = try {
(value[0] as String?)?.toInt()
} catch (e: Exception) {
null
}
val minutes = try {
(value[1] as String?)?.toInt()
} catch (e: Exception) {
null
}
if (hours != null && minutes != null) {
row.value = hours * 60 + minutes
} else if (hours != null) {
row.value = hours * 60
} else if (minutes != null) {
row.value = minutes
}
}
} else {
row.minutes = 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)
}
}
// when (row) {
// is QueryCondition.DateQuery -> {
// if (value != null && value is Date) {
// row.singleValue = value
// }
// }
// is QueryCondition.Duration -> {
// if (value is ArrayList<*>) {
//
// }
// }
// is QueryCondition.SingleInt -> {
// if (value != null && value is String) {
// row.singleValue = value.toInt()
// }
// }
// is QueryCondition.ListOfDouble -> row.listOfValues = arrayListOf<Double>().apply {
// if (value != null && value is String) this.add(value.toDouble())
// }
// is QueryCondition.ListOfInt -> row.listOfValues = arrayListOf<Int>().apply {
// if (value != null && value is String) this.add(value.toInt())
// }
// is QueryCondition.ListOfString -> row.listOfValues = arrayListOf<String>().apply {
// if (value != null && value is String) this.add(value)
// }
// }
// 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)
}
}
this.model.updateRowsSelection(this.rowRepresentableAdapter, row, forceDeselection)
println("list of selected rows : $selectedRows")
// println("list of selected rows : $selectedRows")
// Update UI
this.rowRepresentableAdapter.refreshRow(row)
@ -258,18 +287,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")
}
getRealm().executeTransaction {
currentFilter?.remove(this.model.filterCategoryRow)
currentFilter?.createOrUpdateFilterConditions(this.selectedRows)
}
this.activityModel.selectedCategoryRow?.let { category ->
getRealm().executeTransaction {
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,116 @@
package net.pokeranalytics.android.ui.modules.filter
import android.content.Context
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import net.pokeranalytics.android.model.filter.QueryCondition
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.BaseFilterItemRow
import net.pokeranalytics.android.ui.view.rowrepresentable.FilterCategoryRow
import net.pokeranalytics.android.ui.view.rowrepresentable.FilterItemRow
import net.pokeranalytics.android.ui.view.rowrepresentable.ValueListFilterItemRow
import net.pokeranalytics.android.util.NULL_TEXT
import timber.log.Timber
class FilterDetailsViewModelFactory(var filter: Filter, 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>()
// private var rowsForFilterSubcategoryRow: HashMap<FilterSectionRow, ArrayList<RowRepresentable>> =
// HashMap()
init {
this.rows.addAll(categoryRow.filterElements)
this.defineSelectedItems()
}
override fun adapterRows(): List<RowRepresentable>? {
return this.rows
}
override fun charSequenceForRow(row: RowRepresentable, context: Context): CharSequence {
val filterItemRow = row as? BaseFilterItemRow
filterItemRow?.let {
return when (val condition = it.rawCondition) {
is QueryCondition.ListOfValues<*> -> condition.firstValue(context) ?: NULL_TEXT
else -> super.charSequenceForRow(row, context, 0)
}
}
return NULL_TEXT
// return when (row) {
// is BaseFilterItemRow -> {
//
// }
// 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 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.queryCondition
if (condition != null && this.filter.contains(condition)) {
// Load items with appropriate value
this.filter.filterConditions.firstOrNull {
it.queryCondition.id == condition.id
}?.let {
item.updateValue(it)
// item.queryCondition?.updateValueBy(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)
}
}
}
}

@ -20,14 +20,16 @@ class FilterViewModel : ViewModel(), StaticRowRepresentableDataSource {
var filterCopy: Filter? = null
private var categoryRows: ArrayList<RowRepresentable> = ArrayList()
var primaryKey: String? = null
var selectedCategoryRow: RowRepresentable? = null
var selectedCategoryRow: FilterCategoryRow? = null
var isUpdating = false
// Details
val filterCategoryRow: FilterCategoryRow
get() {
return this.selectedCategoryRow as FilterCategoryRow
}
// val filterCategoryRow: FilterCategoryRow
// get() {
// return this.selectedCategoryRow as FilterCategoryRow
// }
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() {
@ -102,9 +104,9 @@ class FiltersActivity : BaseActivity() {
}
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
@ -148,10 +149,11 @@ 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 { _ ->
val categoryRow = row as FilterCategoryRow
this.model.selectedCategoryRow = categoryRow
this.model.currentFilter?.let { _ ->
(activity as FiltersActivity).showDetailsFragment()
(activity as FiltersActivity).showDetailsFragment(categoryRow)
// this.model.filterCategoryRow = row as FilterCategoryRow

@ -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,17 +1,22 @@
package net.pokeranalytics.android.ui.view.rowrepresentable
import android.content.Context
import android.text.InputType
import net.pokeranalytics.android.R
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.ui.view.RowViewType
import java.util.*
interface FilterElementRow : RowRepresentable {
interface FilterItemRow : RowRepresentable {
val queryCondition: QueryCondition?
var filterSectionRow: FilterSectionRow
override fun editingDescriptors(map: Map<String, Any?>): ArrayList<RowRepresentableEditDescriptor>? {
return when (this) {
return when (this.queryCondition) {
is QueryCondition.Duration -> {
val hours: String? by map
val minutes: String? by map
@ -22,9 +27,9 @@ interface FilterElementRow : RowRepresentable {
}
is QueryCondition.ListOfValues<*> -> {
val valueAsString: String? by map
val hint = when (this.operator) {
val hint = when (this.queryCondition?.operator) {
QueryCondition.Operator.MORE, QueryCondition.Operator.LESS -> {
when (this) {
when (this.queryCondition) {
is QueryCondition.CustomFieldNumberQuery -> R.string.value
is QueryCondition.CustomFieldAmountQuery -> R.string.amount
else -> this.filterSectionRow.resId
@ -41,7 +46,7 @@ interface FilterElementRow : RowRepresentable {
}
}
var filterSectionRow: FilterSectionRow
fun updateValue(it: FilterCondition) { }
val sectionToExclude: List<FilterSectionRow>?
get() {
@ -58,4 +63,97 @@ interface FilterElementRow : RowRepresentable {
}
return null
}
}
}
open class BaseFilterItemRow(queryCondition: QueryCondition, override var filterSectionRow: FilterSectionRow) : FilterItemRow {
var rawCondition: QueryCondition = queryCondition
private set
override val queryCondition: QueryCondition?
get() { return rawCondition }
// Row Representable
override fun getDisplayName(context: Context): String {
return this.rawCondition.getDisplayName(context)
}
override val viewType: Int
get() { return this.rawCondition.viewType }
override val bottomSheetType: BottomSheetType
get() { return this.rawCondition.bottomSheetType }
}
abstract class ValueFilterItemRow<T: Comparable<T>>(queryCondition: QueryCondition.SingleValue<T>, filterSectionRow: FilterSectionRow): BaseFilterItemRow(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 updateValue(fc: FilterCondition) {
// TODO
// this.value = fc.queryCondition.
}
}
abstract class ValueListFilterItemRow<T: Comparable<T>>(queryCondition: QueryCondition.ListOfValues<T>, filterSectionRow: FilterSectionRow): BaseFilterItemRow(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 getDisplayName(context: Context): String {
// return this.listCondition.getDisplayName(context, this.list)
// }
override fun updateValue(fc: FilterCondition) {
// TODO
// this.value = fc.queryCondition.
}
}
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)
//interface FilterElementRow : RowRepresentable {
//
//}

@ -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,101 +70,118 @@ 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() {
return this.queryConditions.map {
it.toRowWrapper(this@FilterSectionRow)
}
}
private val queryConditions: List<QueryCondition>
get() {
return when (this@FilterSectionRow) {
// General
CashOrTournament -> Criteria.SessionTypes.queryConditions.mapFirstCondition()
LiveOrOnline -> Criteria.BankrollTypes.queryConditions.mapFirstCondition()
Game -> Criteria.Games.queryConditions.mapFirstCondition()
LimitType -> Criteria.Limits.queryConditions.mapFirstCondition()
TableSize -> Criteria.TableSizes.queryConditions.mapFirstCondition()
// Date
DynamicDate -> arrayListOf(
QueryCondition.IsToday,
QueryCondition.WasYesterday,
QueryCondition.WasTodayAndYesterday,
QueryCondition.DuringThisWeek,
QueryCondition.DuringThisMonth,
QueryCondition.DuringThisYear
)
WeekdayOrWeekend -> arrayListOf(QueryCondition.IsWeekDay, QueryCondition.IsWeekEnd)
Year -> Criteria.Years.queryConditions.mapFirstCondition()
DayOfWeek -> Criteria.DaysOfWeek.queryConditions.mapFirstCondition()
MonthOfYear -> Criteria.MonthsOfYear.queryConditions.mapFirstCondition()
// Duration
SessionDuration -> QueryCondition.moreOrLess<QueryCondition.Duration>()
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
val data = arrayListOf<RowRepresentable>().apply {
this.addAll(
when (this@FilterSectionRow) {
// General
CashOrTournament -> Criteria.SessionTypes.queryConditions.mapFirstCondition()
LiveOrOnline -> Criteria.BankrollTypes.queryConditions.mapFirstCondition()
Game -> Criteria.Games.queryConditions.mapFirstCondition()
LimitType -> Criteria.Limits.queryConditions.mapFirstCondition()
TableSize -> Criteria.TableSizes.queryConditions.mapFirstCondition()
// Date
DynamicDate -> arrayListOf(
QueryCondition.IsToday,
QueryCondition.WasYesterday,
QueryCondition.WasTodayAndYesterday,
QueryCondition.DuringThisWeek,
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()
MonthOfYear -> Criteria.MonthsOfYear.queryConditions.mapFirstCondition()
// Duration
SessionDuration -> QueryCondition.moreOrLess<QueryCondition.Duration>()
TimeFrameRange -> arrayListOf(QueryCondition.StartedFromTime(), QueryCondition.EndedToTime())
// Sessions
//Sessions -> arrayListOf(QueryCondition.LastGame(), QueryCondition.LastSession())
// Cash
Blind -> Criteria.Blinds.queryConditions.mapFirstCondition()
// Sessions
//Sessions -> arrayListOf(QueryCondition.LastGame(), QueryCondition.LastSession())
// Cash
Blind -> Criteria.Blinds.queryConditions.mapFirstCondition()
// CashRebuyCount -> QueryCondition.moreOrLess<QueryCondition.Rebuy>()
// Tournament
TournamentType -> Criteria.TournamentTypes.queryConditions.mapFirstCondition()
// Tournament
TournamentType -> Criteria.TournamentTypes.queryConditions.mapFirstCondition()
// CompletionPercentage -> arrayListOf()
TournamentFinalPosition -> QueryCondition.moreOrLess<QueryCondition.TournamentFinalPosition>()
TournamentNumberOfPlayer -> QueryCondition.moreOrLess<QueryCondition.TournamentNumberOfPlayer>()
TournamentEntryFee -> Criteria.TournamentFees.queryConditions.mapFirstCondition()
TournamentName -> Criteria.TournamentNames.queryConditions.mapFirstCondition()
TournamentFeature -> Criteria.TournamentFeatures.queryConditions.mapFirstCondition()
Location -> Criteria.Locations.queryConditions.mapFirstCondition()
Bankroll -> Criteria.Bankrolls.queryConditions.mapFirstCondition()
MultiTabling -> QueryCondition.moreOrLess<QueryCondition.NumberOfTable>()
//NumberOfPlayers -> QueryCondition.moreOrLess<QueryCondition.TournamentNumberOfPlayer>()
NumberOfRebuy -> QueryCondition.moreOrLess<QueryCondition.NumberOfRebuy>()
TournamentFinalPosition -> QueryCondition.moreOrLess<QueryCondition.TournamentFinalPosition>()
TournamentNumberOfPlayer -> QueryCondition.moreOrLess<QueryCondition.TournamentNumberOfPlayer>()
TournamentEntryFee -> Criteria.TournamentFees.queryConditions.mapFirstCondition()
TournamentName -> Criteria.TournamentNames.queryConditions.mapFirstCondition()
TournamentFeature -> Criteria.TournamentFeatures.queryConditions.mapFirstCondition()
Location -> Criteria.Locations.queryConditions.mapFirstCondition()
Bankroll -> Criteria.Bankrolls.queryConditions.mapFirstCondition()
MultiTabling -> QueryCondition.moreOrLess<QueryCondition.NumberOfTable>()
//NumberOfPlayers -> QueryCondition.moreOrLess<QueryCondition.TournamentNumberOfPlayer>()
NumberOfRebuy -> QueryCondition.moreOrLess<QueryCondition.NumberOfRebuy>()
// MultiPlayer -> arrayListOf()
Value -> arrayListOf<QueryCondition>().apply {
addAll(QueryCondition.moreOrLess<QueryCondition.NetAmountWon>())
addAll(QueryCondition.moreOrLess<QueryCondition.NetAmountLost>())
}
TransactionType -> Criteria.TransactionTypes.queryConditions.mapFirstCondition()
is CustomField -> {
val cf = this@FilterSectionRow.customField
if (cf.isListType) {
Criteria.ListCustomFields(cf.id).queryConditions.mapFirstCondition()
} else if (cf.isAmountType) {
QueryCondition.moreOrLess<QueryCondition.CustomFieldAmountQuery>().apply {
this.forEach {
it.customFieldId = cf.id
}
}
} else {
QueryCondition.moreOrLess<QueryCondition.CustomFieldNumberQuery>().apply {
this.forEach {
it.customFieldId = cf.id
}
}
}
}
else -> arrayListOf()
}.apply {
this.forEach {
it.filterSectionRow = this@FilterSectionRow
Value -> arrayListOf<QueryCondition>().apply {
addAll(QueryCondition.moreOrLess<QueryCondition.NetAmountWon>())
addAll(QueryCondition.moreOrLess<QueryCondition.NetAmountLost>())
}
TransactionType -> Criteria.TransactionTypes.queryConditions.mapFirstCondition()
is CustomField -> {
val cf = this@FilterSectionRow.customField
when {
cf.isListType -> {
Criteria.ListCustomFields(cf.id).queryConditions.mapFirstCondition()
}
cf.isAmountType -> {
QueryCondition.moreOrLess<QueryCondition.CustomFieldAmountQuery>().apply {
this.forEach {
it.customFieldId = cf.id
}
}
}
else -> {
QueryCondition.moreOrLess<QueryCondition.CustomFieldNumberQuery>().apply {
this.forEach {
it.customFieldId = cf.id
}
}
}
}
)
}
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() {

Loading…
Cancel
Save