Improve mass creation performances

feature/top10
Laurent 7 years ago
commit 90be7a995d
  1. 18
      app/src/main/java/net/pokeranalytics/android/PokerAnalyticsApplication.kt
  2. 4
      app/src/main/java/net/pokeranalytics/android/calculus/Calculator.kt
  3. 2
      app/src/main/java/net/pokeranalytics/android/calculus/Stat.kt
  4. 4
      app/src/main/java/net/pokeranalytics/android/exceptions/Exceptions.kt
  5. 18
      app/src/main/java/net/pokeranalytics/android/model/LiveData.kt
  6. 2
      app/src/main/java/net/pokeranalytics/android/model/interfaces/CountableUsage.kt
  7. 2
      app/src/main/java/net/pokeranalytics/android/model/interfaces/Manageable.kt
  8. 20
      app/src/main/java/net/pokeranalytics/android/model/realm/Bankroll.kt
  9. 20
      app/src/main/java/net/pokeranalytics/android/model/realm/Game.kt
  10. 65
      app/src/main/java/net/pokeranalytics/android/model/realm/Location.kt
  11. 68
      app/src/main/java/net/pokeranalytics/android/model/realm/Session.kt
  12. 20
      app/src/main/java/net/pokeranalytics/android/model/realm/TournamentFeature.kt
  13. 19
      app/src/main/java/net/pokeranalytics/android/model/realm/TournamentName.kt
  14. 19
      app/src/main/java/net/pokeranalytics/android/model/realm/TransactionType.kt
  15. 29
      app/src/main/java/net/pokeranalytics/android/ui/activity/components/PokerAnalyticsActivity.kt
  16. 23
      app/src/main/java/net/pokeranalytics/android/ui/fragment/CurrenciesFragment.kt
  17. 2
      app/src/main/java/net/pokeranalytics/android/ui/fragment/DataListFragment.kt
  18. 30
      app/src/main/java/net/pokeranalytics/android/ui/fragment/EditableDataFragment.kt
  19. 10
      app/src/main/java/net/pokeranalytics/android/ui/fragment/HistoryFragment.kt
  20. 205
      app/src/main/java/net/pokeranalytics/android/ui/fragment/LocationDataFragment.kt
  21. 2
      app/src/main/java/net/pokeranalytics/android/ui/fragment/SessionFragment.kt
  22. 10
      app/src/main/java/net/pokeranalytics/android/ui/fragment/SettingsFragment.kt
  23. 42
      app/src/main/java/net/pokeranalytics/android/ui/fragment/StatsFragment.kt
  24. 14
      app/src/main/java/net/pokeranalytics/android/ui/view/HistorySessionDiffCallback.kt
  25. 26
      app/src/main/java/net/pokeranalytics/android/ui/view/RowViewType.kt
  26. 9
      app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/CustomizableRowRepresentable.kt
  27. 16
      app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/LocationRow.kt
  28. 10
      app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/SettingRow.kt
  29. 26
      app/src/main/java/net/pokeranalytics/android/util/LocationManager.kt
  30. 37
      app/src/main/res/layout/row_loader.xml
  31. 1
      app/src/main/res/values/strings.xml

