diff --git a/app/src/androidTest/java/net/pokeranalytics/android/ExampleInstrumentedUnitTest.kt b/app/src/androidTest/java/net/pokeranalytics/android/ExampleInstrumentedUnitTest.kt index b5c48af6..85ef68bf 100644 --- a/app/src/androidTest/java/net/pokeranalytics/android/ExampleInstrumentedUnitTest.kt +++ b/app/src/androidTest/java/net/pokeranalytics/android/ExampleInstrumentedUnitTest.kt @@ -7,6 +7,7 @@ import net.pokeranalytics.android.calculus.ComputedResults import net.pokeranalytics.android.calculus.SessionGroup import net.pokeranalytics.android.calculus.Stat import net.pokeranalytics.android.model.realm.Session +import net.pokeranalytics.android.model.realm.SessionSet import net.pokeranalytics.android.model.realm.TimeFrame import org.junit.Assert import org.junit.Assert.assertEquals @@ -26,7 +27,7 @@ class ExampleInstrumentedUnitTest : RealmInstrumentedUnitTest() { // convenience extension fun Session.Companion.testInstance(netResult: Double, startDate: Date, endDate: Date?): Session { - val session: Session = Session.newInstance() + val session: Session = Session.newInstance(super.mockRealm, false) session.result?.netResult = netResult session.timeFrame?.setDate(startDate, endDate) return session @@ -67,8 +68,8 @@ class ExampleInstrumentedUnitTest : RealmInstrumentedUnitTest() { realm.beginTransaction() - s1.timeFrame?.setDate(sd1, ed1) // duration = 1h, hourly = -100, bb100 = -200bb / 25hands * 100 = -800 - s2.timeFrame?.setDate(sd2, ed2) // duration = 3h, hourly = 100, bb100 = 150 / 75 * 100 = +200 + s1.timeFrame?.setDate(sd1, ed1) // netDuration = 1h, hourly = -100, bb100 = -200bb / 25hands * 100 = -800 + s2.timeFrame?.setDate(sd2, ed2) // netDuration = 3h, hourly = 100, bb100 = 150 / 75 * 100 = +200 realm.copyToRealmOrUpdate(s1) realm.copyToRealmOrUpdate(s2) @@ -102,7 +103,7 @@ class ExampleInstrumentedUnitTest : RealmInstrumentedUnitTest() { if (duration != null) { assertEquals(4.0, duration.value, delta) } else { - Assert.fail("No duration stat") + Assert.fail("No netDuration stat") } val hourlyRate = results.computedStat(Stat.HOURLY_RATE) @@ -207,7 +208,6 @@ class ExampleInstrumentedUnitTest : RealmInstrumentedUnitTest() { realm.insert(s1) realm.insert(s2) - realm.commitTransaction() val sdf = SimpleDateFormat("dd/M/yyyy hh:mm") @@ -216,10 +216,9 @@ class ExampleInstrumentedUnitTest : RealmInstrumentedUnitTest() { val sd2 = sdf.parse("01/1/2019 08:00") val ed2 = sdf.parse("01/1/2019 11:00") - realm.beginTransaction() - s1.timeFrame?.setDate(sd1, ed1) // duration = 1h, hourly = -100, bb100 = -200bb / 25hands * 100 = -800 - s2.timeFrame?.setDate(sd2, ed2) // duration = 4h, hourly = 100, bb100 = 150 / 75 * 100 = +200 + s1.timeFrame?.setDate(sd1, ed1) // netDuration = 1h, hourly = -100, bb100 = -200bb / 25hands * 100 = -800 + s2.timeFrame?.setDate(sd2, ed2) // netDuration = 4h, hourly = 100, bb100 = 150 / 75 * 100 = +200 realm.copyToRealmOrUpdate(s1) realm.copyToRealmOrUpdate(s2) @@ -274,7 +273,6 @@ class ExampleInstrumentedUnitTest : RealmInstrumentedUnitTest() { realm.insert(s1) realm.insert(s2) realm.insert(s3) - realm.commitTransaction() val sdf = SimpleDateFormat("dd/M/yyyy hh:mm") @@ -285,11 +283,9 @@ class ExampleInstrumentedUnitTest : RealmInstrumentedUnitTest() { val sd3 = sdf.parse("01/1/2019 03:00") val ed3 = sdf.parse("01/1/2019 06:00") - realm.beginTransaction() - - s1.timeFrame?.setDate(sd1, ed1) // duration = 4h - s2.timeFrame?.setDate(sd2, ed2) // duration = 4h - s3.timeFrame?.setDate(sd3, ed3) // duration = 3h + s1.timeFrame?.setDate(sd1, ed1) // netDuration = 4h + s2.timeFrame?.setDate(sd2, ed2) // netDuration = 4h + s3.timeFrame?.setDate(sd3, ed3) // netDuration = 3h realm.copyToRealmOrUpdate(s1) realm.copyToRealmOrUpdate(s2) @@ -370,9 +366,9 @@ class ExampleInstrumentedUnitTest : RealmInstrumentedUnitTest() { realm.beginTransaction() - s1.timeFrame?.setDate(sd1, ed1) // duration = 4h - s2.timeFrame?.setDate(sd2, ed2) // duration = 4h - s3.timeFrame?.setDate(sd3, ed3) // duration = 3h + s1.timeFrame?.setDate(sd1, ed1) // netDuration = 4h + s2.timeFrame?.setDate(sd2, ed2) // netDuration = 4h + s3.timeFrame?.setDate(sd3, ed3) // netDuration = 3h realm.copyToRealmOrUpdate(s1) realm.copyToRealmOrUpdate(s2) @@ -393,12 +389,9 @@ class ExampleInstrumentedUnitTest : RealmInstrumentedUnitTest() { if (duration != null) { assertEquals(8.0, duration.value, delta) } else { - Assert.fail("No duration stat") + Assert.fail("No netDuration stat") } -// realm.beginTransaction() -// s1.deleteFromRealm() -// realm.commitTransaction() realm.executeTransaction { s1.deleteFromRealm() } @@ -414,4 +407,112 @@ class ExampleInstrumentedUnitTest : RealmInstrumentedUnitTest() { } } + + + @Test + fun testSessionSetCount() { + + val realm = this.mockRealm + + realm.beginTransaction() + val s1 = realm.createObject(Session::class.java, "1") + + s1.timeFrame = realm.createObject(TimeFrame::class.java) + + s1.result = realm.createObject(net.pokeranalytics.android.model.realm.Result::class.java) + + realm.insert(s1) + + val sdf = SimpleDateFormat("dd/M/yyyy hh:mm") + + val sd1 = sdf.parse("01/1/2019 09:00") + val ed1 = sdf.parse("01/1/2019 10:00") + + s1.timeFrame?.setDate(sd1, ed1) // netDuration = 1h, hourly = -100, bb100 = -200bb / 25hands * 100 = -800 + + realm.copyToRealmOrUpdate(s1) + realm.commitTransaction() + + val sets = realm.where(SessionSet::class.java).findAll() + + Assert.assertEquals(1, sets.size) + + val set = sets.first() + if (set != null) { + Assert.assertEquals(sd1.time, set.timeFrame?.startDate?.time) + Assert.assertEquals(ed1.time, set.timeFrame?.endDate?.time) + } else { + Assert.fail("No set") + } + + } + + @Test + fun testSessionSetCount2() { + + val realm = this.mockRealm + + realm.beginTransaction() + val s1 = realm.createObject(Session::class.java, "1") + val s2 = realm.createObject(Session::class.java, "2") + + s1.timeFrame = realm.createObject(TimeFrame::class.java) + s2.timeFrame = realm.createObject(TimeFrame::class.java) + + s1.result = realm.createObject(net.pokeranalytics.android.model.realm.Result::class.java) + s2.result = realm.createObject(net.pokeranalytics.android.model.realm.Result::class.java) + + realm.insert(s1) + realm.insert(s2) + + val sdf = SimpleDateFormat("dd/M/yyyy hh:mm") + + val sd1 = sdf.parse("01/1/2019 09:00") + val ed1 = sdf.parse("01/1/2019 10:00") + val sd2 = sdf.parse("01/2/2018 09:00") + val ed2 = sdf.parse("01/2/2018 10:00") + + s1.timeFrame?.let { + it.setStart(sd1) + it.setEnd(ed1) + } + + s2.timeFrame?.let { + it.setStart(sd2) + it.setEnd(ed2) + } + +// s1.timeFrame?.setDate(sd1, ed1) // netDuration = 1h, hourly = -100, bb100 = -200bb / 25hands * 100 = -800 +// s2.timeFrame?.setDate(sd2, ed2) // netDuration = 1h, hourly = -100, bb100 = -200bb / 25hands * 100 = -800 + + realm.copyToRealmOrUpdate(s1) + realm.copyToRealmOrUpdate(s2) + + realm.commitTransaction() + + val sets = realm.where(SessionSet::class.java).findAll() + + Assert.assertEquals(2, sets.size) + +// val set = sets.first() +// if (set != null) { +// Assert.assertEquals(sd1.time, set.timeFrame?.startDate?.time) +// Assert.assertEquals(ed1.time, set.timeFrame?.endDate?.time) +// } else { +// Assert.fail("No set") +// } + + } + +// @Test +// fun testDurationConversion() { +// +// val duration = 6.7555561274509826 +// val longDuration = duration.toLong() +// val formatted = longDuration.toMinutes() +// +// assert(formatted == "11:00") +// } + + } \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 83fac011..312c9703 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -30,6 +30,7 @@ android:windowSoftInputMode="adjustNothing" /> + ().findAll().random() - val result = Result() - result.buyin = arrayListOf(100, 200, 300, 500, 1000, 2000).random().toDouble() - result.netResult = arrayListOf( - -2500.0, -2000.0, -1500.0, -1000.0, -500.0, 200.0, 1000.0, 1500.0, - 2500.0 - ).random() - session.result = result + session.result?.let { result -> + result.buyin = arrayListOf(100, 200, 300, 500, 1000, 2000).random().toDouble() + result.netResult = arrayListOf( + -2500.0, -2000.0, -1500.0, -1000.0, -500.0, 200.0, 1000.0, 1500.0, + 2500.0 + ).random() + } realm.copyToRealmOrUpdate(session) } @@ -172,6 +178,16 @@ class PokerAnalyticsApplication : Application() { realm.close() + val sets = realm.where(SessionSet::class.java).findAll() + +// Timber.d("sets = ${sets.size}") +// +// sets.forEach { set -> +// Timber.d("set sd = : ${set.timeFrame?.startDate}, ed = ${set.timeFrame?.endDate}") +// } + + + } } \ No newline at end of file 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 cf3414de..171d5285 100644 --- a/app/src/main/java/net/pokeranalytics/android/calculus/Stat.kt +++ b/app/src/main/java/net/pokeranalytics/android/calculus/Stat.kt @@ -7,7 +7,7 @@ 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.formatted -import net.pokeranalytics.android.util.toMinutes +import net.pokeranalytics.android.util.formattedHourlyDuration /** * An enum representing all the types of Session statistics @@ -138,7 +138,7 @@ class ComputedStat(stat: Stat, value: Double) { return TextFormat("${value.toInt()}") } // white durations Stat.DURATION, Stat.AVERAGE_DURATION -> { - return TextFormat("${value.toLong().toMinutes()}") + return TextFormat(value.formattedHourlyDuration()) } // red/green percentages Stat.WIN_RATIO, Stat.ROI -> { val color = if (value >= this.stat.threshold) R.color.green else R.color.red 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 cdff56ca..a93e0cc1 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 @@ -38,6 +38,7 @@ open class Session : RealmObject(), SessionInterface, Savable, companion object { fun newInstance(realm: Realm, isTournament: Boolean): Session { val session = Session() + session.timeFrame = TimeFrame() session.result = Result() session.bankroll = realm.where().findFirst() session.type = if (isTournament) Session.Type.TOURNAMENT.ordinal else Session.Type.CASH_GAME.ordinal @@ -60,7 +61,7 @@ open class Session : RealmObject(), SessionInterface, Savable, var timeFrame: TimeFrame? = null set(value) { field = value - value?.let { it.notifySessionDateChange(this) } +// value?.let { it.notifySessionDateChange(this) } } // The time frame sessionGroup, which can contain multiple sessions @@ -143,7 +144,8 @@ open class Session : RealmObject(), SessionInterface, Savable, when (getState()) { SessionState.PENDING, SessionState.PLANNED -> { val sessionTimeFrame = this.timeFrame ?: realm.createObject(TimeFrame::class.java) - sessionTimeFrame.setDate(Date(), null) + sessionTimeFrame.setStart(Date()) +// sessionTimeFrame.setDate(Date(), null) this.timeFrame = sessionTimeFrame } SessionState.PAUSED -> { @@ -179,7 +181,8 @@ open class Session : RealmObject(), SessionInterface, Savable, SessionState.STARTED, SessionState.PAUSED -> { this.timeFrame?.paused = false this.timeFrame?.pauseDate = null - this.timeFrame?.setDate(null, Date()) + this.timeFrame?.setEnd(Date()) +// this.timeFrame?.setDate(null, Date()) } else -> throw Exception("Stopping session in unmanaged state") } @@ -199,7 +202,7 @@ open class Session : RealmObject(), SessionInterface, Savable, } /** - * Return the duration of the current session + * Return the netDuration of the current session */ fun getDuration(): String { val startDate = timeFrame?.startDate ?: Date() @@ -578,7 +581,7 @@ open class Session : RealmObject(), SessionInterface, Savable, localResult.cashout = (value as String).toDouble() val timeFrameToUpdate = if (timeFrame != null) timeFrame as TimeFrame else realm.createObject(TimeFrame::class.java) - timeFrameToUpdate.setDate(null, Date()) + timeFrameToUpdate.setEnd(Date()) timeFrame = timeFrameToUpdate } @@ -589,7 +592,8 @@ open class Session : RealmObject(), SessionInterface, Savable, SessionRow.END_DATE -> if (value is Date?) { val timeFrameToUpdate = if (timeFrame != null) timeFrame as TimeFrame else realm.createObject(TimeFrame::class.java) - timeFrameToUpdate.setDate(null, value) +// timeFrameToUpdate.setDate(null, value) + timeFrameToUpdate.setEnd(value) timeFrame = timeFrameToUpdate } SessionRow.GAME -> { @@ -623,7 +627,8 @@ open class Session : RealmObject(), SessionInterface, Savable, } else { val timeFrameToUpdate = if (timeFrame != null) timeFrame as TimeFrame else realm.createObject(TimeFrame::class.java) - timeFrameToUpdate.setDate(value, null) + timeFrameToUpdate.setStart(value) +// timeFrameToUpdate.setDate(value, null) timeFrame = timeFrameToUpdate } } diff --git a/app/src/main/java/net/pokeranalytics/android/model/realm/SessionSet.kt b/app/src/main/java/net/pokeranalytics/android/model/realm/SessionSet.kt index 659787a8..88b02fb0 100644 --- a/app/src/main/java/net/pokeranalytics/android/model/realm/SessionSet.kt +++ b/app/src/main/java/net/pokeranalytics/android/model/realm/SessionSet.kt @@ -9,6 +9,16 @@ import io.realm.annotations.LinkingObjects open class SessionSet() : RealmObject() { + companion object { + + fun newInstance(realm: Realm) : SessionSet { + val sessionSet: SessionSet = realm.createObject(SessionSet::class.java) + sessionSet.timeFrame = realm.createObject(TimeFrame::class.java) + return realm.copyToRealm(sessionSet) + } + + } + /** * The timeframe of the set, i.e. its start & end date */ @@ -21,13 +31,13 @@ open class SessionSet() : RealmObject() { @LinkingObjects("sessionSet") val sessions: RealmResults? = null - @Ignore // a duration shortcut + @Ignore // a netDuration shortcut var duration: Long = 0L get() { - return this.timeFrame?.duration ?: 0L + return this.timeFrame?.netDuration ?: 0L } - @Ignore // a duration in hour + @Ignore // a netDuration in hour var hourlyDuration: Double = 0.0 get() { return this.timeFrame?.hourlyDuration ?: 0.0 @@ -39,7 +49,7 @@ open class SessionSet() : RealmObject() { return this.sessions?.sumByDouble { it.value } ?: 0.0 } - @Ignore // a duration shortcut + @Ignore // a netDuration shortcut var hourlyRate: Double = 0.0 get () { return this.netResult / this.hourlyDuration @@ -51,15 +61,6 @@ open class SessionSet() : RealmObject() { @Ignore var bbNetResult: Double = 0.0 - companion object { - - fun newInstance(realm: Realm) : SessionSet { - val sessionSet: SessionSet = realm.createObject(SessionSet::class.java) - sessionSet.timeFrame = realm.createObject(TimeFrame::class.java) - return sessionSet - } - - } } diff --git a/app/src/main/java/net/pokeranalytics/android/model/realm/TimeFrame.kt b/app/src/main/java/net/pokeranalytics/android/model/realm/TimeFrame.kt index 8ac2f2fd..d8f548ea 100644 --- a/app/src/main/java/net/pokeranalytics/android/model/realm/TimeFrame.kt +++ b/app/src/main/java/net/pokeranalytics/android/model/realm/TimeFrame.kt @@ -1,6 +1,5 @@ package net.pokeranalytics.android.model.realm -import io.realm.Realm import io.realm.RealmObject import io.realm.RealmQuery import io.realm.RealmResults @@ -26,32 +25,32 @@ open class TimeFrame : RealmObject() { this.computeDuration() } - // The latest pause date - var pauseDate: Date? = null - set(value) { - field?.let { - if (value == null && field != null) { - breakDuration += Date().time - it.time - } - } - field = value - this.computeDuration() - } - - // The break duration + // The latest pause date + var pauseDate: Date? = null + set(value) { + field?.let { + if (value == null && field != null) { + breakDuration += Date().time - it.time + } + } + field = value + this.computeDuration() + } + + // The break netDuration var breakDuration: Long = 0L set(value) { field = value this.computeDuration() } - // the total duration - var duration: Long = 0L + // the total netDuration + var netDuration: Long = 0L private set var hourlyDuration: Double = 0.0 get() { - return this.duration / 3600000.0 // 3.6 millions of milliseconds + return this.netDuration / 3600000.0 // 3.6 millions of milliseconds } // indicates a state of pause @@ -73,29 +72,35 @@ open class TimeFrame : RealmObject() { var set: SessionSet? = null get() = this.sets?.first() - fun setDate(startDate: Date?, endDate: Date?) { - - startDate?.let { - this.startDate = startDate + fun setStart(startDate: Date) { + this.startDate = startDate + this.session?.let { + this.notifySessionDateChange(it) } + } + fun setEnd(endDate: Date?) { this.endDate = endDate + this.session?.let { + this.notifySessionDateChange(it) + } + } - this.computeDuration() + fun setDate(startDate: Date, endDate: Date?) { + this.startDate = startDate + this.endDate = endDate this.session?.let { this.notifySessionDateChange(it) } - } /** - * Computes the net duration of the session + * Computes the net netDuration of the session */ private fun computeDuration() { var endDate: Date = this.endDate ?: Date() - val netDuration = endDate.time - this.startDate.time - this.breakDuration - this.duration = netDuration + this.netDuration = endDate.time - this.startDate.time - this.breakDuration } /** @@ -103,25 +108,35 @@ open class TimeFrame : RealmObject() { * Makes all necessary changes to keep sequential time frames */ fun notifySessionDateChange(owner: Session) { - val realm = Realm.getDefaultInstance() - var query: RealmQuery = realm.where(SessionSet::class.java) + + var query: RealmQuery = this.realm.where(SessionSet::class.java) query.isNotNull("timeFrame") // Timber.d("this> sd = : ${this.startDate}, ed = ${this.endDate}") + val sets = realm.where(SessionSet::class.java).findAll() +// Timber.d("set count = ${sets.size}") + if (this.endDate == null) { - query.greaterThan("timeFrame.startDate", this.startDate).or().greaterThan("timeFrame.endDate", this.startDate) + query.greaterThanOrEqualTo("timeFrame.startDate", this.startDate) + .or() + .greaterThanOrEqualTo("timeFrame.endDate", this.startDate) + .or() + .isNull("timeFrame.endDate") } else { val endDate = this.endDate!! query - .lessThan("timeFrame.startDate", this.startDate) - .greaterThan("timeFrame.endDate", this.startDate) + .lessThanOrEqualTo("timeFrame.startDate", this.startDate) + .greaterThanOrEqualTo("timeFrame.endDate", this.startDate) + .or() + .lessThanOrEqualTo("timeFrame.startDate", endDate) + .greaterThanOrEqualTo("timeFrame.endDate", endDate) .or() - .lessThan("timeFrame.startDate", endDate) - .greaterThan("timeFrame.endDate", endDate) + .greaterThanOrEqualTo("timeFrame.startDate", this.startDate) + .lessThanOrEqualTo("timeFrame.endDate", endDate) .or() - .greaterThan("timeFrame.startDate", this.startDate) - .lessThan("timeFrame.endDate", endDate) + .isNull("timeFrame.endDate") + .lessThanOrEqualTo("timeFrame.startDate", endDate) } val sessionGroups = query.findAll() @@ -137,7 +152,7 @@ open class TimeFrame : RealmObject() { when (sessionSets.size) { 0 -> this.createSessionGroup(owner) - 1 -> this.updateSingleSessionGroup(owner, sessionSets.first()!!) + 1 -> this.updateSessionGroup(owner, sessionSets.first()!!) else -> this.mergeSessionGroups(owner, sessionSets) } @@ -148,9 +163,7 @@ open class TimeFrame : RealmObject() { */ private fun createSessionGroup(owner: Session) { - val realm = Realm.getDefaultInstance() - - val set: SessionSet = SessionSet.newInstance(realm) + val set: SessionSet = SessionSet.newInstance(this.realm) set.timeFrame?.let { it.startDate = this.startDate it.endDate = this.endDate @@ -160,29 +173,53 @@ open class TimeFrame : RealmObject() { owner.sessionSet = set - Timber.d("sd = : ${set.timeFrame?.startDate}, ed = ${set.timeFrame?.endDate}") +// Timber.d("sd = : ${set.timeFrame?.startDate}, ed = ${set.timeFrame?.endDate}") + Timber.d("netDuration 1 = : ${set.timeFrame?.netDuration}") } /** - * Single session sessionGroup update + * Single SessionSet update, the session might be the owner * Changes the sessionGroup timeframe using the current timeframe dates */ - private fun updateSingleSessionGroup(owner: Session, sessionSet: SessionSet) { + private fun updateSessionGroup(owner: Session, sessionSet: SessionSet) { - var groupTimeFrame: TimeFrame = sessionSet.timeFrame!! // tested in the query + var timeFrame: TimeFrame = sessionSet.timeFrame!! // tested in the query +// timeFrame.setDate(this.startDate, this.endDate) - if (this.startDate.before(groupTimeFrame.startDate)) { - groupTimeFrame.startDate = this.startDate - } - val endDate = this.endDate - if (endDate != null && groupTimeFrame.endDate != null && endDate.after(groupTimeFrame.endDate)) { - groupTimeFrame.endDate = endDate - } else if (endDate == null) { - groupTimeFrame.endDate = null - } + val sisterSessions = sessionSet.sessions!! // shouldn't crash ever + + // if we have only one session in the set and that it corresponds to the set + if (sessionSet.sessions?.size == 1 && sessionSet.sessions?.first() == owner) { + timeFrame.setDate(this.startDate, this.endDate) + } else { // there are 2+ sessions to manage and possible splits + + val endDate = this.endDate + + // case where all sessions are over but the set is not, we might have a split, so we delete the set and save everything again + if (endDate != null && sisterSessions.all { it.timeFrame?.endDate != null } && timeFrame.endDate == null) { + var sessions = mutableListOf(owner) + sessionSet.sessions?.forEach { sessions.add(it) } + sessionSet.deleteFromRealm() + sessions.forEach { it.timeFrame?.notifySessionDateChange(it) } + } else { - owner.sessionSet = sessionSet + if (this.startDate.before(timeFrame.startDate)) { + timeFrame.startDate = this.startDate + } + if (endDate != null && timeFrame.endDate != null && endDate.after(timeFrame.endDate)) { + timeFrame.endDate = endDate + } else if (endDate == null) { + timeFrame.endDate = null + } + + owner.sessionSet = sessionSet + +// Timber.d("sd = : ${sessionSet.timeFrame?.startDate}, ed = ${sessionSet.timeFrame?.endDate}") + Timber.d("netDuration 2 = : ${sessionSet.timeFrame?.netDuration}") + } + + } } @@ -216,25 +253,27 @@ open class TimeFrame : RealmObject() { // get all sessions from sets var sessions = mutableSetOf() - sessionSets.forEach { it.sessions?.asIterable()?.let { it1 -> sessions.addAll(it1) } } + sessionSets.forEach { set -> + set.sessions?.asIterable()?.let { sessions.addAll(it) } + } // delete all sets sessionSets.deleteAllFromRealm() // Create a new sets - val set: SessionSet = SessionSet.newInstance(realm) + val set: SessionSet = SessionSet.newInstance(this.realm) set.timeFrame?.let { - it.startDate = startDate - it.endDate = endDate + it.setDate(startDate, endDate) } ?: run { throw ModelException("TimeFrame should never be null here") } // Add the session linked to this timeframe to the new sessionGroup - owner.sessionSet = set + owner.sessionSet = set // Add all orphan sessions sessions.forEach { it.sessionSet = set } + Timber.d("netDuration 3 = : ${set.timeFrame?.netDuration}") } diff --git a/app/src/main/java/net/pokeranalytics/android/ui/activity/CurrenciesActivity.kt b/app/src/main/java/net/pokeranalytics/android/ui/activity/CurrenciesActivity.kt new file mode 100644 index 00000000..e2cb7471 --- /dev/null +++ b/app/src/main/java/net/pokeranalytics/android/ui/activity/CurrenciesActivity.kt @@ -0,0 +1,23 @@ +package net.pokeranalytics.android.ui.activity + +import android.content.Context +import android.content.Intent +import android.os.Bundle +import net.pokeranalytics.android.R +import net.pokeranalytics.android.ui.activity.components.PokerAnalyticsActivity + +class CurrenciesActivity : PokerAnalyticsActivity() { + + companion object { + fun newInstance(context: Context) { + val intent = Intent(context, CurrenciesActivity::class.java) + context.startActivity(intent) + } + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_currencies) + } + +} \ No newline at end of file diff --git a/app/src/main/java/net/pokeranalytics/android/ui/fragment/CurrenciesFragment.kt b/app/src/main/java/net/pokeranalytics/android/ui/fragment/CurrenciesFragment.kt new file mode 100644 index 00000000..9665c990 --- /dev/null +++ b/app/src/main/java/net/pokeranalytics/android/ui/fragment/CurrenciesFragment.kt @@ -0,0 +1,116 @@ +package net.pokeranalytics.android.ui.fragment + +import android.content.Context +import android.os.Bundle +import android.preference.Preference +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.recyclerview.widget.LinearLayoutManager +import kotlinx.android.synthetic.main.fragment_data_list.* +import net.pokeranalytics.android.R +import net.pokeranalytics.android.model.LiveData +import net.pokeranalytics.android.ui.activity.components.PokerAnalyticsActivity +import net.pokeranalytics.android.ui.adapter.LiveRowRepresentableDataSource +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.RowViewType +import net.pokeranalytics.android.ui.view.rowrepresentable.HeaderRowRepresentable +import java.util.* +import java.util.prefs.Preferences + +class CurrenciesFragment : PokerAnalyticsFragment(), StaticRowRepresentableDataSource, RowRepresentableDelegate { + + private val mostUsedCurrencyCodes = arrayListOf("EUR", "USD", "CAD", "GBP", "AUD", "CNY") + private val systemCurrencies = Currency.getAvailableCurrencies() + + private val mostUsedCurrencies = this.mostUsedCurrencyCodes.map { code -> + CurrencyRow( + this.systemCurrencies.filter { + it.currencyCode == code + }.first() + ) + } + + private val availableCurrencies = this.systemCurrencies.filter { + !mostUsedCurrencyCodes.contains(it.currencyCode) + }.sortedBy { + it.displayName + }.map { + CurrencyRow(it) + } + + private class CurrencyRow(var currency:Currency) : RowRepresentable { + + override fun localizedTitle(context: Context): String { + return currency.getDisplayName(Locale.getDefault()) + } + + fun value(): String { + return "${currency.currencyCode} (${currency.getSymbol(Locale.getDefault())})" + } + + override val viewType: Int = RowViewType.TITLE_VALUE.ordinal + } + + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { + return inflater.inflate(R.layout.fragment_currencies, container, false) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + initData() + initUI() + } + + + // StaticRowRepresentableDataSource + + override fun adapterRows(): List? { + val rows = ArrayList() + rows.addAll(mostUsedCurrencies) + rows.add(HeaderRowRepresentable(customViewType = RowViewType.HEADER_TITLE, resId = R.string.currency)) + rows.addAll(availableCurrencies) + return rows + + } + + override fun stringForRow(row: RowRepresentable): String { + return (row as CurrencyRow).value() + } + + // RowRepresentableDelegate + override fun onRowSelected(position: Int, row: RowRepresentable, fromAction: Boolean) { + } + + private fun initData() { + } + + /** + * Init UI + */ + private fun initUI() { + + val activity = activity as PokerAnalyticsActivity + + // Avoid a bug during setting the title + toolbar.title = activity.baseContext.getString( R.string.currency) + + activity.setSupportActionBar(toolbar) + activity.supportActionBar?.setDisplayHomeAsUpEnabled(true) + setHasOptionsMenu(true) + + val viewManager = LinearLayoutManager(requireContext()) + val dataListAdapter = RowRepresentableAdapter(this, this) + + recyclerView.apply { + setHasFixedSize(true) + layoutManager = viewManager + adapter = dataListAdapter + } + } +} \ No newline at end of file diff --git a/app/src/main/java/net/pokeranalytics/android/ui/fragment/SettingsFragment.kt b/app/src/main/java/net/pokeranalytics/android/ui/fragment/SettingsFragment.kt index af907192..113114b2 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/fragment/SettingsFragment.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/fragment/SettingsFragment.kt @@ -8,7 +8,7 @@ import android.widget.Toast import androidx.recyclerview.widget.LinearLayoutManager import kotlinx.android.synthetic.main.fragment_settings.* import net.pokeranalytics.android.BuildConfig -import net.pokeranalytics.android.R +import net.pokeranalytics.android.ui.activity.CurrenciesActivity import net.pokeranalytics.android.ui.activity.DataListActivity import net.pokeranalytics.android.ui.activity.components.PokerAnalyticsActivity import net.pokeranalytics.android.ui.adapter.RowRepresentableAdapter @@ -18,6 +18,9 @@ import net.pokeranalytics.android.ui.fragment.components.PokerAnalyticsFragment import net.pokeranalytics.android.ui.view.RowRepresentable import net.pokeranalytics.android.ui.view.rowrepresentable.SettingRow import net.pokeranalytics.android.util.* +import android.content.Intent + + class SettingsFragment : PokerAnalyticsFragment(), RowRepresentableDelegate, StaticRowRepresentableDataSource { @@ -47,7 +50,7 @@ class SettingsFragment : PokerAnalyticsFragment(), RowRepresentableDelegate, Sta override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { - return inflater.inflate(R.layout.fragment_settings, container, false) + return inflater.inflate(net.pokeranalytics.android.R.layout.fragment_settings, container, false) } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { @@ -67,6 +70,9 @@ class SettingsFragment : PokerAnalyticsFragment(), RowRepresentableDelegate, Sta SettingRow.RATE_APP -> parentActivity.openPlayStorePage() SettingRow.CONTACT_US -> parentActivity.openContactMail() SettingRow.BUG_REPORT -> Toast.makeText(requireContext(), "Bug report", Toast.LENGTH_SHORT).show() + SettingRow.CURRENCY -> { + CurrenciesActivity.newInstance(requireContext()) + } SettingRow.FOLLOW_US -> { when(position) { 0 -> parentActivity.openUrl(BLOG) @@ -75,7 +81,6 @@ class SettingsFragment : PokerAnalyticsFragment(), RowRepresentableDelegate, Sta 3 -> parentActivity.openUrl(FACEBOOK) } } - SettingRow.CURRENCY -> Toast.makeText(requireContext(), "Currency", Toast.LENGTH_SHORT).show() SettingRow.PRIVACY_POLICY -> parentActivity.openUrl(URL_PRIVACY_POLICY) SettingRow.TERMS_OF_USE -> parentActivity.openUrl(URL_TERMS) SettingRow.GDPR -> Toast.makeText(requireContext(), "Show GDPR", Toast.LENGTH_SHORT).show() diff --git a/app/src/main/java/net/pokeranalytics/android/util/DateExtension.kt b/app/src/main/java/net/pokeranalytics/android/util/DateExtension.kt index af945f5e..6029e96b 100644 --- a/app/src/main/java/net/pokeranalytics/android/util/DateExtension.kt +++ b/app/src/main/java/net/pokeranalytics/android/util/DateExtension.kt @@ -84,7 +84,7 @@ fun Date.getMonthAndYear(): String { return SimpleDateFormat("MMMM YYYY", Locale.getDefault()).format(this).capitalize() } -// Return the duration between two dates +// Return the netDuration between two dates fun Date.getDuration(toDate: Date) : String { val difference = (toDate.time - this.time).toInt() val numOfDays = (difference / (1000 * 60 * 60 * 24)) diff --git a/app/src/main/java/net/pokeranalytics/android/util/NumbersExtension.kt b/app/src/main/java/net/pokeranalytics/android/util/NumbersExtension.kt index 40ca65f8..d4d4bfda 100644 --- a/app/src/main/java/net/pokeranalytics/android/util/NumbersExtension.kt +++ b/app/src/main/java/net/pokeranalytics/android/util/NumbersExtension.kt @@ -25,6 +25,10 @@ fun Double.toCurrency(): String { return format.format(this) } +fun Double.formattedHourlyDuration() : String { + return (this * 1000 * 3600).toLong().toMinutes() +} + // Return the time from milliseconds to hours:minutes fun Long.toMinutes() : String { val totalMinutes = this / (1000 * 60) diff --git a/app/src/main/java/net/pokeranalytics/android/util/Preferences.kt b/app/src/main/java/net/pokeranalytics/android/util/Preferences.kt index a283f7dc..f62d4674 100644 --- a/app/src/main/java/net/pokeranalytics/android/util/Preferences.kt +++ b/app/src/main/java/net/pokeranalytics/android/util/Preferences.kt @@ -6,7 +6,7 @@ import java.util.* class Preferences { - enum class Keys(identifier: String) { + enum class Keys(var identifier: String) { CURRENCY_LANGUAGE("CurrencyLanguage") } @@ -15,13 +15,13 @@ class Preferences { fun setString(key: Keys, value: String, context: Context) { var preferences = PreferenceManager.getDefaultSharedPreferences(context) var editor = preferences.edit() - editor.putString(key.toString(), value) + editor.putString(key.identifier, value) editor.commit() } fun getString(key: Keys, context: Context) : String? { var preferences = PreferenceManager.getDefaultSharedPreferences(context) - return preferences.getString(key.name, null) + return preferences.getString(key.identifier, null) } fun setCurrencyLanguage(language: String, context: Context) { @@ -29,6 +29,18 @@ class Preferences { } fun getCurrencyLocale(context : Context) : Locale { + + /* + + java.util.Currency usd = java.util.Currency.getInstance("USD"); + java.text.NumberFormat format = java.text.NumberFormat.getCurrencyInstance( + java.util.Locale.JAPAN); + format.setCurrency(usd); + System.out.println(format.format(23.23)); + format.setMaximumFractionDigits(usd.getDefaultFractionDigits()); + System.out.println(format.format(23.23)); + + */ val currencyLanguage = Preferences.getString(Keys.CURRENCY_LANGUAGE, context) if (currencyLanguage != null) { return Locale(currencyLanguage) diff --git a/app/src/main/res/layout/activity_currencies.xml b/app/src/main/res/layout/activity_currencies.xml new file mode 100644 index 00000000..72f6fd70 --- /dev/null +++ b/app/src/main/res/layout/activity_currencies.xml @@ -0,0 +1,15 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_currencies.xml b/app/src/main/res/layout/fragment_currencies.xml new file mode 100644 index 00000000..bab049a9 --- /dev/null +++ b/app/src/main/res/layout/fragment_currencies.xml @@ -0,0 +1,61 @@ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file