update and fix time frame filtering (from hour/minute to hour/minute)

dev
Razmig Sarkissian 7 years ago
parent 3c26986a41
commit ddd2ce26f7
  1. 36
      app/src/androidTest/java/net/pokeranalytics/android/unitTests/filter/DateFilterInstrumentedUnitTest.kt
  2. 22
      app/src/main/java/net/pokeranalytics/android/model/filter/Query.kt
  3. 51
      app/src/main/java/net/pokeranalytics/android/model/filter/QueryCondition.kt
  4. 5
      app/src/main/java/net/pokeranalytics/android/model/migrations/PokerAnalyticsMigration.kt
  5. 30
      app/src/main/java/net/pokeranalytics/android/model/realm/Filter.kt
  6. 39
      app/src/main/java/net/pokeranalytics/android/model/realm/Session.kt
  7. 9
      app/src/main/java/net/pokeranalytics/android/ui/fragment/FiltersFragment.kt
  8. 6
      app/src/main/java/net/pokeranalytics/android/util/extensions/DateExtension.kt
  9. 7
      app/src/main/java/net/pokeranalytics/android/util/extensions/NumbersExtension.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.FilterCondition
import net.pokeranalytics.android.model.realm.Session import net.pokeranalytics.android.model.realm.Session
import net.pokeranalytics.android.ui.view.rowrepresentable.FilterSectionRow import net.pokeranalytics.android.ui.view.rowrepresentable.FilterSectionRow
import net.pokeranalytics.android.util.extensions.hourMinute
import net.pokeranalytics.android.util.extensions.startOfDay import net.pokeranalytics.android.util.extensions.startOfDay
import org.junit.Assert import org.junit.Assert
import org.junit.Test import org.junit.Test
@ -481,4 +482,39 @@ class DateFilterInstrumentedUnitTest : BaseFilterInstrumentedUnitTest() {
Assert.assertEquals(s1.id, (this).id) 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<Session>(realm, Query(filter, filter2))
Assert.assertEquals(1, sessions.size)
sessions[0]?.run {
Assert.assertEquals(s2.id, (this).id)
}
}
} }