@ -6,6 +6,7 @@ import io.realm.RealmConfiguration
import io.realm.RealmResults
import io.realm.kotlin.where
import net.pokeranalytics.android.model.Limit
import net.pokeranalytics.android.model.realm.Bankroll
import net.pokeranalytics.android.model.realm.Game
import net.pokeranalytics.android.model.realm.Session
import net.pokeranalytics.android.model.utils.Seed
@ -75,18 +76,21 @@ class PokerAnalyticsApplication : Application() {
-2500.0, -2000.0, -1500.0, -1000.0, -500.0, 200.0, 1000.0, 1500.0, 2500.0
)
Thread().run() {
val commitFrequency = 100
Thread() {
try {
val realm = Realm.getDefaultInstance()
val games = realm.where<Game>().findAll()
val bankroll = realm.where<Bankroll>().findAll().firstOrNull()
// Test endedSessions
val sessions = realm.where<Session>().findAll()
if (sessions.size < 10) {
val numberOfSessions = 10000
val numberOfSessions = 2000
Timber.d("*** Start creating ${numberOfSessions} fake sessions...")
val s = Date()
@ -95,17 +99,17 @@ class PokerAnalyticsApplication : Application() {
for (index in 0..numberOfSessions) {
if (index % 1000 == 999) {
if (index % commitFrequency == 0) {
Timber.d("****** committing at ${index} sessions...")
realm.commitTransaction()
realm.beginTransaction()
}
val session = Session.newInstance(realm, false)
val session = Session.newInstance(realm, false, bankroll)
val calendar = Calendar.getInstance()
calendar.set(
(2017..2018).random(),
(2016..2018).random(),
(0..11).random(),
(0..28).random(),
(0..23).random(),
@ -117,8 +121,6 @@ class PokerAnalyticsApplication : Application() {
calendar.add(Calendar.MINUTE, (0..59).random())
val endDate = calendar.time
// val timeFrame = TimeFrame()
session.startDate = startDate
session.endDate = endDate
session.creationDate = startDate
@ -147,7 +149,7 @@ class PokerAnalyticsApplication : Application() {
Timber.e(e)
}
}
}.start()
}

@ -2,6 +2,7 @@ package net.pokeranalytics.android.calculus
import net.pokeranalytics.android.calculus.Stat.*
import net.pokeranalytics.android.model.realm.SessionSet
import timber.log.Timber
/**
* The class performing stats computation
@ -56,6 +57,7 @@ class Calculator {
companion object {
fun computePreAggregation(sets: List<SessionSet>, options: Options): List<ComputedResults> {
Timber.d("sets = ${sets.size}")
return listOf()
}
@ -89,6 +91,8 @@ class Calculator {
*/
fun compute(sessionGroup: SessionGroup, options: Options) : ComputedResults {
Timber.d(">>>> Start computing group ${sessionGroup.name}, ${sessionGroup.sessions.size} sessions")
val sessions: List<SessionInterface> = sessionGroup.sessions
val sessionSets = sessionGroup.sessions.mapNotNull { it.sessionSet }.toHashSet()

@ -162,7 +162,7 @@ class ComputedStat(stat: Stat, value: Double) {
* Returns a TextFormat instance for an evolution value located at the specified [index]
*/
fun evolutionValueFormat(index: Int) : TextFormat {
return TextFormat("undef")
return TextFormat("undef ${index}")
}
}

@ -7,7 +7,3 @@ class ModelException(message: String) : Exception(message) {
class FormattingException(message: String) : Exception(message) {
}
class TypeException(message: String) : Exception(message) {
}

@ -40,12 +40,24 @@ enum class LiveData : Localizable {
fun setUseCount(realm: Realm, realmResults: RealmResults<*>) {
realm.executeTransaction {
realmResults.forEach { countableUsage ->
when (this) {
TOURNAMENT_FEATURE -> {
(countableUsage as CountableUsage).useCount = it.where<Session>().contains(
"tournamentFeatures.id",
countableUsage.id
).count().toInt()
}
else -> {
(countableUsage as CountableUsage).useCount = it.where<Session>().equalTo(
"${relatedEntity.simpleName.toLowerCase()}.id",
countableUsage.uniqueIdentifier()
"${relatedEntity.simpleName.decapitalize()}.id",
countableUsage.id
).count().toInt()
}
}
}
}
}
/**
@ -81,7 +93,7 @@ enum class LiveData : Localizable {
}
fun deleteData(realm: Realm, data: Manageable) {
realm.where(this.relatedEntity).equalTo("id", data.uniqueIdentifier()).findAll().deleteAllFromRealm()
realm.where(this.relatedEntity).equalTo("id", data.id).findAll().deleteAllFromRealm()
}
fun updateOrCreate(realm: Realm, primaryKey: String?): RealmObject {

@ -6,5 +6,5 @@ package net.pokeranalytics.android.model.interfaces
interface CountableUsage : Identifiable {
var useCount: Int
get() { return 0 }
set(newValue) {}
set(_) {}
}

@ -16,7 +16,7 @@ interface Identifiable {
/**
* A unique identifier getter
*/
fun uniqueIdentifier(): String
var id: String
}
/**

@ -11,6 +11,7 @@ import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.RowRepresentableEditDescriptor
import net.pokeranalytics.android.ui.view.rowrepresentable.BankrollRow
import net.pokeranalytics.android.ui.view.rowrepresentable.SimpleRow
import timber.log.Timber
import java.util.*
import kotlin.collections.ArrayList
@ -22,10 +23,17 @@ open class Bankroll(name: String = "") : RealmObject(), Manageable,
var bankroll: Bankroll = Bankroll()
return bankroll
}
val rowRepresentation : List<RowRepresentable> by lazy {
val rows = ArrayList<RowRepresentable>()
rows.add(SimpleRow.NAME)
rows.addAll(BankrollRow.values())
rows
}
}
@PrimaryKey
var id = UUID.randomUUID().toString()
override var id = UUID.randomUUID().toString()
// the name of the bankroll
var name: String = name
@ -43,17 +51,9 @@ open class Bankroll(name: String = "") : RealmObject(), Manageable,
return this.name
}
override fun uniqueIdentifier(): String {
return this.id
}
// Row Representable Datasource
override fun adapterRows(): List<RowRepresentable>? {
val rows = ArrayList<RowRepresentable>()
rows.add(SimpleRow.NAME)
rows.addAll(BankrollRow.values())
return rows
return Bankroll.rowRepresentation
}
override fun stringForRow(row: RowRepresentable): String {

@ -20,8 +20,17 @@ import kotlin.collections.ArrayList
open class Game : RealmObject(), Manageable, StaticRowRepresentableDataSource, RowRepresentable, CountableUsage {
companion object {
val rowRepresentation : List<RowRepresentable> by lazy {
val rows = ArrayList<RowRepresentable>()
rows.add(SimpleRow.NAME)
rows.addAll(GameRow.values())
rows
}
}
@PrimaryKey
var id = UUID.randomUUID().toString()
override var id = UUID.randomUUID().toString()
// The name of the game
var name: String = ""
@ -36,15 +45,8 @@ open class Game : RealmObject(), Manageable, StaticRowRepresentableDataSource, R
return this.name
}
override fun uniqueIdentifier(): String {
return this.id
}
override fun adapterRows(): List<RowRepresentable>? {
val rows = ArrayList<RowRepresentable>()
rows.add(SimpleRow.NAME)
rows.addAll(GameRow.values())
return rows
return Game.rowRepresentation
}
override fun stringForRow(row: RowRepresentable): String {

@ -2,23 +2,18 @@ package net.pokeranalytics.android.model.realm
import com.google.android.libraries.places.api.model.Place
import io.realm.RealmObject
import io.realm.annotations.Ignore
import io.realm.annotations.PrimaryKey
import net.pokeranalytics.android.R
import net.pokeranalytics.android.model.interfaces.Manageable
import net.pokeranalytics.android.ui.adapter.StaticRowRepresentableDataSource
import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.RowRepresentableEditDescriptor
import net.pokeranalytics.android.ui.view.rowrepresentable.LocationRow
import net.pokeranalytics.android.ui.view.rowrepresentable.SimpleRow
import java.util.*
import kotlin.collections.ArrayList
open class Location : RealmObject(), Manageable, StaticRowRepresentableDataSource, RowRepresentable {
open class Location : RealmObject(), Manageable, RowRepresentable {
@PrimaryKey
var id = UUID.randomUUID().toString()
override var id = UUID.randomUUID().toString()
// The name of the location
var name: String = ""
@ -32,69 +27,13 @@ open class Location : RealmObject(), Manageable, StaticRowRepresentableDataSourc
// the latitude of the location
var latitude: Double? = null
@Ignore
var isLookingForPlaces = false
override fun getDisplayName(): String {
return this.name
}
override fun uniqueIdentifier(): String {
return this.id
}
override fun adapterRows(): List<RowRepresentable>? {
val rows = ArrayList<RowRepresentable>()
rows.add(SimpleRow.NAME)
rows.addAll(LocationRow.values())
return rows
}
override fun stringForRow(row: RowRepresentable): String {
return when (row) {
SimpleRow.NAME -> this.name
LocationRow.ADDRESS -> this.address
else -> return super.stringForRow(row)
}
}
override fun boolForRow(row: RowRepresentable): Boolean {
return when(row) {
LocationRow.LOCATE_ME -> return isLookingForPlaces
else -> super.boolForRow(row)
}
}
override fun editDescriptors(row: RowRepresentable): ArrayList<RowRepresentableEditDescriptor> {
val data = java.util.ArrayList<RowRepresentableEditDescriptor>()
when (row) {
SimpleRow.NAME -> data.add(
RowRepresentableEditDescriptor(
this.name,
SimpleRow.NAME.resId
)
)
LocationRow.ADDRESS -> data.add(
RowRepresentableEditDescriptor(
this.address,
LocationRow.ADDRESS.resId
)
)
}
return data
}
override fun updateValue(value: Any?, row: RowRepresentable) {
when (row) {
SimpleRow.NAME -> this.name = value as String? ?: ""
LocationRow.ADDRESS -> this.address = value as String? ?: ""
LocationRow.LOCATE_ME -> {
isLookingForPlaces = false
if (value is Place) {
setPlace(value)
}
}
}
}

@ -28,7 +28,7 @@ import net.pokeranalytics.android.ui.adapter.UnmanagedRowRepresentableException
import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.RowRepresentableEditDescriptor
import net.pokeranalytics.android.ui.view.RowViewType
import net.pokeranalytics.android.ui.view.rowrepresentable.HeaderRowRepresentable
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.*
@ -36,6 +36,8 @@ import net.pokeranalytics.android.util.extensions.*
import java.util.*
import java.util.Currency
import kotlin.collections.ArrayList
import kotlin.properties.Delegates
import kotlin.reflect.KProperty
open class Session : RealmObject(), SessionInterface, Manageable, StaticRowRepresentableDataSource, RowRepresentable,
Timed {
@ -46,17 +48,21 @@ open class Session : RealmObject(), SessionInterface, Manageable, StaticRowRepre
}
companion object {
fun newInstance(realm: Realm, isTournament: Boolean): Session {
fun newInstance(realm: Realm, isTournament: Boolean, bankroll: Bankroll? = null): Session {
val session = Session()
session.result = Result()
if (bankroll != null) {
session.bankroll = bankroll
} else {
session.bankroll = realm.where<Bankroll>().findFirst()
}
session.type = if (isTournament) Session.Type.TOURNAMENT.ordinal else Session.Type.CASH_GAME.ordinal
return realm.copyToRealm(session)
}
}
@PrimaryKey
var id = UUID.randomUUID().toString()
override var id = UUID.randomUUID().toString()
/**
* Indicates the type of session, cash game or tournament
@ -110,6 +116,11 @@ open class Session : RealmObject(), SessionInterface, Manageable, StaticRowRepre
* The start date of the break
*/
override var pauseDate: Date? = null
set(value) {
field = value
this.updateRowRepresentation()
}
// The time frame of the Session, i.e. the start & end date
// var timeFrame: TimeFrame? = null
@ -186,6 +197,7 @@ open class Session : RealmObject(), SessionInterface, Manageable, StaticRowRepre
} else if (this.sessionSet != null) {
SessionSetManager.removeFromTimeline(this)
}
this.updateRowRepresentation()
}
/**
@ -224,22 +236,6 @@ open class Session : RealmObject(), SessionInterface, Manageable, StaticRowRepre
return this.result?.net ?: 0.0
}
/*
public var numberOfHandsPerHour: Double {
var playersHandsPerHour: Int = Session.livePlayersHandsPerHour // default is live
if let bankroll = self.bankroll {
playersHandsPerHour = bankroll.isLive() ? Session.livePlayersHandsPerHour : Session.onlinePlayersHandsPerHour
}
var numberOfPlayers: Int = 9 // default is 9 players
if let playersAtTable = self.tableSize?.intValue {
numberOfPlayers = playersAtTable
}
return Double(playersHandsPerHour) / Double(numberOfPlayers)
}
*/
@Ignore
val ONLINE_PLAYER_HANDS_PER_HOUR = 400.0
@Ignore
@ -250,7 +246,7 @@ open class Session : RealmObject(), SessionInterface, Manageable, StaticRowRepre
*/
val numberOfHandsPerHour: Double
get() {
val tableSize = this.tableSize ?: 9
val tableSize = this.tableSize ?: 9 // 9 is the default table size if null
val isLive = this.bankroll?.live ?: true
val playerHandsPerHour = if (isLive) LIVE_PLAYER_HANDS_PER_HOUR else ONLINE_PLAYER_HANDS_PER_HOUR
return playerHandsPerHour / tableSize.toDouble()
@ -461,22 +457,21 @@ open class Session : RealmObject(), SessionInterface, Manageable, StaticRowRepre
@Ignore
override val viewType: Int = RowViewType.ROW_SESSION.ordinal
override fun uniqueIdentifier(): String {
return this.id
}
override fun getDisplayName(): String {
return "Session ${this.creationDate}"
}
override fun adapterRows(): List<RowRepresentable>? {
@Ignore
private var rowRepresentationForCurrentState : List<RowRepresentable> = this.updatedRowRepresentationForCurrentState()
private fun updatedRowRepresentationForCurrentState(): List<RowRepresentable> {
val rows = ArrayList<RowRepresentable>()
// Headers
when (getState()) {
SessionState.STARTED -> {
rows.add(
HeaderRowRepresentable(
CustomizableRowRepresentable(
RowViewType.HEADER_TITLE_AMOUNT_BIG,
title = getFormattedDuration(),
computedStat = ComputedStat(Stat.NETRESULT, result?.net ?: 0.0)
@ -486,7 +481,7 @@ open class Session : RealmObject(), SessionInterface, Manageable, StaticRowRepre
}
SessionState.PAUSED -> {
rows.add(
HeaderRowRepresentable(
CustomizableRowRepresentable(
RowViewType.HEADER_TITLE_AMOUNT_BIG,
resId = R.string.pause,
computedStat = ComputedStat(Stat.NETRESULT, result?.net ?: 0.0)
@ -496,33 +491,29 @@ open class Session : RealmObject(), SessionInterface, Manageable, StaticRowRepre
}
SessionState.FINISHED -> {
rows.add(
HeaderRowRepresentable(
CustomizableRowRepresentable(
RowViewType.HEADER_TITLE_AMOUNT_BIG,
title = getFormattedDuration(),
computedStat = ComputedStat(Stat.NETRESULT, result?.net ?: 0.0)
)
)
rows.add(
HeaderRowRepresentable(
CustomizableRowRepresentable(
RowViewType.HEADER_TITLE_AMOUNT,
resId = R.string.hour_rate_without_pauses,
computedStat = ComputedStat(Stat.HOURLY_RATE, this.hourlyRate)
)
)
//TODO V2: Add Bankroll variation
/*
if (!isTournament()) {
rows.add(
HeaderRowRepresentable(
CustomizableRowRepresentable(
RowViewType.HEADER_TITLE_VALUE,
resId = R.string.bankroll_variation,
computedStat = ComputedStat(Stat.HOURLY_RATE, 0.0)
)
)
}
*/
rows.add(SeparatorRowRepresentable())
}
else -> {
@ -534,6 +525,15 @@ open class Session : RealmObject(), SessionInterface, Manageable, StaticRowRepre
return rows
}
private fun updateRowRepresentation() {
this.rowRepresentationForCurrentState = this.updatedRowRepresentationForCurrentState()
}
override fun adapterRows(): List<RowRepresentable>? {
return this.rowRepresentationForCurrentState
}
override fun boolForRow(row: RowRepresentable): Boolean {
return false
}

@ -16,8 +16,17 @@ import kotlin.collections.ArrayList
open class TournamentFeature : RealmObject(), Manageable, StaticRowRepresentableDataSource, RowRepresentable,
CountableUsage {
companion object {
val rowRepresentation : List<RowRepresentable> by lazy {
val rows = ArrayList<RowRepresentable>()
rows.add(SimpleRow.NAME)
rows.addAll(TournamentFeatureRow.values())
rows
}
}
@PrimaryKey
var id = UUID.randomUUID().toString()
override var id = UUID.randomUUID().toString()
// The name of the feature
var name: String = ""
@ -29,15 +38,8 @@ open class TournamentFeature : RealmObject(), Manageable, StaticRowRepresentable
return this.name
}
override fun uniqueIdentifier(): String {
return this.id
}
override fun adapterRows(): List<RowRepresentable>? {
val rows = ArrayList<RowRepresentable>()
rows.add(SimpleRow.NAME)
rows.addAll(TournamentFeatureRow.values())
return rows
return TournamentFeature.rowRepresentation
}
override fun stringForRow(row: RowRepresentable): String {

@ -15,9 +15,17 @@ import kotlin.collections.ArrayList
open class TournamentName : RealmObject(), Manageable, StaticRowRepresentableDataSource, RowRepresentable {
companion object {
val rowRepresentation : List<RowRepresentable> by lazy {
val rows = ArrayList<RowRepresentable>()
rows.add(SimpleRow.NAME)
rows.addAll(TournamentNameRow.values())
rows
}
}
@PrimaryKey
var id = UUID.randomUUID().toString()
override var id = UUID.randomUUID().toString()
// The name of the tournament
var name: String = ""
@ -26,10 +34,6 @@ open class TournamentName : RealmObject(), Manageable, StaticRowRepresentableDat
return this.name
}
override fun uniqueIdentifier(): String {
return this.id
}
override fun updateValue(value: Any?, row: RowRepresentable) {
when (row) {
SimpleRow.NAME -> this.name = value as String? ?: ""
@ -37,10 +41,7 @@ open class TournamentName : RealmObject(), Manageable, StaticRowRepresentableDat
}
override fun adapterRows(): List<RowRepresentable>? {
val rows = ArrayList<RowRepresentable>()
rows.add(SimpleRow.NAME)
rows.addAll(TournamentNameRow.values())
return rows
return TournamentName.rowRepresentation
}
override fun stringForRow(row: RowRepresentable): String {

@ -15,9 +15,17 @@ import kotlin.collections.ArrayList
open class TransactionType : RealmObject(), Manageable, StaticRowRepresentableDataSource, RowRepresentable {
companion object {
val rowRepresentation : List<RowRepresentable> by lazy {
val rows = ArrayList<RowRepresentable>()
rows.add(SimpleRow.NAME)
rows.addAll(TransactionTypeRow.values())
rows
}
}
@PrimaryKey
var id = UUID.randomUUID().toString()
override var id = UUID.randomUUID().toString()
// The name of the transaction type
var name: String = ""
@ -35,15 +43,8 @@ open class TransactionType : RealmObject(), Manageable, StaticRowRepresentableDa
return this.name
}
override fun uniqueIdentifier(): String {
return this.id
}
override fun adapterRows(): List<RowRepresentable>? {
val rows = ArrayList<RowRepresentable>()
rows.add(SimpleRow.NAME)
rows.addAll(TransactionTypeRow.values())
return rows
return TransactionType.rowRepresentation
}
override fun stringForRow(row: RowRepresentable): String {

@ -68,6 +68,13 @@ open class PokerAnalyticsActivity : AppCompatActivity() {
return realm
}
/**
* Return if the location permission has been granted by the user
*/
fun hasLocationPermissionGranted() : Boolean {
return ContextCompat.checkSelfPermission(this, ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED
}
/**
* Ask for location permission
*/
@ -78,7 +85,6 @@ open class PokerAnalyticsActivity : AppCompatActivity() {
)
}
/**
* Ask for places request
*/
@ -118,4 +124,25 @@ open class PokerAnalyticsActivity : AppCompatActivity() {
}
}
/**
* Find the current location
*/
fun findCurrentLocation(callback: ((location: Location?) -> Unit)?) {
if (LocationManager(this).databaseContainsLocationsWithCoordinates()) {
if (ContextCompat.checkSelfPermission(this, ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
LocationManager(this).findNearestLocationFromUser(callback)
} else {
askForLocationPermission { granted ->
if (granted) {
LocationManager(this).findNearestLocationFromUser(callback)
} else {
callback?.invoke(null)
}
}
}
} else {
callback?.invoke(null)
}
}
}

@ -1,7 +1,6 @@
package net.pokeranalytics.android.ui.fragment
import android.app.Activity
import android.content.Intent
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
@ -16,15 +15,24 @@ 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 net.pokeranalytics.android.ui.view.rowrepresentable.SeparatorRowRepresentable
import net.pokeranalytics.android.util.Preferences
import java.util.*
class CurrenciesFragment : PokerAnalyticsFragment(), StaticRowRepresentableDataSource, RowRepresentableDelegate {
private val mostUsedCurrencyCodes = arrayListOf("EUR", "USD", "CAD", "GBP", "AUD", "CNY")
private val systemCurrencies = Currency.getAvailableCurrencies()
companion object {
val rowRepresentation : List<RowRepresentable> by lazy {
val rows = ArrayList<RowRepresentable>()
rows.addAll(mostUsedCurrencies)
rows.add(SeparatorRowRepresentable())
rows.addAll(availableCurrencies)
rows
}
val mostUsedCurrencyCodes = arrayListOf("EUR", "USD", "CAD", "GBP", "AUD", "CNY")
val systemCurrencies = Currency.getAvailableCurrencies()
private val mostUsedCurrencies = this.mostUsedCurrencyCodes.map { code ->
CurrencyRow(
@ -41,6 +49,7 @@ class CurrenciesFragment : PokerAnalyticsFragment(), StaticRowRepresentableDataS
}.map {
CurrencyRow(it)
}
}
private class CurrencyRow(var currency:Currency) : RowRepresentable {
@ -70,11 +79,7 @@ class CurrenciesFragment : PokerAnalyticsFragment(), StaticRowRepresentableDataS
// StaticRowRepresentableDataSource
override fun adapterRows(): List<RowRepresentable>? {
val rows = ArrayList<RowRepresentable>()
rows.addAll(mostUsedCurrencies)
rows.add(SeparatorRowRepresentable())
rows.addAll(availableCurrencies)
return rows
return CurrenciesFragment.rowRepresentation
}

@ -70,7 +70,7 @@ class DataListFragment : PokerAnalyticsFragment(), LiveRowRepresentableDataSourc
EditableDataActivity.newInstance(
requireContext(),
it.ordinal,
(row as Manageable).uniqueIdentifier()
(row as Manageable).id
)
}
}

@ -4,7 +4,6 @@ import android.app.Activity.RESULT_OK
import android.content.Intent
import android.os.Bundle
import android.view.*
import android.widget.Toast
import androidx.appcompat.app.AlertDialog
import androidx.recyclerview.widget.LinearLayoutManager
import io.realm.RealmObject
@ -35,7 +34,9 @@ open class EditableDataFragment : PokerAnalyticsFragment(), RowRepresentableDele
private var editableMenu: Menu? = null
private var dataType: Int? = null
private var primaryKey: String? = null
private var isUpdating = false
var isUpdating = false
var shouldOpenKeyboard = true
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.fragment_editable_data, container, false)
@ -64,7 +65,7 @@ open class EditableDataFragment : PokerAnalyticsFragment(), RowRepresentableDele
}
override fun onRowSelected(position: Int, row: RowRepresentable, fromAction: Boolean) {
BottomSheetFragment.create(fragmentManager, row, this, (this.item as RowRepresentableDataSource).editDescriptors(row))
BottomSheetFragment.create(fragmentManager, row, this, getDataSource().editDescriptors(row))
}
override fun onRowValueChanged(value: Any?, row: RowRepresentable) {
@ -91,6 +92,12 @@ open class EditableDataFragment : PokerAnalyticsFragment(), RowRepresentableDele
}
}
/**
* Return the data source
*/
open fun getDataSource(): RowRepresentableDataSource {
return this.item as RowRepresentableDataSource
}
/**
* Init data
@ -99,21 +106,22 @@ open class EditableDataFragment : PokerAnalyticsFragment(), RowRepresentableDele
if (this.dataType != null) {
val proxyItem: RealmObject? = this.liveDataType.getData(this.getRealm(), primaryKey)
proxyItem?.let {
//TODO: Localize
this.appBar.toolbar.title = "Update ${this.liveDataType.localizedTitle(this.parentActivity).toLowerCase().capitalize()}"
isUpdating = true
} ?: run {
//TODO: Localize
this.appBar.toolbar.title = "New ${this.liveDataType.localizedTitle(this.parentActivity).toLowerCase().capitalize()}"
}
this.item = this.liveDataType.updateOrCreate(this.getRealm(), primaryKey)
this.rowRepresentableAdapter = RowRepresentableAdapter(
(this.item as RowRepresentableDataSource),
this
)
val dataSource = getDataSource()
this.rowRepresentableAdapter = RowRepresentableAdapter(getDataSource(), this)
this.recyclerView.adapter = rowRepresentableAdapter
// When creating an object, open automatically the keyboard for the first row
if (!isUpdating && this.item is RowRepresentableDataSource) {
val row = (this.item as RowRepresentableDataSource).adapterRows()?.firstOrNull()
if (!isUpdating && shouldOpenKeyboard) {
val row = dataSource.adapterRows()?.firstOrNull()
row?.let {
onRowSelected(0, it)
}
@ -132,13 +140,13 @@ open class EditableDataFragment : PokerAnalyticsFragment(), RowRepresentableDele
/**
* Save data
*/
private fun saveData() {
fun saveData() {
if ((this.item as Savable).isValidForSave()) {
this.getRealm().executeTransaction {
val item = it.copyToRealmOrUpdate(this.item)
val uniqueIdentifier = if (item is Identifiable) {
item.uniqueIdentifier()
item.id
} else ""
finishActivityWithResult(uniqueIdentifier)

@ -24,11 +24,11 @@ import net.pokeranalytics.android.ui.view.HistorySessionDiffCallback
import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.RowViewType
import net.pokeranalytics.android.ui.view.SmoothScrollLinearLayoutManager
import net.pokeranalytics.android.ui.view.rowrepresentable.HeaderRowRepresentable
import net.pokeranalytics.android.util.extensions.getMonthAndYear
import net.pokeranalytics.android.util.extensions.isSameDay
import net.pokeranalytics.android.util.extensions.isSameMonth
import net.pokeranalytics.android.util.extensions.longDate
import net.pokeranalytics.android.ui.view.rowrepresentable.CustomizableRowRepresentable
import java.util.*
class HistoryFragment : PokerAnalyticsFragment(), LiveRowRepresentableDataSource, RowRepresentableDelegate {
@ -68,7 +68,7 @@ class HistoryFragment : PokerAnalyticsFragment(), LiveRowRepresentableDataSource
//rows.clear()
//endedSessions.addAll(getRealm().copyFromRealm(realmSessions))
createSessionsHeaders()
// createSessionsHeaders()
}
/**
@ -128,7 +128,7 @@ class HistoryFragment : PokerAnalyticsFragment(), LiveRowRepresentableDataSource
if (groupedByDay) {
if (!calendar.isSameDay(currentCalendar) || index == 0) {
calendar.time = currentCalendar.time
val header = HeaderRowRepresentable(
val header = CustomizableRowRepresentable(
customViewType = RowViewType.HEADER_TITLE,
title = session.creationDate.longDate()
)
@ -137,7 +137,7 @@ class HistoryFragment : PokerAnalyticsFragment(), LiveRowRepresentableDataSource
} else {
if (!calendar.isSameMonth(currentCalendar) || index == 0) {
calendar.time = currentCalendar.time
val header = HeaderRowRepresentable(
val header = CustomizableRowRepresentable(
customViewType = RowViewType.HEADER_TITLE,
title = session.creationDate.getMonthAndYear()
)
@ -175,6 +175,6 @@ class HistoryFragment : PokerAnalyticsFragment(), LiveRowRepresentableDataSource
}
override fun onRowSelected(position: Int, row: RowRepresentable, fromAction: Boolean) {
SessionActivity.newInstance(requireContext(), sessionId = (row as Manageable).uniqueIdentifier())
SessionActivity.newInstance(requireContext(), sessionId = (row as Manageable).id)
}
}

@ -1,36 +1,209 @@
package net.pokeranalytics.android.ui.fragment
import net.pokeranalytics.android.exceptions.TypeException
import android.os.Bundle
import android.view.View
import com.google.android.libraries.places.api.model.PlaceLikelihood
import net.pokeranalytics.android.R
import net.pokeranalytics.android.model.realm.Location
import net.pokeranalytics.android.ui.helpers.PlacePickerManager
import net.pokeranalytics.android.ui.adapter.RowRepresentableDataSource
import net.pokeranalytics.android.ui.adapter.StaticRowRepresentableDataSource
import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.RowRepresentableEditDescriptor
import net.pokeranalytics.android.ui.view.RowViewType
import net.pokeranalytics.android.ui.view.rowrepresentable.CustomizableRowRepresentable
import net.pokeranalytics.android.ui.view.rowrepresentable.LocationRow
import net.pokeranalytics.android.ui.view.rowrepresentable.SimpleRow
import timber.log.Timber
/**
* Custom EditableDataFragment to manage the LOCATE_ME case
*/
class LocationDataFragment: EditableDataFragment() {
class LocationDataFragment : EditableDataFragment(), StaticRowRepresentableDataSource {
override fun onRowSelected(position: Int, row: RowRepresentable, fromAction: Boolean) {
when(row) {
LocationRow.LOCATE_ME -> {
if (item is Location) {
(item as Location).isLookingForPlaces = true
PlacePickerManager.create(parentActivity, row, this)
rowRepresentableAdapter.refreshRow(row)
} else {
throw TypeException("Need to manage LocationRow.LOCATE_ME for ${item::class.java}")
// Return the item as a Location object
private val location: Location
get() {
return this.item as Location
}
// Loader boolean
private var isLookingForPlaces: Boolean = false
private var placesForRows: HashMap<CustomizableRowRepresentable, PlaceLikelihood> = HashMap()
private var rowPlaces: ArrayList<CustomizableRowRepresentable> = ArrayList()
private var locationActivated = false
val rows = ArrayList<RowRepresentable>()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
shouldOpenKeyboard = false
locationActivated = parentActivity.hasLocationPermissionGranted()
if (isUpdating) {
// If we update a location, we set the switch to the correct value
locationActivated = location.latitude != null && location.longitude != null
} else if (locationActivated) {
// If we create a new location, we try to locate the user by default
isLookingForPlaces = true
getSuggestionsPlaces()
}
updateAdapterUI()
}
override fun getDataSource(): RowRepresentableDataSource {
return this
}
override fun adapterRows(): List<RowRepresentable>? {
return rows
}
override fun stringForRow(row: RowRepresentable): String {
return when (row) {
SimpleRow.NAME -> location.name
else -> return super.stringForRow(row)
}
else -> super.onRowSelected(position, row, fromAction)
}
override fun boolForRow(row: RowRepresentable): Boolean {
return when (row) {
LocationRow.LOCATION_PERMISSION_SWITCH -> return locationActivated
else -> super.boolForRow(row)
}
}
override fun editDescriptors(row: RowRepresentable): ArrayList<RowRepresentableEditDescriptor> {
val data = java.util.ArrayList<RowRepresentableEditDescriptor>()
when (row) {
SimpleRow.NAME -> data.add(
RowRepresentableEditDescriptor(
location.name,
SimpleRow.NAME.resId
)
)
}
return data
}
override fun onRowSelected(position: Int, row: RowRepresentable, fromAction: Boolean) {
// If we click on a location row, save the location (and finish activity)
placesForRows[row]?.place?.let { place ->
location.setPlace(place)
saveData()
return
}
super.onRowSelected(position, row, fromAction)
}
override fun onRowValueChanged(value: Any?, row: RowRepresentable) {
super.onRowValueChanged(value, row)
when (row) {
LocationRow.LOCATE_ME -> {
rowRepresentableAdapter.notifyDataSetChanged()
LocationRow.LOCATION_PERMISSION_SWITCH -> {
if (value is Boolean && value != locationActivated) {
rowPlaces.clear()
locationActivated = value
isLookingForPlaces = value
if (value) {
updateAdapterUI()
getSuggestionsPlaces()
} else {
clearCurrentLocation()
updateAdapterUI()
}
}
}
else -> super.onRowValueChanged(value, row)
}
}
/**
* Clear current location
*/
private fun clearCurrentLocation() {
location.latitude = null
location.longitude = null
}
/**
* Refresh rows
*/
private fun refreshRows() {
rows.clear()
rows.add(SimpleRow.NAME)
rows.add(LocationRow.LOCATION_PERMISSION_SWITCH)
if (isLookingForPlaces) {
rows.add(LocationRow.LOCATION_LOADER)
}
if (locationActivated && rowPlaces.size > 0) {
rows.add(CustomizableRowRepresentable(resId = R.string.suggestions))
for (row in rowPlaces) {
rows.add(row)
}
}
}
/**
* Update UI adapter
*/
private fun updateAdapterUI() {
val currentRowsSize = rows.size
refreshRows()
val newRowsSize = rows.size
if (currentRowsSize < newRowsSize) {
rowRepresentableAdapter.notifyItemRangeInserted(currentRowsSize, newRowsSize - currentRowsSize)
} else {
rowRepresentableAdapter.notifyItemRangeRemoved(newRowsSize, currentRowsSize - newRowsSize)
}
}
/**
* Return the places around the user
*/
private fun getSuggestionsPlaces() {
val maxResults = 5
parentActivity.askForPlacesRequest { success, places ->
if (success) {
// Try to get the location of the user
parentActivity.findCurrentLocation {currentLocation ->
currentLocation?.let {
Timber.d("Current location: ${it.latitude}, ${it.longitude}")
location.latitude = currentLocation.latitude
location.longitude = currentLocation.longitude
}
}
}
if (success && places.size > 0) {
rowPlaces.clear()
placesForRows.clear()
for ((index, place) in places.withIndex()) {
if (index < maxResults) {
val row = CustomizableRowRepresentable(customViewType = RowViewType.LOCATION_TITLE, title = place.place.name, isSelectable = true)
rowPlaces.add(row)
placesForRows[row] = place
}
}
locationActivated = true
isLookingForPlaces = false
updateAdapterUI()
} else {
isLookingForPlaces = false
locationActivated = false
updateAdapterUI()
}
}
}

@ -215,7 +215,6 @@ class SessionFragment : PokerAnalyticsFragment(), RowRepresentableDelegate {
* Update adapter UI
*/
private fun updateAdapterUI(scrollToTop: Boolean) {
currentSession.adapterRows()?.let {
val diffResult = DiffUtil.calculateDiff(RowRepresentableDiffCallback(it, oldRows))
sessionAdapter.updateRows(diffResult)
@ -225,7 +224,6 @@ class SessionFragment : PokerAnalyticsFragment(), RowRepresentableDelegate {
if (scrollToTop) {
recyclerView.smoothScrollToPosition(0)
}
}
}

@ -43,6 +43,12 @@ class SettingsFragment : PokerAnalyticsFragment(), RowRepresentableDelegate, Sta
return fragment
}
val rowRepresentation : List<RowRepresentable> by lazy {
val rows = ArrayList<RowRepresentable>()
rows.addAll(SettingRow.getRows())
rows
}
val REQUEST_CODE_CURRENCY : Int = 0
}
@ -74,9 +80,7 @@ class SettingsFragment : PokerAnalyticsFragment(), RowRepresentableDelegate, Sta
}
override fun adapterRows(): List<RowRepresentable>? {
val rows = ArrayList<RowRepresentable>()
rows.addAll(SettingRow.getRows())
return rows
return SettingsFragment.rowRepresentation
}
override fun onRowSelected(position: Int, row: RowRepresentable, fromAction: Boolean) {

@ -5,11 +5,9 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.LinearLayoutManager
import io.realm.Realm
import kotlinx.android.synthetic.main.fragment_stats.*
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.*
import net.pokeranalytics.android.R
import net.pokeranalytics.android.calculus.*
import net.pokeranalytics.android.model.StatRepresentable
@ -19,7 +17,7 @@ import net.pokeranalytics.android.ui.adapter.RowRepresentableAdapter
import net.pokeranalytics.android.ui.adapter.StaticRowRepresentableDataSource
import net.pokeranalytics.android.ui.fragment.components.SessionObserverFragment
import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.rowrepresentable.HeaderRowRepresentable
import net.pokeranalytics.android.ui.view.rowrepresentable.CustomizableRowRepresentable
import net.pokeranalytics.android.util.NULL_TEXT
import timber.log.Timber
import java.util.*
@ -111,26 +109,36 @@ class StatsFragment : SessionObserverFragment(), StaticRowRepresentableDataSourc
private fun launchStatComputation() {
GlobalScope.launch(coroutineContext) {
var results = listOf<ComputedResults>()
val test = GlobalScope.async {
val s = Date()
Timber.d(">>> start...")
GlobalScope.launch(context = this.coroutineContext) {
val results = compute()
showResults(results)
}
results = createSessionGroupsAndStartCompute()
val e = Date()
val duration = (e.time - s.time) / 1000.0
Timber.d(">>> ended in ${duration} seconds")
}
test.await()
showResults(results)
}
private fun compute() : List<ComputedResults> {
}
suspend private fun createSessionGroupsAndStartCompute() : List<ComputedResults> {
val cgSessions = mutableListOf<Session>()
val tSessions = mutableListOf<Session>()
super.endedSessions.forEach { session ->
val realm = Realm.getDefaultInstance()
val allSessions = realm.where(Session::class.java).isNotNull("endDate").findAll()
Timber.d(">>>>> number of sessions to compute = ${allSessions.size}")
allSessions.forEach { session ->
if (session.isCashGame()) {
cgSessions.add(session)
} else {
@ -139,12 +147,14 @@ class StatsFragment : SessionObserverFragment(), StaticRowRepresentableDataSourc
}
val allStats: List<Stat> = listOf(Stat.NETRESULT, Stat.HOURLY_RATE, Stat.AVERAGE, Stat.NUMBER_OF_SETS, Stat.AVERAGE_DURATION, Stat.DURATION)
val allSessionGroup = SessionGroup(getString(R.string.all), super.endedSessions, allStats)
val allSessionGroup = SessionGroup(getString(R.string.all), allSessions, allStats)
val cgStats: List<Stat> = listOf(Stat.NETRESULT, Stat.HOURLY_RATE, Stat.NET_BB_PER_100_HANDS, Stat.HOURLY_RATE_BB, Stat.AVERAGE, Stat.STANDARD_DEVIATION_HOURLY, Stat.WIN_RATIO, Stat.NUMBER_OF_GAMES, Stat.AVERAGE_BUYIN)
val cgSessionGroup = SessionGroup(getString(R.string.cash_game), cgSessions, cgStats)
val tStats: List<Stat> = listOf(Stat.NETRESULT, Stat.HOURLY_RATE, Stat.ROI, Stat.WIN_RATIO, Stat.NUMBER_OF_GAMES, Stat.AVERAGE_BUYIN)
val tSessionGroup = SessionGroup(getString(R.string.tournament), tSessions, tStats)
Timber.d(">>>>> Start computations...")
return Calculator.computeGroups(listOf(allSessionGroup, cgSessionGroup, tSessionGroup), Calculator.Options())
}
@ -166,10 +176,10 @@ class StatsFragment : SessionObserverFragment(), StaticRowRepresentableDataSourc
val rows: ArrayList<RowRepresentable> = ArrayList()
results.forEach { results ->
rows.add(HeaderRowRepresentable(title = results.group.name))
results.group.stats?.forEach { stat ->
rows.add(StatRepresentable(stat, results.computedStat(stat)))
results.forEach { result ->
rows.add(CustomizableRowRepresentable(title = result.group.name))
result.group.stats?.forEach { stat ->
rows.add(StatRepresentable(stat, result.computedStat(stat)))
}
}

@ -3,7 +3,7 @@ package net.pokeranalytics.android.ui.view
import androidx.annotation.Nullable
import androidx.recyclerview.widget.DiffUtil
import net.pokeranalytics.android.model.realm.Session
import net.pokeranalytics.android.ui.view.rowrepresentable.HeaderRowRepresentable
import net.pokeranalytics.android.ui.view.rowrepresentable.CustomizableRowRepresentable
class HistorySessionDiffCallback(var newRows: List<RowRepresentable>, var oldRows: List<RowRepresentable>) :
DiffUtil.Callback() {
@ -22,9 +22,9 @@ class HistorySessionDiffCallback(var newRows: List<RowRepresentable>, var oldRow
val session1 = oldRows[oldItemPosition] as Session
val session2 = newRows[newItemPosition] as Session
return session1.id == session2.id
} else if (oldRows[oldItemPosition] is HeaderRowRepresentable && newRows[newItemPosition] is HeaderRowRepresentable) {
val header1 = oldRows[oldItemPosition] as HeaderRowRepresentable
val header2 = newRows[newItemPosition] as HeaderRowRepresentable
} else if (oldRows[oldItemPosition] is CustomizableRowRepresentable && newRows[newItemPosition] is CustomizableRowRepresentable) {
val header1 = oldRows[oldItemPosition] as CustomizableRowRepresentable
val header2 = newRows[newItemPosition] as CustomizableRowRepresentable
return header1.title == header2.title
}
@ -40,9 +40,9 @@ class HistorySessionDiffCallback(var newRows: List<RowRepresentable>, var oldRow
return false //session1.id == session2.id
} else if (oldRows[oldItemPosition] is HeaderRowRepresentable && newRows[newItemPosition] is HeaderRowRepresentable) {
val header1 = oldRows[oldItemPosition] as HeaderRowRepresentable
val header2 = newRows[newItemPosition] as HeaderRowRepresentable
} else if (oldRows[oldItemPosition] is CustomizableRowRepresentable && newRows[newItemPosition] is CustomizableRowRepresentable) {
val header1 = oldRows[oldItemPosition] as CustomizableRowRepresentable
val header2 = newRows[newItemPosition] as CustomizableRowRepresentable
return header1.title == header2.title
}

@ -14,7 +14,7 @@ import kotlinx.android.synthetic.main.row_history_session.view.*
import net.pokeranalytics.android.R
import net.pokeranalytics.android.model.realm.Session
import net.pokeranalytics.android.ui.adapter.RowRepresentableAdapter
import net.pokeranalytics.android.ui.view.rowrepresentable.HeaderRowRepresentable
import net.pokeranalytics.android.ui.view.rowrepresentable.CustomizableRowRepresentable
/**
* An interface used to factor the configuration of RecyclerView.ViewHolder
@ -35,6 +35,7 @@ enum class RowViewType(private var layoutRes: Int) {
HEADER_TITLE_VALUE(R.layout.row_header_title_value),
HEADER_TITLE_AMOUNT(R.layout.row_header_title_amount),
HEADER_TITLE_AMOUNT_BIG(R.layout.row_header_title_amount_big),
LOCATION_TITLE(R.layout.row_title),
// Row
TITLE(R.layout.row_title),
@ -46,6 +47,7 @@ enum class RowViewType(private var layoutRes: Int) {
DATA(R.layout.row_title),
BOTTOM_SHEET_DATA(R.layout.row_bottom_sheet_title),
TITLE_CHECK(R.layout.row_title_check),
LOADER(R.layout.row_loader),
// Custom row
ROW_SESSION(R.layout.row_history_session),
@ -66,10 +68,10 @@ enum class RowViewType(private var layoutRes: Int) {
return when (this) {
// Header Row View Holder
HEADER_TITLE, HEADER_TITLE_VALUE, HEADER_TITLE_AMOUNT, HEADER_TITLE_AMOUNT_BIG -> HeaderViewHolder(layout)
HEADER_TITLE, HEADER_TITLE_VALUE, HEADER_TITLE_AMOUNT, HEADER_TITLE_AMOUNT_BIG, LOCATION_TITLE -> TitleViewHolder(layout)
// Row View Holder
TITLE, TITLE_ARROW, TITLE_VALUE, TITLE_VALUE_ARROW, TITLE_GRID, TITLE_SWITCH, TITLE_CHECK, DATA, BOTTOM_SHEET_DATA -> RowViewHolder(
TITLE, TITLE_ARROW, TITLE_VALUE, TITLE_VALUE_ARROW, TITLE_GRID, TITLE_SWITCH, TITLE_CHECK, DATA, BOTTOM_SHEET_DATA, LOADER -> RowViewHolder(
layout
)
@ -96,10 +98,10 @@ enum class RowViewType(private var layoutRes: Int) {
/**
* Display a header
*/
inner class HeaderViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView), BindableHolder {
inner class TitleViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView), BindableHolder {
override fun bind(position: Int, row: RowRepresentable, adapter: RowRepresentableAdapter) {
if (row is HeaderRowRepresentable) {
if (row is CustomizableRowRepresentable) {
// Title
itemView.findViewById<AppCompatTextView>(R.id.title)?.let {
@ -116,6 +118,18 @@ enum class RowViewType(private var layoutRes: Int) {
it.text = row.value
}
}
// Listener
row.isSelectable?.let { isSelectable ->
if (isSelectable) {
val listener = View.OnClickListener {
adapter.delegate?.onRowSelected(position, row)
}
itemView.findViewById<View?>(R.id.container)?.let {
it.setOnClickListener(listener)
}
}
}
}
}
}
@ -199,7 +213,7 @@ enum class RowViewType(private var layoutRes: Int) {
itemView.findViewById<AppCompatTextView?>(R.id.title)?.text = row.localizedTitle(itemView.context)
// Value
itemView.findViewById<AppCompatTextView?>(R.id.value)?.let {view ->
itemView.findViewById<AppCompatTextView?>(R.id.value)?.let { view ->
adapter.dataSource.contentDescriptorForRow(row)?.textFormat?.let {
view.text = it.text
view.setTextColor(it.getColor(itemView.context))

@ -6,14 +6,15 @@ import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.RowViewType
/**
* A class to display headers as row representable
* A class to display a title (and a value) as a Row Representable object
*/
class HeaderRowRepresentable(
class CustomizableRowRepresentable(
var customViewType: RowViewType? = RowViewType.HEADER_TITLE,
override var resId: Int? = null,
var title: String? = null,
var value: String? = null,
var computedStat: ComputedStat? = null
var computedStat: ComputedStat? = null,
var isSelectable: Boolean? = false
) : RowRepresentable {
override fun localizedTitle(context: Context): String {
@ -27,8 +28,6 @@ class HeaderRowRepresentable(
return "LOCALISATION NOT FOUND"
}
override val viewType: Int = customViewType?.ordinal ?: RowViewType.HEADER_TITLE.ordinal
}

@ -7,30 +7,30 @@ import net.pokeranalytics.android.ui.view.RowViewType
enum class LocationRow : RowRepresentable {
ADDRESS,
LOCATE_ME;
LOCATION_PERMISSION_SWITCH,
LOCATION_LOADER;
override val resId: Int?
get() {
return when (this) {
ADDRESS -> R.string.address
LOCATE_ME -> R.string.geo_locate
LOCATION_PERMISSION_SWITCH -> R.string.geo_locate
LOCATION_LOADER -> null
}
}
override val viewType: Int
get() {
return when (this) {
ADDRESS -> RowViewType.TITLE_VALUE.ordinal
LOCATE_ME -> RowViewType.ROW_BUTTON.ordinal
LOCATION_PERMISSION_SWITCH -> RowViewType.TITLE_SWITCH.ordinal
LOCATION_LOADER -> RowViewType.LOADER.ordinal
}
}
override val bottomSheetType: BottomSheetType
get() {
return when (this) {
ADDRESS -> BottomSheetType.EDIT_TEXT
LOCATE_ME -> BottomSheetType.NONE
LOCATION_PERMISSION_SWITCH -> BottomSheetType.NONE
LOCATION_LOADER -> BottomSheetType.NONE
}
}

@ -40,24 +40,24 @@ enum class SettingRow : RowRepresentable {
fun getRows(): ArrayList<RowRepresentable> {
val rows = ArrayList<RowRepresentable>()
rows.add(HeaderRowRepresentable(customViewType = RowViewType.HEADER_TITLE, resId = R.string.information))
rows.add(CustomizableRowRepresentable(customViewType = RowViewType.HEADER_TITLE, resId = R.string.information))
rows.addAll(arrayListOf(VERSION, RATE_APP, CONTACT_US, BUG_REPORT))
rows.add(HeaderRowRepresentable(customViewType = RowViewType.HEADER_TITLE, resId = R.string.follow_us))
rows.add(CustomizableRowRepresentable(customViewType = RowViewType.HEADER_TITLE, resId = R.string.follow_us))
rows.addAll(arrayListOf(FOLLOW_US))
rows.add(HeaderRowRepresentable(customViewType = RowViewType.HEADER_TITLE, resId = R.string.preferences))
rows.add(CustomizableRowRepresentable(customViewType = RowViewType.HEADER_TITLE, resId = R.string.preferences))
rows.addAll(arrayListOf(CURRENCY))
rows.add(
HeaderRowRepresentable(
CustomizableRowRepresentable(
customViewType = RowViewType.HEADER_TITLE,
resId = R.string.data_management
)
)
rows.addAll(arrayListOf(BANKROLL, GAME, LOCATION, TOURNAMENT_NAME, TOURNAMENT_FEATURE))
rows.add(HeaderRowRepresentable(customViewType = RowViewType.HEADER_TITLE, resId = R.string.terms))
rows.add(CustomizableRowRepresentable(customViewType = RowViewType.HEADER_TITLE, resId = R.string.terms))
rows.addAll(arrayListOf(PRIVACY_POLICY, TERMS_OF_USE, GDPR))
return rows

@ -44,6 +44,8 @@ class LocationManager(private var context: Context) {
// Call findCurrentPlace and handle the response (first check that the user has granted permission).
if (ContextCompat.checkSelfPermission(context, ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
val placeResponse = placesClient.findCurrentPlace(request)
placeResponse.addOnCompleteListener { task ->
val places = ArrayList<PlaceLikelihood>()
if (task.isSuccessful) {
@ -142,7 +144,31 @@ class LocationManager(private var context: Context) {
// If we don't have the permission, return null
callback?.invoke(null)
}
}
/**
* Return the current location of the user
*/
fun findCurrentLocation(callback: ((location: android.location.Location?) -> Unit)?) {
val fusedLocationClient: FusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(context)
if (ContextCompat.checkSelfPermission(context, ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
fusedLocationClient.lastLocation.addOnSuccessListener { location: android.location.Location? ->
// Got last known location. In some rare situations this can be null.
location?.let { currentLocation ->
callback?.invoke(currentLocation)
} ?: run {
// If the current location is null, return null
callback?.invoke(null)
}
}.addOnCanceledListener {
// If there was a problem during the call to last location, return null
callback?.invoke(null)
}
} else {
callback?.invoke(null)
}
}
}

@ -0,0 +1,37 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="56dp"
android:background="?selectableItemBackground">
<androidx.core.widget.ContentLoadingProgressBar
android:id="@+id/progressBar"
style="?android:attr/progressBarStyleSmall"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:layout_marginBottom="8dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guidelineStart"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_begin="0dp" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guidelineEnd"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_end="0dp" />
</androidx.constraintlayout.widget.ConstraintLayout>

@ -19,6 +19,7 @@
<string name="hands_played">Hands played</string>
<string name="address">Address</string>
<string name="suggestions">Suggestions</string>
<string name="data_deleted" formatted="false">%s deleted</string>
<string name="end_date_not_possible">The end date should be after the start date</string>

Loading…
Cancel
Save