refactoring + fixing rates setting

feature/top10
Laurent 7 years ago
parent 77de0e9b01
commit 0b8062e4c5
  1. 62
      app/src/main/java/net/pokeranalytics/android/PokerAnalyticsApplication.kt
  2. 19
      app/src/main/java/net/pokeranalytics/android/model/interfaces/Manageable.kt
  3. 6
      app/src/main/java/net/pokeranalytics/android/model/realm/Bankroll.kt
  4. 38
      app/src/main/java/net/pokeranalytics/android/model/realm/Currency.kt
  5. 32
      app/src/main/java/net/pokeranalytics/android/model/realm/Session.kt
  6. 22
      app/src/main/java/net/pokeranalytics/android/ui/activity/HomeActivity.kt
  7. 5
      app/src/main/java/net/pokeranalytics/android/ui/activity/components/PokerAnalyticsActivity.kt
  8. 21
      app/src/main/java/net/pokeranalytics/android/ui/fragment/BankrollDataFragment.kt
  9. 61
      app/src/main/java/net/pokeranalytics/android/ui/fragment/EditableDataFragment.kt
  10. 2
      app/src/main/java/net/pokeranalytics/android/ui/fragment/SessionFragment.kt
  11. 10
      app/src/main/java/net/pokeranalytics/android/util/CurrencyUtils.kt

@ -5,7 +5,6 @@ import com.crashlytics.android.Crashlytics
import io.fabric.sdk.android.Fabric import io.fabric.sdk.android.Fabric
import io.realm.Realm import io.realm.Realm
import io.realm.RealmConfiguration import io.realm.RealmConfiguration
import io.realm.RealmResults
import io.realm.kotlin.where import io.realm.kotlin.where
import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@ -40,7 +39,7 @@ class PokerAnalyticsApplication : Application() {
} }
if (BuildConfig.DEBUG) { if (BuildConfig.DEBUG) {
this.createFakeSessions() // debug // this.createFakeSessions() // debug
} }
} }
@ -61,63 +60,4 @@ class PokerAnalyticsApplication : Application() {
} }
//
// private fun createFakeStats() {
//
// val buyinList = arrayListOf(100.0, 200.0, 300.0, 500.0, 1000.0, 2000.0)
// val resultsList = arrayListOf(
// -2500.0, -2000.0, -1500.0, -1000.0, -500.0, 200.0, 1000.0, 1500.0, 2500.0
// )
//
// val commitFrequency = 100
//
// Thread() {
//
// try {
//
// val realm = Realm.getDefaultInstance()
//
// // Test endedSessions
// val pstats = realm.where<ComputableResult>().findAll()
// if (pstats.size < 10) {
//
// val numberOfSessions = 2000
// Timber.d("*** Start creating ${numberOfSessions} fake computables...")
//
// val s = Date()
//
// realm.beginTransaction()
//
// for (index in 0..numberOfSessions) {
//
// if (index % commitFrequency == 0) {
// Timber.d("****** committing at ${index} computables...")
// realm.commitTransaction()
// realm.beginTransaction()
// }
//
// val ps = realm.createObject(ComputableResult::class.java)
// ps.ratedBuyin = buyinList.random()
// ps.ratedNet = resultsList.random()
//
// }
//
// realm.commitTransaction()
//
// val e = Date()
// val duration = (e.time - s.time) / 1000.0
// Timber.d("*** ended in ${duration} seconds")
//
// }
//
// realm.close()
//
// } catch (e: Exception) {
// Timber.e(e)
// }
//
// }.start()
//
// }
} }

