diff --git a/app/src/androidTest/java/net/pokeranalytics/android/unitTests/filter/DateFilterInstrumentedUnitTest.kt b/app/src/androidTest/java/net/pokeranalytics/android/unitTests/filter/DateFilterInstrumentedUnitTest.kt index a09ba699..46782e1b 100644 --- a/app/src/androidTest/java/net/pokeranalytics/android/unitTests/filter/DateFilterInstrumentedUnitTest.kt +++ b/app/src/androidTest/java/net/pokeranalytics/android/unitTests/filter/DateFilterInstrumentedUnitTest.kt @@ -8,6 +8,7 @@ import net.pokeranalytics.android.model.realm.Filter import net.pokeranalytics.android.model.realm.FilterCondition import net.pokeranalytics.android.model.realm.Session import net.pokeranalytics.android.ui.view.rowrepresentable.FilterSectionRow +import net.pokeranalytics.android.util.extensions.hourMinute import net.pokeranalytics.android.util.extensions.startOfDay import org.junit.Assert import org.junit.Test @@ -481,4 +482,39 @@ class DateFilterInstrumentedUnitTest : BaseFilterInstrumentedUnitTest() { Assert.assertEquals(s1.id, (this).id) } } + + @Test + fun testFomTimeToTime() { + + val realm = this.mockRealm + realm.beginTransaction() + + val cal = Calendar.getInstance() // creates calendar + cal.time = Date() // sets calendar time/date + cal.set(Calendar.HOUR_OF_DAY, 14) // adds one hour + + println("<<<<< s1 ${cal.hourMinute()}") + val s1 = Session.testInstance(100.0, false, cal.time, 1) + println("<<<<< s1 ${cal.hourMinute()}") + cal.add(Calendar.HOUR_OF_DAY, 2) // adds one hour + println("<<<<< s2 ${cal.hourMinute()}") + val s2 = Session.testInstance(100.0, true, cal.time, 1) + println("<<<<< s2 ${cal.hourMinute()}") + + cal.set(Calendar.HOUR_OF_DAY, 23) // adds one hour + println("<<<<< s3 ${cal.hourMinute()}") + val s3 = Session.testInstance(100.0, true, cal.time, 2) + println("<<<<< s3 ${cal.hourMinute()}") + + realm.commitTransaction() + + val filter = QueryCondition.StartedFromTime(s2.startDate!!) + val filter2 = QueryCondition.EndedToTime(s2.endDate!!) + val sessions = Filter.queryOn(realm, Query(filter, filter2)) + + 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/filter/Query.kt b/app/src/main/java/net/pokeranalytics/android/model/filter/Query.kt index ffcfdd62..a977bb50 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 @@ -1,6 +1,7 @@ package net.pokeranalytics.android.model.filter import io.realm.RealmQuery +import io.realm.kotlin.where fun List.mapFirstCondition() : List { return this.map { it.conditions.first() } @@ -45,9 +46,26 @@ class Query { inline fun queryWith(query: RealmQuery): RealmQuery { var realmQuery = query - this.conditions.forEach { - realmQuery = it.queryWith(realmQuery) + + val queryFromTime = this.conditions.filter { + it is QueryCondition.StartedFromTime + }.firstOrNull() + val queryToTime = this.conditions.filter { + it is QueryCondition.EndedToTime + }.firstOrNull() + + println("<<<<< query ft $queryFromTime") + println("<<<<< query tt $queryToTime") + this.conditions.forEach { + if (it is QueryCondition.StartedFromTime) { + realmQuery = it.queryWith(realmQuery, queryToTime) + } else if (it is QueryCondition.EndedToTime) { + realmQuery = it.queryWith(realmQuery, queryFromTime) + } else { + realmQuery = it.queryWith(realmQuery) + } } + 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 88be28b0..a5223c38 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 @@ -20,6 +20,7 @@ import net.pokeranalytics.android.ui.view.rowrepresentable.FilterSectionRow import net.pokeranalytics.android.util.NULL_TEXT import net.pokeranalytics.android.util.UserDefaults import net.pokeranalytics.android.util.extensions.endOfDay +import net.pokeranalytics.android.util.extensions.hourMinute import net.pokeranalytics.android.util.extensions.startOfDay import net.pokeranalytics.android.util.extensions.toCurrency import java.text.DateFormatSymbols @@ -403,17 +404,17 @@ sealed class QueryCondition : FilterElementRow { override val bottomSheetType: BottomSheetType = BottomSheetType.DOUBLE_EDIT_TEXT } - class StartedFromTime: TimeQuery() { + class StartedFromTime(startTime:Date = Date().startOfDay()): TimeQuery() { override var operator = Operator.MORE init { - this.singleValue = Date().startOfDay() + this.singleValue = startTime } } - class EndedToTime: TimeQuery() { + class EndedToTime(endTime:Date = Date().endOfDay()): TimeQuery() { override var operator = Operator.LESS init { - this.singleValue = Date().endOfDay() + this.singleValue = endTime } } @@ -421,7 +422,7 @@ sealed class QueryCondition : FilterElementRow { * 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] */ - inline fun queryWith(realmQuery: RealmQuery): RealmQuery { + inline fun queryWith(realmQuery: RealmQuery, otherQueryCondition:QueryCondition? = null): RealmQuery { val fieldName = FilterHelper.fieldNameForQueryType(this::class.java) fieldName ?: throw PokerAnalyticsException.QueryValueMapUnknown @@ -429,54 +430,74 @@ sealed class QueryCondition : FilterElementRow { //is Between -> realmQuery.between(fieldName, leftValue, rightValue) //is BetweenLeftExclusive -> realmQuery.greaterThan(fieldName, leftValue).and().lessThanOrEqualTo(fieldName, rightValue) //is BetweenRightExclusive -> realmQuery.greaterThanOrEqualTo(fieldName, leftValue).and().lessThan(fieldName, rightValue) - IsLive, IsOnline -> return realmQuery.equalTo(fieldName, this == IsLive) - IsCash -> return realmQuery.equalTo(fieldName, Session.Type.CASH_GAME.ordinal) - IsTournament -> return realmQuery.equalTo(fieldName, Session.Type.TOURNAMENT.ordinal) - IsWeekEnd, IsWeekDay -> { + is IsLive, is IsOnline -> return realmQuery.equalTo(fieldName, this == IsLive) + is IsCash -> return realmQuery.equalTo(fieldName, Session.Type.CASH_GAME.ordinal) + is IsTournament -> return realmQuery.equalTo(fieldName, Session.Type.TOURNAMENT.ordinal) + is IsWeekEnd, is IsWeekDay -> { var query = realmQuery if (this == IsWeekDay) { query = realmQuery.not() } return query.`in`(fieldName, arrayOf(Calendar.SATURDAY, Calendar.SUNDAY)) } - IsToday -> { + is IsToday -> { val startDate = Date() return realmQuery.greaterThanOrEqualTo(fieldName, startDate.startOfDay()).and().lessThanOrEqualTo(fieldName, startDate.endOfDay()) } - WasTodayAndYesterday-> { + is WasTodayAndYesterday -> { val startDate = Date() val calendar = Calendar.getInstance() calendar.time = startDate calendar.add(Calendar.HOUR_OF_DAY, -24) return realmQuery.greaterThanOrEqualTo(fieldName, calendar.time.startOfDay()).and().lessThanOrEqualTo(fieldName, startDate.endOfDay()) } - WasYesterday -> { + is WasYesterday -> { val calendar = Calendar.getInstance() calendar.time = Date() calendar.add(Calendar.HOUR_OF_DAY, -24) return realmQuery.greaterThanOrEqualTo(fieldName, calendar.time.startOfDay()).and().lessThanOrEqualTo(fieldName, calendar.time.endOfDay()) } - DuringThisWeek -> { + is DuringThisWeek -> { val startDate = Date() val calendar = Calendar.getInstance() calendar.time = startDate calendar.set(Calendar.DAY_OF_WEEK_IN_MONTH, Calendar.SUNDAY) return realmQuery.greaterThanOrEqualTo(fieldName, calendar.time.startOfDay()).and().lessThanOrEqualTo(fieldName, startDate.endOfDay()) } - DuringThisMonth -> { + is DuringThisMonth -> { val startDate = Date() val calendar = Calendar.getInstance() calendar.time = startDate calendar.set(Calendar.DAY_OF_MONTH, 1) return realmQuery.greaterThanOrEqualTo(fieldName, calendar.time.startOfDay()).and().lessThanOrEqualTo(fieldName, startDate.endOfDay()) } - DuringThisYear -> { + is DuringThisYear -> { val startDate = Date() val calendar = Calendar.getInstance() calendar.time = startDate calendar.set(Calendar.DAY_OF_YEAR, 1) return realmQuery.greaterThanOrEqualTo(fieldName, calendar.time.startOfDay()).and().lessThanOrEqualTo(fieldName, startDate.endOfDay()) } + is StartedFromTime -> { + val calendar = Calendar.getInstance() + 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() + calendar.time = singleValue + realmQuery.lessThanOrEqualTo(fieldName, calendar.hourMinute()) + if (otherQueryCondition is StartedFromTime) { + calendar.time = otherQueryCondition.singleValue + realmQuery.greaterThanOrEqualTo(fieldName, calendar.hourMinute()) + } + return realmQuery + } } return when (operator) { diff --git a/app/src/main/java/net/pokeranalytics/android/model/migrations/PokerAnalyticsMigration.kt b/app/src/main/java/net/pokeranalytics/android/model/migrations/PokerAnalyticsMigration.kt index a9127c93..524d1119 100644 --- a/app/src/main/java/net/pokeranalytics/android/model/migrations/PokerAnalyticsMigration.kt +++ b/app/src/main/java/net/pokeranalytics/android/model/migrations/PokerAnalyticsMigration.kt @@ -112,6 +112,11 @@ class PokerAnalyticsMigration : RealmMigration { it.addField("duplicateValue", Boolean::class.java) it.addRealmListField("entries", CustomFieldEntry::class.java) } + + schema.get("Session")?.let { + it.addField("startDateHourMinuteComponent", Double::class.java).setNullable("startDateHourMinuteComponent", true) + it.addField("endDateHourMinuteComponent", Double::class.java).setNullable("endDateHourMinuteComponent", true) + } currentVersion++ } } diff --git a/app/src/main/java/net/pokeranalytics/android/model/realm/Filter.kt b/app/src/main/java/net/pokeranalytics/android/model/realm/Filter.kt index a4588e04..89aae3d1 100644 --- a/app/src/main/java/net/pokeranalytics/android/model/realm/Filter.kt +++ b/app/src/main/java/net/pokeranalytics/android/model/realm/Filter.kt @@ -32,15 +32,12 @@ open class Filter : RealmObject(), RowRepresentable { } inline fun queryOn(realm: Realm, query: Query, sortField: String? = null): RealmResults { - var realmQuery = realm.where() - query.conditions.forEach { - realmQuery = it.queryWith(realmQuery) - } + val realmQuery = realm.where() sortField?.let { - realmQuery.sort(it) - } - Timber.d(">>> Filter query: ${realmQuery.description}") - return realmQuery.findAll() + return query.queryWith(realmQuery).sort(it).findAll() + } ?: run { + return query.queryWith(realmQuery).findAll() + } } fun sortedByUsage(realm: Realm): RealmResults { @@ -125,22 +122,19 @@ open class Filter : RealmObject(), RowRepresentable { } inline fun results(firstField: String? = null, secondField: String? = null): RealmResults { - var realmQuery = realm.where() - this.filterConditions.map { - it.queryCondition - }.forEach { - realmQuery = it.queryWith(realmQuery) - } + + val realmQuery = realm.where() if (firstField != null && secondField != null) { - return realmQuery.distinct(firstField, secondField).findAll() + return this.query.queryWith(realmQuery).distinct(firstField, secondField).findAll() } if (firstField != null) { - return realmQuery.distinct(firstField).findAll() + return this.query.queryWith(realmQuery).distinct(firstField).findAll() } - return realmQuery.findAll() - } + + return this.query.queryWith(realmQuery).findAll() + } val query: Query get() { 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 5d5061c1..e9cae7ad 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 @@ -88,6 +88,8 @@ open class Session : RealmObject(), Savable, Editable, StaticRowRepresentableDat AnyMonthOfYear::class.java -> "month" AnyYear::class.java -> "year" IsToday::class.java, WasYesterday::class.java, WasTodayAndYesterday::class.java, DuringThisYear::class.java, DuringThisMonth::class.java, DuringThisWeek::class.java -> "startDate" + StartedFromTime::class.java -> "startDateHourMinuteComponent" + EndedToTime::class.java -> "endDateHourMinuteComponent" else -> null } } @@ -118,12 +120,39 @@ open class Session : RealmObject(), Savable, Editable, StaticRowRepresentableDat override var year: Int? = null override var dayOfMonth: Int? = null + private var startDateHourMinuteComponent: Double? = null + get() { + if (field == null && startDate != null) { + val cal = Calendar.getInstance() + cal.time = startDate + field = cal.hourMinute() + } + return field + } + + private var endDateHourMinuteComponent: Double? = null + get() { + if (field == null && endDate != null) { + val cal = Calendar.getInstance() + cal.time = endDate + field = cal.hourMinute() + } + return field + } + /** * The start date of the session */ var startDate: Date? = null set(value) { field = value + if (field == null) { + startDateHourMinuteComponent = null + } else { + val cal = Calendar.getInstance() + cal.time = field + startDateHourMinuteComponent = cal.hourMinute() + } this.updateTimeParameter(field) this.computeNetDuration() @@ -142,7 +171,15 @@ open class Session : RealmObject(), Savable, Editable, StaticRowRepresentableDat var endDate: Date? = null set(value) { field = value - this.computeNetDuration() + if (field == null) { + endDateHourMinuteComponent = null + } else { + val cal = Calendar.getInstance() + cal.time = field + endDateHourMinuteComponent = cal.hourMinute() + } + + this.computeNetDuration() this.dateChanged() this.defineDefaultTournamentBuyinIfNecessary() this.computeStats() diff --git a/app/src/main/java/net/pokeranalytics/android/ui/fragment/FiltersFragment.kt b/app/src/main/java/net/pokeranalytics/android/ui/fragment/FiltersFragment.kt index e485a5e0..9aeb056d 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/fragment/FiltersFragment.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/fragment/FiltersFragment.kt @@ -11,7 +11,6 @@ import kotlinx.android.synthetic.main.fragment_editable_data.* import kotlinx.android.synthetic.main.fragment_filters.view.* import net.pokeranalytics.android.R import net.pokeranalytics.android.model.realm.Filter -import net.pokeranalytics.android.model.realm.Session import net.pokeranalytics.android.ui.activity.FilterDetailsActivity import net.pokeranalytics.android.ui.activity.FiltersActivity import net.pokeranalytics.android.ui.activity.components.PokerAnalyticsActivity @@ -93,7 +92,7 @@ open class FiltersFragment : RealmFragment(), StaticRowRepresentableDataSource, override fun onOptionsItemSelected(item: MenuItem?): Boolean { when (item!!.itemId) { - R.id.save -> validUpdates() + R.id.save -> validateUpdates() R.id.delete -> deleteFilter() } return true @@ -185,10 +184,10 @@ open class FiltersFragment : RealmFragment(), StaticRowRepresentableDataSource, } /** - * Valid the updates of the queryWith + * Validate the updates of the queryWith */ - private fun validUpdates() { - Timber.d("Valid queryWith updates") + private fun validateUpdates() { + Timber.d("Validate queryWith updates") val filterId = currentFilter?.id ?: "" finishActivityWithResult(filterId) } diff --git a/app/src/main/java/net/pokeranalytics/android/util/extensions/DateExtension.kt b/app/src/main/java/net/pokeranalytics/android/util/extensions/DateExtension.kt index 7c905504..519cdd94 100644 --- a/app/src/main/java/net/pokeranalytics/android/util/extensions/DateExtension.kt +++ b/app/src/main/java/net/pokeranalytics/android/util/extensions/DateExtension.kt @@ -7,6 +7,12 @@ import java.util.* // Calendar +// Return a double representing the hour / minute of a date from a calendar +fun Calendar.hourMinute(): Double { + return (this.get(Calendar.HOUR_OF_DAY) + this.get(Calendar.MINUTE).toDouble()/60.0).roundOffDecimal() +} + + // Return if the calendar dates are in the same month fun Calendar.isSameMonth(calendar: Calendar): Boolean { return calendar.get(Calendar.YEAR) == this.get(Calendar.YEAR) && diff --git a/app/src/main/java/net/pokeranalytics/android/util/extensions/NumbersExtension.kt b/app/src/main/java/net/pokeranalytics/android/util/extensions/NumbersExtension.kt index c2578945..1313248c 100644 --- a/app/src/main/java/net/pokeranalytics/android/util/extensions/NumbersExtension.kt +++ b/app/src/main/java/net/pokeranalytics/android/util/extensions/NumbersExtension.kt @@ -3,6 +3,7 @@ package net.pokeranalytics.android.util.extensions import android.content.Context import net.pokeranalytics.android.R import java.lang.Math.abs +import java.math.RoundingMode import java.text.DecimalFormat import java.text.NumberFormat import java.util.* @@ -36,6 +37,12 @@ fun Double.round(): String { return formatter.format(this) } +fun Double.roundOffDecimal(): Double { + val df = DecimalFormat("#.##") + df.roundingMode = RoundingMode.CEILING + return df.format(this).toDouble() +} + fun Double.formatted(): String { val format = NumberFormat.getNumberInstance() format.maximumFractionDigits = 2