diff --git a/app/build.gradle b/app/build.gradle index a60e3a05..e633f19c 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -121,7 +121,7 @@ dependencies { testImplementation 'com.android.support.test:rules:1.0.2' //testImplementation 'androidx.test.espresso:espresso-core:3.1.0' - + implementation "com.ibm.icu:icu4j:53.1" } apply plugin: 'com.google.gms.google-services' \ No newline at end of file diff --git a/app/src/androidTest/java/net/pokeranalytics/android/model/CriteriaTest.kt b/app/src/androidTest/java/net/pokeranalytics/android/model/CriteriaTest.kt index 1248af55..bd0bf7ee 100644 --- a/app/src/androidTest/java/net/pokeranalytics/android/model/CriteriaTest.kt +++ b/app/src/androidTest/java/net/pokeranalytics/android/model/CriteriaTest.kt @@ -1,14 +1,15 @@ package net.pokeranalytics.android.model +import android.content.Context import net.pokeranalytics.android.components.BaseFilterInstrumentedUnitTest import net.pokeranalytics.android.model.filter.QueryCondition import net.pokeranalytics.android.model.realm.Session import org.junit.Assert.assertEquals import org.junit.Test import java.util.* +import androidx.test.platform.app.InstrumentationRegistry class CriteriaTest : BaseFilterInstrumentedUnitTest() { - @Test fun getQueryConditions() { @@ -57,9 +58,12 @@ class CriteriaTest : BaseFilterInstrumentedUnitTest() { val criterias = listOf(Criteria.MonthsOfYear, Criteria.DaysOfWeek) val combined = criterias.combined() + val context = InstrumentationRegistry.getInstrumentation().context + combined.forEach { it.conditions.forEach {qc-> - println(qc.getDisplayName()) + + println(qc.getDisplayName(context)) } } } @@ -86,11 +90,12 @@ class CriteriaTest : BaseFilterInstrumentedUnitTest() { val lastValue = firstValue + 10 realm.commitTransaction() + val context = InstrumentationRegistry.getInstrumentation().context val allMonths = Criteria.AllMonthsUpToNow.queries allMonths.forEach { it.conditions.forEach { qc-> - println("<<<<< ${qc.getDisplayName()}") + println("<<<<< ${qc.getDisplayName(context)}") } } } diff --git a/app/src/androidTest/java/net/pokeranalytics/android/unitTests/filter/CustomFieldFilterInstrumentedUnitTest.kt b/app/src/androidTest/java/net/pokeranalytics/android/unitTests/filter/CustomFieldFilterInstrumentedUnitTest.kt new file mode 100644 index 00000000..b7f5a163 --- /dev/null +++ b/app/src/androidTest/java/net/pokeranalytics/android/unitTests/filter/CustomFieldFilterInstrumentedUnitTest.kt @@ -0,0 +1,75 @@ +package net.pokeranalytics.android.unitTests.filter + +import androidx.test.ext.junit.runners.AndroidJUnit4 +import io.realm.RealmList +import net.pokeranalytics.android.components.BaseFilterInstrumentedUnitTest +import net.pokeranalytics.android.model.filter.Query +import net.pokeranalytics.android.model.filter.QueryCondition +import net.pokeranalytics.android.model.realm.* +import net.pokeranalytics.android.ui.view.rowrepresentable.FilterSectionRow +import org.junit.Assert +import org.junit.Test +import org.junit.runner.RunWith +import java.util.* + +@RunWith(AndroidJUnit4::class) +class CustomFieldFilterInstrumentedUnitTest : BaseFilterInstrumentedUnitTest() { + + @Test + fun testCustomFieldListFilter() { + + val realm = this.mockRealm + realm.beginTransaction() + + val cf1 = CustomField() + cf1.type = CustomField.Type.LIST.ordinal + cf1.addEntry() + cf1.addEntry() + cf1.entries.first()?.value = "super" + cf1.entries.last()?.value = "nul" + + val s1 = Session.testInstance(100.0, false, Date(), 1) + s1.customFieldEntries.add(cf1.entries.first()) + val s2 = Session.testInstance(100.0, true, Date(), 1) + s2.customFieldEntries.add(cf1.entries.last()) + realm.commitTransaction() + + val sessions = Filter.queryOn(realm, Query(QueryCondition.CustomFieldListQuery(cf1.entries.first()!!))) + + Assert.assertEquals(1, sessions.size) + sessions[0]?.run { + Assert.assertEquals(s1.id, (this).id) + } + } + + @Test + fun testCustomFieldAmountFilter() { + + val realm = this.mockRealm + realm.beginTransaction() + + val cf1 = CustomField() + cf1.type = CustomField.Type.AMOUNT.ordinal + + val cfe1 = CustomFieldEntry() + cfe1.customField = cf1 + cfe1.value = "30.0" + + val cfe2 = CustomFieldEntry() + cfe2.customField = cf1 + cfe2.value = "100.0" + + val s1 = Session.testInstance(100.0, false, Date(), 1) + s1.customFieldEntries.add(cfe1) + val s2 = Session.testInstance(100.0, true, Date(), 1) + s2.customFieldEntries.add(cfe2) + realm.commitTransaction() + + val sessions = Filter.queryOn(realm, Query(QueryCondition.CustomFieldNumberQuery(cf1.id, 100.0))) + + Assert.assertEquals(1, sessions.size) + sessions[0]?.run { + Assert.assertEquals(s2.id, (this).id) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/net/pokeranalytics/android/model/Criteria.kt b/app/src/main/java/net/pokeranalytics/android/model/Criteria.kt index 42ab77d2..6af0cf14 100644 --- a/app/src/main/java/net/pokeranalytics/android/model/Criteria.kt +++ b/app/src/main/java/net/pokeranalytics/android/model/Criteria.kt @@ -93,7 +93,7 @@ sealed class Criteria(override var uniqueIdentifier: Int) : IntIdentifiable, Row distincts.distinct().forEach { val condition: QueryCondition.CustomFieldNumberQuery = QueryCondition.CustomFieldNumberQuery().apply { this.customFieldId = this@ListCriteria.customField.id - listOfValues = arrayListOf(it.value.toDouble()) + listOfValues = arrayListOf(it.value) } objects.add(condition) objects.sorted() diff --git a/app/src/main/java/net/pokeranalytics/android/model/filter/Query.kt b/app/src/main/java/net/pokeranalytics/android/model/filter/Query.kt index 6f5baf3c..7663317e 100644 --- a/app/src/main/java/net/pokeranalytics/android/model/filter/Query.kt +++ b/app/src/main/java/net/pokeranalytics/android/model/filter/Query.kt @@ -68,11 +68,14 @@ class Query { } } + //println("<<<<<< ${realmQuery.description}") val queryLast = this.conditions.filter { it is QueryCondition.Last }.firstOrNull() - queryLast?.let { - return realmQuery.limit((it as QueryCondition.Last).singleValue.toLong()) + queryLast?.let {qc -> + (qc as QueryCondition.Last).singleValue?.let { + return realmQuery.limit(it.toLong()) + } } return realmQuery } diff --git a/app/src/main/java/net/pokeranalytics/android/model/filter/QueryCondition.kt b/app/src/main/java/net/pokeranalytics/android/model/filter/QueryCondition.kt index 7ed57873..b85ad0e2 100644 --- a/app/src/main/java/net/pokeranalytics/android/model/filter/QueryCondition.kt +++ b/app/src/main/java/net/pokeranalytics/android/model/filter/QueryCondition.kt @@ -1,6 +1,7 @@ package net.pokeranalytics.android.model.filter import android.content.Context +import com.ibm.icu.text.RuleBasedNumberFormat import io.realm.Realm import io.realm.RealmQuery import io.realm.RealmResults @@ -113,52 +114,58 @@ sealed class QueryCondition : FilterElementRow { abstract var listOfValues: ArrayList abstract fun labelForValue(value:T, context: Context): String + open fun entityName(context: Context): String { + return baseId + } + override fun getDisplayName(context: Context): String { + val prefix = this.resId?.let { + context.getString(it)+" " + } ?: "" + return when (listOfValues.size) { 0 -> return NULL_TEXT - 1,2 -> listOfValues.map { labelForValue(it, context) }.joinToString(", ") - else -> "${listOfValues.size} $baseId" + 1,2 -> prefix+ listOfValues.map { labelForValue(it, context) }.joinToString(", ") + else -> "${listOfValues.size} $prefix ${entityName(context)}" } } override fun compareTo(other: ListOfValues): Int { return listOfValues.sorted().first().compareTo(other.listOfValues.sorted().first()) } + + fun firstValue(context:Context): String? { + return this.listOfValues.firstOrNull()?.let { this.labelForValue(it, context) } + } } abstract class SingleValue: ListOfValues() where T:Comparable { override var listOfValues = ArrayList() - abstract var singleValue : T + abstract var singleValue : T? } abstract class ListOfDouble: ListOfValues() { open var sign: Int = 1 override var operator: Operator = Operator.ANY - override var listOfValues = arrayListOf(0.0) + override var listOfValues : ArrayList = arrayListOf() override fun updateValueBy(filterCondition: FilterCondition) { super.updateValueBy(filterCondition) listOfValues = filterCondition.getValues() } override fun labelForValue(value: Double, context: Context): String { - val prefix = this.resId?.let { - context.getString(it)+" " - } ?: "" - return prefix+value.toCurrency(UserDefaults.currency) + return value.toCurrency(UserDefaults.currency) } } abstract class ListOfInt: ListOfValues() { override var operator: Operator = Operator.ANY - override var listOfValues = arrayListOf(0) + override var listOfValues : ArrayList = arrayListOf() override fun updateValueBy(filterCondition: FilterCondition) { super.updateValueBy(filterCondition) listOfValues = filterCondition.getValues() } override fun labelForValue(value: Int, context: Context): String { - val prefix = this.resId?.let { - context.getString(it)+" " - } ?: "" - return prefix+value.toString() + return value.toString() } } @@ -174,19 +181,16 @@ sealed class QueryCondition : FilterElementRow { abstract class SingleDate: SingleValue() { override fun labelForValue(value: Date, context: Context): String { - val prefix = this.resId?.let { - context.getString(it)+" " - } ?: "" - return prefix+value.shortDate() + return value.shortDate() } override var listOfValues = ArrayList() - override var singleValue: Date - get() { return listOfValues.firstOrNull() ?: Date() } + override var singleValue: Date? + get() { return listOfValues.firstOrNull() } set(value) { listOfValues.removeAll(this.listOfValues) - listOfValues.add(value) + value?.let { listOfValues.add(it) } } override fun updateValueBy(filterCondition: FilterCondition) { @@ -197,17 +201,14 @@ sealed class QueryCondition : FilterElementRow { abstract class SingleInt: SingleValue() { override fun labelForValue(value: Int, context: Context): String { - val prefix = this.resId?.let { - context.getString(it)+" " - } ?: "" - return prefix+value.toString() + return value.toString() } - override var singleValue: Int - get() { return listOfValues.firstOrNull() ?: 0 } + override var singleValue: Int? + get() { return listOfValues.firstOrNull() } set(value) { listOfValues.removeAll(this.listOfValues) - listOfValues.add(value) + value?.let { listOfValues.add(it) } } override fun updateValueBy(filterCondition: FilterCondition) { @@ -235,17 +236,22 @@ sealed class QueryCondition : FilterElementRow { override fun getDisplayName(context: Context): String { val realm = Realm.getDefaultInstance() + val entityName = entityName(realm) val completeLabel = when (listOfValues.size) { - 0 -> return NULL_TEXT + 0 -> NULL_TEXT 1,2 -> { - return listOfValues.map { labelForValue(realm, it) }.joinToString(", ") + listOfValues.map { labelForValue(realm, it) }.joinToString(", ") } - else -> "${listOfValues.size} $baseId" + else -> "${listOfValues.size} $entityName" } realm.close() return completeLabel } + open fun entityName(realm: Realm): String { + return baseId + } + private fun labelForValue(realm:Realm, value:String): String { val query = realm.where(entity) return query.equalTo("id", value).findFirst()?.name ?: NULL_TEXT @@ -260,6 +266,15 @@ sealed class QueryCondition : FilterElementRow { abstract class DateQuery: SingleDate(), 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 + } } abstract class TimeQuery: DateQuery() { @@ -358,10 +373,11 @@ sealed class QueryCondition : FilterElementRow { class NumberOfTable: ListOfInt() { override fun labelForValue(value: Int, context: Context): String { - val prefix = this.resId?.let { - context.getString(it) + " " - } ?: "" - return prefix + value.toString() + " " + context.getString(R.string.tables) + return value.toString() + } + + override fun entityName(context: Context): String { + return context.getString(R.string.number_of_tables) } } @@ -372,10 +388,7 @@ sealed class QueryCondition : FilterElementRow { } override fun labelForValue(value: Double, context: Context): String { - val prefix = this.resId?.let { - context.getString(it) + " " - } ?: "" - return prefix + value.toString() + return value.toString() } } @@ -386,11 +399,8 @@ sealed class QueryCondition : FilterElementRow { } override fun labelForValue(value: Int, context: Context): String { - val prefix = this.resId?.let { - context.getString(it) + " " - } ?: "" - //TODO add a int helper to display 1st, 2nd, 3rd, 4th, etc. - return prefix + value.toString() + val nf = RuleBasedNumberFormat(Locale.getDefault(), RuleBasedNumberFormat.ORDINAL) + return nf.format(value) } } @@ -401,10 +411,11 @@ sealed class QueryCondition : FilterElementRow { class TournamentNumberOfPlayer: ListOfInt() { override fun labelForValue(value: Int, context: Context): String { - val prefix = this.resId?.let { - context.getString(it) + " " - } ?: "" - return prefix + value.toString() + context.getString(R.string.number_of_players) + return value.toString() + } + + override fun entityName(context: Context): String { + return context.getString(R.string.number_of_players) } } @@ -450,10 +461,7 @@ sealed class QueryCondition : FilterElementRow { class TournamentFee: ListOfDouble() { override fun labelForValue(value: Double, context: Context): String { - val prefix = this.resId?.let { - context.getString(it)+" " - } ?: "" - return prefix+value.toCurrency(UserDefaults.currency) + return value.toCurrency(UserDefaults.currency) } } @@ -462,52 +470,118 @@ sealed class QueryCondition : FilterElementRow { override val viewType: Int = RowViewType.TITLE_VALUE_CHECK.ordinal override fun labelForValue(value: Int, context: Context): String { - val suffix = this.resId?.let { + return value.toString() + } + + override fun entityName(context: Context): String { + return this.resId?.let { " "+context.getString(it) } ?: "" - return value.toString() + suffix } } class Duration: SingleInt() { override var operator = Operator.EQUALS - var minutes:Int + var minutes:Int? get() { return singleValue } - set(value) { listOfValues = arrayListOf(value) } + set(value) { singleValue = value } override val viewType: Int = RowViewType.TITLE_VALUE_CHECK.ordinal override val bottomSheetType: BottomSheetType = BottomSheetType.DOUBLE_EDIT_TEXT + + override fun labelForValue(value: Int, context: Context): String { + val nf = RuleBasedNumberFormat(Locale.getDefault(), RuleBasedNumberFormat.DURATION) + return nf.format(value.toDouble()) + } } - class StartedFromTime(startTime:Date = Date().startOfDay()): TimeQuery() { + class StartedFromTime: TimeQuery() { override var operator = Operator.MORE - init { - this.listOfValues = arrayListOf(startTime) - } } - class EndedToTime(endTime:Date = Date().endOfDay()): TimeQuery() { + class EndedToTime: TimeQuery() { override var operator = Operator.LESS - init { - this.listOfValues = arrayListOf(endTime) - } } - interface CustomFieldQuery { + interface CustomFieldRelated { var customFieldId : String? + + fun customFieldName(realm: Realm): String { + val query = realm.where(CustomField::class.java) + val name = query.equalTo("id", customFieldId).findFirst()?.name + return name?.let { + "$it " + } ?: run { "" } + } + } + + class CustomFieldQuery() : QueryDataCondition() { + override var entity: Class = CustomField::class.java + constructor(customField: CustomField): this() { + this.setObject(customField) + } } - class CustomFieldNumberQuery : ListOfDouble(), CustomFieldQuery { + open class CustomFieldNumberQuery() : ListOfString(), CustomFieldRelated { override var customFieldId : String? = null + override var operator: Operator = Operator.EQUALS + constructor(customFieldId: String, value: Double): this() { + this.listOfValues = arrayListOf(value.toString()) + this.customFieldId = customFieldId + } + + override fun getDisplayName(context: Context): String { + val realm = Realm.getDefaultInstance() + val name = customFieldName(realm) + val prefix = this.resId?.let { + context.getString(it)+" " + } ?: "" + + val completeLabel = when (listOfValues.size) { + 0 -> return NULL_TEXT + 1,2 -> { + return name+prefix+listOfValues.map { labelForValue(it, context) }.joinToString(", ") + } + else -> "${listOfValues.size} $prefix $name" + } + realm.close() + return completeLabel + } + + override fun labelForValue(value: String, context: Context): String { + return value + } + + override fun updateValueBy(filterCondition: FilterCondition) { + super.updateValueBy(filterCondition) + listOfValues = filterCondition.getValues() + customFieldId = filterCondition.stringValue + } + } + + class CustomFieldAmountQuery : CustomFieldNumberQuery() { + override fun labelForValue(value: String, context: Context): String { + return value.toDouble().toCurrency(UserDefaults.currency) + } } - class CustomFieldListQuery() : QueryDataCondition(), CustomFieldQuery { + class CustomFieldListQuery() : QueryDataCondition(), CustomFieldRelated { override var entity: Class = CustomFieldEntry::class.java override var customFieldId : String? = null constructor(customFieldEntry: CustomFieldEntry): this() { this.setObject(customFieldEntry) this.customFieldId = customFieldEntry.customField?.id } + + override fun entityName(realm: Realm): String { + return customFieldName(realm) + } + + override fun updateValueBy(filterCondition: FilterCondition) { + super.updateValueBy(filterCondition) + listOfValues = filterCondition.getValues() + customFieldId = filterCondition.stringValue + } } /** @@ -550,11 +624,14 @@ sealed class QueryCondition : FilterElementRow { return realmQuery.greaterThanOrEqualTo(fieldName, calendar.time.startOfDay()).and().lessThanOrEqualTo(fieldName, calendar.time.endOfDay()) } is PastDay -> { - 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()) + 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 } is DuringThisWeek -> { val startDate = Date() @@ -599,11 +676,17 @@ sealed class QueryCondition : FilterElementRow { } } + if (this is CustomFieldRelated) { + FilterHelper.fieldNameForQueryType(CustomFieldQuery::class.java)?.let { + realmQuery.equalTo(it, customFieldId) + } + } + return when (operator) { Operator.EQUALS -> { when (this) { - is SingleDate -> realmQuery.equalTo(fieldName, singleValue) - is SingleInt -> realmQuery.equalTo(fieldName, singleValue) + is SingleDate -> realmQuery.equalTo(fieldName, singleValue?:throw PokerAnalyticsException.FilterElementExpectedValueMissing) + is SingleInt -> realmQuery.equalTo(fieldName, singleValue?:throw PokerAnalyticsException.FilterElementExpectedValueMissing) is ListOfInt -> realmQuery.equalTo(fieldName, listOfValues.first()) is ListOfDouble -> realmQuery.equalTo(fieldName, listOfValues.first() * sign) is ListOfString -> realmQuery.equalTo(fieldName, listOfValues.first()) @@ -612,8 +695,8 @@ sealed class QueryCondition : FilterElementRow { } Operator.MORE -> { when (this) { - is SingleDate -> realmQuery.greaterThanOrEqualTo(fieldName, singleValue) - is SingleInt -> realmQuery.greaterThanOrEqualTo(fieldName, singleValue) + is SingleDate -> realmQuery.greaterThanOrEqualTo(fieldName, singleValue?:throw PokerAnalyticsException.FilterElementExpectedValueMissing) + is SingleInt -> realmQuery.greaterThanOrEqualTo(fieldName, singleValue?:throw PokerAnalyticsException.FilterElementExpectedValueMissing) is ListOfInt -> realmQuery.greaterThanOrEqualTo(fieldName, listOfValues.first()) is ListOfDouble -> realmQuery.greaterThanOrEqualTo(fieldName, listOfValues.first() * sign) else -> realmQuery @@ -621,8 +704,8 @@ sealed class QueryCondition : FilterElementRow { } Operator.LESS -> { when (this) { - is SingleDate -> realmQuery.lessThanOrEqualTo(fieldName, singleValue) - is SingleInt -> realmQuery.lessThanOrEqualTo(fieldName, singleValue) + is SingleDate -> realmQuery.lessThanOrEqualTo(fieldName, singleValue?:throw PokerAnalyticsException.FilterElementExpectedValueMissing) + is SingleInt -> realmQuery.lessThanOrEqualTo(fieldName, singleValue?:throw PokerAnalyticsException.FilterElementExpectedValueMissing) is ListOfInt -> realmQuery.lessThanOrEqualTo(fieldName, listOfValues.first()) is ListOfDouble -> realmQuery.lessThanOrEqualTo(fieldName, listOfValues.first() * sign) else -> realmQuery diff --git a/app/src/main/java/net/pokeranalytics/android/model/realm/CustomField.kt b/app/src/main/java/net/pokeranalytics/android/model/realm/CustomField.kt index 7a204e7c..ee0ace73 100644 --- a/app/src/main/java/net/pokeranalytics/android/model/realm/CustomField.kt +++ b/app/src/main/java/net/pokeranalytics/android/model/realm/CustomField.kt @@ -77,8 +77,11 @@ open class CustomField : RealmObject(), NameManageable, StaticRowRepresentableDa val isListType: Boolean get() { return this.type == Type.LIST.uniqueIdentifier } + val isAmountType: Boolean + get() { return this.type == Type.AMOUNT.uniqueIdentifier } - override fun localizedTitle(context: Context): String { + + override fun localizedTitle(context: Context): String { return this.name } diff --git a/app/src/main/java/net/pokeranalytics/android/model/realm/FilterCondition.kt b/app/src/main/java/net/pokeranalytics/android/model/realm/FilterCondition.kt index d0ca264d..35e8fba9 100644 --- a/app/src/main/java/net/pokeranalytics/android/model/realm/FilterCondition.kt +++ b/app/src/main/java/net/pokeranalytics/android/model/realm/FilterCondition.kt @@ -19,8 +19,12 @@ open class FilterCondition() : RealmObject() { this.filterName ?: throw PokerAnalyticsException.FilterElementUnknownName this.operator = row.operator.ordinal when (row) { - is QueryCondition.SingleInt -> this.setValue(row.singleValue) - is QueryCondition.SingleDate -> this.setValue(row.singleValue) + is QueryCondition.CustomFieldRelated -> { + this.setValues(filterElementRows.flatMap { (it as QueryCondition.ListOfString).listOfValues }) + this.stringValue = row.customFieldId + } + is QueryCondition.SingleInt -> this.setValue(row.singleValue?:throw PokerAnalyticsException.FilterElementExpectedValueMissing) + is QueryCondition.SingleDate -> this.setValue(row.singleValue?:throw PokerAnalyticsException.FilterElementExpectedValueMissing) 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 }) diff --git a/app/src/main/java/net/pokeranalytics/android/model/realm/Session.kt b/app/src/main/java/net/pokeranalytics/android/model/realm/Session.kt index 11f87c4f..a8636a63 100644 --- a/app/src/main/java/net/pokeranalytics/android/model/realm/Session.kt +++ b/app/src/main/java/net/pokeranalytics/android/model/realm/Session.kt @@ -94,7 +94,10 @@ open class Session : RealmObject(), Savable, Editable, StaticRowRepresentableDat StartedFromTime::class.java -> "startDateHourMinuteComponent" EndedToTime::class.java -> "endDateHourMinuteComponent" Duration::class.java -> "netDuration" - else -> null + CustomFieldListQuery::class.java -> "customFieldEntries.id" + CustomFieldAmountQuery::class.java, CustomFieldNumberQuery::class.java -> "customFieldEntries.value" + CustomFieldQuery::class.java -> "customFieldEntries.customField.id" + else -> null } } } diff --git a/app/src/main/java/net/pokeranalytics/android/ui/fragment/FeedFragment.kt b/app/src/main/java/net/pokeranalytics/android/ui/fragment/FeedFragment.kt index fa6d129e..9f4393ba 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/fragment/FeedFragment.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/fragment/FeedFragment.kt @@ -28,6 +28,7 @@ import net.pokeranalytics.android.ui.adapter.FeedTransactionRowRepresentableAdap import net.pokeranalytics.android.ui.adapter.RowRepresentableDelegate import net.pokeranalytics.android.ui.fragment.components.FilterableFragment import net.pokeranalytics.android.ui.interfaces.FilterActivityRequestCode +import net.pokeranalytics.android.ui.interfaces.FilterHandler import net.pokeranalytics.android.ui.interfaces.FilterableType import net.pokeranalytics.android.ui.view.RowRepresentable import net.pokeranalytics.android.ui.view.SmoothScrollLinearLayoutManager @@ -98,6 +99,16 @@ class FeedFragment : FilterableFragment(), RowRepresentableDelegate { realmTransactions.removeAllChangeListeners() } + override fun setUserVisibleHint(isVisibleToUser: Boolean) { + super.setUserVisibleHint(isVisibleToUser) + if (isVisibleToUser) { + if (FilterHandler.filterWasUpdated) { + this.initData() + FilterHandler.filterWasUpdated = false + } + } + } + override fun onRowSelected(position: Int, row: RowRepresentable, fromAction: Boolean) { when (row) { is Session -> SessionActivity.newInstance(requireContext(), sessionId = (row as Editable).id) diff --git a/app/src/main/java/net/pokeranalytics/android/ui/fragment/FilterDetailsFragment.kt b/app/src/main/java/net/pokeranalytics/android/ui/fragment/FilterDetailsFragment.kt index b5cff020..1d6a480e 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/fragment/FilterDetailsFragment.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/fragment/FilterDetailsFragment.kt @@ -1,6 +1,7 @@ package net.pokeranalytics.android.ui.fragment import android.app.Activity.RESULT_OK +import android.content.Context import android.content.Intent import android.os.Bundle import android.view.LayoutInflater @@ -21,6 +22,7 @@ import net.pokeranalytics.android.ui.fragment.components.RealmFragment import net.pokeranalytics.android.ui.fragment.components.bottomsheet.BottomSheetFragment import net.pokeranalytics.android.ui.helpers.DateTimePickerManager import net.pokeranalytics.android.ui.view.RowRepresentable +import net.pokeranalytics.android.ui.view.RowRepresentableEditDescriptor import net.pokeranalytics.android.ui.view.RowViewType import net.pokeranalytics.android.ui.view.rowrepresentable.FilterCategoryRow import net.pokeranalytics.android.ui.view.rowrepresentable.FilterElementRow @@ -78,28 +80,32 @@ open class FilterDetailsFragment : RealmFragment(), StaticRowRepresentableDataS when (row) { is QueryCondition.DateQuery -> DateTimePickerManager.create(requireContext(), row, this, row.singleValue, onlyDate = !row.showTime, onlyTime = row.showTime) is QueryCondition.Duration -> { - val hours = if (row.minutes / 60 > 0) (row.minutes / 60).toString() else "" - val minutes = if (row.minutes % 60 > 0) (row.minutes % 60).toString() else "" - val data = row.editingDescriptors(mapOf("hours" to hours, "minutes" to minutes)) + var hours: String? = null + var minutes: String? = null + row.minutes?.let { + hours = if (it / 60 > 0) (it / 60).toString() else null + minutes = if (it % 60 > 0) (it % 60).toString() else null + } + val data = row.editingDescriptors(mapOf("hours" to hours, "minutes" to minutes)) BottomSheetFragment.create(fragmentManager, row, this, data, true) } - is QueryCondition.ListOfValues<*> -> { - val valueAsString = row.listOfValues.firstOrNull()?.toString() ?: "" + var valueAsString: String? = null + row.listOfValues.firstOrNull()?.let { + valueAsString = row.listOfValues.firstOrNull()?.toString() + } val data = row.editingDescriptors(mapOf("valueAsString" to valueAsString)) BottomSheetFragment.create(fragmentManager, row, this, data, true) } } } - override fun stringForRow(row: RowRepresentable): String { - return when (row) { - is QueryCondition.DateQuery -> if (row.showTime) row.singleValue.shortTime() else row.singleValue.shortDate() - is QueryCondition.Duration -> row.minutes.toMinutes(requireContext()) - is QueryCondition.ListOfValues<*> -> row.listOfValues.firstOrNull()?.toString() ?: NULL_TEXT - else -> super.stringForRow(row) - } - } + override fun stringForRow(row: RowRepresentable, context: Context): String { + return when (row) { + is QueryCondition.ListOfValues<*> -> row.firstValue(context) + else -> super.stringForRow(row) + } ?: NULL_TEXT + } override fun isSelected(row: RowRepresentable): Boolean { return selectedRows.contains(row) @@ -110,29 +116,41 @@ open class FilterDetailsFragment : RealmFragment(), StaticRowRepresentableDataS Timber.d("onRowValueChanged: $row $value") when (row) { - is QueryCondition.DateQuery -> row.singleValue = if (value != null && value is Date) value else Date() + is QueryCondition.DateQuery -> row.singleValue = if (value != null && value is Date) value else null is QueryCondition.Duration -> { if (value is ArrayList<*>) { - val hours = try { - (value[0] as String? ?: "0").toInt() + val hours: Int? = try { + (value[0] as String?)?.toInt() } catch (e: Exception) { - 0 + null } val minutes = try { - (value[1] as String? ?: "0").toInt() + (value[1] as String?)?.toInt() } catch (e: Exception) { - 0 + null } - - row.minutes = hours * 60 + minutes + 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 + } } else { - row.minutes = 0 + row.minutes = null } } - is QueryCondition.SingleInt -> row.singleValue = if (value != null && value is String) value.toInt() else 0 - is QueryCondition.ListOfDouble-> row.listOfValues = arrayListOf(if (value != null && value is String) value.toDouble() else 0.0) - is QueryCondition.ListOfInt-> row.listOfValues = arrayListOf(if (value != null && value is String) value.toInt() else 0) - } + is QueryCondition.SingleInt -> row.singleValue = if (value != null && value is String) value.toInt() else null + is QueryCondition.ListOfDouble-> row.listOfValues = arrayListOf().apply { + if (value != null && value is String) this.add(value.toDouble()) + } + is QueryCondition.ListOfInt-> row.listOfValues = arrayListOf().apply { + if (value != null && value is String) this.add(value.toInt()) + } + is QueryCondition.ListOfString-> row.listOfValues = arrayListOf().apply { + if (value != null && value is String) this.add(value) + } + } // Remove the row before updating the selected rows list selectedRows.remove(row as FilterElementRow) diff --git a/app/src/main/java/net/pokeranalytics/android/ui/fragment/StatisticsFragment.kt b/app/src/main/java/net/pokeranalytics/android/ui/fragment/StatisticsFragment.kt index dee2be17..f4419aaf 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/fragment/StatisticsFragment.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/fragment/StatisticsFragment.kt @@ -64,6 +64,16 @@ class StatisticsFragment : FilterableFragment(), FilterHandler { launchStatComputation() } + override fun setUserVisibleHint(isVisibleToUser: Boolean) { + super.setUserVisibleHint(isVisibleToUser) + if (isVisibleToUser) { + if (FilterHandler.filterWasUpdated) { + this.launchStatComputation() + FilterHandler.filterWasUpdated = false + } + } + } + private fun initUI() { val fragmentTransaction = requireFragmentManager().beginTransaction() val fragment = ComposableTableReportFragment.newInstance(null) diff --git a/app/src/main/java/net/pokeranalytics/android/ui/interfaces/FilterHandler.kt b/app/src/main/java/net/pokeranalytics/android/ui/interfaces/FilterHandler.kt index a2068f3b..cbfdd6a7 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/interfaces/FilterHandler.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/interfaces/FilterHandler.kt @@ -30,6 +30,9 @@ enum class FilterableType { } interface FilterHandler { + companion object { + var filterWasUpdated: Boolean = false + } fun createFilter() fun applyFilter() @@ -37,6 +40,7 @@ interface FilterHandler { fun saveFilter(context: Context, filterId:String) { Preferences.setActiveFilterId(filterId, context) + filterWasUpdated = true this.applyFilter() } @@ -87,6 +91,7 @@ interface FilterHandler { 2 -> FiltersActivity.newInstanceForResult(fragment = fragment, filterId = filterId, currentFilterable = currentFilterable) 3 -> { Preferences.removeActiveFilterId(context) + filterWasUpdated = true removeFilter() } } diff --git a/app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/FilterSectionRow.kt b/app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/FilterSectionRow.kt index 4428b680..414a73bc 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/FilterSectionRow.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/FilterSectionRow.kt @@ -1,5 +1,6 @@ package net.pokeranalytics.android.ui.view.rowrepresentable +import android.content.Context import net.pokeranalytics.android.R import net.pokeranalytics.android.exceptions.PokerAnalyticsException import net.pokeranalytics.android.model.Criteria @@ -57,6 +58,15 @@ sealed class FilterSectionRow(override val resId: Int?) : RowRepresentable { open val name = this::class.simpleName ?: throw PokerAnalyticsException.FilterElementUnknownName + override fun getDisplayName(context: Context): String { + when (this) { + is CustomField -> { + return customField.name + } + } + return name + } + val allowMultiSelection: Boolean get() = (this.selectionType == SelectionType.MULTIPLE) @@ -124,6 +134,12 @@ sealed class FilterSectionRow(override val resId: Int?) : RowRepresentable { is CustomField -> { if (this@FilterSectionRow.customField.isListType) { Criteria.ListCustomFields(this@FilterSectionRow.customField).queryConditions.mapFirstCondition() + } else if (this@FilterSectionRow.customField.isAmountType) { + QueryCondition.moreOrLess().apply { + this.forEach { + it.customFieldId = this@FilterSectionRow.customField.id + } + } } else { QueryCondition.moreOrLess().apply { this.forEach {