@ -1,11 +1,9 @@
package net.pokeranalytics.android.model.interfaces package net.pokeranalytics.android.model.interfaces
import io.realm.Realm import io.realm.RealmModel
import io.realm.RealmObject import io.realm.RealmObject
import io.realm.kotlin.where
import net.pokeranalytics.android.R import net.pokeranalytics.android.R
import net.pokeranalytics.android.exceptions.ModelException import net.pokeranalytics.android.exceptions.ModelException
import net.pokeranalytics.android.model.realm.Session
import net.pokeranalytics.android.ui.view.RowRepresentable import net.pokeranalytics.android.ui.view.RowRepresentable
enum class ManageableStatus { enum class ManageableStatus {
@ -17,7 +15,7 @@ enum class ManageableStatus {
/** /**
* An interface to grouped object which are managed by the database * An interface to grouped object which are managed by the database
*/ */
interface Manageable : Savable, Deletable, Identifiable, Editable interface Manageable : Savable, Deletable, Editable
interface NameManageable: Manageable { interface NameManageable: Manageable {
var name: String var name: String
@ -27,7 +25,10 @@ interface NameManageable: Manageable {
} }
override fun alreadyExists(): Boolean { override fun alreadyExists(): Boolean {
return (this as RealmObject).realm.where((this as RealmObject)::class.java).equalTo("name", this.name).findAll().isNotEmpty() if (this is RealmObject && this.realm != null) {
return (this as RealmObject).realm.where(this::class.java).equalTo("name", this.name).findAll().isNotEmpty()
}
return false
} }
override fun getFailedSaveMessage(status: ManageableStatus): Int { override fun getFailedSaveMessage(status: ManageableStatus): Int {
@ -43,7 +44,7 @@ interface NameManageable: Manageable {
/** /**
* An interface associate a unique identifier to an object * An interface associate a unique identifier to an object
*/ */
interface Identifiable { interface Identifiable : RealmModel {
/** /**
* A unique identifier getter * A unique identifier getter
@ -54,7 +55,7 @@ interface Identifiable {
/** /**
* An interface to update the fields of an object * An interface to update the fields of an object
*/ */
interface Editable { interface Editable : Identifiable {
/** /**
* a method to handle the modification of the object. * a method to handle the modification of the object.
* Through [RowRepresentable] the object is able to update the right variable with the new value. * Through [RowRepresentable] the object is able to update the right variable with the new value.
@ -65,7 +66,7 @@ interface Editable {
/** /**
* An interface to easily handle the validity of any object we want to save * An interface to easily handle the validity of any object we want to save
*/ */
interface Savable { interface Savable : Identifiable {
fun isValidForSave(): Boolean fun isValidForSave(): Boolean
fun alreadyExists(): Boolean fun alreadyExists(): Boolean
@ -96,7 +97,7 @@ interface Savable {
/** /**
* An interface to easily handle the validity of any object we want to delete * An interface to easily handle the validity of any object we want to delete
*/ */
interface Deletable { interface Deletable : Identifiable {
/** /**
* A method to define if an object is safe for deletion in database * A method to define if an object is safe for deletion in database

@ -82,7 +82,11 @@ open class Bankroll() : RealmObject(), NameManageable, StaticRowRepresentableDat
this.currency?.code = value as String? this.currency?.code = value as String?
} }
BankrollRow.RATE -> { BankrollRow.RATE -> {
this.currency?.rate = (value as String? ?: "0").toDouble() value?.let { rate ->
this.currency?.rate = (rate as String).toDouble()
} ?: run {
this.currency?.rate = null
}
} }
} }
} }

@ -1,12 +1,15 @@
package net.pokeranalytics.android.model.realm package net.pokeranalytics.android.model.realm
import io.realm.Realm
import io.realm.RealmObject import io.realm.RealmObject
import io.realm.annotations.Ignore
import io.realm.annotations.PrimaryKey import io.realm.annotations.PrimaryKey
import java.util.* import java.util.*
open class Currency : RealmObject() { open class Currency : RealmObject() {
@Ignore
val DEFAULTRATE: Double = 1.0
@PrimaryKey @PrimaryKey
var id = UUID.randomUUID().toString() var id = UUID.randomUUID().toString()
@ -18,21 +21,26 @@ open class Currency : RealmObject() {
/** /**
* The rate of the currency with the main currency * The rate of the currency with the main currency
*/ */
var rate: Double? = 1.0 var rate: Double? = DEFAULTRATE
fun refreshAllRelatedComputableResults(realm:Realm) { fun refreshRelatedRatedValues() {
val rate = this.rate ?: 1.0
val query = realm.where(ComputableResult::class.java)
query.`in`("session.bankroll.currency.id", arrayOf(this.id))
val cResults = query.findAll()
cResults.forEach { computable ->
computable.session?.result?.net?.let {
computable.ratedNet = it * rate
}
computable.session?.result?.buyin?.let {
computable.ratedBuyin = it * rate
}
if (this.realm != null) {
val rate = this.rate ?: DEFAULTRATE
val query = this.realm.where(ComputableResult::class.java)
query.`in`("session.bankroll.currency.id", arrayOf(this.id))
val cResults = query.findAll()
cResults.forEach { computable ->
computable.session?.result?.net?.let {
computable.ratedNet = it * rate
}
computable.session?.result?.buyin?.let {
computable.ratedBuyin = it * rate
}
}
} }
} }
} }

@ -40,7 +40,7 @@ import java.util.*
import java.util.Currency import java.util.Currency
import kotlin.collections.ArrayList import kotlin.collections.ArrayList
open class Session : RealmObject(), Identifiable, Editable, StaticRowRepresentableDataSource, RowRepresentable, Timed, open class Session : RealmObject(), Identifiable, Manageable, StaticRowRepresentableDataSource, RowRepresentable, Timed,
TimeFilterable { TimeFilterable {
enum class Type { enum class Type {
@ -367,6 +367,28 @@ open class Session : RealmObject(), Identifiable, Editable, StaticRowRepresentab
throw ModelException("Session should have an existing Result relationship") throw ModelException("Session should have an existing Result relationship")
} }
// Manageable
override fun isValidForSave(): Boolean {
return this.bankroll != null
}
override fun alreadyExists(): Boolean {
return false
}
override fun getFailedSaveMessage(status: ManageableStatus): Int {
return 0 // @todo
}
override fun isValidForDelete(): Boolean {
return true
}
override fun getFailedDeleteMessage(): Int {
return 0 // @todo
}
// States // States
/** /**
@ -731,13 +753,13 @@ open class Session : RealmObject(), Identifiable, Editable, StaticRowRepresentab
this.breakDuration = if (value != null) (value as String).toLong() * 60 * 1000 else 0 this.breakDuration = if (value != null) (value as String).toLong() * 60 * 1000 else 0
} }
SessionRow.BUY_IN -> { SessionRow.BUY_IN -> {
val localResult = if (result != null) result as Result else realm.createObject(Result::class.java) val localResult = if (this.result != null) this.result as Result else realm.createObject(Result::class.java)
localResult.buyin = value as Double? localResult.buyin = value as Double?
result = localResult this.result = localResult
this.updateRowRepresentation() this.updateRowRepresentation()
} }
SessionRow.CASHED_OUT, SessionRow.PRIZE, SessionRow.NET_RESULT -> { SessionRow.CASHED_OUT, SessionRow.PRIZE, SessionRow.NET_RESULT -> {
val localResult = if (result != null) result as Result else realm.createObject(Result::class.java) val localResult = if (this.result != null) this.result as Result else realm.createObject(Result::class.java)
if (value == null) { if (value == null) {
localResult.cashout = null localResult.cashout = null
@ -746,7 +768,7 @@ open class Session : RealmObject(), Identifiable, Editable, StaticRowRepresentab
this.end() this.end()
} }
result = localResult this.result = localResult
} }
SessionRow.COMMENT -> comment = value as String? ?: "" SessionRow.COMMENT -> comment = value as String? ?: ""

@ -7,8 +7,10 @@ import android.view.Menu
import android.view.MenuItem import android.view.MenuItem
import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AlertDialog
import com.google.android.material.bottomnavigation.BottomNavigationView import com.google.android.material.bottomnavigation.BottomNavigationView
import io.realm.RealmResults
import kotlinx.android.synthetic.main.activity_home.* import kotlinx.android.synthetic.main.activity_home.*
import net.pokeranalytics.android.R import net.pokeranalytics.android.R
import net.pokeranalytics.android.model.realm.Currency
import net.pokeranalytics.android.ui.activity.components.PokerAnalyticsActivity import net.pokeranalytics.android.ui.activity.components.PokerAnalyticsActivity
import net.pokeranalytics.android.ui.adapter.HomePagerAdapter import net.pokeranalytics.android.ui.adapter.HomePagerAdapter
import net.pokeranalytics.android.util.Preferences import net.pokeranalytics.android.util.Preferences
@ -27,6 +29,8 @@ class HomeActivity : PokerAnalyticsActivity() {
private var homeMenu: Menu? = null private var homeMenu: Menu? = null
private lateinit var currencies: RealmResults<Currency>
private val mOnNavigationItemSelectedListener = BottomNavigationView.OnNavigationItemSelectedListener { item -> private val mOnNavigationItemSelectedListener = BottomNavigationView.OnNavigationItemSelectedListener { item ->
when (item.itemId) { when (item.itemId) {
net.pokeranalytics.android.R.id.navigation_history -> { net.pokeranalytics.android.R.id.navigation_history -> {
@ -49,6 +53,7 @@ class HomeActivity : PokerAnalyticsActivity() {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setContentView(R.layout.activity_home) setContentView(R.layout.activity_home)
observeRealmObjects()
initUI() initUI()
checkFirstLaunch() checkFirstLaunch()
} }
@ -68,6 +73,23 @@ class HomeActivity : PokerAnalyticsActivity() {
return super.onOptionsItemSelected(item) return super.onOptionsItemSelected(item)
} }
private fun observeRealmObjects() {
val realm = getRealm()
// observe currency changes
this.currencies = realm.where(Currency::class.java).findAll()
this.currencies.addChangeListener { t, set ->
realm.beginTransaction()
t.forEach {
it.refreshRelatedRatedValues()
}
realm.commitTransaction()
}
}
/** /**
* Init UI * Init UI
*/ */

@ -3,7 +3,6 @@ package net.pokeranalytics.android.ui.activity.components
import android.Manifest import android.Manifest
import android.Manifest.permission.ACCESS_FINE_LOCATION import android.Manifest.permission.ACCESS_FINE_LOCATION
import android.content.pm.PackageManager import android.content.pm.PackageManager
import android.os.Bundle
import android.view.MenuItem import android.view.MenuItem
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat import androidx.core.app.ActivityCompat
@ -25,10 +24,6 @@ open class PokerAnalyticsActivity : AppCompatActivity() {
private val realm = Realm.getDefaultInstance() private val realm = Realm.getDefaultInstance()
private var permissionCallback: ((granted: Boolean) -> Unit)? = null private var permissionCallback: ((granted: Boolean) -> Unit)? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
}
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) { override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults) super.onRequestPermissionsResult(requestCode, permissions, grantResults)

@ -17,9 +17,9 @@ import net.pokeranalytics.android.ui.view.RowViewType
import net.pokeranalytics.android.ui.view.rowrepresentable.BankrollRow import net.pokeranalytics.android.ui.view.rowrepresentable.BankrollRow
import net.pokeranalytics.android.ui.view.rowrepresentable.CustomizableRowRepresentable import net.pokeranalytics.android.ui.view.rowrepresentable.CustomizableRowRepresentable
import net.pokeranalytics.android.ui.view.rowrepresentable.SimpleRow import net.pokeranalytics.android.ui.view.rowrepresentable.SimpleRow
import net.pokeranalytics.android.util.CurrencyUtils
import net.pokeranalytics.android.util.NULL_TEXT import net.pokeranalytics.android.util.NULL_TEXT
import net.pokeranalytics.android.util.Preferences import net.pokeranalytics.android.util.Preferences
import net.pokeranalytics.android.util.extensions.round
import retrofit2.Call import retrofit2.Call
import retrofit2.Response import retrofit2.Response
import java.util.* import java.util.*
@ -93,10 +93,10 @@ class BankrollDataFragment : EditableDataFragment(), StaticRowRepresentableDataS
} }
} }
BankrollRow.RATE -> { BankrollRow.RATE -> {
bankroll.currency?.let { this.bankroll.currency?.rate?.let { rate ->
(it.rate ?: 1.0).round() CurrencyUtils.getCurrencyRateFormatter().format(rate)
} ?: run { } ?: run {
1.0.round() CurrencyUtils.getCurrencyRateFormatter().format(1.0)
} }
} }
else -> super.stringForRow(row) else -> super.stringForRow(row)
@ -114,7 +114,14 @@ class BankrollDataFragment : EditableDataFragment(), StaticRowRepresentableDataS
override fun editDescriptors(row: RowRepresentable): ArrayList<RowRepresentableEditDescriptor>? { override fun editDescriptors(row: RowRepresentable): ArrayList<RowRepresentableEditDescriptor>? {
return when (row) { return when (row) {
SimpleRow.NAME -> row.editingDescriptors(mapOf("defaultValue" to this.bankroll.name)) SimpleRow.NAME -> row.editingDescriptors(mapOf("defaultValue" to this.bankroll.name))
BankrollRow.RATE -> row.editingDescriptors(mapOf("defaultValue" to (this.bankroll.currency?.rate ?: 1.0).round())) BankrollRow.RATE -> {
this.bankroll.currency?.rate?.let { rate ->
row.editingDescriptors(mapOf("defaultValue" to CurrencyUtils.getCurrencyRateFormatter().format(rate)))
} ?: run {
row.editingDescriptors(mapOf("defaultValue" to ""))
}
}
else -> null else -> null
} }
} }
@ -132,7 +139,7 @@ class BankrollDataFragment : EditableDataFragment(), StaticRowRepresentableDataS
// Clear the value when the currency has been updated // Clear the value when the currency has been updated
if (row == BankrollRow.CURRENCY) { if (row == BankrollRow.CURRENCY) {
lastRefreshRateCall = 0 this.lastRefreshRateCall = 0
} }
updateAdapterUI() updateAdapterUI()
@ -162,7 +169,7 @@ class BankrollDataFragment : EditableDataFragment(), StaticRowRepresentableDataS
rows.add(BankrollRow.LIVE) rows.add(BankrollRow.LIVE)
rows.add(CustomizableRowRepresentable(customViewType = RowViewType.HEADER_TITLE, resId = R.string.currency)) rows.add(CustomizableRowRepresentable(customViewType = RowViewType.HEADER_TITLE, resId = R.string.currency))
rows.add(BankrollRow.CURRENCY) rows.add(BankrollRow.CURRENCY)
if (differentCurrency) { if (this.differentCurrency) {
rows.add(BankrollRow.RATE) rows.add(BankrollRow.RATE)
rows.add(BankrollRow.REFRESH_RATE) rows.add(BankrollRow.REFRESH_RATE)
} }

@ -12,8 +12,10 @@ import kotlinx.android.synthetic.main.fragment_editable_data.view.*
import net.pokeranalytics.android.R import net.pokeranalytics.android.R
import net.pokeranalytics.android.exceptions.ConfigurationException import net.pokeranalytics.android.exceptions.ConfigurationException
import net.pokeranalytics.android.model.LiveData import net.pokeranalytics.android.model.LiveData
import net.pokeranalytics.android.model.interfaces.* import net.pokeranalytics.android.model.interfaces.Editable
import net.pokeranalytics.android.model.realm.Bankroll import net.pokeranalytics.android.model.interfaces.Manageable
import net.pokeranalytics.android.model.interfaces.ManageableStatus
import net.pokeranalytics.android.model.interfaces.Savable
import net.pokeranalytics.android.ui.activity.EditableDataActivity import net.pokeranalytics.android.ui.activity.EditableDataActivity
import net.pokeranalytics.android.ui.activity.components.PokerAnalyticsActivity import net.pokeranalytics.android.ui.activity.components.PokerAnalyticsActivity
import net.pokeranalytics.android.ui.adapter.RowRepresentableAdapter import net.pokeranalytics.android.ui.adapter.RowRepresentableAdapter
@ -141,35 +143,42 @@ open class EditableDataFragment : PokerAnalyticsFragment(), RowRepresentableDele
* Save data * Save data
*/ */
fun saveData() { fun saveData() {
if (this.item is Savable) {
val status = (this.item as Savable).saveStatus()
when (status) {
ManageableStatus.VALID -> {
this.getRealm().executeTransaction {
val item = it.copyToRealmOrUpdate(this.item)
if (item is Bankroll) {
item.currency?.refreshAllRelatedComputableResults(it)
}
val uniqueIdentifier = if (item is Identifiable) {
item.id
} else ""
finishActivityWithResult(uniqueIdentifier) val savable = this.item
when (savable) {
is Savable -> {
val status = savable.saveStatus()
when (status) {
ManageableStatus.VALID -> {
this.getRealm().executeTransaction {
val managedItem = it.copyToRealmOrUpdate(this.item)
if (managedItem is Savable) {
val uniqueIdentifier = (managedItem as Savable).id
finishActivityWithResult(uniqueIdentifier)
}
// if (managedItem is Bankroll) {
// managedItem.currency?.refreshRelatedRatedValues(it)
// }
//
// val uniqueIdentifier = (managedItem as Savable).id
// finishActivityWithResult(uniqueIdentifier)
}
}
else -> {
val message = savable.getFailedSaveMessage(status)
val builder = AlertDialog.Builder(requireContext())
.setMessage(message)
.setNegativeButton(R.string.ok, null)
builder.show()
} }
} }
else -> {
val message = (this.item as Savable).getFailedSaveMessage(status) } else -> {
val builder = AlertDialog.Builder(requireContext()) throw ConfigurationException("Save action called on un-Savable object")
.setMessage(message)
.setNegativeButton(R.string.ok, null)
builder.show()
}
} }
} else {
throw ConfigurationException("Save action called on un-Savable object")
} }
} }
/** /**

@ -204,8 +204,6 @@ class SessionFragment : PokerAnalyticsFragment(), RowRepresentableDelegate {
sessionMenu?.findItem(R.id.restart)?.isVisible = true sessionMenu?.findItem(R.id.restart)?.isVisible = true
sessionMenu?.findItem(R.id.stop)?.isVisible = false sessionMenu?.findItem(R.id.stop)?.isVisible = false
} }
else -> {
}
} }
} }

@ -30,6 +30,16 @@ class CurrencyUtils {
return currencyFormatter return currencyFormatter
} }
/**
* Get a currency rate formatter
*/
fun getCurrencyRateFormatter() : NumberFormat {
val currencyFormatter = NumberFormat.getInstance()
currencyFormatter.minimumFractionDigits = 0
currencyFormatter.maximumFractionDigits = 6
return currencyFormatter
}
} }
} }
Loading…
Cancel
Save