diff --git a/app/src/main/java/net/pokeranalytics/android/PokerAnalyticsApplication.kt b/app/src/main/java/net/pokeranalytics/android/PokerAnalyticsApplication.kt index ec7cabd2..5e4e8b1d 100644 --- a/app/src/main/java/net/pokeranalytics/android/PokerAnalyticsApplication.kt +++ b/app/src/main/java/net/pokeranalytics/android/PokerAnalyticsApplication.kt @@ -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().findAll() + val bankroll = realm.where().findAll().firstOrNull() // Test endedSessions val sessions = realm.where().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() } diff --git a/app/src/main/java/net/pokeranalytics/android/calculus/Calculator.kt b/app/src/main/java/net/pokeranalytics/android/calculus/Calculator.kt index af416dbb..ce276d86 100644 --- a/app/src/main/java/net/pokeranalytics/android/calculus/Calculator.kt +++ b/app/src/main/java/net/pokeranalytics/android/calculus/Calculator.kt @@ -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, options: Options): List { + 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 = sessionGroup.sessions val sessionSets = sessionGroup.sessions.mapNotNull { it.sessionSet }.toHashSet() @@ -193,7 +197,7 @@ class Calculator { )) } - // Create stats + // Create stats results.addStats(setOf( ComputedStat(NETRESULT, sum), ComputedStat(DURATION, duration), diff --git a/app/src/main/java/net/pokeranalytics/android/calculus/Stat.kt b/app/src/main/java/net/pokeranalytics/android/calculus/Stat.kt index 3fc798a5..31b94ec1 100644 --- a/app/src/main/java/net/pokeranalytics/android/calculus/Stat.kt +++ b/app/src/main/java/net/pokeranalytics/android/calculus/Stat.kt @@ -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}") } } diff --git a/app/src/main/java/net/pokeranalytics/android/exceptions/Exceptions.kt b/app/src/main/java/net/pokeranalytics/android/exceptions/Exceptions.kt index c3751f9c..2f391884 100644 --- a/app/src/main/java/net/pokeranalytics/android/exceptions/Exceptions.kt +++ b/app/src/main/java/net/pokeranalytics/android/exceptions/Exceptions.kt @@ -7,7 +7,3 @@ class ModelException(message: String) : Exception(message) { class FormattingException(message: String) : Exception(message) { } - -class TypeException(message: String) : Exception(message) { - -} \ No newline at end of file diff --git a/app/src/main/java/net/pokeranalytics/android/model/LiveData.kt b/app/src/main/java/net/pokeranalytics/android/model/LiveData.kt index 6cf7c826..11c2c6a7 100644 --- a/app/src/main/java/net/pokeranalytics/android/model/LiveData.kt +++ b/app/src/main/java/net/pokeranalytics/android/model/LiveData.kt @@ -40,10 +40,22 @@ enum class LiveData : Localizable { fun setUseCount(realm: Realm, realmResults: RealmResults<*>) { realm.executeTransaction { realmResults.forEach { countableUsage -> - (countableUsage as CountableUsage).useCount = it.where().equalTo( - "${relatedEntity.simpleName.toLowerCase()}.id", - countableUsage.uniqueIdentifier() - ).count().toInt() + + when (this) { + TOURNAMENT_FEATURE -> { + (countableUsage as CountableUsage).useCount = it.where().contains( + "tournamentFeatures.id", + countableUsage.id + ).count().toInt() + } + else -> { + (countableUsage as CountableUsage).useCount = it.where().equalTo( + "${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 { diff --git a/app/src/main/java/net/pokeranalytics/android/model/extensions/SessionExtensions.kt b/app/src/main/java/net/pokeranalytics/android/model/extensions/SessionExtensions.kt index 5b335cfa..02d9495b 100644 --- a/app/src/main/java/net/pokeranalytics/android/model/extensions/SessionExtensions.kt +++ b/app/src/main/java/net/pokeranalytics/android/model/extensions/SessionExtensions.kt @@ -43,4 +43,4 @@ fun Session.getState(): SessionState { } } -} +} \ No newline at end of file diff --git a/app/src/main/java/net/pokeranalytics/android/model/interfaces/CountableUsage.kt b/app/src/main/java/net/pokeranalytics/android/model/interfaces/CountableUsage.kt index fcfc8db7..3d03abdb 100644 --- a/app/src/main/java/net/pokeranalytics/android/model/interfaces/CountableUsage.kt +++ b/app/src/main/java/net/pokeranalytics/android/model/interfaces/CountableUsage.kt @@ -6,5 +6,5 @@ package net.pokeranalytics.android.model.interfaces interface CountableUsage : Identifiable { var useCount: Int get() { return 0 } - set(newValue) {} + set(_) {} } \ No newline at end of file diff --git a/app/src/main/java/net/pokeranalytics/android/model/interfaces/Manageable.kt b/app/src/main/java/net/pokeranalytics/android/model/interfaces/Manageable.kt index fa848ab3..9c160607 100644 --- a/app/src/main/java/net/pokeranalytics/android/model/interfaces/Manageable.kt +++ b/app/src/main/java/net/pokeranalytics/android/model/interfaces/Manageable.kt @@ -16,7 +16,7 @@ interface Identifiable { /** * A unique identifier getter */ - fun uniqueIdentifier(): String + var id: String } /** diff --git a/app/src/main/java/net/pokeranalytics/android/model/realm/Bankroll.kt b/app/src/main/java/net/pokeranalytics/android/model/realm/Bankroll.kt index 94249270..fc2463e3 100644 --- a/app/src/main/java/net/pokeranalytics/android/model/realm/Bankroll.kt +++ b/app/src/main/java/net/pokeranalytics/android/model/realm/Bankroll.kt @@ -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 by lazy { + val rows = ArrayList() + 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? { - val rows = ArrayList() - rows.add(SimpleRow.NAME) - rows.addAll(BankrollRow.values()) - return rows + return Bankroll.rowRepresentation } override fun stringForRow(row: RowRepresentable): String { diff --git a/app/src/main/java/net/pokeranalytics/android/model/realm/Game.kt b/app/src/main/java/net/pokeranalytics/android/model/realm/Game.kt index 1bd28aa7..2161d591 100644 --- a/app/src/main/java/net/pokeranalytics/android/model/realm/Game.kt +++ b/app/src/main/java/net/pokeranalytics/android/model/realm/Game.kt @@ -20,8 +20,17 @@ import kotlin.collections.ArrayList open class Game : RealmObject(), Manageable, StaticRowRepresentableDataSource, RowRepresentable, CountableUsage { + companion object { + val rowRepresentation : List by lazy { + val rows = ArrayList() + 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? { - val rows = ArrayList() - rows.add(SimpleRow.NAME) - rows.addAll(GameRow.values()) - return rows + return Game.rowRepresentation } override fun stringForRow(row: RowRepresentable): String { diff --git a/app/src/main/java/net/pokeranalytics/android/model/realm/Location.kt b/app/src/main/java/net/pokeranalytics/android/model/realm/Location.kt index 028e06fa..8db529ba 100644 --- a/app/src/main/java/net/pokeranalytics/android/model/realm/Location.kt +++ b/app/src/main/java/net/pokeranalytics/android/model/realm/Location.kt @@ -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? { - val rows = ArrayList() - 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 { - val data = java.util.ArrayList() - 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) - } - } } } diff --git a/app/src/main/java/net/pokeranalytics/android/model/realm/Session.kt b/app/src/main/java/net/pokeranalytics/android/model/realm/Session.kt index 4cb6366a..25193159 100644 --- a/app/src/main/java/net/pokeranalytics/android/model/realm/Session.kt +++ b/app/src/main/java/net/pokeranalytics/android/model/realm/Session.kt @@ -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() - session.bankroll = realm.where().findFirst() + if (bankroll != null) { + session.bankroll = bankroll + } else { + session.bankroll = realm.where().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? { + @Ignore + private var rowRepresentationForCurrentState : List = this.updatedRowRepresentationForCurrentState() + + private fun updatedRowRepresentationForCurrentState(): List { val rows = ArrayList() // 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? { + return this.rowRepresentationForCurrentState + + } + override fun boolForRow(row: RowRepresentable): Boolean { return false } diff --git a/app/src/main/java/net/pokeranalytics/android/model/realm/TournamentFeature.kt b/app/src/main/java/net/pokeranalytics/android/model/realm/TournamentFeature.kt index a21a156e..e5774dc8 100644 --- a/app/src/main/java/net/pokeranalytics/android/model/realm/TournamentFeature.kt +++ b/app/src/main/java/net/pokeranalytics/android/model/realm/TournamentFeature.kt @@ -16,8 +16,17 @@ import kotlin.collections.ArrayList open class TournamentFeature : RealmObject(), Manageable, StaticRowRepresentableDataSource, RowRepresentable, CountableUsage { + companion object { + val rowRepresentation : List by lazy { + val rows = ArrayList() + 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? { - val rows = ArrayList() - rows.add(SimpleRow.NAME) - rows.addAll(TournamentFeatureRow.values()) - return rows + return TournamentFeature.rowRepresentation } override fun stringForRow(row: RowRepresentable): String { diff --git a/app/src/main/java/net/pokeranalytics/android/model/realm/TournamentName.kt b/app/src/main/java/net/pokeranalytics/android/model/realm/TournamentName.kt index b76c03fc..7d149a82 100644 --- a/app/src/main/java/net/pokeranalytics/android/model/realm/TournamentName.kt +++ b/app/src/main/java/net/pokeranalytics/android/model/realm/TournamentName.kt @@ -15,9 +15,17 @@ import kotlin.collections.ArrayList open class TournamentName : RealmObject(), Manageable, StaticRowRepresentableDataSource, RowRepresentable { + companion object { + val rowRepresentation : List by lazy { + val rows = ArrayList() + 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? { - val rows = ArrayList() - rows.add(SimpleRow.NAME) - rows.addAll(TournamentNameRow.values()) - return rows + return TournamentName.rowRepresentation } override fun stringForRow(row: RowRepresentable): String { diff --git a/app/src/main/java/net/pokeranalytics/android/model/realm/TransactionType.kt b/app/src/main/java/net/pokeranalytics/android/model/realm/TransactionType.kt index 87dd38bc..91a17662 100644 --- a/app/src/main/java/net/pokeranalytics/android/model/realm/TransactionType.kt +++ b/app/src/main/java/net/pokeranalytics/android/model/realm/TransactionType.kt @@ -15,9 +15,17 @@ import kotlin.collections.ArrayList open class TransactionType : RealmObject(), Manageable, StaticRowRepresentableDataSource, RowRepresentable { + companion object { + val rowRepresentation : List by lazy { + val rows = ArrayList() + 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? { - val rows = ArrayList() - rows.add(SimpleRow.NAME) - rows.addAll(TransactionTypeRow.values()) - return rows + return TransactionType.rowRepresentation } override fun stringForRow(row: RowRepresentable): String { diff --git a/app/src/main/java/net/pokeranalytics/android/ui/activity/components/PokerAnalyticsActivity.kt b/app/src/main/java/net/pokeranalytics/android/ui/activity/components/PokerAnalyticsActivity.kt index da29643a..e02ebd15 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/activity/components/PokerAnalyticsActivity.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/activity/components/PokerAnalyticsActivity.kt @@ -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) + } + } + } \ No newline at end of file diff --git a/app/src/main/java/net/pokeranalytics/android/ui/fragment/CurrenciesFragment.kt b/app/src/main/java/net/pokeranalytics/android/ui/fragment/CurrenciesFragment.kt index 3eda8388..c94f2ab9 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/fragment/CurrenciesFragment.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/fragment/CurrenciesFragment.kt @@ -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,30 +15,40 @@ 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 by lazy { + val rows = ArrayList() + 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( - this.systemCurrencies.filter { - it.currencyCode == code - }.first() - ) - } - private val availableCurrencies = this.systemCurrencies.filter { - !mostUsedCurrencyCodes.contains(it.currencyCode) - }.sortedBy { - it.displayName - }.map { - CurrencyRow(it) + 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 { @@ -70,11 +79,7 @@ class CurrenciesFragment : PokerAnalyticsFragment(), StaticRowRepresentableDataS // StaticRowRepresentableDataSource override fun adapterRows(): List? { - val rows = ArrayList() - rows.addAll(mostUsedCurrencies) - rows.add(SeparatorRowRepresentable()) - rows.addAll(availableCurrencies) - return rows + return CurrenciesFragment.rowRepresentation } diff --git a/app/src/main/java/net/pokeranalytics/android/ui/fragment/DataListFragment.kt b/app/src/main/java/net/pokeranalytics/android/ui/fragment/DataListFragment.kt index 38b724d7..7ec02447 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/fragment/DataListFragment.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/fragment/DataListFragment.kt @@ -70,7 +70,7 @@ class DataListFragment : PokerAnalyticsFragment(), LiveRowRepresentableDataSourc EditableDataActivity.newInstance( requireContext(), it.ordinal, - (row as Manageable).uniqueIdentifier() + (row as Manageable).id ) } } diff --git a/app/src/main/java/net/pokeranalytics/android/ui/fragment/EditableDataFragment.kt b/app/src/main/java/net/pokeranalytics/android/ui/fragment/EditableDataFragment.kt index 992b817a..ce7cdcbd 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/fragment/EditableDataFragment.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/fragment/EditableDataFragment.kt @@ -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) diff --git a/app/src/main/java/net/pokeranalytics/android/ui/fragment/HistoryFragment.kt b/app/src/main/java/net/pokeranalytics/android/ui/fragment/HistoryFragment.kt index 1adaf2d9..a0b81cd8 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/fragment/HistoryFragment.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/fragment/HistoryFragment.kt @@ -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) } } \ No newline at end of file diff --git a/app/src/main/java/net/pokeranalytics/android/ui/fragment/LocationDataFragment.kt b/app/src/main/java/net/pokeranalytics/android/ui/fragment/LocationDataFragment.kt index a4643159..27eaaefe 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/fragment/LocationDataFragment.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/fragment/LocationDataFragment.kt @@ -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 { + + // 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 = HashMap() + private var rowPlaces: ArrayList = ArrayList() + private var locationActivated = false + + val rows = ArrayList() + + 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? { + return rows + } + + override fun stringForRow(row: RowRepresentable): String { + return when (row) { + SimpleRow.NAME -> location.name + else -> return super.stringForRow(row) + } + } + + 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 { + val data = java.util.ArrayList() + when (row) { + SimpleRow.NAME -> data.add( + RowRepresentableEditDescriptor( + location.name, + SimpleRow.NAME.resId + ) + ) + } + return data + } 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}") - } - } - else -> super.onRowSelected(position, row, fromAction) + // 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() } } } diff --git a/app/src/main/java/net/pokeranalytics/android/ui/fragment/SessionFragment.kt b/app/src/main/java/net/pokeranalytics/android/ui/fragment/SessionFragment.kt index a8f0e4c5..60e39b00 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/fragment/SessionFragment.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/fragment/SessionFragment.kt @@ -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) - } } } diff --git a/app/src/main/java/net/pokeranalytics/android/ui/fragment/SettingsFragment.kt b/app/src/main/java/net/pokeranalytics/android/ui/fragment/SettingsFragment.kt index 2fbe5ea6..685194e7 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/fragment/SettingsFragment.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/fragment/SettingsFragment.kt @@ -43,6 +43,12 @@ class SettingsFragment : PokerAnalyticsFragment(), RowRepresentableDelegate, Sta return fragment } + val rowRepresentation : List by lazy { + val rows = ArrayList() + rows.addAll(SettingRow.getRows()) + rows + } + val REQUEST_CODE_CURRENCY : Int = 0 } @@ -74,9 +80,7 @@ class SettingsFragment : PokerAnalyticsFragment(), RowRepresentableDelegate, Sta } override fun adapterRows(): List? { - val rows = ArrayList() - rows.addAll(SettingRow.getRows()) - return rows + return SettingsFragment.rowRepresentation } override fun onRowSelected(position: Int, row: RowRepresentable, fromAction: Boolean) { diff --git a/app/src/main/java/net/pokeranalytics/android/ui/fragment/StatsFragment.kt b/app/src/main/java/net/pokeranalytics/android/ui/fragment/StatsFragment.kt index d7326fa9..c07f5c7d 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/fragment/StatsFragment.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/fragment/StatsFragment.kt @@ -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() { - val s = Date() - Timber.d(">>> start...") + GlobalScope.launch(coroutineContext) { - GlobalScope.launch(context = this.coroutineContext) { - val results = compute() - showResults(results) - } + var results = listOf() + val test = GlobalScope.async { + val s = Date() + Timber.d(">>> start...") + + results = createSessionGroupsAndStartCompute() + + val e = Date() + val duration = (e.time - s.time) / 1000.0 + Timber.d(">>> ended in ${duration} seconds") - 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 { + suspend private fun createSessionGroupsAndStartCompute() : List { val cgSessions = mutableListOf() val tSessions = mutableListOf() - 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 = 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 = 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 = 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 = 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))) } } diff --git a/app/src/main/java/net/pokeranalytics/android/ui/view/HistorySessionDiffCallback.kt b/app/src/main/java/net/pokeranalytics/android/ui/view/HistorySessionDiffCallback.kt index a0badd28..09ecd30a 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/view/HistorySessionDiffCallback.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/view/HistorySessionDiffCallback.kt @@ -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, var oldRows: List) : DiffUtil.Callback() { @@ -22,9 +22,9 @@ class HistorySessionDiffCallback(var newRows: List, 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, 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 } diff --git a/app/src/main/java/net/pokeranalytics/android/ui/view/RowViewType.kt b/app/src/main/java/net/pokeranalytics/android/ui/view/RowViewType.kt index c2f01dab..b6b9fcde 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/view/RowViewType.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/view/RowViewType.kt @@ -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(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(R.id.container)?.let { + it.setOnClickListener(listener) + } + } + } } } } @@ -199,7 +213,7 @@ enum class RowViewType(private var layoutRes: Int) { itemView.findViewById(R.id.title)?.text = row.localizedTitle(itemView.context) // Value - itemView.findViewById(R.id.value)?.let {view -> + itemView.findViewById(R.id.value)?.let { view -> adapter.dataSource.contentDescriptorForRow(row)?.textFormat?.let { view.text = it.text view.setTextColor(it.getColor(itemView.context)) diff --git a/app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/HeaderRowRepresentable.kt b/app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/CustomizableRowRepresentable.kt similarity index 80% rename from app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/HeaderRowRepresentable.kt rename to app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/CustomizableRowRepresentable.kt index 94e274a5..50a23ee9 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/HeaderRowRepresentable.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/CustomizableRowRepresentable.kt @@ -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 } diff --git a/app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/LocationRow.kt b/app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/LocationRow.kt index 188c51b9..6440e2f6 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/LocationRow.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/LocationRow.kt @@ -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 } } diff --git a/app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/SettingRow.kt b/app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/SettingRow.kt index f5e6c690..43502fbe 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/SettingRow.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/SettingRow.kt @@ -40,24 +40,24 @@ enum class SettingRow : RowRepresentable { fun getRows(): ArrayList { val rows = ArrayList() - 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 diff --git a/app/src/main/java/net/pokeranalytics/android/util/LocationManager.kt b/app/src/main/java/net/pokeranalytics/android/util/LocationManager.kt index a410f1c2..30d974d4 100644 --- a/app/src/main/java/net/pokeranalytics/android/util/LocationManager.kt +++ b/app/src/main/java/net/pokeranalytics/android/util/LocationManager.kt @@ -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() 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) + } } } \ No newline at end of file diff --git a/app/src/main/res/layout/row_loader.xml b/app/src/main/res/layout/row_loader.xml new file mode 100644 index 00000000..721df4fc --- /dev/null +++ b/app/src/main/res/layout/row_loader.xml @@ -0,0 +1,37 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index a19a6f50..d343fa64 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -19,6 +19,7 @@ Hands played Address + Suggestions %s deleted The end date should be after the start date