Merge branch 'master' of gitlab.com:stax-river/poker-analytics

feature/top10
Aurelien Hubert 7 years ago
commit 709db5b5ea
  1. 143
      app/src/androidTest/java/net/pokeranalytics/android/ExampleInstrumentedUnitTest.kt
  2. 1
      app/src/main/AndroidManifest.xml
  3. 40
      app/src/main/java/net/pokeranalytics/android/PokerAnalyticsApplication.kt
  4. 4
      app/src/main/java/net/pokeranalytics/android/calculus/Stat.kt
  5. 19
      app/src/main/java/net/pokeranalytics/android/model/realm/Session.kt
  6. 27
      app/src/main/java/net/pokeranalytics/android/model/realm/SessionSet.kt
  7. 155
      app/src/main/java/net/pokeranalytics/android/model/realm/TimeFrame.kt
  8. 23
      app/src/main/java/net/pokeranalytics/android/ui/activity/CurrenciesActivity.kt
  9. 116
      app/src/main/java/net/pokeranalytics/android/ui/fragment/CurrenciesFragment.kt
  10. 11
      app/src/main/java/net/pokeranalytics/android/ui/fragment/SettingsFragment.kt
  11. 2
      app/src/main/java/net/pokeranalytics/android/util/DateExtension.kt
  12. 4
      app/src/main/java/net/pokeranalytics/android/util/NumbersExtension.kt
  13. 18
      app/src/main/java/net/pokeranalytics/android/util/Preferences.kt
  14. 15
      app/src/main/res/layout/activity_currencies.xml
  15. 61
      app/src/main/res/layout/fragment_currencies.xml

@ -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")
// }
}

@ -30,6 +30,7 @@
android:windowSoftInputMode="adjustNothing" />
<activity android:name=".ui.activity.EditableDataActivity" />
<activity android:name=".ui.activity.CurrenciesActivity" />
<meta-data
android:name="preloaded_fonts"

@ -131,8 +131,8 @@ class PokerAnalyticsApplication : Application() {
for (index in 0..50) {
realm.executeTransaction {
val session = Session()
session.id = UUID.randomUUID().toString()
val session = Session.newInstance(realm, false)
// session.id = UUID.randomUUID().toString()
val calendar = Calendar.getInstance()
calendar.set(
@ -148,21 +148,27 @@ class PokerAnalyticsApplication : Application() {
calendar.add(Calendar.MINUTE, (0..59).random())
val endDate = calendar.time
val timeFrame = TimeFrame()
timeFrame.setDate(startDate, endDate)
session.timeFrame = timeFrame
// val timeFrame = TimeFrame()
session.timeFrame?.let {
// it.startDate = startDate
// it.endDate = endDate
it.setDate(startDate, endDate)
}
// session.timeFrame = timeFrame
session.creationDate = startDate
session.limit = Limit.values().random().ordinal
session.game = realm.where<Game>().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}")
// }
}
}

@ -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

@ -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<Bankroll>().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
}
}

@ -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<Session>? = 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
}
}
}

@ -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<SessionSet> = realm.where(SessionSet::class.java)
var query: RealmQuery<SessionSet> = 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<Session>(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<Session>()
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}")
}

@ -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)
}
}

@ -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<RowRepresentable>? {
val rows = ArrayList<RowRepresentable>()
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
}
}
}

@ -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()

@ -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))

@ -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)

@ -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)

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical">
<fragment
android:id="@+id/currenciesFragment"
android:name="net.pokeranalytics.android.ui.fragment.CurrenciesFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:layout="@layout/fragment_currencies" />
</LinearLayout>

@ -0,0 +1,61 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.core.widget.NestedScrollView
android:id="@+id/nestedScrollView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.core.widget.NestedScrollView>
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/appBar"
android:layout_width="match_parent"
android:layout_height="128dp"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">
<com.google.android.material.appbar.CollapsingToolbarLayout
android:id="@+id/collapsingToolbar"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:collapsedTitleTextAppearance="@style/PokerAnalyticsTheme.Toolbar.CollapsedTitleAppearance"
app:contentScrim="?attr/colorPrimary"
app:expandedTitleGravity="bottom"
app:expandedTitleMarginStart="72dp"
app:expandedTitleTextAppearance="@style/PokerAnalyticsTheme.Toolbar.ExpandedTitleAppearance"
app:layout_scrollFlags="scroll|exitUntilCollapsed|snap">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_collapseMode="pin"
app:title="Poker Analytics"
app:titleTextColor="@color/white" />
</com.google.android.material.appbar.CollapsingToolbarLayout>
</com.google.android.material.appbar.AppBarLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
Loading…
Cancel
Save