diff --git a/app/build.gradle b/app/build.gradle index 06b06296..d7300416 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -57,6 +57,11 @@ dependencies { implementation 'androidx.lifecycle:lifecycle-extensions:2.0.0' implementation 'androidx.browser:browser:1.0.0' + // Retrofit + implementation 'com.squareup.retrofit2:retrofit:2.5.0' + implementation 'com.squareup.retrofit2:converter-gson:2.5.0' + implementation 'com.squareup.okhttp3:logging-interceptor:3.9.1' + implementation 'com.google.code.gson:gson:2.8.5' // Places implementation 'com.google.android.libraries.places:places:1.0.0' diff --git a/app/src/androidTest/java/net/pokeranalytics/android/FilterInstrumentedUnitTest.kt b/app/src/androidTest/java/net/pokeranalytics/android/FilterInstrumentedUnitTest.kt deleted file mode 100644 index 57e961e6..00000000 --- a/app/src/androidTest/java/net/pokeranalytics/android/FilterInstrumentedUnitTest.kt +++ /dev/null @@ -1,440 +0,0 @@ -package net.pokeranalytics.android - -import androidx.test.ext.junit.runners.AndroidJUnit4 -import io.realm.RealmResults -import net.pokeranalytics.android.model.filter.FilterManager -import net.pokeranalytics.android.model.filter.SessionFilterable -import net.pokeranalytics.android.model.realm.Bankroll -import net.pokeranalytics.android.model.realm.Result -import net.pokeranalytics.android.model.realm.Session -import org.junit.Assert -import org.junit.Test -import org.junit.runner.RunWith -import java.util.* -import java.util.prefs.Preferences - -@RunWith(AndroidJUnit4::class) -class FilterInstrumentedUnitTest : RealmInstrumentedUnitTest() { - - // convenience extension - fun Session.Companion.testInstance(netResult: Double, isTournament: Boolean, startDate: Date, endDate: Int, bankroll:Bankroll? = null): Session { - val session: Session = Session.newInstance(super.mockRealm, isTournament, bankroll) - session.result?.netResult = netResult - session.startDate = startDate - val cal = Calendar.getInstance() // creates calendar - cal.time = startDate // sets calendar time/date - cal.add(Calendar.HOUR_OF_DAY, endDate) // adds one hour - session.endDate = cal.time // returns new date object, one hour in the future - return session - } - - @Test - fun testCashFilter() { - - val realm = this.mockRealm - realm.beginTransaction() - - val s1 = Session.testInstance(100.0, false, Date(), 1) - val s2 = Session.testInstance(100.0, true, Date(), 1) - realm.commitTransaction() - - val sessions = FilterManager().filter( - realm, - Session::class.java, - arrayListOf(SessionFilterable.CASH) - ) as RealmResults - - Assert.assertEquals(1, sessions.size) - sessions[0]?.run { - Assert.assertEquals(Session.Type.CASH_GAME.ordinal, this.type) - } - } - - @Test - fun testTournamentFilter() { - - val realm = this.mockRealm - realm.beginTransaction() - - val s1 = Session.testInstance(100.0, false, Date(), 1) - val s2 = Session.testInstance(100.0, true, Date(), 1) - realm.commitTransaction() - - val sessions = FilterManager().filter( - realm, - Session::class.java, - arrayListOf(SessionFilterable.TOURNAMENT) - ) as RealmResults - - Assert.assertEquals(1, sessions.size) - sessions[0]?.run { - Assert.assertEquals(Session.Type.TOURNAMENT.ordinal, this.type) - } - } - - @Test - fun testLiveFilter() { - - val realm = this.mockRealm - - realm.beginTransaction() - val b1 = realm.createObject(Bankroll::class.java, "1") - val b2 = realm.createObject(Bankroll::class.java, "2") - b1.live = true - b2.live = false - - val s1 = Session.testInstance(100.0, false, Date(), 1, b1) - val s2 = Session.testInstance(100.0, true, Date(), 1, b2) - realm.commitTransaction() - - val sessions = FilterManager().filter( - realm, - Session::class.java, - arrayListOf(SessionFilterable.LIVE) - ) as RealmResults - - Assert.assertEquals(1, sessions.size) - sessions[0]?.bankroll?.run { - Assert.assertEquals(true, this.live) - } - } - - @Test - fun testOnlineFilter() { - - val realm = this.mockRealm - realm.beginTransaction() - val b1 = realm.createObject(Bankroll::class.java, "1") - val b2 = realm.createObject(Bankroll::class.java, "2") - b1.live = false - b2.live = true - - val s1 = Session.testInstance(100.0, false, Date(), 1, b1) - val s2 = Session.testInstance(100.0, true, Date(), 1, b2) - realm.commitTransaction() - - val sessions = FilterManager().filter( - realm, - Session::class.java, - arrayListOf(SessionFilterable.ONLINE) - ) as RealmResults - - Assert.assertEquals(1, sessions.size) - sessions[0]?.bankroll?.run { - Assert.assertEquals(false, this.live) - } - } - - @Test - fun testStartedFomDateFilter() { - - val realm = this.mockRealm - realm.beginTransaction() - - val cal = Calendar.getInstance() // creates calendar - cal.time = Date() // sets calendar time/date - val s1 = Session.testInstance(100.0, false, cal.time, 1) - - cal.add(Calendar.HOUR_OF_DAY, 2) // adds one hour - val s2 = Session.testInstance(100.0, true, cal.time, 1) - realm.commitTransaction() - - var filter = SessionFilterable.STARTED_FROM_DATE - filter.valueMap = mapOf("date" to s2.startDate) - - val sessions = FilterManager().filter( - realm, - Session::class.java, - arrayListOf(filter) - ) as RealmResults - - Assert.assertEquals(1, sessions.size) - sessions[0]?.run { - Assert.assertEquals(s2.id, this.id) - } - } - - @Test - fun testStartedToDateFilter() { - - val realm = this.mockRealm - realm.beginTransaction() - - val cal = Calendar.getInstance() // creates calendar - cal.time = Date() // sets calendar time/date - val s1 = Session.testInstance(100.0, false, cal.time, 1) - - cal.add(Calendar.HOUR_OF_DAY, 2) // adds one hour - val s2 = Session.testInstance(100.0, true, cal.time, 1) - - realm.commitTransaction() - - var filter = SessionFilterable.STARTED_TO_DATE - filter.valueMap = mapOf("date" to s1.startDate) - - val sessions = FilterManager().filter( - realm, - Session::class.java, - arrayListOf(filter) - ) as RealmResults - - Assert.assertEquals(1, sessions.size) - sessions[0]?.run { - Assert.assertEquals(s1.id, this.id) - } - } - - @Test - fun testEndedFomDateFilter() { - - val realm = this.mockRealm - realm.beginTransaction() - - val cal = Calendar.getInstance() // creates calendar - cal.time = Date() // sets calendar time/date - val s1 = Session.testInstance(100.0, false, cal.time, 1) - - cal.add(Calendar.HOUR_OF_DAY, 2) // adds one hour - val s2 = Session.testInstance(100.0, true, cal.time, 1) - - realm.commitTransaction() - - var filter = SessionFilterable.ENDED_FROM_DATE - filter.valueMap = mapOf("date" to s2.endDate) - - val sessions = FilterManager().filter( - realm, - Session::class.java, - arrayListOf(filter) - ) as RealmResults - - Assert.assertEquals(1, sessions.size) - sessions[0]?.run { - Assert.assertEquals(s2.id, this.id) - } - } - - @Test - fun testEndedToDateFilter() { - - val realm = this.mockRealm - realm.beginTransaction() - - val cal = Calendar.getInstance() // creates calendar - cal.time = Date() // sets calendar time/date - val s1 = Session.testInstance(100.0, false, cal.time, 1) - - cal.add(Calendar.HOUR_OF_DAY, 2) // adds one hour - val s2 = Session.testInstance(100.0, true, cal.time, 1) - realm.commitTransaction() - - - var filter = SessionFilterable.ENDED_TO_DATE - filter.valueMap = mapOf("date" to s1.endDate) - - val sessions = FilterManager().filter( - realm, - Session::class.java, - arrayListOf(filter) - ) as RealmResults - - Assert.assertEquals(1, sessions.size) - sessions[0]?.run { - Assert.assertEquals(s1.id, this.id) - } - } - - @Test - fun testSingleBlindNoCurrencyFilter() { - - val realm = this.mockRealm - realm.beginTransaction() - - val currency = realm.createObject(net.pokeranalytics.android.model.realm.Currency::class.java, "1") - currency.code = "AUD" - - val b1 = realm.createObject(Bankroll::class.java, "1") - val b2 = realm.createObject(Bankroll::class.java, "2") - b2.currency = currency - - val s1 = Session.testInstance(100.0, false, Date(), 1, b1) - s1.cgBigBlind = 1.0 - s1.cgSmallBlind = 0.5 - - val s2 = Session.testInstance(100.0, false, Date(), 1, b1) - s2.cgBigBlind = 1.0 - s2.cgSmallBlind = 0.5 - - val s3 = Session.testInstance(100.0, false, Date(), 1, b1) - s3.cgBigBlind = 2.0 - s3.cgSmallBlind = 1.0 - - realm.commitTransaction() - - - var filter = SessionFilterable.BLINDS - filter.valueMap = mapOf("map" to arrayOf(mapOf( - "sb" to 0.5, - "bb" to 1.0, - "code" to null - ))) - - val sessions = FilterManager().filter( - realm, - Session::class.java, - arrayListOf(filter) - ) as RealmResults - - Assert.assertEquals(2, sessions.size) - sessions.map { - Assert.assertTrue(arrayListOf(s1.id, s2.id).contains(it.id)) - } - } - - @Test - fun testSingleBlindNoSmallBlindNoCurrencyFilter() { - - val realm = this.mockRealm - realm.beginTransaction() - - val currency = realm.createObject(net.pokeranalytics.android.model.realm.Currency::class.java, "1") - currency.code = "AUD" - - val b1 = realm.createObject(Bankroll::class.java, "1") - val b2 = realm.createObject(Bankroll::class.java, "2") - b2.currency = currency - - val s1 = Session.testInstance(100.0, false, Date(), 1, b1) - s1.cgBigBlind = 1.0 - s1.cgSmallBlind = 0.5 - - val s2 = Session.testInstance(100.0, false, Date(), 1, b1) - s2.cgBigBlind = 1.0 - s2.cgSmallBlind = 0.5 - - val s3 = Session.testInstance(100.0, false, Date(), 1, b1) - s3.cgBigBlind = 2.0 - s3.cgSmallBlind = 1.0 - - realm.commitTransaction() - - - var filter = SessionFilterable.BLINDS - filter.valueMap = mapOf("map" to arrayOf(mapOf( - "sb" to null, - "bb" to 1.0, - "code" to null - ))) - - val sessions = FilterManager().filter( - realm, - Session::class.java, - arrayListOf(filter) - ) as RealmResults - - Assert.assertEquals(2, sessions.size) - sessions.map { - Assert.assertTrue(arrayListOf(s1.id, s2.id).contains(it.id)) - } - } - - @Test - fun testSingleBlindCurrencyFilter() { - - val realm = this.mockRealm - realm.beginTransaction() - - val currency = realm.createObject(net.pokeranalytics.android.model.realm.Currency::class.java, "1") - currency.code = "AUD" - - val b1 = realm.createObject(Bankroll::class.java, "1") - val b2 = realm.createObject(Bankroll::class.java, "2") - b2.currency = currency - - val s1 = Session.testInstance(100.0, false, Date(), 1, b1) - s1.cgBigBlind = 1.0 - s1.cgSmallBlind = 0.5 - - val s2 = Session.testInstance(100.0, false, Date(), 1, b1) - s2.cgBigBlind = 1.0 - s2.cgSmallBlind = 0.5 - - val s3 = Session.testInstance(100.0, false, Date(), 1, b2) - s3.cgBigBlind = 2.0 - s3.cgSmallBlind = 1.0 - - realm.commitTransaction() - - - var filter = SessionFilterable.BLINDS - filter.valueMap = mapOf("map" to arrayOf(mapOf( - "sb" to 1.0, - "bb" to 2.0, - "code" to "AUD" - ))) - - val sessions = FilterManager().filter( - realm, - Session::class.java, - arrayListOf(filter) - ) as RealmResults - - Assert.assertEquals(1, sessions.size) - sessions.map { - Assert.assertEquals(s3.id, it.id) - } - } - - @Test - fun testMultiBlindNoCurrencyFilter() { - - val realm = this.mockRealm - realm.beginTransaction() - - val currency = realm.createObject(net.pokeranalytics.android.model.realm.Currency::class.java, "1") - currency.code = "AUD" - - val b1 = realm.createObject(Bankroll::class.java, "1") - val b2 = realm.createObject(Bankroll::class.java, "2") - b2.currency = currency - - val s1 = Session.testInstance(100.0, false, Date(), 1, b1) - s1.cgBigBlind = 1.0 - s1.cgSmallBlind = 0.5 - - val s2 = Session.testInstance(100.0, false, Date(), 1, b1) - s2.cgBigBlind = 2.0 - s2.cgSmallBlind = 1.0 - - val s3 = Session.testInstance(100.0, false, Date(), 1, b2) - s3.cgBigBlind = 2.0 - s3.cgSmallBlind = 1.0 - - realm.commitTransaction() - - - var filter = SessionFilterable.BLINDS - filter.valueMap = mapOf("map" to arrayOf( - mapOf( - "sb" to 1.0, - "bb" to 2.0, - "code" to null - ), - mapOf( - "sb" to 0.5, - "bb" to 1.0, - "code" to null - ))) - - val sessions = FilterManager().filter( - realm, - Session::class.java, - arrayListOf(filter) - ) as RealmResults - - Assert.assertEquals(2, sessions.size) - sessions.map { - Assert.assertTrue(arrayListOf(s1.id, s2.id).contains(it.id)) - } - } -} \ No newline at end of file diff --git a/app/src/androidTest/java/net/pokeranalytics/android/filter/BaseFilterInstrumentedUnitTest.kt b/app/src/androidTest/java/net/pokeranalytics/android/filter/BaseFilterInstrumentedUnitTest.kt new file mode 100644 index 00000000..3b80c3c2 --- /dev/null +++ b/app/src/androidTest/java/net/pokeranalytics/android/filter/BaseFilterInstrumentedUnitTest.kt @@ -0,0 +1,41 @@ +package net.pokeranalytics.android.filter + +import io.realm.RealmList +import net.pokeranalytics.android.RealmInstrumentedUnitTest +import net.pokeranalytics.android.model.realm.* +import java.util.* + +open class BaseFilterInstrumentedUnitTest : RealmInstrumentedUnitTest() { + + // convenience extension + fun Session.Companion.testInstance( + netResult: Double = 0.0, + isTournament: Boolean = false, + startDate: Date = Date(), + endDate: Int = 1, + bankroll: Bankroll? = null, + game: Game? = null, + location : Location? = null, + tournamentName: TournamentName? = null, + tournamentFeatures: RealmList = RealmList(), + numberOfTable: Int = 1, + limit: Int? = null, + tableSize: Int? = null + ): Session { + val session: Session = Session.newInstance(super.mockRealm, isTournament, bankroll) + session.game = game + session.location = location + session.tournamentFeatures = tournamentFeatures + session.tournamentName = tournamentName + session.limit = limit + session.numberOfTables = numberOfTable + session.tableSize = tableSize + session.result?.netResult = netResult + session.startDate = startDate + val cal = Calendar.getInstance() // creates calendar + cal.time = startDate // sets calendar time/date + cal.add(Calendar.HOUR_OF_DAY, endDate) // adds one hour + session.endDate = cal.time // returns new date object, one hour in the future + return session + } +} \ No newline at end of file diff --git a/app/src/androidTest/java/net/pokeranalytics/android/filter/BlindFilterInstrumentedTest.kt b/app/src/androidTest/java/net/pokeranalytics/android/filter/BlindFilterInstrumentedTest.kt new file mode 100644 index 00000000..a3ffd4a9 --- /dev/null +++ b/app/src/androidTest/java/net/pokeranalytics/android/filter/BlindFilterInstrumentedTest.kt @@ -0,0 +1,205 @@ +package net.pokeranalytics.android.filter + +import net.pokeranalytics.android.model.filter.FilterManager +import net.pokeranalytics.android.model.filter.SessionFilterable +import net.pokeranalytics.android.model.realm.Bankroll +import net.pokeranalytics.android.model.realm.Session +import org.junit.Assert +import org.junit.Test +import java.util.* + +class BlindFilterInstrumentedTest : BaseFilterInstrumentedUnitTest() { + @Test + fun testSingleBlindNoCurrencyFilter() { + + val realm = this.mockRealm + realm.beginTransaction() + + val currency = realm.createObject(net.pokeranalytics.android.model.realm.Currency::class.java, "1") + currency.code = "AUD" + + val b1 = realm.createObject(Bankroll::class.java, "1") + val b2 = realm.createObject(Bankroll::class.java, "2") + b2.currency = currency + + val s1 = Session.testInstance(100.0, false, Date(), 1, b1) + s1.cgBigBlind = 1.0 + s1.cgSmallBlind = 0.5 + + val s2 = Session.testInstance(100.0, false, Date(), 1, b1) + s2.cgBigBlind = 1.0 + s2.cgSmallBlind = 0.5 + + val s3 = Session.testInstance(100.0, false, Date(), 1, b1) + s3.cgBigBlind = 2.0 + s3.cgSmallBlind = 1.0 + + realm.commitTransaction() + + + val filter = SessionFilterable.BLINDS + filter.valueMap = mapOf("map" to arrayOf(mapOf( + "sb" to 0.5, + "bb" to 1.0, + "code" to null + ))) + + val sessions = FilterManager().filter( + realm, + Session::class.java, + arrayListOf(filter) + ) + + Assert.assertEquals(2, sessions.size) + sessions.map { + Assert.assertTrue(arrayListOf(s1.id, s2.id).contains((it as Session).id)) + } + } + + @Test + fun testSingleBlindNoSmallBlindNoCurrencyFilter() { + + val realm = this.mockRealm + realm.beginTransaction() + + val currency = realm.createObject(net.pokeranalytics.android.model.realm.Currency::class.java, "1") + currency.code = "AUD" + + val b1 = realm.createObject(Bankroll::class.java, "1") + val b2 = realm.createObject(Bankroll::class.java, "2") + b2.currency = currency + + val s1 = Session.testInstance(100.0, false, Date(), 1, b1) + s1.cgBigBlind = 1.0 + s1.cgSmallBlind = 0.5 + + val s2 = Session.testInstance(100.0, false, Date(), 1, b1) + s2.cgBigBlind = 1.0 + s2.cgSmallBlind = 0.5 + + val s3 = Session.testInstance(100.0, false, Date(), 1, b1) + s3.cgBigBlind = 2.0 + s3.cgSmallBlind = 1.0 + + realm.commitTransaction() + + + val filter = SessionFilterable.BLINDS + filter.valueMap = mapOf("map" to arrayOf(mapOf( + "sb" to null, + "bb" to 1.0, + "code" to null + ))) + + val sessions = FilterManager().filter( + realm, + Session::class.java, + arrayListOf(filter) + ) + + Assert.assertEquals(2, sessions.size) + sessions.map { + Assert.assertTrue(arrayListOf(s1.id, s2.id).contains((it as Session).id)) + } + } + + @Test + fun testSingleBlindCurrencyFilter() { + + val realm = this.mockRealm + realm.beginTransaction() + + val currency = realm.createObject(net.pokeranalytics.android.model.realm.Currency::class.java, "1") + currency.code = "AUD" + + val b1 = realm.createObject(Bankroll::class.java, "1") + val b2 = realm.createObject(Bankroll::class.java, "2") + b2.currency = currency + + val s1 = Session.testInstance(100.0, false, Date(), 1, b1) + s1.cgBigBlind = 1.0 + s1.cgSmallBlind = 0.5 + + val s2 = Session.testInstance(100.0, false, Date(), 1, b1) + s2.cgBigBlind = 1.0 + s2.cgSmallBlind = 0.5 + + val s3 = Session.testInstance(100.0, false, Date(), 1, b2) + s3.cgBigBlind = 2.0 + s3.cgSmallBlind = 1.0 + + realm.commitTransaction() + + + val filter = SessionFilterable.BLINDS + filter.valueMap = mapOf("map" to arrayOf(mapOf( + "sb" to 1.0, + "bb" to 2.0, + "code" to "AUD" + ))) + + val sessions = FilterManager().filter( + realm, + Session::class.java, + arrayListOf(filter) + ) + + Assert.assertEquals(1, sessions.size) + sessions.map { + Assert.assertEquals(s3.id, (it as Session).id) + } + } + + @Test + fun testMultiBlindNoCurrencyFilter() { + + val realm = this.mockRealm + realm.beginTransaction() + + val currency = realm.createObject(net.pokeranalytics.android.model.realm.Currency::class.java, "1") + currency.code = "AUD" + + val b1 = realm.createObject(Bankroll::class.java, "1") + val b2 = realm.createObject(Bankroll::class.java, "2") + b2.currency = currency + + val s1 = Session.testInstance(100.0, false, Date(), 1, b1) + s1.cgBigBlind = 1.0 + s1.cgSmallBlind = 0.5 + + val s2 = Session.testInstance(100.0, false, Date(), 1, b1) + s2.cgBigBlind = 2.0 + s2.cgSmallBlind = 1.0 + + val s3 = Session.testInstance(100.0, false, Date(), 1, b2) + s3.cgBigBlind = 2.0 + s3.cgSmallBlind = 1.0 + + realm.commitTransaction() + + + val filter = SessionFilterable.BLINDS + filter.valueMap = mapOf("map" to arrayOf( + mapOf( + "sb" to 1.0, + "bb" to 2.0, + "code" to null + ), + mapOf( + "sb" to 0.5, + "bb" to 1.0, + "code" to null + ))) + + val sessions = FilterManager().filter( + realm, + Session::class.java, + arrayListOf(filter) + ) + + Assert.assertEquals(2, sessions.size) + sessions.map { + Assert.assertTrue(arrayListOf(s1.id, s2.id).contains((it as Session).id)) + } + } +} \ No newline at end of file diff --git a/app/src/androidTest/java/net/pokeranalytics/android/filter/DateFilterInstrumentedUnitTest.kt b/app/src/androidTest/java/net/pokeranalytics/android/filter/DateFilterInstrumentedUnitTest.kt new file mode 100644 index 00000000..700856ab --- /dev/null +++ b/app/src/androidTest/java/net/pokeranalytics/android/filter/DateFilterInstrumentedUnitTest.kt @@ -0,0 +1,274 @@ +package net.pokeranalytics.android.filter + +import androidx.test.ext.junit.runners.AndroidJUnit4 +import net.pokeranalytics.android.model.filter.DateFilterable +import net.pokeranalytics.android.model.filter.FilterManager +import net.pokeranalytics.android.model.realm.Session +import org.junit.Assert +import org.junit.Test +import org.junit.runner.RunWith +import java.util.* + +@RunWith(AndroidJUnit4::class) +class DateFilterInstrumentedUnitTest : BaseFilterInstrumentedUnitTest() { + + @Test + fun testDayOfWeekFilter() { + + val realm = this.mockRealm + realm.beginTransaction() + + val cal = Calendar.getInstance() // creates calendar + cal.time = Date() // sets calendar time/date + val s1 = Session.testInstance(100.0, false, cal.time) + cal.add(Calendar.DAY_OF_MONTH, 1) // adds one hour + Session.testInstance(100.0, true, cal.time) + realm.commitTransaction() + + val filter = DateFilterable.DAY_OF_WEEK + cal.time = s1.startDate + filter.valueMap = mapOf("dayOfWeek" to cal.get(Calendar.DAY_OF_WEEK)) + + val sessions = FilterManager().filter( + realm, + Session::class.java, + arrayListOf(filter) + ) + + Assert.assertEquals(1, sessions.size) + sessions[0]?.run { + Assert.assertEquals(s1.id, (this as Session).id) + } + } + + @Test + fun testMonthFilter() { + + val realm = this.mockRealm + realm.beginTransaction() + val cal = Calendar.getInstance() + cal.time = Date() + val s1 = Session.testInstance(100.0, false, cal.time) + cal.add(Calendar.MONTH, 1) + + Session.testInstance(100.0, true, cal.time) + realm.commitTransaction() + + val filter = DateFilterable.MONTH + cal.time = s1.startDate + filter.valueMap = mapOf("month" to cal.get(Calendar.MONTH)) + + val sessions = FilterManager().filter( + realm, + Session::class.java, + arrayListOf(filter) + ) + + Assert.assertEquals(1, sessions.size) + sessions[0]?.run { + Assert.assertEquals(s1.id, (this as Session).id) + } + } + + @Test + fun testYearFilter() { + + val realm = this.mockRealm + realm.beginTransaction() + val cal = Calendar.getInstance() + cal.time = Date() + val s1 = Session.testInstance(100.0, false, cal.time) + cal.add(Calendar.YEAR, 1) + + Session.testInstance(100.0, true, cal.time) + realm.commitTransaction() + + val filter = DateFilterable.YEAR + cal.time = s1.startDate + filter.valueMap = mapOf("year" to cal.get(Calendar.YEAR)) + + val sessions = FilterManager().filter( + realm, + Session::class.java, + arrayListOf(filter) + ) + + Assert.assertEquals(1, sessions.size) + sessions[0]?.run { + Assert.assertEquals(s1.id, (this as Session).id) + } + } + + + @Test + fun testWeekEndFilter() { + + val realm = this.mockRealm + realm.beginTransaction() + val cal = Calendar.getInstance() + cal.time = Date() + cal.set(Calendar.DAY_OF_WEEK, Calendar.SATURDAY) + val s1 = Session.testInstance(100.0, false, cal.time) + cal.set(Calendar.DAY_OF_WEEK, Calendar.TUESDAY) + + Session.testInstance(100.0, true, cal.time) + realm.commitTransaction() + val sessions = FilterManager().filter( + realm, + Session::class.java, + arrayListOf(DateFilterable.WEEK_END) + ) + + Assert.assertEquals(1, sessions.size) + sessions[0]?.run { + Assert.assertEquals(s1.id, (this as Session).id) + } + } + + @Test + fun testWeekDayFilter() { + + val realm = this.mockRealm + realm.beginTransaction() + val cal = Calendar.getInstance() + cal.time = Date() + cal.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY) + val s1 = Session.testInstance(100.0, false, cal.time) + cal.set(Calendar.DAY_OF_WEEK, Calendar.SUNDAY) + + Session.testInstance(100.0, true, cal.time) + realm.commitTransaction() + val sessions = FilterManager().filter( + realm, + Session::class.java, + arrayListOf(DateFilterable.WEEK_DAY) + ) + + Assert.assertEquals(1, sessions.size) + sessions[0]?.run { + Assert.assertEquals(s1.id, (this as Session).id) + } + } + + @Test + fun testStartedFomDateFilter() { + + val realm = this.mockRealm + realm.beginTransaction() + + val cal = Calendar.getInstance() // creates calendar + cal.time = Date() // sets calendar time/date + + Session.testInstance(100.0, false, cal.time, 1) + + cal.add(Calendar.HOUR_OF_DAY, 2) // adds one hour + val s2 = Session.testInstance(100.0, true, cal.time, 1) + realm.commitTransaction() + + val filter = DateFilterable.STARTED_FROM_DATE + filter.valueMap = mapOf("date" to s2.startDate) + + val sessions = FilterManager().filter( + realm, + Session::class.java, + arrayListOf(filter) + ) + + Assert.assertEquals(1, sessions.size) + sessions[0]?.run { + Assert.assertEquals(s2.id, (this as Session).id) + } + } + + @Test + fun testStartedToDateFilter() { + + val realm = this.mockRealm + realm.beginTransaction() + + val cal = Calendar.getInstance() // creates calendar + cal.time = Date() // sets calendar time/date + val s1 = Session.testInstance(100.0, false, cal.time, 1) + + cal.add(Calendar.HOUR_OF_DAY, 2) // adds one hour + Session.testInstance(100.0, true, cal.time, 1) + + realm.commitTransaction() + + val filter = DateFilterable.STARTED_TO_DATE + filter.valueMap = mapOf("date" to s1.startDate) + + val sessions = FilterManager().filter( + realm, + Session::class.java, + arrayListOf(filter) + ) + + Assert.assertEquals(1, sessions.size) + sessions[0]?.run { + Assert.assertEquals(s1.id, (this as Session).id) + } + } + + @Test + fun testEndedFomDateFilter() { + + val realm = this.mockRealm + realm.beginTransaction() + + val cal = Calendar.getInstance() // creates calendar + cal.time = Date() // sets calendar time/date + + Session.testInstance(100.0, false, cal.time, 1) + + cal.add(Calendar.HOUR_OF_DAY, 2) // adds one hour + val s2 = Session.testInstance(100.0, true, cal.time, 1) + + realm.commitTransaction() + + val filter = DateFilterable.ENDED_FROM_DATE + filter.valueMap = mapOf("date" to s2.endDate) + + val sessions = FilterManager().filter( + realm, + Session::class.java, + arrayListOf(filter) + ) + + Assert.assertEquals(1, sessions.size) + sessions[0]?.run { + Assert.assertEquals(s2.id, (this as Session).id) + } + } + + @Test + fun testEndedToDateFilter() { + + val realm = this.mockRealm + realm.beginTransaction() + + val cal = Calendar.getInstance() // creates calendar + cal.time = Date() // sets calendar time/date + val s1 = Session.testInstance(100.0, false, cal.time, 1) + + cal.add(Calendar.HOUR_OF_DAY, 2) // adds one hour + + Session.testInstance(100.0, true, cal.time, 1) + realm.commitTransaction() + + + val filter = DateFilterable.ENDED_TO_DATE + filter.valueMap = mapOf("date" to s1.endDate) + + val sessions = FilterManager().filter( + realm, + Session::class.java, + arrayListOf(filter) + ) + + Assert.assertEquals(1, sessions.size) + sessions[0]?.run { + Assert.assertEquals(s1.id, (this as Session).id) + } + } +} \ No newline at end of file diff --git a/app/src/androidTest/java/net/pokeranalytics/android/filter/ExceptionFilterInstrumentedTest.kt b/app/src/androidTest/java/net/pokeranalytics/android/filter/ExceptionFilterInstrumentedTest.kt new file mode 100644 index 00000000..bc453c26 --- /dev/null +++ b/app/src/androidTest/java/net/pokeranalytics/android/filter/ExceptionFilterInstrumentedTest.kt @@ -0,0 +1,55 @@ +package net.pokeranalytics.android.filter + +import androidx.test.ext.junit.runners.AndroidJUnit4 +import net.pokeranalytics.android.exceptions.FilterValueMapException +import net.pokeranalytics.android.model.filter.DateFilterable +import net.pokeranalytics.android.model.filter.FilterManager +import net.pokeranalytics.android.model.filter.SessionFilterable +import net.pokeranalytics.android.model.realm.Session +import org.junit.Test +import org.junit.runner.RunWith +import java.util.* + +@RunWith(AndroidJUnit4::class) +class ExceptionFilterInstrumentedTest: BaseFilterInstrumentedUnitTest() { + + @Test(expected = FilterValueMapException::class) + fun testFilterException() { + val realm = this.mockRealm + FilterManager().filter( + realm, + Session::class.java, + arrayListOf(SessionFilterable.BLINDS) + ) + } + + @Test(expected = FilterValueMapException::class) + fun testValueKeyFilterException() { + val filter = DateFilterable.STARTED_FROM_DATE + filter.valueMap = mapOf("bob" to Date()) + + val realm = this.mockRealm + FilterManager().filter( + realm, + Session::class.java, + arrayListOf(filter) + ) + } + + @Test(expected = FilterValueMapException::class) + fun testSubValueKeyFilterException() { + val filter = SessionFilterable.BLINDS + filter.valueMap = mapOf("map" to arrayOf(mapOf( + "bob" to 0.5, + "bb" to 1.0, + "code" to null + ))) + + val realm = this.mockRealm + FilterManager().filter( + realm, + Session::class.java, + arrayListOf(filter) + ) + } +} \ No newline at end of file diff --git a/app/src/androidTest/java/net/pokeranalytics/android/filter/SessionFilterInstrumentedUnitTest.kt b/app/src/androidTest/java/net/pokeranalytics/android/filter/SessionFilterInstrumentedUnitTest.kt new file mode 100644 index 00000000..5b477aef --- /dev/null +++ b/app/src/androidTest/java/net/pokeranalytics/android/filter/SessionFilterInstrumentedUnitTest.kt @@ -0,0 +1,567 @@ +package net.pokeranalytics.android.filter + +import androidx.test.ext.junit.runners.AndroidJUnit4 +import io.realm.RealmList +import net.pokeranalytics.android.model.filter.FilterManager +import net.pokeranalytics.android.model.filter.SessionFilterable +import net.pokeranalytics.android.model.realm.* +import org.junit.Assert +import org.junit.Test +import org.junit.runner.RunWith +import java.util.* + +@RunWith(AndroidJUnit4::class) +class SessionFilterInstrumentedUnitTest : BaseFilterInstrumentedUnitTest() { + + @Test + fun testCashFilter() { + + val realm = this.mockRealm + realm.beginTransaction() + + Session.testInstance(100.0, false, Date(), 1) + Session.testInstance(100.0, true, Date(), 1) + realm.commitTransaction() + + val sessions = FilterManager().filter( + realm, + Session::class.java, + arrayListOf(SessionFilterable.CASH) + ) + + Assert.assertEquals(1, sessions.size) + sessions[0]?.run { + Assert.assertEquals(Session.Type.CASH_GAME.ordinal, (this as Session).type) + } + } + + @Test + fun testTournamentFilter() { + + val realm = this.mockRealm + realm.beginTransaction() + + Session.testInstance(100.0, false, Date(), 1) + Session.testInstance(100.0, true, Date(), 1) + realm.commitTransaction() + + val sessions = FilterManager().filter( + realm, + Session::class.java, + arrayListOf(SessionFilterable.TOURNAMENT) + ) + + Assert.assertEquals(1, sessions.size) + sessions[0]?.run { + Assert.assertEquals(Session.Type.TOURNAMENT.ordinal, (this as Session).type) + } + } + + @Test + fun testLiveFilter() { + + val realm = this.mockRealm + + realm.beginTransaction() + val b1 = realm.createObject(Bankroll::class.java, "1") + val b2 = realm.createObject(Bankroll::class.java, "2") + b1.live = true + b2.live = false + + Session.testInstance(100.0, false, Date(), 1, b1) + Session.testInstance(100.0, true, Date(), 1, b2) + realm.commitTransaction() + + val sessions = FilterManager().filter( + realm, + Session::class.java, + arrayListOf(SessionFilterable.LIVE) + ) + + Assert.assertEquals(1, sessions.size) + (sessions[0] as Session).bankroll?.run { + Assert.assertEquals(true, this.live) + } + } + + @Test + fun testOnlineFilter() { + + val realm = this.mockRealm + realm.beginTransaction() + val b1 = realm.createObject(Bankroll::class.java, "1") + val b2 = realm.createObject(Bankroll::class.java, "2") + b1.live = false + b2.live = true + + Session.testInstance(100.0, false, Date(), 1, b1) + Session.testInstance(100.0, true, Date(), 1, b2) + realm.commitTransaction() + + val sessions = FilterManager().filter( + realm, + Session::class.java, + arrayListOf(SessionFilterable.ONLINE) + ) + + Assert.assertEquals(1, sessions.size) + (sessions[0] as Session).bankroll?.run { + Assert.assertEquals(false, this.live) + } + } + + @Test + fun testBankrollFilter() { + val realm = this.mockRealm + realm.beginTransaction() + val b1 = realm.createObject(Bankroll::class.java, "1") + val b2 = realm.createObject(Bankroll::class.java, "2") + b1.live = false + b2.live = true + Session.testInstance(bankroll = b1) + Session.testInstance(bankroll = b2) + realm.commitTransaction() + + val filter = SessionFilterable.BANKROLL + filter.valueMap = mapOf("ids" to arrayOf(b1.id)) + + val sessions = FilterManager().filter( + realm, + Session::class.java, + arrayListOf(filter) + ) + + Assert.assertEquals(1, sessions.size) + (sessions[0] as Session).bankroll?.run { + Assert.assertEquals(b1.id, this.id) + } + } + + @Test + fun testMultipleBankrollFilter() { + val realm = this.mockRealm + realm.beginTransaction() + val b1 = realm.createObject(Bankroll::class.java, "1") + val b2 = realm.createObject(Bankroll::class.java, "2") + val b3 = realm.createObject(Bankroll::class.java, "3") + Session.testInstance(bankroll = b1) + Session.testInstance(bankroll = b2) + Session.testInstance(bankroll = b3) + Session.testInstance(bankroll = b1) + Session.testInstance(bankroll = b2) + Session.testInstance(bankroll = b3) + Session.testInstance(bankroll = b1) + Session.testInstance(bankroll = b2) + Session.testInstance(bankroll = b3) + realm.commitTransaction() + + val filter = SessionFilterable.BANKROLL + filter.valueMap = mapOf("ids" to arrayOf(b1.id, b2.id)) + + val sessions = FilterManager().filter( + realm, + Session::class.java, + arrayListOf(filter) + ) + + Assert.assertEquals(6, sessions.size) + + val result = arrayListOf(b1.id, b2.id) + + sessions.forEach { + Assert.assertTrue(result.contains((it as Session).bankroll?.id)) + } + } + + @Test + fun testGameFilter() { + val realm = this.mockRealm + realm.beginTransaction() + val g1 = realm.createObject(Game::class.java, "1") + val g2 = realm.createObject(Game::class.java, "2") + Session.testInstance(game = g1) + Session.testInstance(game = g2) + realm.commitTransaction() + + val filter = SessionFilterable.GAME + filter.valueMap = mapOf("ids" to arrayOf(g2.id)) + + val sessions = FilterManager().filter( + realm, + Session::class.java, + arrayListOf(filter) + ) + + Assert.assertEquals(1, sessions.size) + (sessions[0] as Session).game?.run { + Assert.assertEquals(g2.id, this.id) + } + } + + @Test + fun testMultipleGameFilter() { + val realm = this.mockRealm + realm.beginTransaction() + val g1 = realm.createObject(Game::class.java, "1") + val g2 = realm.createObject(Game::class.java, "2") + val g3 = realm.createObject(Game::class.java, "3") + Session.testInstance(game = g1) + Session.testInstance(game = g2) + Session.testInstance(game = g3) + Session.testInstance(game = g1) + Session.testInstance(game = g2) + Session.testInstance(game = g3) + Session.testInstance(game = g1) + Session.testInstance(game = g2) + Session.testInstance(game = g3) + realm.commitTransaction() + + val filter = SessionFilterable.GAME + filter.valueMap = mapOf("ids" to arrayOf(g2.id, g3.id)) + + val sessions = FilterManager().filter( + realm, + Session::class.java, + arrayListOf(filter) + ) + + Assert.assertEquals(6, sessions.size) + + val result = arrayListOf(g2.id, g3.id) + + sessions.forEach { + Assert.assertTrue(result.contains((it as Session).game?.id)) + } + } + + @Test + fun testLocationFilter() { + val realm = this.mockRealm + realm.beginTransaction() + val l1 = realm.createObject(Location::class.java, "1") + val l2 = realm.createObject(Location::class.java, "2") + Session.testInstance(location = l1) + Session.testInstance(location = l2) + realm.commitTransaction() + + val filter = SessionFilterable.LOCATION + filter.valueMap = mapOf("ids" to arrayOf(l1.id)) + + val sessions = FilterManager().filter( + realm, + Session::class.java, + arrayListOf(filter) + ) + + Assert.assertEquals(1, sessions.size) + (sessions[0] as Session).location?.run { + Assert.assertEquals(l1.id, this.id) + } + } + + @Test + fun testMultipleLocationFilter() { + val realm = this.mockRealm + realm.beginTransaction() + val l1 = realm.createObject(Location::class.java, "1") + val l2 = realm.createObject(Location::class.java, "2") + val l3 = realm.createObject(Location::class.java, "3") + Session.testInstance(location = l1) + Session.testInstance(location = l2) + Session.testInstance(location = l3) + Session.testInstance(location = l1) + Session.testInstance(location = l2) + Session.testInstance(location = l3) + Session.testInstance(location = l1) + Session.testInstance(location = l2) + Session.testInstance(location = l3) + realm.commitTransaction() + + val filter = SessionFilterable.LOCATION + filter.valueMap = mapOf("ids" to arrayOf(l1.id, l3.id)) + + val sessions = FilterManager().filter( + realm, + Session::class.java, + arrayListOf(filter) + ) + + Assert.assertEquals(6, sessions.size) + + val result = arrayListOf(l2.id, l3.id) + + sessions.forEach { + Assert.assertTrue(result.contains((it as Session).location?.id)) + } + } + + @Test + fun testTournamentNameFilter() { + val realm = this.mockRealm + realm.beginTransaction() + val t1 = realm.createObject(TournamentName::class.java, "1") + val t2 = realm.createObject(TournamentName::class.java, "2") + Session.testInstance(tournamentName = t1) + Session.testInstance(tournamentName = t2) + realm.commitTransaction() + + val filter = SessionFilterable.TOURNAMENT_NAME + filter.valueMap = mapOf("ids" to arrayOf(t1.id)) + + val sessions = FilterManager().filter( + realm, + Session::class.java, + arrayListOf(filter) + ) + + Assert.assertEquals(1, sessions.size) + (sessions[0] as Session).tournamentName?.run { + Assert.assertEquals(t1.id, this.id) + } + } + + @Test + fun testMultipleTournamentNameFilter() { + val realm = this.mockRealm + realm.beginTransaction() + val t1 = realm.createObject(TournamentName::class.java, "1") + val t2 = realm.createObject(TournamentName::class.java, "2") + val t3 = realm.createObject(TournamentName::class.java, "3") + Session.testInstance(tournamentName = t1) + Session.testInstance(tournamentName = t2) + Session.testInstance(tournamentName = t3) + Session.testInstance(tournamentName = t1) + Session.testInstance(tournamentName = t2) + Session.testInstance(tournamentName = t3) + Session.testInstance(tournamentName = t1) + Session.testInstance(tournamentName = t2) + Session.testInstance(tournamentName = t3) + realm.commitTransaction() + + val filter = SessionFilterable.TOURNAMENT_NAME + filter.valueMap = mapOf("ids" to arrayOf(t1.id, t2.id)) + + val sessions = FilterManager().filter( + realm, + Session::class.java, + arrayListOf(filter) + ) + + Assert.assertEquals(6, sessions.size) + + val result = arrayListOf(t1.id, t2.id) + + sessions.forEach { + Assert.assertTrue(result.contains((it as Session).tournamentName?.id)) + } + } + + @Test + fun testAllTournamentFeatureFilter() { + val realm = this.mockRealm + realm.beginTransaction() + val t1 = realm.createObject(TournamentFeature::class.java, "1") + val t2 = realm.createObject(TournamentFeature::class.java, "2") + val t3 = realm.createObject(TournamentFeature::class.java, "3") + val t4 = realm.createObject(TournamentFeature::class.java, "4") + Session.testInstance(tournamentFeatures = RealmList(t1,t2)) + Session.testInstance(tournamentFeatures = RealmList(t2,t3)) + Session.testInstance(tournamentFeatures = RealmList(t3,t4)) + val s = Session.testInstance(tournamentFeatures = RealmList(t1,t2,t3,t4)) + Session.testInstance(tournamentFeatures = RealmList(t1,t4)) + Session.testInstance(tournamentFeatures = RealmList(t1,t3)) + Session.testInstance(tournamentFeatures = RealmList(t2,t4, t3)) + Session.testInstance(tournamentFeatures = RealmList(t1)) + realm.commitTransaction() + + val filter = SessionFilterable.ALL_TOURNAMENT_FEATURES + filter.valueMap = mapOf("ids" to arrayOf(t1.id, t2.id, t3.id, t4.id)) + + val sessions = FilterManager().filter( + realm, + Session::class.java, + arrayListOf(filter) + ) + + Assert.assertEquals(1, sessions.size) + (sessions[0] as Session)?.run { + Assert.assertEquals(s.id, this.id) + } + } + + @Test + fun testAnyTournamentFeatureFilter() { + val realm = this.mockRealm + realm.beginTransaction() + val t1 = realm.createObject(TournamentFeature::class.java, "1") + val t2 = realm.createObject(TournamentFeature::class.java, "2") + val t3 = realm.createObject(TournamentFeature::class.java, "3") + val t4 = realm.createObject(TournamentFeature::class.java, "4") + Session.testInstance(tournamentFeatures = RealmList(t1,t2)) + Session.testInstance(tournamentFeatures = RealmList(t2,t3)) + Session.testInstance(tournamentFeatures = RealmList(t3,t4)) + Session.testInstance(tournamentFeatures = RealmList(t1,t2,t3,t4)) + Session.testInstance(tournamentFeatures = RealmList(t1,t4)) + Session.testInstance(tournamentFeatures = RealmList(t1,t3)) + Session.testInstance(tournamentFeatures = RealmList(t2,t4, t3)) + Session.testInstance(tournamentFeatures = RealmList(t1)) + realm.commitTransaction() + + val filter = SessionFilterable.ANY_TOURNAMENT_FEATURES + filter.valueMap = mapOf("ids" to arrayOf(t1.id, t2.id, t3.id, t4.id)) + + val sessions = FilterManager().filter( + realm, + Session::class.java, + arrayListOf(filter) + ) + + Assert.assertEquals(8, sessions.size) + } + + @Test + fun testSingleAnyTournamentFeatureFilter() { + val realm = this.mockRealm + realm.beginTransaction() + val t1 = realm.createObject(TournamentFeature::class.java, "1") + val t2 = realm.createObject(TournamentFeature::class.java, "2") + val t3 = realm.createObject(TournamentFeature::class.java, "3") + val t4 = realm.createObject(TournamentFeature::class.java, "4") + val s1 = Session.testInstance(tournamentFeatures = RealmList(t1,t2)) + val s2 = Session.testInstance(tournamentFeatures = RealmList(t2,t3)) + Session.testInstance(tournamentFeatures = RealmList(t3,t4)) + val s3 = Session.testInstance(tournamentFeatures = RealmList(t1,t2,t3,t4)) + Session.testInstance(tournamentFeatures = RealmList(t1,t4)) + Session.testInstance(tournamentFeatures = RealmList(t1,t3)) + val s4 = Session.testInstance(tournamentFeatures = RealmList(t2,t4, t3)) + Session.testInstance(tournamentFeatures = RealmList(t1)) + realm.commitTransaction() + + val filter = SessionFilterable.ANY_TOURNAMENT_FEATURES + filter.valueMap = mapOf("ids" to arrayOf(t2.id)) + + val sessions = FilterManager().filter( + realm, + Session::class.java, + arrayListOf(filter) + ) + + val result = arrayListOf(s1.id, s2.id, s3.id, s4.id) + + Assert.assertEquals(4, sessions.size) + sessions.forEach { + Assert.assertTrue(result.contains((it as Session).id)) + } + } + + @Test + fun testTableSizeFilter() { + val realm = this.mockRealm + realm.beginTransaction() + val s1 = Session.testInstance(tableSize = 2) + val s2 = Session.testInstance(tableSize = 4) + Session.testInstance(tableSize = 9) + Session.testInstance(tableSize = 10) + realm.commitTransaction() + + val filter = SessionFilterable.TABLE_SIZE + filter.valueMap = mapOf("values" to arrayOf(2,4)) + + val sessions = FilterManager().filter( + realm, + Session::class.java, + arrayListOf(filter) + ) + + Assert.assertEquals(2, sessions.size) + + val result = arrayListOf(s1.id, s2.id) + sessions.forEach { + Assert.assertTrue(result.contains((it as Session).id)) + } + } + + @Test + fun testMoreThanNetResultFilter() { + val realm = this.mockRealm + realm.beginTransaction() + Session.testInstance(netResult = 200.0) + val s1 = Session.testInstance(netResult = 500.0) + Session.testInstance(netResult = 50.0) + val s2 = Session.testInstance(netResult = 570.0) + realm.commitTransaction() + + val filter = SessionFilterable.MORE_THAN_NET_RESULT + filter.valueMap = mapOf("net" to 204.0) + + val sessions = FilterManager().filter( + realm, + Session::class.java, + arrayListOf(filter) + ) + + Assert.assertEquals(2, sessions.size) + + val result = arrayListOf(s1.id, s2.id) + sessions.forEach { + Assert.assertTrue(result.contains((it as Session).id)) + } + } + + @Test + fun testLessThanNetResultFilter() { + val realm = this.mockRealm + realm.beginTransaction() + val s1 = Session.testInstance(netResult = 200.0) + val s2 = Session.testInstance(netResult = 500.0) + val s3 = Session.testInstance(netResult = 50.0) + Session.testInstance(netResult = 570.0) + realm.commitTransaction() + + val filter = SessionFilterable.LESS_THAN_NET_RESULT + filter.valueMap = mapOf("net" to 540.0) + + val sessions = FilterManager().filter( + realm, + Session::class.java, + arrayListOf(filter) + ) + + Assert.assertEquals(3, sessions.size) + + val result = arrayListOf(s1.id, s2.id, s3.id) + sessions.forEach { + Assert.assertTrue(result.contains((it as Session).id)) + } + } + + @Test + fun tesNetResultFilter() { + val realm = this.mockRealm + realm.beginTransaction() + val s1 = Session.testInstance(netResult = 200.0) + val s2 = Session.testInstance(netResult = 500.0) + val s3 = Session.testInstance(netResult = 50.0) + Session.testInstance(netResult = 570.0) + realm.commitTransaction() + + val filterMore = SessionFilterable.MORE_THAN_NET_RESULT + filterMore.valueMap = mapOf("net" to 200.0) + + val filterLess = SessionFilterable.LESS_THAN_NET_RESULT + filterLess.valueMap = mapOf("net" to 400.0) + + val sessions = FilterManager().filter( + realm, + Session::class.java, + arrayListOf(filterLess, filterMore) + ) + + Assert.assertEquals(1, sessions.size) + + val result = arrayListOf(s1.id) + sessions.forEach { + Assert.assertTrue(result.contains((it as Session).id)) + } + } +} \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index a7bce528..f3d02022 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -42,9 +42,16 @@ android:launchMode="singleTop" /> + + + + val original = chain.request() + val originalHttpUrl = original.url() + + val url = originalHttpUrl.newBuilder() + .addQueryParameter("apiKey", context.getString(R.string.currency_converter_api)) + .build() + + val requestBuilder = original.newBuilder() + .url(url) + + chain.proceed(requestBuilder.build()) + } + httpClient.addInterceptor(interceptor) + + val client = httpClient + .readTimeout(60, TimeUnit.SECONDS) + .connectTimeout(60, TimeUnit.SECONDS) + .build() + + val retrofit = Retrofit.Builder() + .addConverterFactory(GsonConverterFactory.create()) + .baseUrl(serviceEndpoint.value) + .client(client) + .build() + + currencyConverterApi = retrofit.create(CurrencyConverterApi::class.java) + } + + return currencyConverterApi + } + + } + + @GET("convert") + fun convert(@Query("q") currencies: String, @Query("compact") compact: String = "y"): Call> + +} diff --git a/app/src/main/java/net/pokeranalytics/android/calculus/Stat.kt b/app/src/main/java/net/pokeranalytics/android/calculus/Stat.kt index 31b94ec1..7765025e 100644 --- a/app/src/main/java/net/pokeranalytics/android/calculus/Stat.kt +++ b/app/src/main/java/net/pokeranalytics/android/calculus/Stat.kt @@ -5,10 +5,11 @@ import net.pokeranalytics.android.R import net.pokeranalytics.android.exceptions.FormattingException import net.pokeranalytics.android.ui.view.RowRepresentable import net.pokeranalytics.android.ui.view.RowViewType -import net.pokeranalytics.android.util.FormatUtils +import net.pokeranalytics.android.util.CurrencyUtils import net.pokeranalytics.android.util.NULL_TEXT import net.pokeranalytics.android.util.extensions.formatted import net.pokeranalytics.android.util.extensions.formattedHourlyDuration +import java.util.* /** * An enum representing all the types of Session statistics @@ -99,7 +100,7 @@ enum class Stat : RowRepresentable { /** * ComputedStat contains a [stat] and their associated [value] */ -class ComputedStat(stat: Stat, value: Double) { +class ComputedStat(var stat: Stat, var value: Double, var currency: Currency? = null) { constructor(stat: Stat, value: Double, previousValue: Double?) : this(stat, value) { if (previousValue != null) { @@ -107,16 +108,6 @@ class ComputedStat(stat: Stat, value: Double) { } } - /** - * The statistic type - */ - var stat: Stat = stat - - /** - * The stat value - */ - var value: Double = value - /** * The variation of the stat */ @@ -135,7 +126,7 @@ class ComputedStat(stat: Stat, value: Double) { // Amounts + red/green Stat.NETRESULT, Stat.HOURLY_RATE, Stat.AVERAGE, Stat.NET_BB_PER_100_HANDS, Stat.HOURLY_RATE_BB, Stat.AVERAGE_NET_BB -> { - val numberFormat= FormatUtils.getCurrencyFormatter(context) + val numberFormat= CurrencyUtils.getCurrencyFormatter(context, currency) val color = if (this.value >= this.stat.threshold) R.color.green else R.color.red return TextFormat(numberFormat.format(this.value), color) } // white integers @@ -148,10 +139,10 @@ class ComputedStat(stat: Stat, value: Double) { Stat.WIN_RATIO, Stat.ROI -> { val color = if (value * 100 >= this.stat.threshold) R.color.green else R.color.red return TextFormat("${(value * 100).formatted()}%", color) - } // white amounts + } // white amountsr Stat.AVERAGE_BUYIN, Stat.STANDARD_DEVIATION, Stat.STANDARD_DEVIATION_HOURLY, Stat.STANDARD_DEVIATION_BB_PER_100_HANDS -> { - val numberFormat= FormatUtils.getCurrencyFormatter(context) + val numberFormat= CurrencyUtils.getCurrencyFormatter(context, currency) return TextFormat(numberFormat.format(this.value)) } else -> throw FormattingException("Stat formatting of ${this.stat.name} not handled") diff --git a/app/src/main/java/net/pokeranalytics/android/exceptions/Exceptions.kt b/app/src/main/java/net/pokeranalytics/android/exceptions/Exceptions.kt index ac0e2564..deefbc3c 100644 --- a/app/src/main/java/net/pokeranalytics/android/exceptions/Exceptions.kt +++ b/app/src/main/java/net/pokeranalytics/android/exceptions/Exceptions.kt @@ -10,4 +10,8 @@ class FormattingException(message: String) : Exception(message) { class RowRepresentableEditDescriptorException(message: String) : Exception(message) { +} + +class FilterValueMapException(message: String) : Exception(message) { + } \ No newline at end of file diff --git a/app/src/main/java/net/pokeranalytics/android/model/LiveData.kt b/app/src/main/java/net/pokeranalytics/android/model/LiveData.kt index c89da1bc..5fdd89aa 100644 --- a/app/src/main/java/net/pokeranalytics/android/model/LiveData.kt +++ b/app/src/main/java/net/pokeranalytics/android/model/LiveData.kt @@ -145,6 +145,9 @@ enum class LiveData : Localizable { } } + /** + * Return the new entity title + */ fun newEntityLocalizedTitle(context: Context): String { return "${context.getString(R.string.new_entity)} ${this.localizedTitle(context)}" } diff --git a/app/src/main/java/net/pokeranalytics/android/model/filter/DateFilterable.kt b/app/src/main/java/net/pokeranalytics/android/model/filter/DateFilterable.kt new file mode 100644 index 00000000..b2cad68a --- /dev/null +++ b/app/src/main/java/net/pokeranalytics/android/model/filter/DateFilterable.kt @@ -0,0 +1,77 @@ +package net.pokeranalytics.android.model.filter + +import io.realm.RealmObject +import io.realm.RealmQuery +import net.pokeranalytics.android.model.filter.interfaces.Filterable +import java.util.* + +enum class DateFilterable : Filterable { + STARTED_FROM_DATE, + STARTED_TO_DATE, + ENDED_FROM_DATE, + ENDED_TO_DATE, + DAY_OF_WEEK, + MONTH, + YEAR, + WEEK_DAY, + WEEK_END, + ; + + private enum class Field(var fieldName:String) { + START_DATE("startDate"), + END_DATE("endDate"), + DAY("dayOfWeek"), + MONTH("month"), + YEAR("year"), + } + + override var valueMap : Map? = null + + override val filterValuesExceptedKeys : Array? + get() { + return when (this) { + STARTED_FROM_DATE, STARTED_TO_DATE, ENDED_FROM_DATE, ENDED_TO_DATE -> arrayOf("date") + DAY_OF_WEEK -> arrayOf("dayOfWeek") + MONTH -> arrayOf("month") + YEAR -> arrayOf("year") + else -> null + } + } + + override fun filter(realmQuery: RealmQuery): RealmQuery { + return when (this) { + STARTED_FROM_DATE -> { + val date : Date by filterValues + realmQuery.greaterThanOrEqualTo(Field.START_DATE.fieldName, date) + } + STARTED_TO_DATE -> { + val date : Date by filterValues + realmQuery.lessThanOrEqualTo(Field.START_DATE.fieldName, date) + } + ENDED_FROM_DATE -> { + val date : Date by filterValues + realmQuery.greaterThanOrEqualTo(Field.END_DATE.fieldName, date) + } + ENDED_TO_DATE -> { + val date : Date by filterValues + realmQuery.lessThanOrEqualTo(Field.END_DATE.fieldName, date) + } + DAY_OF_WEEK -> { + val dayOfWeek : Int by filterValues + realmQuery.equalTo(Field.DAY.fieldName, dayOfWeek) + } + MONTH -> { + val month: Int by filterValues + realmQuery.equalTo(Field.MONTH.fieldName, month) + } + YEAR -> { + val year: Int by filterValues + realmQuery.equalTo(Field.YEAR.fieldName, year) + } + WEEK_END -> { + realmQuery.`in`(Field.DAY.fieldName, arrayOf(Calendar.SATURDAY,Calendar.SUNDAY)) + } + WEEK_DAY -> WEEK_END.filter(realmQuery.not()) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/net/pokeranalytics/android/model/filter/FilterComponent.kt b/app/src/main/java/net/pokeranalytics/android/model/filter/FilterComponent.kt index 157ed965..d647bfa1 100644 --- a/app/src/main/java/net/pokeranalytics/android/model/filter/FilterComponent.kt +++ b/app/src/main/java/net/pokeranalytics/android/model/filter/FilterComponent.kt @@ -1,118 +1,5 @@ package net.pokeranalytics.android.model.filter -import io.realm.RealmObject -import io.realm.RealmQuery -import net.pokeranalytics.android.model.realm.Session -import java.util.* - - enum class FilterComponent { } - -enum class SessionFilterable(var fieldName:String? = null) : Filterable { - LIVE("bankroll.live"), - CASH("type"), - ONLINE, - TOURNAMENT, - BANKROLL("bankroll.id"), - GAME("game.id"), - LIMIT("limit"), - TABLE_SIZE("tableSize"), - LOCATION("location.id"), - NUMBEROFTABLE("numberOfTable"), - COMMENT("comment"), - TOURNAMENT_TYPE("tournamentType"), - TOURNAMENT_NAME("tournamentName.id"), - TOURNAMENT_FEATURES("tournamentFeature.id"), - TOURNAMENT_NUMBER_OF_PLAYER("tournamentNumberOfPlayers"), - TOURNAMENT_ENTRY_FEE("tournamentEntryFee"), - RESULT_BUYIN("result.ratedBuyin"), - RESULT_CASHED_OUT("result.cashout"), - RESULT_NET("result.ratedNet"), - RESULT_TIPS("result.tips"), - STARTED_FROM_DATE, - STARTED_TO_DATE, - ENDED_FROM_DATE, - ENDED_TO_DATE, - BLINDS, - ; - - private enum class Field(var fieldName:String) { - START_DATE("startDate"), - END_DATE("endDate"), - CURRENCY("bankroll.currency"), - CURRENCY_CODE("bankroll.currency.code"), - BIG_BLIND("cgBigBlind"), - SMALL_BLIND("cgSmallBlind"); - } - - var valueMap : Map? = null - - override fun filter(realmQuery: RealmQuery<*>): RealmQuery { - return when (this) { - LIVE -> realmQuery.equalTo(this.fieldName, true) - CASH -> realmQuery.equalTo(this.fieldName, Session.Type.CASH_GAME.ordinal) - ONLINE -> LIVE.filter(realmQuery.not()) - TOURNAMENT -> CASH.filter(realmQuery.not()) - BANKROLL -> { - val ids : Array by valueMap - realmQuery.`in`(this.fieldName, ids) - } - STARTED_FROM_DATE -> { - val date : Date by valueMap - realmQuery.greaterThanOrEqualTo(Field.START_DATE.fieldName, date) - } - STARTED_TO_DATE -> { - val date : Date by valueMap - realmQuery.lessThanOrEqualTo(Field.START_DATE.fieldName, date) - } - ENDED_FROM_DATE -> { - val date : Date by valueMap - realmQuery.greaterThanOrEqualTo(Field.END_DATE.fieldName, date) - } - ENDED_TO_DATE -> { - val date : Date by valueMap - realmQuery.lessThanOrEqualTo(Field.END_DATE.fieldName, date) - } - - BLINDS -> { - val map : Array> by valueMap - var finalQuery = realmQuery - map.forEachIndexed { index, it -> - - val sb : Double? by it - val bb : Double? by it - val code : String? by it - - finalQuery - .beginGroup() - - sb?.let { - finalQuery - .equalTo(Field.SMALL_BLIND.fieldName, sb) - .and() - } - - finalQuery - .equalTo(Field.BIG_BLIND.fieldName, bb) - .and() - - code?.let { - finalQuery.equalTo(Field.CURRENCY_CODE.fieldName, code) - } ?: run { - finalQuery.isNull(Field.CURRENCY_CODE.fieldName) - } - - finalQuery.endGroup() - - if (index < map.size - 1) { - finalQuery.or() - } - } - finalQuery - } - else -> realmQuery - } as RealmQuery - } -} \ No newline at end of file diff --git a/app/src/main/java/net/pokeranalytics/android/model/filter/Filterable.kt b/app/src/main/java/net/pokeranalytics/android/model/filter/Filterable.kt index 05ab4baf..bfac5991 100644 --- a/app/src/main/java/net/pokeranalytics/android/model/filter/Filterable.kt +++ b/app/src/main/java/net/pokeranalytics/android/model/filter/Filterable.kt @@ -4,8 +4,7 @@ import io.realm.Realm import io.realm.RealmObject import io.realm.RealmQuery import io.realm.RealmResults -import net.pokeranalytics.android.model.LiveData -import net.pokeranalytics.android.model.realm.* +import net.pokeranalytics.android.model.filter.interfaces.Filterable /** * We want to be able to store filters in the database: @@ -33,20 +32,11 @@ import net.pokeranalytics.android.model.realm.* * */ -interface Filterable { - fun filter(realmQuery: RealmQuery<*>): RealmQuery -} - class FilterManager { - - fun test(realmResults: RealmResults) { - realmResults.where().greaterThan("test", 5).findAll() - } - fun filter(realm:Realm, relatedEntity: Class, queries:List): RealmResults<*> { - var realmQuery = realm.where(relatedEntity) + var realmQuery : RealmQuery = realm.where(relatedEntity) queries.forEach { - realmQuery = it.filter(realmQuery).and() + realmQuery = (it.filter(realmQuery)).and() } return realmQuery.findAll() } diff --git a/app/src/main/java/net/pokeranalytics/android/model/filter/SessionFilterable.kt b/app/src/main/java/net/pokeranalytics/android/model/filter/SessionFilterable.kt new file mode 100644 index 00000000..ee3eb862 --- /dev/null +++ b/app/src/main/java/net/pokeranalytics/android/model/filter/SessionFilterable.kt @@ -0,0 +1,147 @@ +package net.pokeranalytics.android.model.filter + +import io.realm.RealmObject +import io.realm.RealmQuery +import net.pokeranalytics.android.exceptions.FilterValueMapException +import net.pokeranalytics.android.model.filter.interfaces.Filterable +import net.pokeranalytics.android.model.realm.Session + +enum class SessionFilterable(private var fieldName:String? = null): Filterable { + LIVE, + CASH, + ONLINE, + TOURNAMENT, + BANKROLL("bankroll.id"), + GAME("game.id"), + TOURNAMENT_NAME("tournamentName.id"), + ANY_TOURNAMENT_FEATURES, + ALL_TOURNAMENT_FEATURES, + LOCATION("location.id"), + LIMIT("limit"), + TABLE_SIZE("tableSize"), + NUMBER_OF_TABLE("numberOfTable"), + TOURNAMENT_TYPE("tournamentType"), + BLINDS, + LESS_THAN_NET_RESULT, + MORE_THAN_NET_RESULT, + ; + + private enum class Field(var fieldName:String) { + LIVE("bankroll.live"), + CASH("type"), + CURRENCY("bankroll.currency"), + CURRENCY_CODE("bankroll.currency.code"), + BIG_BLIND("cgBigBlind"), + SMALL_BLIND("cgSmallBlind"), + COMMENT("comment"), + TOURNAMENT_FEATURES("tournamentFeatures.id"), + TOURNAMENT_NUMBER_OF_PLAYER("tournamentNumberOfPlayers"), + TOURNAMENT_ENTRY_FEE("tournamentEntryFee"), + RESULT_BUY_IN("result.buyin"), + RESULT_CASHED_OUT("result.cashout"), + RESULT_NET("result.ratedNet"), + RESULT_TIPS("result.tips"), + ; + } + + override var valueMap : Map? = null + + override val filterValuesExceptedKeys : Array? + get() { + return when (this) { + BANKROLL, GAME, LOCATION, ANY_TOURNAMENT_FEATURES, ALL_TOURNAMENT_FEATURES -> arrayOf("ids") + LIMIT, TOURNAMENT_TYPE, TABLE_SIZE, NUMBER_OF_TABLE -> arrayOf("values") + BLINDS -> arrayOf("map") + MORE_THAN_NET_RESULT, LESS_THAN_NET_RESULT -> arrayOf("net") + else -> null + } + } + + var between: Boolean = false + var moreThan: Boolean = false + var lessThan: Boolean = false + var strict: Boolean = false + + override fun filter(realmQuery: RealmQuery): RealmQuery { + return when (this) { + LIVE -> realmQuery.equalTo(Field.LIVE.fieldName, true) + CASH -> realmQuery.equalTo(Field.CASH.fieldName, Session.Type.CASH_GAME.ordinal) + ONLINE -> LIVE.filter(realmQuery.not()) + TOURNAMENT -> CASH.filter(realmQuery.not()) + ALL_TOURNAMENT_FEATURES -> { + val ids : Array by filterValues + ids.forEach { + realmQuery.equalTo(Field.TOURNAMENT_FEATURES.fieldName, it) + } + realmQuery + } + ANY_TOURNAMENT_FEATURES -> { + val ids : Array by filterValues + realmQuery.`in`(Field.TOURNAMENT_FEATURES.fieldName, ids) + } + BANKROLL, GAME, LOCATION, TOURNAMENT_NAME -> { + val ids : Array by filterValues + this.fieldName?.let { + realmQuery.`in`(it, ids) + } ?: run { + throw FilterValueMapException("fieldName is missing") + } + } + LIMIT, TOURNAMENT_TYPE, TABLE_SIZE, NUMBER_OF_TABLE -> { + val values : Array? by filterValues + this.fieldName?.let { + realmQuery.`in`(it, values) + } ?: run { + throw FilterValueMapException("fieldName is missing") + } + } + MORE_THAN_NET_RESULT, LESS_THAN_NET_RESULT -> { + val net : Double by filterValues + if (this == LESS_THAN_NET_RESULT) { + realmQuery.not() + } + realmQuery.greaterThanOrEqualTo(Field.RESULT_NET.fieldName, net) + } + BLINDS -> { + val map : Array> by filterValues + val expectedSubKeys = arrayOf("sb", "bb", "code") + map.forEachIndexed { index, subMap -> + val missingKeys = subMap.keys.filter { !expectedSubKeys.contains(it) } + if (subMap.keys.size == expectedSubKeys.size && missingKeys.isNotEmpty()) { + throw FilterValueMapException("subValueMap does not contain $missingKeys") + } + + val sb : Double? by subMap + val bb : Double? by subMap + val code : String? by subMap + + realmQuery + .beginGroup() + + sb?.let { + realmQuery + .equalTo(Field.SMALL_BLIND.fieldName, sb) + .and() + } + + realmQuery + .equalTo(Field.BIG_BLIND.fieldName, bb) + .and() + + code?.let { + realmQuery.equalTo(Field.CURRENCY_CODE.fieldName, code) + } ?: run { + realmQuery.isNull(Field.CURRENCY_CODE.fieldName) + } + + realmQuery.endGroup() + + if (index < map.size - 1) { + realmQuery.or() + } + } + realmQuery + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/net/pokeranalytics/android/model/filter/interfaces/Filterable.kt b/app/src/main/java/net/pokeranalytics/android/model/filter/interfaces/Filterable.kt new file mode 100644 index 00000000..509ee118 --- /dev/null +++ b/app/src/main/java/net/pokeranalytics/android/model/filter/interfaces/Filterable.kt @@ -0,0 +1,8 @@ +package net.pokeranalytics.android.model.filter.interfaces + +import io.realm.RealmObject +import io.realm.RealmQuery + +interface Filterable : ValueFilterable { + fun filter(realmQuery: RealmQuery): RealmQuery +} diff --git a/app/src/main/java/net/pokeranalytics/android/model/filter/interfaces/TimeFilterable.kt b/app/src/main/java/net/pokeranalytics/android/model/filter/interfaces/TimeFilterable.kt new file mode 100644 index 00000000..f900d86d --- /dev/null +++ b/app/src/main/java/net/pokeranalytics/android/model/filter/interfaces/TimeFilterable.kt @@ -0,0 +1,20 @@ +package net.pokeranalytics.android.model.filter.interfaces + +import java.util.* + +interface TimeFilterable { + + var dayOfWeek : Int? + var month : Int? + var year : Int? + + fun updateTimeParameter(startDate: Date?) { + startDate?.let { + val cal = Calendar.getInstance() + cal.time = it + dayOfWeek = cal.get(Calendar.DAY_OF_WEEK) + month = cal.get(Calendar.MONTH) + year = cal.get(Calendar.YEAR) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/net/pokeranalytics/android/model/filter/interfaces/ValueFilterable.kt b/app/src/main/java/net/pokeranalytics/android/model/filter/interfaces/ValueFilterable.kt new file mode 100644 index 00000000..451b2c30 --- /dev/null +++ b/app/src/main/java/net/pokeranalytics/android/model/filter/interfaces/ValueFilterable.kt @@ -0,0 +1,28 @@ +package net.pokeranalytics.android.model.filter.interfaces + +import net.pokeranalytics.android.exceptions.FilterValueMapException + +interface ValueFilterable { + + var valueMap: Map? + + var filterValues : Map? + get() { + this.filterValuesExceptedKeys?.let { valueMapExceptedKeys -> + valueMap?.let { map -> + var missingKeys = map.keys.filter { !valueMapExceptedKeys.contains(it) } + if (map.keys.size == valueMapExceptedKeys.size && missingKeys.isNotEmpty()) { + throw FilterValueMapException("valueMap does not contain ${missingKeys}") + } + } ?: run { + throw FilterValueMapException("valueMap null not expected") + } + } + return this.valueMap + } + set(value) { + valueMap = value + } + + val filterValuesExceptedKeys : Array? +} \ No newline at end of file diff --git a/app/src/main/java/net/pokeranalytics/android/model/interfaces/Timed.kt b/app/src/main/java/net/pokeranalytics/android/model/interfaces/Timed.kt index 08316cda..0bb7fc80 100644 --- a/app/src/main/java/net/pokeranalytics/android/model/interfaces/Timed.kt +++ b/app/src/main/java/net/pokeranalytics/android/model/interfaces/Timed.kt @@ -14,7 +14,6 @@ interface Timed { var netDuration: Long - /** * Computes the net netDuration of the session */ 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 76816b65..d626d6fd 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 @@ -18,6 +18,7 @@ import net.pokeranalytics.android.model.TableSize import net.pokeranalytics.android.model.TournamentType import net.pokeranalytics.android.model.extensions.SessionState import net.pokeranalytics.android.model.extensions.getState +import net.pokeranalytics.android.model.filter.interfaces.TimeFilterable import net.pokeranalytics.android.model.interfaces.Manageable import net.pokeranalytics.android.model.interfaces.Timed import net.pokeranalytics.android.model.utils.SessionSetManager @@ -29,13 +30,15 @@ import net.pokeranalytics.android.ui.view.RowViewType import net.pokeranalytics.android.ui.view.rowrepresentable.CustomizableRowRepresentable import net.pokeranalytics.android.ui.view.rowrepresentable.SeparatorRowRepresentable import net.pokeranalytics.android.ui.view.rowrepresentable.SessionRow +import net.pokeranalytics.android.util.CurrencyUtils import net.pokeranalytics.android.util.NULL_TEXT import net.pokeranalytics.android.util.extensions.* import java.util.* import java.util.Currency import kotlin.collections.ArrayList -open class Session : RealmObject(), Manageable, StaticRowRepresentableDataSource, RowRepresentable, Timed { +open class Session : RealmObject(), Manageable, StaticRowRepresentableDataSource, RowRepresentable, Timed, + TimeFilterable { // @Ignore // var rate: Double = 0.0 @@ -87,12 +90,18 @@ open class Session : RealmObject(), Manageable, StaticRowRepresentableDataSource // Timed interface + override var dayOfWeek : Int? = null + override var month: Int? = null + override var year: Int? = null + /** * The start date of the session */ var startDate: Date? = null set(value) { field = value + + this.updateTimeParameter(field) this.computeNetDuration() // nullifies endate when setting the start date after the end date if (value != null && this.endDate != null && value.after(this.endDate)) { @@ -515,7 +524,7 @@ open class Session : RealmObject(), Manageable, StaticRowRepresentableDataSource CustomizableRowRepresentable( RowViewType.HEADER_TITLE_AMOUNT_BIG, title = getFormattedDuration(), - computedStat = ComputedStat(Stat.NETRESULT, result?.net ?: 0.0) + computedStat = ComputedStat(Stat.NETRESULT, result?.net ?: 0.0, CurrencyUtils.getCurrency(bankroll)) ) ) rows.add(SeparatorRowRepresentable()) @@ -525,7 +534,7 @@ open class Session : RealmObject(), Manageable, StaticRowRepresentableDataSource CustomizableRowRepresentable( RowViewType.HEADER_TITLE_AMOUNT_BIG, resId = R.string.pause, - computedStat = ComputedStat(Stat.NETRESULT, result?.net ?: 0.0) + computedStat = ComputedStat(Stat.NETRESULT, result?.net ?: 0.0, CurrencyUtils.getCurrency(bankroll)) ) ) rows.add(SeparatorRowRepresentable()) @@ -535,14 +544,14 @@ open class Session : RealmObject(), Manageable, StaticRowRepresentableDataSource CustomizableRowRepresentable( RowViewType.HEADER_TITLE_AMOUNT_BIG, title = getFormattedDuration(), - computedStat = ComputedStat(Stat.NETRESULT, result?.net ?: 0.0) + computedStat = ComputedStat(Stat.NETRESULT, result?.net ?: 0.0, CurrencyUtils.getCurrency(bankroll)) ) ) rows.add( CustomizableRowRepresentable( RowViewType.HEADER_TITLE_AMOUNT, resId = R.string.hour_rate_without_pauses, - computedStat = ComputedStat(Stat.HOURLY_RATE, this.hourlyRate) + computedStat = ComputedStat(Stat.HOURLY_RATE, this.hourlyRate, CurrencyUtils.getCurrency(bankroll)) ) ) @@ -551,7 +560,7 @@ open class Session : RealmObject(), Manageable, StaticRowRepresentableDataSource CustomizableRowRepresentable( RowViewType.HEADER_TITLE_VALUE, resId = R.string.bankroll_variation, - computedStat = ComputedStat(Stat.HOURLY_RATE, 0.0) + computedStat = ComputedStat(Stat.HOURLY_RATE, 0.0, CurrencyUtils.getCurrency(bankroll)) ) ) } @@ -583,18 +592,18 @@ open class Session : RealmObject(), Manageable, StaticRowRepresentableDataSource SessionRow.BANKROLL -> bankroll?.name ?: NULL_TEXT SessionRow.BLINDS -> getBlinds() SessionRow.BREAK_TIME -> if (this.breakDuration > 0.0) this.breakDuration.toMinutes() else NULL_TEXT - SessionRow.BUY_IN -> this.result?.buyin?.toCurrency() ?: NULL_TEXT - SessionRow.CASHED_OUT, SessionRow.PRIZE, SessionRow.NET_RESULT -> this.result?.cashout?.toCurrency() ?: NULL_TEXT + SessionRow.BUY_IN -> this.result?.buyin?.toCurrency(CurrencyUtils.getCurrency(bankroll)) ?: NULL_TEXT + SessionRow.CASHED_OUT, SessionRow.PRIZE, SessionRow.NET_RESULT -> this.result?.cashout?.toCurrency(CurrencyUtils.getCurrency(bankroll)) ?: NULL_TEXT SessionRow.COMMENT -> if (this.comment.isNotEmpty()) this.comment else NULL_TEXT SessionRow.END_DATE -> this.endDate?.shortDateTime() ?: NULL_TEXT SessionRow.GAME -> getGameTitle() - SessionRow.INITIAL_BUY_IN -> tournamentEntryFee?.toCurrency() ?: NULL_TEXT + SessionRow.INITIAL_BUY_IN -> tournamentEntryFee?.toCurrency(CurrencyUtils.getCurrency(bankroll)) ?: NULL_TEXT SessionRow.LOCATION -> location?.name ?: NULL_TEXT SessionRow.PLAYERS -> tournamentNumberOfPlayers?.toString() ?: NULL_TEXT SessionRow.POSITION -> result?.tournamentFinalPosition?.toString() ?: NULL_TEXT SessionRow.START_DATE -> this.startDate?.shortDateTime() ?: NULL_TEXT SessionRow.TABLE_SIZE -> this.tableSize?.let { TableSize(it).localizedTitle(context) } ?: NULL_TEXT - SessionRow.TIPS -> result?.tips?.toCurrency() ?: NULL_TEXT + SessionRow.TIPS -> result?.tips?.toCurrency(CurrencyUtils.getCurrency(bankroll)) ?: NULL_TEXT SessionRow.TOURNAMENT_TYPE -> this.tournamentType?.let { TournamentType.values()[it].localizedTitle(context) } ?: run { @@ -605,10 +614,12 @@ open class Session : RealmObject(), Manageable, StaticRowRepresentableDataSource "${tournamentFeatures.subList(0,2).joinToString { it.name }}, ..." - } else { + } else if (tournamentFeatures.size > 0) { tournamentFeatures.joinToString { it.name } + } else { + NULL_TEXT } } SessionRow.TOURNAMENT_NAME -> tournamentName?.name ?: NULL_TEXT @@ -711,6 +722,7 @@ open class Session : RealmObject(), Manageable, StaticRowRepresentableDataSource val localResult = if (result != null) result as Result else realm.createObject(Result::class.java) localResult.buyin = value as Double? result = localResult + this.updateRowRepresentation() } SessionRow.CASHED_OUT, SessionRow.PRIZE, SessionRow.NET_RESULT -> { val localResult = if (result != null) result as Result else realm.createObject(Result::class.java) diff --git a/app/src/main/java/net/pokeranalytics/android/model/retrofit/ConvertResult.kt b/app/src/main/java/net/pokeranalytics/android/model/retrofit/ConvertResult.kt new file mode 100644 index 00000000..1520c711 --- /dev/null +++ b/app/src/main/java/net/pokeranalytics/android/model/retrofit/ConvertResult.kt @@ -0,0 +1,11 @@ +package net.pokeranalytics.android.model.retrofit + +import com.google.gson.annotations.SerializedName + +/** + * Currency Converter mapping class + */ +class CurrencyConverterValue { + @SerializedName("val") + var value: Double? = 0.0 +} \ No newline at end of file diff --git a/app/src/main/java/net/pokeranalytics/android/ui/activity/FilterDetailsActivity.kt b/app/src/main/java/net/pokeranalytics/android/ui/activity/FilterDetailsActivity.kt new file mode 100644 index 00000000..8d6b4148 --- /dev/null +++ b/app/src/main/java/net/pokeranalytics/android/ui/activity/FilterDetailsActivity.kt @@ -0,0 +1,60 @@ +package net.pokeranalytics.android.ui.activity + +import android.content.Context +import android.content.Intent +import android.os.Bundle +import androidx.fragment.app.Fragment +import net.pokeranalytics.android.R +import net.pokeranalytics.android.ui.activity.components.PokerAnalyticsActivity +import net.pokeranalytics.android.ui.fragment.FilterDetailsFragment + +class FilterDetailsActivity : PokerAnalyticsActivity() { + + enum class IntentKey(val keyName: String) { + FILTER_CATEGORY_ORDINAL("FILTER_CATEGORY_ORDINAL") + } + + companion object { + /** + * Default constructor + */ + fun newInstance(context: Context, filterCategoryOrdinal: Int) { + val intent = Intent(context, FilterDetailsActivity::class.java) + intent.putExtra(IntentKey.FILTER_CATEGORY_ORDINAL.keyName, filterCategoryOrdinal) + context.startActivity(intent) + } + + /** + * Create a new instance for result + */ + fun newInstanceForResult(fragment: Fragment, filterCategoryOrdinal: Int, requestCode: Int) { + val intent = Intent(fragment.requireContext(), FilterDetailsActivity::class.java) + intent.putExtra(IntentKey.FILTER_CATEGORY_ORDINAL.keyName, filterCategoryOrdinal) + fragment.startActivityForResult(intent, requestCode) + } + } + + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_filter_details) + initUI() + } + + /** + * Init UI + */ + private fun initUI() { + + val fragmentManager = supportFragmentManager + val fragmentTransaction = fragmentManager.beginTransaction() + val filterCategoryOrdinal = intent.getIntExtra(IntentKey.FILTER_CATEGORY_ORDINAL.keyName, 0) + + val fragment = FilterDetailsFragment() + fragmentTransaction.add(R.id.container, fragment) + fragmentTransaction.commit() + fragment.setData(filterCategoryOrdinal) + + } + +} \ No newline at end of file diff --git a/app/src/main/java/net/pokeranalytics/android/ui/activity/FiltersActivity.kt b/app/src/main/java/net/pokeranalytics/android/ui/activity/FiltersActivity.kt new file mode 100644 index 00000000..70652990 --- /dev/null +++ b/app/src/main/java/net/pokeranalytics/android/ui/activity/FiltersActivity.kt @@ -0,0 +1,59 @@ +package net.pokeranalytics.android.ui.activity + +import android.content.Context +import android.content.Intent +import android.os.Bundle +import androidx.fragment.app.Fragment +import net.pokeranalytics.android.R +import net.pokeranalytics.android.ui.activity.components.PokerAnalyticsActivity +import net.pokeranalytics.android.ui.fragment.FiltersFragment + +class FiltersActivity : PokerAnalyticsActivity() { + + enum class IntentKey(val keyName: String) { + DATA_TYPE("DATA_TYPE"), + PRIMARY_KEY("PRIMARY_KEY"); + } + + companion object { + /** + * Default constructor + */ + fun newInstance(context: Context) { + val intent = Intent(context, FiltersActivity::class.java) + context.startActivity(intent) + } + + /** + * Create a new instance for result + */ + fun newInstanceForResult(fragment: Fragment, requestCode: Int) { + val intent = Intent(fragment.requireContext(), FiltersActivity::class.java) + fragment.startActivityForResult(intent, requestCode) + } + } + + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_filters) + initUI() + } + + /** + * Init UI + */ + private fun initUI() { + + val fragmentManager = supportFragmentManager + val fragmentTransaction = fragmentManager.beginTransaction() + + val fragment = FiltersFragment() + fragmentTransaction.add(R.id.container, fragment) + fragmentTransaction.commit() + //fragment.setData(dataType, primaryKey) + + } + + +} \ No newline at end of file diff --git a/app/src/main/java/net/pokeranalytics/android/ui/activity/HomeActivity.kt b/app/src/main/java/net/pokeranalytics/android/ui/activity/HomeActivity.kt index 9711602c..56084034 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/activity/HomeActivity.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/activity/HomeActivity.kt @@ -3,6 +3,8 @@ package net.pokeranalytics.android.ui.activity import android.content.Context import android.content.Intent import android.os.Bundle +import android.view.Menu +import android.view.MenuItem import androidx.appcompat.app.AlertDialog import com.google.android.material.bottomnavigation.BottomNavigationView import kotlinx.android.synthetic.main.activity_home.* @@ -10,6 +12,7 @@ import net.pokeranalytics.android.R import net.pokeranalytics.android.ui.activity.components.PokerAnalyticsActivity import net.pokeranalytics.android.ui.adapter.HomePagerAdapter import net.pokeranalytics.android.util.Preferences +import timber.log.Timber class HomeActivity : PokerAnalyticsActivity() { @@ -22,6 +25,8 @@ class HomeActivity : PokerAnalyticsActivity() { } } + private var homeMenu: Menu? = null + private val mOnNavigationItemSelectedListener = BottomNavigationView.OnNavigationItemSelectedListener { item -> when (item.itemId) { net.pokeranalytics.android.R.id.navigation_history -> { @@ -48,10 +53,26 @@ class HomeActivity : PokerAnalyticsActivity() { checkFirstLaunch() } + override fun onCreateOptionsMenu(menu: Menu?): Boolean { + menuInflater.inflate(R.menu.home_menu, menu) + this.homeMenu = menu + return super.onCreateOptionsMenu(menu) + } + + override fun onOptionsItemSelected(item: MenuItem?): Boolean { + when (item?.itemId) { + R.id.filter -> manageFilters() + } + return super.onOptionsItemSelected(item) + } + /** * Init UI */ private fun initUI() { + + setSupportActionBar(toolbar) + navigation.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener) navigation.selectedItemId = net.pokeranalytics.android.R.id.navigation_history @@ -80,16 +101,63 @@ class HomeActivity : PokerAnalyticsActivity() { * Display a new fragment */ private fun displayFragment(index: Int) { + viewPager.setCurrentItem(index, false) + updateToolbar(index) + } - toolbar.title = when (index) { - 0 -> getString(R.string.title_history) - 1 -> getString(R.string.title_stats) - 2 -> getString(R.string.title_settings) - else -> "" + /** + * Update toolbar + */ + private fun updateToolbar(index: Int) { + when (index) { + 0 -> { + toolbar.title = getString(R.string.title_history) + homeMenu?.findItem(R.id.filter)?.isVisible = true + } + 1 -> { + toolbar.title = getString(R.string.title_stats) + homeMenu?.findItem(R.id.filter)?.isVisible = false + } + 2 -> { + toolbar.title = getString(R.string.title_settings) + homeMenu?.findItem(R.id.filter)?.isVisible = false + } } - - viewPager.setCurrentItem(index, false) } + /** + * Manage filters + */ + private fun manageFilters() { + + val filterSelected = false + + val choices = ArrayList() + choices.add(getString(R.string.new_str)) + + if (filterSelected) { + choices.add(getString(R.string.modify_current_filter)) + choices.add(getString(R.string.load_from_db)) + choices.add(getString(R.string.remove_filter)) + } + + val builder = AlertDialog.Builder(this) + builder.setTitle(R.string.filter_selection) + .setCancelable(true) + .setItems(choices.toTypedArray()) { _, which -> + Timber.d("Click on $which") + + when(which) { + 0 -> FiltersActivity.newInstance(this@HomeActivity) + } + + } + .setNegativeButton(R.string.cancel) {dialog, which -> + Timber.d("Click on cancel") + } + + builder.show() + + } } diff --git a/app/src/main/java/net/pokeranalytics/android/ui/fragment/BankrollDataFragment.kt b/app/src/main/java/net/pokeranalytics/android/ui/fragment/BankrollDataFragment.kt index 616fbfb3..446039ed 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/fragment/BankrollDataFragment.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/fragment/BankrollDataFragment.kt @@ -4,12 +4,10 @@ import android.app.Activity.RESULT_OK import android.content.Intent import android.os.Bundle import android.view.View -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.GlobalScope -import kotlinx.coroutines.delay -import kotlinx.coroutines.launch import net.pokeranalytics.android.R +import net.pokeranalytics.android.api.CurrencyConverterApi import net.pokeranalytics.android.model.realm.Bankroll +import net.pokeranalytics.android.model.retrofit.CurrencyConverterValue import net.pokeranalytics.android.ui.activity.CurrenciesActivity import net.pokeranalytics.android.ui.adapter.RowRepresentableDataSource import net.pokeranalytics.android.ui.adapter.StaticRowRepresentableDataSource @@ -22,6 +20,8 @@ import net.pokeranalytics.android.ui.view.rowrepresentable.SimpleRow import net.pokeranalytics.android.util.NULL_TEXT import net.pokeranalytics.android.util.Preferences import net.pokeranalytics.android.util.extensions.round +import retrofit2.Call +import retrofit2.Response import java.util.* /** @@ -42,6 +42,7 @@ class BankrollDataFragment : EditableDataFragment(), StaticRowRepresentableDataS private lateinit var defaultCurrency: Currency private val rows = ArrayList() private var isRefreshingRate = false + private var lastRefreshRateCall = 0L override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) @@ -111,25 +112,20 @@ class BankrollDataFragment : EditableDataFragment(), StaticRowRepresentableDataS override fun onRowSelected(position: Int, row: RowRepresentable, fromAction: Boolean) { when (row) { BankrollRow.CURRENCY -> CurrenciesActivity.newInstanceForResult(this@BankrollDataFragment, BankrollDataFragment.REQUEST_CODE_CURRENCY) - BankrollRow.REFRESH_RATE -> { - isRefreshingRate = true - - //TODO: Call web-service to get the currency rate - GlobalScope.launch(Dispatchers.Main) { - delay(1500) - isRefreshingRate = false - rowRepresentableAdapter.refreshRow(BankrollRow.REFRESH_RATE) - } - rowRepresentableAdapter.refreshRow(BankrollRow.REFRESH_RATE) - } + BankrollRow.REFRESH_RATE -> refreshRate() else -> super.onRowSelected(position, row, fromAction) } } override fun onRowValueChanged(value: Any?, row: RowRepresentable) { super.onRowValueChanged(value, row) - updateAdapterUI() + // Clear the value when the currency has been updated + if (row == BankrollRow.CURRENCY) { + lastRefreshRateCall = 0 + } + + updateAdapterUI() } /** @@ -157,8 +153,6 @@ class BankrollDataFragment : EditableDataFragment(), StaticRowRepresentableDataS rows.add(CustomizableRowRepresentable(customViewType = RowViewType.HEADER_TITLE, resId = R.string.currency)) rows.add(BankrollRow.CURRENCY) - val defaultCurrency = Currency.getInstance(Preferences.getCurrencyLocale(this.parentActivity)) - var differentCurrency = false bankroll.currency?.let { bankrollCurrency -> differentCurrency = bankrollCurrency.code != defaultCurrency.currencyCode @@ -186,5 +180,40 @@ class BankrollDataFragment : EditableDataFragment(), StaticRowRepresentableDataS } } + /** + * Refresh the rate with the Currency Converter API + */ + private fun refreshRate() { + + // Check if the last call was older than 10 seconds + if (System.currentTimeMillis() - lastRefreshRateCall < 10 * 1000 || isRefreshingRate) { + return + } + lastRefreshRateCall = System.currentTimeMillis() + + val currenciesConverterValue = "${defaultCurrency.currencyCode}_${bankroll?.currency?.code}" + val call = CurrencyConverterApi.getApi(requireContext())?.convert(currenciesConverterValue) + call?.enqueue(object : retrofit2.Callback> { + + override fun onResponse(call: Call>, response: Response>) { + response.body()?.let { + it[currenciesConverterValue]?.value?.let {rate -> + onRowValueChanged(rate.toString(), BankrollRow.RATE) + } + } + + isRefreshingRate = false + rowRepresentableAdapter.refreshRow(BankrollRow.REFRESH_RATE) + } + + override fun onFailure(call: Call>, t: Throwable) { + isRefreshingRate = false + rowRepresentableAdapter.refreshRow(BankrollRow.REFRESH_RATE) + } + }) + + isRefreshingRate = true + rowRepresentableAdapter.refreshRow(BankrollRow.REFRESH_RATE) + } } \ No newline at end of file diff --git a/app/src/main/java/net/pokeranalytics/android/ui/fragment/EditableDataFragment.kt b/app/src/main/java/net/pokeranalytics/android/ui/fragment/EditableDataFragment.kt index ce7cdcbd..ed1dd71f 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/fragment/EditableDataFragment.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/fragment/EditableDataFragment.kt @@ -111,7 +111,7 @@ open class EditableDataFragment : PokerAnalyticsFragment(), RowRepresentableDele isUpdating = true } ?: run { //TODO: Localize - this.appBar.toolbar.title = "New ${this.liveDataType.localizedTitle(this.parentActivity).toLowerCase().capitalize()}" + this.appBar.toolbar.title = this.liveDataType.newEntityLocalizedTitle(requireContext()) } this.item = this.liveDataType.updateOrCreate(this.getRealm(), primaryKey) 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 new file mode 100644 index 00000000..a6b90282 --- /dev/null +++ b/app/src/main/java/net/pokeranalytics/android/ui/fragment/FilterDetailsFragment.kt @@ -0,0 +1,245 @@ +package net.pokeranalytics.android.ui.fragment + +import android.os.Bundle +import android.view.* +import androidx.recyclerview.widget.LinearLayoutManager +import io.realm.RealmObject +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.ui.activity.components.PokerAnalyticsActivity +import net.pokeranalytics.android.ui.adapter.RowRepresentableAdapter +import net.pokeranalytics.android.ui.adapter.RowRepresentableDataSource +import net.pokeranalytics.android.ui.adapter.RowRepresentableDelegate +import net.pokeranalytics.android.ui.fragment.components.PokerAnalyticsFragment +import net.pokeranalytics.android.ui.view.RowRepresentable +import net.pokeranalytics.android.ui.view.RowViewType +import net.pokeranalytics.android.ui.view.rowrepresentable.FilterCategoryRow +import net.pokeranalytics.android.ui.view.rowrepresentable.FilterSubcategoryRow +import timber.log.Timber + + +open class FilterDetailsFragment : PokerAnalyticsFragment(), RowRepresentableDataSource, RowRepresentableDelegate { + + lateinit var parentActivity: PokerAnalyticsActivity + lateinit var item: RealmObject + lateinit var rowRepresentableAdapter: RowRepresentableAdapter + + + private var rows: ArrayList = ArrayList() + private var filterMenu: Menu? = null + private var filterCategory: FilterCategoryRow? = null + + var isUpdating = false + var shouldOpenKeyboard = true + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { + return inflater.inflate(R.layout.fragment_filter_details, container, false) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + initUI() + initData() + } + + override fun onCreateOptionsMenu(menu: Menu?, inflater: MenuInflater?) { + /* + inflater?.inflate(R.menu.editable_data, menu) + this.filterMenu = menu + */ + updateMenuUI() + super.onCreateOptionsMenu(menu, inflater) + } + + + override fun onOptionsItemSelected(item: MenuItem?): Boolean { + when (item!!.itemId) { + R.id.save -> saveData() + R.id.delete -> deleteData() + } + return true + } + + override fun onRowSelected(position: Int, row: RowRepresentable, fromAction: Boolean) { + super.onRowSelected(position, row, fromAction) + + + filterCategory?.let { + for (subcategory in it.getSubcategories()) { + if (subcategory.getFilterRows(getRealm()).contains(row)) { + if (subcategory.getType() == FilterSubcategoryRow.Type.SINGLE) { + for (filterRow in subcategory.getFilterRows(getRealm())) { + selectedRows.remove(filterRow) + } + } + } + } + } + + if (selectedRows.contains(row)) { + selectedRows.remove(row) + } else { + selectedRows.add(row) + } + + rowRepresentableAdapter.notifyDataSetChanged() + } + + val selectedRows = ArrayList() + + override fun isSelected(row: RowRepresentable): Boolean { + return selectedRows.contains(row) + } + + override fun onRowValueChanged(value: Any?, row: RowRepresentable) { + super.onRowValueChanged(value, row) + } + + override fun adapterRows(): List? { + return rows + } + + override fun rowRepresentableForPosition(position: Int): RowRepresentable? { + return rows[position] + } + + override fun numberOfRows(): Int { + return rows.size + } + + override fun viewTypeForPosition(position: Int): Int { + val rowViewType = rowRepresentableForPosition(position)?.viewType ?: -1 + return if (rowViewType != -1) rowViewType else RowViewType.TITLE_CHECK.ordinal + } + + override fun indexForRow(row: RowRepresentable): Int { + return rows.indexOf(row) + } + + + /** + * Init UI + */ + private fun initUI() { + parentActivity = activity as PokerAnalyticsActivity + parentActivity.setSupportActionBar(toolbar) + parentActivity.supportActionBar?.setDisplayHomeAsUpEnabled(true) + setHasOptionsMenu(true) + + val viewManager = LinearLayoutManager(requireContext()) + + recyclerView.apply { + setHasFixedSize(true) + layoutManager = viewManager + } + } + + /** + * Init data + */ + private fun initData() { + + Timber.d("initData") + + this.appBar.toolbar.title = getString(R.string.filter) + + filterCategory?.let { + + this.appBar.toolbar.title = it.localizedTitle(requireContext()) + + this.rows.clear() + for (subcategory in it.getSubcategories()) { + this.rows.add(subcategory) + this.rows.addAll(subcategory.getFilterRows(getRealm())) + } + + this.rowRepresentableAdapter = RowRepresentableAdapter(this, this) + this.recyclerView.adapter = rowRepresentableAdapter + } + + } + + /** + * Update menu UI + */ + private fun updateMenuUI() { + /* + editableMenu?.findItem(R.id.delete)?.isVisible = isUpdating + editableMenu?.findItem(R.id.save)?.isVisible = true + */ + } + + /** + * Save data + */ + fun saveData() { + /* + if ((this.item as Savable).isValidForSave()) { + this.getRealm().executeTransaction { + val item = it.copyToRealmOrUpdate(this.item) + + val uniqueIdentifier = if (item is Identifiable) { + item.id + } else "" + + finishActivityWithResult(uniqueIdentifier) + } + } else { + val message = (this.item as Savable).getFailedSaveMessage() + val builder = AlertDialog.Builder(requireContext()) + .setMessage(message) + .setNegativeButton(R.string.ok, null) + builder.show() + } + */ + } + + /** + * Delete data + */ + private fun deleteData() { + /* + val builder = AlertDialog.Builder(requireContext()) + builder.setTitle(R.string.warning) + .setMessage(R.string.are_you_sure_you_want_to_do_that_) + .setNegativeButton(R.string.no, null) + .setPositiveButton(R.string.yes) { _, _ -> + //TODO: Maybe update this code, does the object need to be managed? + this.getRealm().executeTransaction { + this.liveDataType.deleteData(it, (this.item as Manageable)) + } + this.activity?.finish() + } + builder.show() + */ + } + + /** + * Finish the activity with a result + */ + private fun finishActivityWithResult(uniqueIdentifier: String) { + /* + val intent = Intent() + intent.putExtra(EditableDataActivity.IntentKey.DATA_TYPE.keyName, dataType) + intent.putExtra(EditableDataActivity.IntentKey.PRIMARY_KEY.keyName, uniqueIdentifier) + activity?.setResult(RESULT_OK, intent) + */ + activity?.finish() + } + + /** + * Set fragment data + */ + fun setData(filterCategory: Int) { + + this.filterCategory = FilterCategoryRow.values()[filterCategory] + + /* + this.dataType = dataType + this.liveDataType = LiveData.values()[dataType] + this.primaryKey = primaryKey + */ + } + +} \ No newline at end of file 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 new file mode 100644 index 00000000..ed9186d9 --- /dev/null +++ b/app/src/main/java/net/pokeranalytics/android/ui/fragment/FiltersFragment.kt @@ -0,0 +1,191 @@ +package net.pokeranalytics.android.ui.fragment + +import android.os.Bundle +import android.view.* +import androidx.recyclerview.widget.LinearLayoutManager +import io.realm.RealmObject +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.ui.activity.FilterDetailsActivity +import net.pokeranalytics.android.ui.activity.components.PokerAnalyticsActivity +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.PokerAnalyticsFragment +import net.pokeranalytics.android.ui.view.RowRepresentable +import net.pokeranalytics.android.ui.view.rowrepresentable.FilterCategoryRow +import timber.log.Timber + + +open class FiltersFragment : PokerAnalyticsFragment(), StaticRowRepresentableDataSource, RowRepresentableDelegate { + + lateinit var parentActivity: PokerAnalyticsActivity + lateinit var item: RealmObject + lateinit var rowRepresentableAdapter: RowRepresentableAdapter + + private var rows: ArrayList = ArrayList() + private var filterMenu: Menu? = null + private var dataType: Int? = null + private var primaryKey: String? = null + + var isUpdating = false + var shouldOpenKeyboard = true + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { + return inflater.inflate(R.layout.fragment_filters, container, false) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + initUI() + initData() + } + + override fun onCreateOptionsMenu(menu: Menu?, inflater: MenuInflater?) { + /* + inflater?.inflate(R.menu.editable_data, menu) + this.filterMenu = menu + */ + updateMenuUI() + super.onCreateOptionsMenu(menu, inflater) + } + + + override fun onOptionsItemSelected(item: MenuItem?): Boolean { + when (item!!.itemId) { + R.id.save -> saveData() + R.id.delete -> deleteData() + } + return true + } + + override fun adapterRows(): List? { + return rows + } + + override fun onRowSelected(position: Int, row: RowRepresentable, fromAction: Boolean) { + super.onRowSelected(position, row, fromAction) + + if (row is FilterCategoryRow) { + Timber.d("Subcategories: ${row.getSubcategories()}") + FilterDetailsActivity.newInstanceForResult(this, row.ordinal, 1000) + } + + } + + override fun onRowValueChanged(value: Any?, row: RowRepresentable) { + super.onRowValueChanged(value, row) + } + + /** + * Init UI + */ + private fun initUI() { + parentActivity = activity as PokerAnalyticsActivity + parentActivity.setSupportActionBar(toolbar) + parentActivity.supportActionBar?.setDisplayHomeAsUpEnabled(true) + setHasOptionsMenu(true) + + val viewManager = LinearLayoutManager(requireContext()) + + recyclerView.apply { + setHasFixedSize(true) + layoutManager = viewManager + } + } + + /** + * Init data + */ + private fun initData() { + + this.appBar.toolbar.title = getString(R.string.filter) + + rows.addAll(FilterCategoryRow.values()) + + this.rowRepresentableAdapter = RowRepresentableAdapter(this, this) + this.recyclerView.adapter = rowRepresentableAdapter + + } + + /** + * Update menu UI + */ + private fun updateMenuUI() { + /* + editableMenu?.findItem(R.id.delete)?.isVisible = isUpdating + editableMenu?.findItem(R.id.save)?.isVisible = true + */ + } + + /** + * Save data + */ + fun saveData() { + /* + if ((this.item as Savable).isValidForSave()) { + this.getRealm().executeTransaction { + val item = it.copyToRealmOrUpdate(this.item) + + val uniqueIdentifier = if (item is Identifiable) { + item.id + } else "" + + finishActivityWithResult(uniqueIdentifier) + } + } else { + val message = (this.item as Savable).getFailedSaveMessage() + val builder = AlertDialog.Builder(requireContext()) + .setMessage(message) + .setNegativeButton(R.string.ok, null) + builder.show() + } + */ + } + + /** + * Delete data + */ + private fun deleteData() { + /* + val builder = AlertDialog.Builder(requireContext()) + builder.setTitle(R.string.warning) + .setMessage(R.string.are_you_sure_you_want_to_do_that_) + .setNegativeButton(R.string.no, null) + .setPositiveButton(R.string.yes) { _, _ -> + //TODO: Maybe update this code, does the object need to be managed? + this.getRealm().executeTransaction { + this.liveDataType.deleteData(it, (this.item as Manageable)) + } + this.activity?.finish() + } + builder.show() + */ + } + + /** + * Finish the activity with a result + */ + private fun finishActivityWithResult(uniqueIdentifier: String) { + /* + val intent = Intent() + intent.putExtra(EditableDataActivity.IntentKey.DATA_TYPE.keyName, dataType) + intent.putExtra(EditableDataActivity.IntentKey.PRIMARY_KEY.keyName, uniqueIdentifier) + activity?.setResult(RESULT_OK, intent) + */ + activity?.finish() + } + + /** + * Set fragment data + */ + fun setData(dataType: Int, primaryKey: String?) { + /* + this.dataType = dataType + this.liveDataType = LiveData.values()[dataType] + this.primaryKey = primaryKey + */ + } + +} \ No newline at end of file diff --git a/app/src/main/java/net/pokeranalytics/android/ui/fragment/HistoryFragment.kt b/app/src/main/java/net/pokeranalytics/android/ui/fragment/HistoryFragment.kt index 0bcedc4f..175adfc9 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/fragment/HistoryFragment.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/fragment/HistoryFragment.kt @@ -5,7 +5,6 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.core.view.isVisible -import androidx.lifecycle.LiveData import androidx.recyclerview.widget.DiffUtil import io.realm.RealmResults import io.realm.Sort @@ -14,11 +13,7 @@ import kotlinx.android.synthetic.main.fragment_history.* import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.launch import net.pokeranalytics.android.R -import net.pokeranalytics.android.model.filter.FilterManager -import net.pokeranalytics.android.model.filter.Filterable -import net.pokeranalytics.android.model.filter.SessionFilterable import net.pokeranalytics.android.model.interfaces.Manageable -import net.pokeranalytics.android.model.realm.Bankroll import net.pokeranalytics.android.model.realm.Session import net.pokeranalytics.android.ui.activity.SessionActivity import net.pokeranalytics.android.ui.adapter.LiveRowRepresentableDataSource @@ -97,20 +92,6 @@ class HistoryFragment : PokerAnalyticsFragment(), LiveRowRepresentableDataSource * Init data */ private fun initData() { - -/* - var brs = (net.pokeranalytics.android.model.LiveData.BANKROLL.items(getRealm()) as RealmResults).toArray().map{ - (it as Bankroll).id - } - - var br = SessionFilterable.BANKROLL - br.valueMap = mapOf("ids" to arrayOf(brs.last())) - - realmSessions = FilterManager().filter(getRealm(), Session::class.java, arrayListOf(br)) - .sort("creationDate", Sort.DESCENDING) as RealmResults - -// realmSessions = FilterManager().filter(getRealm(), Session::class.java, arrayListOf(SessionFilterable.ONLINE, SessionFilterable.CASH)).sort("creationDate", Sort.DESCENDING) as RealmResults -*/ realmSessions = getRealm().where().findAll().sort("creationDate", Sort.DESCENDING) val viewManager = SmoothScrollLinearLayoutManager(requireContext()) diff --git a/app/src/main/java/net/pokeranalytics/android/ui/fragment/SessionFragment.kt b/app/src/main/java/net/pokeranalytics/android/ui/fragment/SessionFragment.kt index 60e39b00..a067ea5c 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/fragment/SessionFragment.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/fragment/SessionFragment.kt @@ -26,6 +26,7 @@ import net.pokeranalytics.android.ui.view.RowRepresentable import net.pokeranalytics.android.ui.view.RowRepresentableDiffCallback import net.pokeranalytics.android.ui.view.SmoothScrollLinearLayoutManager import net.pokeranalytics.android.ui.view.rowrepresentable.SessionRow +import net.pokeranalytics.android.util.CurrencyUtils import java.util.* @@ -99,9 +100,9 @@ class SessionFragment : PokerAnalyticsFragment(), RowRepresentableDelegate { currentSession.startDate ) SessionRow.BANKROLL -> { - BottomSheetFragment.create(fragmentManager, row, this, data, false) + BottomSheetFragment.create(fragmentManager, row, this, data, false, CurrencyUtils.getCurrency(currentSession.bankroll)) } - else -> BottomSheetFragment.create(fragmentManager, row, this, data) + else -> BottomSheetFragment.create(fragmentManager, row, this, data, currentCurrency = CurrencyUtils.getCurrency(currentSession.bankroll)) } } diff --git a/app/src/main/java/net/pokeranalytics/android/ui/fragment/StatsFragment.kt b/app/src/main/java/net/pokeranalytics/android/ui/fragment/StatsFragment.kt index 6230ef7b..c1effc46 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/fragment/StatsFragment.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/fragment/StatsFragment.kt @@ -30,6 +30,9 @@ class StatsFragment : SessionObserverFragment(), StaticRowRepresentableDataSourc get() = Dispatchers.Main private var rowRepresentables: ArrayList = ArrayList() + private var stringAll = "" + private var stringCashGame = "" + private var stringTournament = "" private lateinit var statsAdapter: RowRepresentableAdapter @@ -55,6 +58,8 @@ class StatsFragment : SessionObserverFragment(), StaticRowRepresentableDataSourc override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) initData() + initUI() + launchStatComputation() } // Row Representable DS @@ -104,10 +109,28 @@ class StatsFragment : SessionObserverFragment(), StaticRowRepresentableDataSourc */ private fun initData() { + this.stringAll = getString(R.string.all) + this.stringCashGame = getString(R.string.cash_game) + this.stringTournament = getString(R.string.tournament) + this.statsAdapter = RowRepresentableAdapter(this) - this.launchStatComputation() } + /** + * Init UI + */ + private fun initUI() { + + val viewManager = LinearLayoutManager(requireContext()) + + recyclerView.apply { + setHasFixedSize(true) + layoutManager = viewManager + adapter = statsAdapter + } + } + + private fun launchStatComputation() { GlobalScope.launch(coroutineContext) { @@ -125,7 +148,10 @@ class StatsFragment : SessionObserverFragment(), StaticRowRepresentableDataSourc } test.await() - showResults(results) + + if (!isDetached) { + showResults(results) + } } } @@ -163,8 +189,6 @@ class StatsFragment : SessionObserverFragment(), StaticRowRepresentableDataSourc val tStats: List = listOf(Stat.NETRESULT, Stat.HOURLY_RATE, Stat.ROI, Stat.WIN_RATIO, Stat.NUMBER_OF_GAMES, Stat.AVERAGE_BUYIN) val tSessionGroup = ComputableGroup(getString(R.string.tournament), tSessions, tStats) - - Timber.d(">>>>> Start computations...") return Calculator.computeGroups(listOf(allSessionGroup, cgSessionGroup, tSessionGroup), Calculator.Options()) @@ -172,16 +196,8 @@ class StatsFragment : SessionObserverFragment(), StaticRowRepresentableDataSourc } private fun showResults(results: List) { - this.rowRepresentables = this.convertResultsIntoRepresentables(results) - - val viewManager = LinearLayoutManager(requireContext()) - - recyclerView.apply { - setHasFixedSize(true) - layoutManager = viewManager - adapter = statsAdapter - } + statsAdapter.notifyDataSetChanged() } private fun convertResultsIntoRepresentables(results: List) : ArrayList { diff --git a/app/src/main/java/net/pokeranalytics/android/ui/fragment/components/bottomsheet/BottomSheetFragment.kt b/app/src/main/java/net/pokeranalytics/android/ui/fragment/components/bottomsheet/BottomSheetFragment.kt index d177f966..82d5060e 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/fragment/components/bottomsheet/BottomSheetFragment.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/fragment/components/bottomsheet/BottomSheetFragment.kt @@ -22,11 +22,13 @@ import net.pokeranalytics.android.ui.view.RowRepresentable import net.pokeranalytics.android.ui.view.RowRepresentableEditDescriptor import net.pokeranalytics.android.ui.view.rowrepresentable.SessionRow import net.pokeranalytics.android.ui.view.rowrepresentable.TransactionRow +import java.util.* open class BottomSheetFragment : BottomSheetDialogFragment() { lateinit var row: RowRepresentable lateinit var delegate: RowRepresentableDelegate + var currentCurrency: Currency? = null private var isClearable: Boolean = true private var rowRepresentableEditDescriptors: ArrayList? = null @@ -40,7 +42,8 @@ open class BottomSheetFragment : BottomSheetDialogFragment() { row: RowRepresentable, delegate: RowRepresentableDelegate, rowRepresentableEditDescriptors: ArrayList?, - isClearable: Boolean? = true + isClearable: Boolean? = true, + currentCurrency: Currency? = null ): BottomSheetFragment { val bottomSheetFragment = row.bottomSheetType.newInstance() bottomSheetFragment.show(fragmentManager, "bottomSheet") @@ -48,7 +51,7 @@ open class BottomSheetFragment : BottomSheetDialogFragment() { bottomSheetFragment.delegate = delegate bottomSheetFragment.rowRepresentableEditDescriptors = rowRepresentableEditDescriptors bottomSheetFragment.isClearable = isClearable ?: true - + bottomSheetFragment.currentCurrency = currentCurrency return bottomSheetFragment } } diff --git a/app/src/main/java/net/pokeranalytics/android/ui/fragment/components/bottomsheet/BottomSheetMultiSelectionFragment.kt b/app/src/main/java/net/pokeranalytics/android/ui/fragment/components/bottomsheet/BottomSheetMultiSelectionFragment.kt index 413d8f82..42872569 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/fragment/components/bottomsheet/BottomSheetMultiSelectionFragment.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/fragment/components/bottomsheet/BottomSheetMultiSelectionFragment.kt @@ -2,18 +2,14 @@ package net.pokeranalytics.android.ui.fragment.components.bottomsheet import android.app.Activity import android.content.Intent -import android.os.Bundle -import android.view.View import io.realm.RealmList import io.realm.RealmObject -import io.realm.RealmResults import net.pokeranalytics.android.exceptions.RowRepresentableEditDescriptorException import net.pokeranalytics.android.model.LiveData import net.pokeranalytics.android.ui.activity.EditableDataActivity import net.pokeranalytics.android.ui.activity.components.PokerAnalyticsActivity import net.pokeranalytics.android.ui.view.RowRepresentable import net.pokeranalytics.android.ui.view.RowViewType -import timber.log.Timber /** * Manage multiple items selection in a bottom sheet list @@ -38,7 +34,6 @@ open class BottomSheetMultiSelectionFragment : BottomSheetListFragment() { } } - //TODO: Set the correct values override fun getValue(): Any? { return selectedRows } @@ -50,16 +45,6 @@ open class BottomSheetMultiSelectionFragment : BottomSheetListFragment() { selectedRows.add(row) } dataAdapter.refreshRow(row) - - /* - realmData?.let { - val selectedData = it[position] - selectedData?.let {data -> - this.delegate.onRowValueChanged(data, this.row) - dismiss() - } - } - */ } override fun isSelected(row: RowRepresentable): Boolean { diff --git a/app/src/main/java/net/pokeranalytics/android/ui/fragment/components/bottomsheet/BottomSheetSumFragment.kt b/app/src/main/java/net/pokeranalytics/android/ui/fragment/components/bottomsheet/BottomSheetSumFragment.kt index 8153eb8f..58f1ff3e 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/fragment/components/bottomsheet/BottomSheetSumFragment.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/fragment/components/bottomsheet/BottomSheetSumFragment.kt @@ -63,7 +63,7 @@ class BottomSheetSumFragment : BottomSheetFragment() { 0.0 } - currentValue.text = currentDefaultValue.toCurrency() + currentValue.text = currentDefaultValue.toCurrency(currentCurrency) // First value val defaultValue1 = try { @@ -72,7 +72,7 @@ class BottomSheetSumFragment : BottomSheetFragment() { 0.0 } - button1.text = "+ ${defaultValue1.toCurrency()}" + button1.text = "+ ${defaultValue1.toCurrency(currentCurrency)}" button1.visibility = if (defaultValue1 > 0) View.VISIBLE else View.GONE button1.setOnClickListener { this.delegate.onRowValueChanged(currentDefaultValue + defaultValue1, row) @@ -86,7 +86,7 @@ class BottomSheetSumFragment : BottomSheetFragment() { 0.0 } - button2.text = "+ ${defaultValue2.toCurrency()}" + button2.text = "+ ${defaultValue2.toCurrency(currentCurrency)}" button2.visibility = if (defaultValue2 > 0) View.VISIBLE else View.GONE button2.setOnClickListener { this.delegate.onRowValueChanged(currentDefaultValue + defaultValue2, row) diff --git a/app/src/main/java/net/pokeranalytics/android/ui/view/RowViewType.kt b/app/src/main/java/net/pokeranalytics/android/ui/view/RowViewType.kt index 2a82aee7..b828c444 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/view/RowViewType.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/view/RowViewType.kt @@ -41,6 +41,7 @@ enum class RowViewType(private var layoutRes: Int) { INFO(R.layout.row_info), // Row + CLASSIC_HEADER_TITLE(R.layout.row_header_title), TITLE(R.layout.row_title), TITLE_ARROW(R.layout.row_title_arrow), TITLE_VALUE(R.layout.row_title_value), @@ -75,7 +76,7 @@ enum class RowViewType(private var layoutRes: Int) { HEADER_TITLE, HEADER_TITLE_VALUE, HEADER_TITLE_AMOUNT, HEADER_TITLE_AMOUNT_BIG, LOCATION_TITLE, INFO -> CustomizableRowViewHolder(layout) // Row View Holder - TITLE, TITLE_ARROW, TITLE_VALUE, TITLE_VALUE_ARROW, TITLE_GRID, TITLE_SWITCH, TITLE_CHECK, DATA, BOTTOM_SHEET_DATA, LOADER -> RowViewHolder( + CLASSIC_HEADER_TITLE, TITLE, TITLE_ARROW, TITLE_VALUE, TITLE_VALUE_ARROW, TITLE_GRID, TITLE_SWITCH, TITLE_CHECK, DATA, BOTTOM_SHEET_DATA, LOADER -> RowViewHolder( layout ) diff --git a/app/src/main/java/net/pokeranalytics/android/ui/view/SessionRowView.kt b/app/src/main/java/net/pokeranalytics/android/ui/view/SessionRowView.kt index 90b3df10..8e79ca03 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/view/SessionRowView.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/view/SessionRowView.kt @@ -14,6 +14,7 @@ import net.pokeranalytics.android.model.TableSize import net.pokeranalytics.android.model.extensions.SessionState import net.pokeranalytics.android.model.extensions.getState import net.pokeranalytics.android.model.realm.Session +import net.pokeranalytics.android.util.CurrencyUtils import net.pokeranalytics.android.util.extensions.getDayNumber import net.pokeranalytics.android.util.extensions.getShortDayName import net.pokeranalytics.android.util.extensions.shortTime @@ -65,7 +66,7 @@ class SessionRowView : FrameLayout { var title = "" if (session.isTournament()) { if (session.tournamentEntryFee != null) { - title += session.tournamentEntryFee?.toCurrency() + title += session.tournamentEntryFee?.toCurrency(CurrencyUtils.getCurrency(session.bankroll)) } session.game?.let { title += (if (title.isNotEmpty()) " " else "") + session.getGameTitle() @@ -140,7 +141,7 @@ class SessionRowView : FrameLayout { rowHistorySession.infoTitle.isVisible = false val result = session.result?.net ?: 0.0 - val formattedStat = ComputedStat(Stat.NETRESULT, result).format(context) + val formattedStat = ComputedStat(Stat.NETRESULT, result, currency = CurrencyUtils.getCurrency(session.bankroll)).format(context) rowHistorySession.gameResult.setTextColor(formattedStat.getColor(context)) rowHistorySession.gameResult.text = formattedStat.text } diff --git a/app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/FilterCategoryRow.kt b/app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/FilterCategoryRow.kt new file mode 100644 index 00000000..af5d5f88 --- /dev/null +++ b/app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/FilterCategoryRow.kt @@ -0,0 +1,91 @@ +package net.pokeranalytics.android.ui.view.rowrepresentable + +import net.pokeranalytics.android.R +import net.pokeranalytics.android.ui.view.RowRepresentable +import net.pokeranalytics.android.ui.view.RowViewType + +enum class FilterCategoryRow : RowRepresentable { + + GENERAL, + DATE, + DURATION, + SESSION, + CASH, + TOURNAMENT, + ONLINE, + RESULT, + TRANSACTION_TYPES, + + // Title Custom fields + LOCATION, + BANKROLL, + PLAYERS; + + override val resId: Int? + get() { + return when (this) { + GENERAL -> R.string.general + DATE -> R.string.date + DURATION -> R.string.duration + SESSION -> R.string.session + CASH -> R.string.cash + TOURNAMENT -> R.string.tournament + ONLINE -> R.string.online + RESULT -> R.string.result + TRANSACTION_TYPES -> R.string.operation_types + LOCATION -> R.string.location + BANKROLL -> R.string.bankroll + PLAYERS -> R.string.players + } + } + + override val viewType: Int + get() { + return when (this) { + GENERAL, DATE, DURATION, SESSION, CASH, TOURNAMENT, ONLINE, RESULT, TRANSACTION_TYPES, + LOCATION, BANKROLL, PLAYERS -> RowViewType.TITLE_VALUE_ARROW.ordinal + } + } + + /** + * Get subcategories of filters + */ + fun getSubcategories(): ArrayList { + val subcategories = ArrayList() + + when (this) { + GENERAL -> subcategories.addAll( + arrayListOf( + FilterSubcategoryRow.CASH_TOURNAMENT, FilterSubcategoryRow.LIVE_ONLINE, FilterSubcategoryRow.GAME, + FilterSubcategoryRow.LIMIT_TYPE, FilterSubcategoryRow.TABLE_SIZE + ) + ) + DATE -> subcategories.addAll( + arrayListOf( + FilterSubcategoryRow.DYNAMIC_DATE, FilterSubcategoryRow.FIXED_DATE, FilterSubcategoryRow.DURATION, FilterSubcategoryRow.YEAR, + FilterSubcategoryRow.WEEKDAYS_OR_WEEKEND, FilterSubcategoryRow.DAY_OF_WEEK, FilterSubcategoryRow.MONTH_OF_YEAR + ) + ) + DURATION -> subcategories.addAll(arrayListOf(FilterSubcategoryRow.SESSION_DURATION, FilterSubcategoryRow.RANGE)) + SESSION -> subcategories.addAll(arrayListOf()) + CASH -> subcategories.addAll(arrayListOf(FilterSubcategoryRow.BLINDS, FilterSubcategoryRow.CASH_RE_BUY_COUNT)) + TOURNAMENT -> subcategories.addAll( + arrayListOf( + FilterSubcategoryRow.TOURNAMENT_TYPE, FilterSubcategoryRow.COMPLETION_PERCENTAGE, FilterSubcategoryRow.PLACE, + FilterSubcategoryRow.PLAYERS_COUNT, FilterSubcategoryRow.TOURNAMENT_RE_BUY_COUNT, FilterSubcategoryRow.BUY_IN + ) + ) + ONLINE -> subcategories.addAll(arrayListOf(FilterSubcategoryRow.MULTI_TABLING)) + RESULT -> subcategories.addAll(arrayListOf(FilterSubcategoryRow.VALUE)) + TRANSACTION_TYPES -> subcategories.addAll(arrayListOf()) + LOCATION -> subcategories.addAll(arrayListOf(FilterSubcategoryRow.LOCATION)) + BANKROLL -> subcategories.addAll(arrayListOf(FilterSubcategoryRow.BANKROLL)) + PLAYERS -> subcategories.addAll(arrayListOf(FilterSubcategoryRow.NUMBER_OF_PLAYERS, FilterSubcategoryRow.MULTI_PLAYER)) + + } + + return subcategories + } + + +} \ No newline at end of file diff --git a/app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/FilterRow.kt b/app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/FilterRow.kt new file mode 100644 index 00000000..67ee210f --- /dev/null +++ b/app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/FilterRow.kt @@ -0,0 +1,27 @@ +package net.pokeranalytics.android.ui.view.rowrepresentable + +import net.pokeranalytics.android.R +import net.pokeranalytics.android.ui.view.RowRepresentable +import net.pokeranalytics.android.ui.view.RowViewType + +enum class FilterRow : RowRepresentable { + + // General + CASH_GAME, + TOURNAMENT, + LIVE, + ONLINE; + + override val resId: Int? + get() { + return when (this) { + CASH_GAME -> R.string.cash_game + TOURNAMENT -> R.string.tournament + LIVE -> R.string.live + ONLINE -> R.string.online + } + } + + override val viewType: Int = RowViewType.TITLE_CHECK.ordinal + +} \ No newline at end of file diff --git a/app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/FilterSubcategoryRow.kt b/app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/FilterSubcategoryRow.kt new file mode 100644 index 00000000..a9a30dbc --- /dev/null +++ b/app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/FilterSubcategoryRow.kt @@ -0,0 +1,146 @@ +package net.pokeranalytics.android.ui.view.rowrepresentable + +import io.realm.Realm +import io.realm.RealmResults +import net.pokeranalytics.android.R +import net.pokeranalytics.android.model.Limit +import net.pokeranalytics.android.model.LiveData +import net.pokeranalytics.android.model.realm.Game +import net.pokeranalytics.android.ui.view.RowRepresentable +import net.pokeranalytics.android.ui.view.RowViewType + +enum class FilterSubcategoryRow : RowRepresentable { + + // General + CASH_TOURNAMENT, + LIVE_ONLINE, + GAME, + LIMIT_TYPE, + TABLE_SIZE, + + // Date + DYNAMIC_DATE, + FIXED_DATE, + DURATION, + YEAR, + WEEKDAYS_OR_WEEKEND, + DAY_OF_WEEK, + MONTH_OF_YEAR, + + // Duration + SESSION_DURATION, + RANGE, + + // Sessions + // - + + // Cash + BLINDS, + CASH_RE_BUY_COUNT, + + // Tournament + TOURNAMENT_TYPE, + COMPLETION_PERCENTAGE, + PLACE, + PLAYERS_COUNT, + TOURNAMENT_RE_BUY_COUNT, + BUY_IN, + + // Online + MULTI_TABLING, + + // Result + VALUE, + + // Transaction types + // - + + // Location + LOCATION, + + // Bankroll + BANKROLL, + + // Players + NUMBER_OF_PLAYERS, + MULTI_PLAYER; + + enum class Type { + SINGLE, + MULTIPLE, + } + + override val resId: Int? + get() { + return when(this) { + CASH_TOURNAMENT -> R.string.cash_or_tournament + LIVE_ONLINE -> R.string.live_or_online + GAME -> R.string.game + LIMIT_TYPE -> R.string.type_de_limite + TABLE_SIZE -> R.string.table_size + + DYNAMIC_DATE -> R.string.dynamic_date + FIXED_DATE -> R.string.fixed_date + DURATION -> R.string.duration + YEAR -> R.string.year + WEEKDAYS_OR_WEEKEND -> R.string.weekdays_or_weekend + DAY_OF_WEEK -> R.string.day_of_the_week + MONTH_OF_YEAR -> R.string.month_of_the_year + + SESSION_DURATION -> R.string.session_duration + RANGE -> R.string.hour_slot + + BLINDS -> R.string.blinds + CASH_RE_BUY_COUNT -> R.string.rebuy_count + + TOURNAMENT_TYPE -> R.string.tournament_type + COMPLETION_PERCENTAGE -> R.string.tournament_completion_percentage_interval + PLACE -> R.string.place + PLAYERS_COUNT -> R.string.players_count + TOURNAMENT_RE_BUY_COUNT -> R.string.rebuy_count + BUY_IN -> R.string.buyin + + MULTI_TABLING -> R.string.multi_tabling + + VALUE -> R.string.value + + LOCATION -> R.string.location + + BANKROLL -> R.string.bankroll + + NUMBER_OF_PLAYERS -> R.string.number_of_players + MULTI_PLAYER -> R.string.multiplayer + } + } + + override val viewType: Int = RowViewType.CLASSIC_HEADER_TITLE.ordinal + + /** + * Return the type of the selection + */ + fun getType() : Type { + return when(this) { + GAME -> Type.MULTIPLE + else -> Type.SINGLE + } + } + + /** + * Returns the filter rows + */ + fun getFilterRows(realm: Realm) : ArrayList { + val rows = ArrayList() + when(this) { + CASH_TOURNAMENT -> rows.addAll(arrayListOf(FilterRow.CASH_GAME, FilterRow.TOURNAMENT)) + LIVE_ONLINE -> rows.addAll(arrayListOf(FilterRow.LIVE, FilterRow.ONLINE)) + GAME -> { + val games = realm.copyFromRealm(LiveData.GAME.items(realm) as RealmResults) + rows.addAll(games) + } + LIMIT_TYPE -> rows.addAll(Limit.values()) + else -> rows.addAll(arrayListOf()) + } + return rows + } + +} \ No newline at end of file diff --git a/app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/SessionRow.kt b/app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/SessionRow.kt index 094f9bd6..c3aca78c 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/SessionRow.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/SessionRow.kt @@ -6,7 +6,6 @@ import net.pokeranalytics.android.R import net.pokeranalytics.android.model.TournamentType import net.pokeranalytics.android.model.extensions.SessionState import net.pokeranalytics.android.model.extensions.getState -import net.pokeranalytics.android.model.realm.Game import net.pokeranalytics.android.model.realm.Session import net.pokeranalytics.android.ui.fragment.components.bottomsheet.BottomSheetType import net.pokeranalytics.android.ui.view.RowRepresentable @@ -277,8 +276,6 @@ enum class SessionRow : RowRepresentable { } else -> null } - - - } + } \ No newline at end of file diff --git a/app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/SettingRow.kt b/app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/SettingRow.kt index 34be219d..8dd14fd9 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/SettingRow.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/SettingRow.kt @@ -27,6 +27,7 @@ enum class SettingRow : RowRepresentable { TOURNAMENT_NAME, TOURNAMENT_FEATURE, TRANSACTION, + TRANSACTION_TYPE, // Terms PRIVACY_POLICY, @@ -56,7 +57,7 @@ enum class SettingRow : RowRepresentable { resId = R.string.data_management ) ) - rows.addAll(arrayListOf(BANKROLL, GAME, LOCATION, TOURNAMENT_NAME, TOURNAMENT_FEATURE, TRANSACTION)) + rows.addAll(arrayListOf(BANKROLL, GAME, LOCATION, TOURNAMENT_NAME, TOURNAMENT_FEATURE, TRANSACTION, TRANSACTION_TYPE)) rows.add(CustomizableRowRepresentable(customViewType = RowViewType.HEADER_TITLE, resId = R.string.terms)) rows.addAll(arrayListOf(PRIVACY_POLICY, TERMS_OF_USE, GDPR)) @@ -106,6 +107,7 @@ enum class SettingRow : RowRepresentable { TOURNAMENT_NAME -> LiveData.TOURNAMENT_NAME TOURNAMENT_FEATURE -> LiveData.TOURNAMENT_FEATURE TRANSACTION -> LiveData.TRANSACTION + TRANSACTION_TYPE -> LiveData.TRANSACTION_TYPE else -> null } } diff --git a/app/src/main/java/net/pokeranalytics/android/util/CurrencyUtils.kt b/app/src/main/java/net/pokeranalytics/android/util/CurrencyUtils.kt new file mode 100644 index 00000000..eaba67bd --- /dev/null +++ b/app/src/main/java/net/pokeranalytics/android/util/CurrencyUtils.kt @@ -0,0 +1,35 @@ +package net.pokeranalytics.android.util + +import android.content.Context +import net.pokeranalytics.android.model.realm.Bankroll +import java.text.NumberFormat +import java.util.* + +class CurrencyUtils { + + companion object { + + /** + * return the currency associated with this bankroll + */ + fun getCurrency(bankroll: Bankroll? = null) : Currency { + val currencyCode = bankroll?.currency?.code ?: Currency.getInstance(Locale.getDefault()).currencyCode + return Currency.getInstance(currencyCode) + } + + /** + * Get a currency formatter + */ + fun getCurrencyFormatter(context: Context, currency: Currency? = null) : NumberFormat { + val currencyFormatter = NumberFormat.getCurrencyInstance(Preferences.getCurrencyLocale(context)) + currency?.let { + currencyFormatter.currency = it + } + currencyFormatter.minimumFractionDigits = 0 + currencyFormatter.maximumFractionDigits = 2 + return currencyFormatter + } + + } + +} \ No newline at end of file diff --git a/app/src/main/java/net/pokeranalytics/android/util/FormatUtils.kt b/app/src/main/java/net/pokeranalytics/android/util/FormatUtils.kt deleted file mode 100644 index 29fbb799..00000000 --- a/app/src/main/java/net/pokeranalytics/android/util/FormatUtils.kt +++ /dev/null @@ -1,20 +0,0 @@ -package net.pokeranalytics.android.util - -import android.content.Context -import java.text.NumberFormat -import java.util.* - -class FormatUtils { - - companion object { - - fun getCurrencyFormatter(context: Context) : NumberFormat { - val formatter = NumberFormat.getCurrencyInstance(Preferences.getCurrencyLocale(context)) - formatter.minimumFractionDigits = 0 - formatter.maximumFractionDigits = 2 - return formatter - } - - } - -} \ No newline at end of file diff --git a/app/src/main/java/net/pokeranalytics/android/util/URL.kt b/app/src/main/java/net/pokeranalytics/android/util/URL.kt index 9e46339c..53bb173a 100644 --- a/app/src/main/java/net/pokeranalytics/android/util/URL.kt +++ b/app/src/main/java/net/pokeranalytics/android/util/URL.kt @@ -16,8 +16,10 @@ enum class URL(var value: String) { FACEBOOK("https://www.facebook.com/171053452998758"), // Support - SUPPORT_EMAIL("support@pokeranalytics.net") + SUPPORT_EMAIL("support@pokeranalytics.net"), + // Currency Converter API + API_CURRENCY_CONVERTER("https://free.currencyconverterapi.com/api/v5/") } 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 d9a7c87a..d98df6b0 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 @@ -2,6 +2,7 @@ package net.pokeranalytics.android.util.extensions import java.text.DecimalFormat import java.text.NumberFormat +import java.util.* // Double @@ -18,11 +19,16 @@ fun Double.formatted(): String { return format.format(this) } -fun Double.toCurrency(): String { - val format = NumberFormat.getCurrencyInstance() - format.maximumFractionDigits = 2 - format.minimumFractionDigits = 0 - return format.format(this) +fun Double.toCurrency(currency: Currency? = null): String { + + val currencyFormatter = NumberFormat.getCurrencyInstance() + currency?.let { + currencyFormatter.currency = currency + } + + currencyFormatter.maximumFractionDigits = 2 + currencyFormatter.minimumFractionDigits = 0 + return currencyFormatter.format(this) } fun Double.formattedHourlyDuration() : String { diff --git a/app/src/main/res/layout/activity_filter_details.xml b/app/src/main/res/layout/activity_filter_details.xml new file mode 100644 index 00000000..70454fb9 --- /dev/null +++ b/app/src/main/res/layout/activity_filter_details.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_filters.xml b/app/src/main/res/layout/activity_filters.xml new file mode 100644 index 00000000..70454fb9 --- /dev/null +++ b/app/src/main/res/layout/activity_filters.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_filter_details.xml b/app/src/main/res/layout/fragment_filter_details.xml new file mode 100644 index 00000000..bab049a9 --- /dev/null +++ b/app/src/main/res/layout/fragment_filter_details.xml @@ -0,0 +1,61 @@ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_filters.xml b/app/src/main/res/layout/fragment_filters.xml new file mode 100644 index 00000000..bab049a9 --- /dev/null +++ b/app/src/main/res/layout/fragment_filters.xml @@ -0,0 +1,61 @@ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/menu/home_menu.xml b/app/src/main/res/menu/home_menu.xml new file mode 100644 index 00000000..38cbd892 --- /dev/null +++ b/app/src/main/res/menu/home_menu.xml @@ -0,0 +1,11 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/secrets.xml b/app/src/main/res/values/secrets.xml index 77732c57..9510e5b7 100644 --- a/app/src/main/res/values/secrets.xml +++ b/app/src/main/res/values/secrets.xml @@ -1,4 +1,5 @@ AIzaSyCg-vgW4YnFsQ_s1iWjgzSq2vT0te3R1Hw + 5ba8d38995282fe8b1c8 \ No newline at end of file diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index 8a13e62f..b9faf4be 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -185,7 +185,7 @@