@ -1,6 +1,7 @@
package net.pokeranalytics.android.model.filter package net.pokeranalytics.android.model.filter
import io.realm.RealmQuery import io.realm.RealmQuery
import io.realm.kotlin.where
fun List<Query>.mapFirstCondition() : List<QueryCondition> { fun List<Query>.mapFirstCondition() : List<QueryCondition> {
return this.map { it.conditions.first() } return this.map { it.conditions.first() }
@ -45,9 +46,26 @@ class Query {
inline fun <reified T : Filterable> queryWith(query: RealmQuery<T>): RealmQuery<T> { inline fun <reified T : Filterable> queryWith(query: RealmQuery<T>): RealmQuery<T> {
var realmQuery = query 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 return realmQuery
} }

@ -20,6 +20,7 @@ import net.pokeranalytics.android.ui.view.rowrepresentable.FilterSectionRow
import net.pokeranalytics.android.util.NULL_TEXT import net.pokeranalytics.android.util.NULL_TEXT
import net.pokeranalytics.android.util.UserDefaults import net.pokeranalytics.android.util.UserDefaults
import net.pokeranalytics.android.util.extensions.endOfDay 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.startOfDay
import net.pokeranalytics.android.util.extensions.toCurrency import net.pokeranalytics.android.util.extensions.toCurrency
import java.text.DateFormatSymbols import java.text.DateFormatSymbols
@ -403,17 +404,17 @@ sealed class QueryCondition : FilterElementRow {
override val bottomSheetType: BottomSheetType = BottomSheetType.DOUBLE_EDIT_TEXT override val bottomSheetType: BottomSheetType = BottomSheetType.DOUBLE_EDIT_TEXT
} }
class StartedFromTime: TimeQuery() { class StartedFromTime(startTime:Date = Date().startOfDay()): TimeQuery() {
override var operator = Operator.MORE override var operator = Operator.MORE
init { init {
this.singleValue = Date().startOfDay() this.singleValue = startTime
} }
} }
class EndedToTime: TimeQuery() { class EndedToTime(endTime:Date = Date().endOfDay()): TimeQuery() {
override var operator = Operator.LESS override var operator = Operator.LESS
init { init {
this.singleValue = Date().endOfDay() this.singleValue = endTime
} }
} }
@ -421,7 +422,7 @@ sealed class QueryCondition : FilterElementRow {
* main method of the enum * 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] * providing a base RealmQuery [realmQuery], the method is able to attached the corresponding query and returns the newly formed [RealmQuery]
*/ */
inline fun <reified T : Filterable> queryWith(realmQuery: RealmQuery<T>): RealmQuery<T> { inline fun <reified T : Filterable> queryWith(realmQuery: RealmQuery<T>, otherQueryCondition:QueryCondition? = null): RealmQuery<T> {
val fieldName = FilterHelper.fieldNameForQueryType<T>(this::class.java) val fieldName = FilterHelper.fieldNameForQueryType<T>(this::class.java)
fieldName ?: throw PokerAnalyticsException.QueryValueMapUnknown fieldName ?: throw PokerAnalyticsException.QueryValueMapUnknown
@ -429,54 +430,74 @@ sealed class QueryCondition : FilterElementRow {
//is Between -> realmQuery.between(fieldName, leftValue, rightValue) //is Between -> realmQuery.between(fieldName, leftValue, rightValue)
//is BetweenLeftExclusive -> realmQuery.greaterThan(fieldName, leftValue).and().lessThanOrEqualTo(fieldName, rightValue) //is BetweenLeftExclusive -> realmQuery.greaterThan(fieldName, leftValue).and().lessThanOrEqualTo(fieldName, rightValue)
//is BetweenRightExclusive -> realmQuery.greaterThanOrEqualTo(fieldName, leftValue).and().lessThan(fieldName, rightValue) //is BetweenRightExclusive -> realmQuery.greaterThanOrEqualTo(fieldName, leftValue).and().lessThan(fieldName, rightValue)
IsLive, IsOnline -> return realmQuery.equalTo(fieldName, this == IsLive) is IsLive, is IsOnline -> return realmQuery.equalTo(fieldName, this == IsLive)
IsCash -> return realmQuery.equalTo(fieldName, Session.Type.CASH_GAME.ordinal) is IsCash -> return realmQuery.equalTo(fieldName, Session.Type.CASH_GAME.ordinal)
IsTournament -> return realmQuery.equalTo(fieldName, Session.Type.TOURNAMENT.ordinal) is IsTournament -> return realmQuery.equalTo(fieldName, Session.Type.TOURNAMENT.ordinal)
IsWeekEnd, IsWeekDay -> { is IsWeekEnd, is IsWeekDay -> {
var query = realmQuery var query = realmQuery
if (this == IsWeekDay) { if (this == IsWeekDay) {
query = realmQuery.not() query = realmQuery.not()
} }
return query.`in`(fieldName, arrayOf(Calendar.SATURDAY, Calendar.SUNDAY)) return query.`in`(fieldName, arrayOf(Calendar.SATURDAY, Calendar.SUNDAY))
} }
IsToday -> { is IsToday -> {
val startDate = Date() val startDate = Date()
return realmQuery.greaterThanOrEqualTo(fieldName, startDate.startOfDay()).and().lessThanOrEqualTo(fieldName, startDate.endOfDay()) return realmQuery.greaterThanOrEqualTo(fieldName, startDate.startOfDay()).and().lessThanOrEqualTo(fieldName, startDate.endOfDay())
} }
WasTodayAndYesterday-> { is WasTodayAndYesterday -> {
val startDate = Date() val startDate = Date()
val calendar = Calendar.getInstance() val calendar = Calendar.getInstance()
calendar.time = startDate calendar.time = startDate
calendar.add(Calendar.HOUR_OF_DAY, -24) calendar.add(Calendar.HOUR_OF_DAY, -24)
return realmQuery.greaterThanOrEqualTo(fieldName, calendar.time.startOfDay()).and().lessThanOrEqualTo(fieldName, startDate.endOfDay()) return realmQuery.greaterThanOrEqualTo(fieldName, calendar.time.startOfDay()).and().lessThanOrEqualTo(fieldName, startDate.endOfDay())
} }
WasYesterday -> { is WasYesterday -> {
val calendar = Calendar.getInstance() val calendar = Calendar.getInstance()
calendar.time = Date() calendar.time = Date()
calendar.add(Calendar.HOUR_OF_DAY, -24) calendar.add(Calendar.HOUR_OF_DAY, -24)
return realmQuery.greaterThanOrEqualTo(fieldName, calendar.time.startOfDay()).and().lessThanOrEqualTo(fieldName, calendar.time.endOfDay()) return realmQuery.greaterThanOrEqualTo(fieldName, calendar.time.startOfDay()).and().lessThanOrEqualTo(fieldName, calendar.time.endOfDay())
} }
DuringThisWeek -> { is DuringThisWeek -> {
val startDate = Date() val startDate = Date()
val calendar = Calendar.getInstance() val calendar = Calendar.getInstance()
calendar.time = startDate calendar.time = startDate
calendar.set(Calendar.DAY_OF_WEEK_IN_MONTH, Calendar.SUNDAY) calendar.set(Calendar.DAY_OF_WEEK_IN_MONTH, Calendar.SUNDAY)
return realmQuery.greaterThanOrEqualTo(fieldName, calendar.time.startOfDay()).and().lessThanOrEqualTo(fieldName, startDate.endOfDay()) return realmQuery.greaterThanOrEqualTo(fieldName, calendar.time.startOfDay()).and().lessThanOrEqualTo(fieldName, startDate.endOfDay())
} }
DuringThisMonth -> { is DuringThisMonth -> {
val startDate = Date() val startDate = Date()
val calendar = Calendar.getInstance() val calendar = Calendar.getInstance()
calendar.time = startDate calendar.time = startDate
calendar.set(Calendar.DAY_OF_MONTH, 1) calendar.set(Calendar.DAY_OF_MONTH, 1)
return realmQuery.greaterThanOrEqualTo(fieldName, calendar.time.startOfDay()).and().lessThanOrEqualTo(fieldName, startDate.endOfDay()) return realmQuery.greaterThanOrEqualTo(fieldName, calendar.time.startOfDay()).and().lessThanOrEqualTo(fieldName, startDate.endOfDay())
} }
DuringThisYear -> { is DuringThisYear -> {
val startDate = Date() val startDate = Date()
val calendar = Calendar.getInstance() val calendar = Calendar.getInstance()
calendar.time = startDate calendar.time = startDate
calendar.set(Calendar.DAY_OF_YEAR, 1) calendar.set(Calendar.DAY_OF_YEAR, 1)
return realmQuery.greaterThanOrEqualTo(fieldName, calendar.time.startOfDay()).and().lessThanOrEqualTo(fieldName, startDate.endOfDay()) 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) { return when (operator) {

@ -112,6 +112,11 @@ class PokerAnalyticsMigration : RealmMigration {
it.addField("duplicateValue", Boolean::class.java) it.addField("duplicateValue", Boolean::class.java)
it.addRealmListField("entries", CustomFieldEntry::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++ currentVersion++
} }
} }

@ -32,15 +32,12 @@ open class Filter : RealmObject(), RowRepresentable {
} }
inline fun <reified T : Filterable> queryOn(realm: Realm, query: Query, sortField: String? = null): RealmResults<T> { inline fun <reified T : Filterable> queryOn(realm: Realm, query: Query, sortField: String? = null): RealmResults<T> {
var realmQuery = realm.where<T>() val realmQuery = realm.where<T>()
query.conditions.forEach {
realmQuery = it.queryWith(realmQuery)
}
sortField?.let { sortField?.let {
realmQuery.sort(it) return query.queryWith(realmQuery).sort(it).findAll()
} } ?: run {
Timber.d(">>> Filter query: ${realmQuery.description}") return query.queryWith(realmQuery).findAll()
return realmQuery.findAll() }
} }
fun sortedByUsage(realm: Realm): RealmResults<Filter> { fun sortedByUsage(realm: Realm): RealmResults<Filter> {
@ -125,22 +122,19 @@ open class Filter : RealmObject(), RowRepresentable {
} }
inline fun <reified T : Filterable> results(firstField: String? = null, secondField: String? = null): RealmResults<T> { inline fun <reified T : Filterable> results(firstField: String? = null, secondField: String? = null): RealmResults<T> {
var realmQuery = realm.where<T>()
this.filterConditions.map { val realmQuery = realm.where<T>()
it.queryCondition
}.forEach {
realmQuery = it.queryWith(realmQuery)
}
if (firstField != null && secondField != null) { if (firstField != null && secondField != null) {
return realmQuery.distinct(firstField, secondField).findAll() return this.query.queryWith(realmQuery).distinct(firstField, secondField).findAll()
} }
if (firstField != null) { 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 val query: Query
get() { get() {

@ -88,6 +88,8 @@ open class Session : RealmObject(), Savable, Editable, StaticRowRepresentableDat
AnyMonthOfYear::class.java -> "month" AnyMonthOfYear::class.java -> "month"
AnyYear::class.java -> "year" AnyYear::class.java -> "year"
IsToday::class.java, WasYesterday::class.java, WasTodayAndYesterday::class.java, DuringThisYear::class.java, DuringThisMonth::class.java, DuringThisWeek::class.java -> "startDate" 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 else -> null
} }
} }
@ -118,12 +120,39 @@ open class Session : RealmObject(), Savable, Editable, StaticRowRepresentableDat
override var year: Int? = null override var year: Int? = null
override var dayOfMonth: 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 * The start date of the session
*/ */
var startDate: Date? = null var startDate: Date? = null
set(value) { set(value) {
field = value field = value
if (field == null) {
startDateHourMinuteComponent = null
} else {
val cal = Calendar.getInstance()
cal.time = field
startDateHourMinuteComponent = cal.hourMinute()
}
this.updateTimeParameter(field) this.updateTimeParameter(field)
this.computeNetDuration() this.computeNetDuration()
@ -142,7 +171,15 @@ open class Session : RealmObject(), Savable, Editable, StaticRowRepresentableDat
var endDate: Date? = null var endDate: Date? = null
set(value) { set(value) {
field = 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.dateChanged()
this.defineDefaultTournamentBuyinIfNecessary() this.defineDefaultTournamentBuyinIfNecessary()
this.computeStats() this.computeStats()

@ -11,7 +11,6 @@ import kotlinx.android.synthetic.main.fragment_editable_data.*
import kotlinx.android.synthetic.main.fragment_filters.view.* import kotlinx.android.synthetic.main.fragment_filters.view.*
import net.pokeranalytics.android.R import net.pokeranalytics.android.R
import net.pokeranalytics.android.model.realm.Filter 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.FilterDetailsActivity
import net.pokeranalytics.android.ui.activity.FiltersActivity import net.pokeranalytics.android.ui.activity.FiltersActivity
import net.pokeranalytics.android.ui.activity.components.PokerAnalyticsActivity import net.pokeranalytics.android.ui.activity.components.PokerAnalyticsActivity
@ -93,7 +92,7 @@ open class FiltersFragment : RealmFragment(), StaticRowRepresentableDataSource,
override fun onOptionsItemSelected(item: MenuItem?): Boolean { override fun onOptionsItemSelected(item: MenuItem?): Boolean {
when (item!!.itemId) { when (item!!.itemId) {
R.id.save -> validUpdates() R.id.save -> validateUpdates()
R.id.delete -> deleteFilter() R.id.delete -> deleteFilter()
} }
return true 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() { private fun validateUpdates() {
Timber.d("Valid queryWith updates") Timber.d("Validate queryWith updates")
val filterId = currentFilter?.id ?: "" val filterId = currentFilter?.id ?: ""
finishActivityWithResult(filterId) finishActivityWithResult(filterId)
} }

@ -7,6 +7,12 @@ import java.util.*
// Calendar // 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 // Return if the calendar dates are in the same month
fun Calendar.isSameMonth(calendar: Calendar): Boolean { fun Calendar.isSameMonth(calendar: Calendar): Boolean {
return calendar.get(Calendar.YEAR) == this.get(Calendar.YEAR) && return calendar.get(Calendar.YEAR) == this.get(Calendar.YEAR) &&

@ -3,6 +3,7 @@ package net.pokeranalytics.android.util.extensions
import android.content.Context import android.content.Context
import net.pokeranalytics.android.R import net.pokeranalytics.android.R
import java.lang.Math.abs import java.lang.Math.abs
import java.math.RoundingMode
import java.text.DecimalFormat import java.text.DecimalFormat
import java.text.NumberFormat import java.text.NumberFormat
import java.util.* import java.util.*
@ -36,6 +37,12 @@ fun Double.round(): String {
return formatter.format(this) return formatter.format(this)
} }
fun Double.roundOffDecimal(): Double {
val df = DecimalFormat("#.##")
df.roundingMode = RoundingMode.CEILING
return df.format(this).toDouble()
}
fun Double.formatted(): String { fun Double.formatted(): String {
val format = NumberFormat.getNumberInstance() val format = NumberFormat.getNumberInstance()
format.maximumFractionDigits = 2 format.maximumFractionDigits = 2

Loading…
Cancel
Save