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

feature/top10
Laurent 7 years ago
commit 914f320126
  1. 7
      app/build.gradle
  2. 3
      app/src/main/AndroidManifest.xml
  3. 3
      app/src/main/java/net/pokeranalytics/android/PokerAnalyticsApplication.kt
  4. 26
      app/src/main/java/net/pokeranalytics/android/model/Limit.kt
  5. 6
      app/src/main/java/net/pokeranalytics/android/model/LiveData.kt
  6. 18
      app/src/main/java/net/pokeranalytics/android/model/realm/Bankroll.kt
  7. 18
      app/src/main/java/net/pokeranalytics/android/model/realm/Game.kt
  8. 11
      app/src/main/java/net/pokeranalytics/android/model/realm/Location.kt
  9. 184
      app/src/main/java/net/pokeranalytics/android/model/realm/Session.kt
  10. 11
      app/src/main/java/net/pokeranalytics/android/model/realm/TournamentFeature.kt
  11. 11
      app/src/main/java/net/pokeranalytics/android/model/realm/TransactionType.kt
  12. 3
      app/src/main/java/net/pokeranalytics/android/ui/activity/HomeActivity.kt
  13. 1
      app/src/main/java/net/pokeranalytics/android/ui/adapter/LimitTypesAdapter.kt
  14. 29
      app/src/main/java/net/pokeranalytics/android/ui/adapter/components/LiveDataAdapter.kt
  15. 72
      app/src/main/java/net/pokeranalytics/android/ui/adapter/components/RowRepresentableAdapter.kt
  16. 30
      app/src/main/java/net/pokeranalytics/android/ui/fragment/DataListFragment.kt
  17. 68
      app/src/main/java/net/pokeranalytics/android/ui/fragment/EditableDataFragment.kt
  18. 47
      app/src/main/java/net/pokeranalytics/android/ui/fragment/HistoryFragment.kt
  19. 56
      app/src/main/java/net/pokeranalytics/android/ui/fragment/SessionFragment.kt
  20. 45
      app/src/main/java/net/pokeranalytics/android/ui/fragment/components/bottomsheet/BottomSheetListFragment.kt
  21. 81
      app/src/main/java/net/pokeranalytics/android/ui/fragment/components/bottomsheet/BottomSheetListGameFragment.kt
  22. 119
      app/src/main/java/net/pokeranalytics/android/ui/fragment/components/bottomsheet/BottomSheetTableSizeGridFragment.kt
  23. 8
      app/src/main/java/net/pokeranalytics/android/ui/view/RowRepresentable.kt
  24. 6
      app/src/main/java/net/pokeranalytics/android/ui/view/RowRepresentableDiffCallback.kt
  25. 68
      app/src/main/java/net/pokeranalytics/android/ui/view/RowViewType.kt
  26. 15
      app/src/main/java/net/pokeranalytics/android/ui/view/SessionRowView.kt
  27. 17
      app/src/main/java/net/pokeranalytics/android/util/Extensions.kt
  28. 21
      app/src/main/java/net/pokeranalytics/android/util/data/LiveRealmData.kt
  29. 11
      app/src/main/java/net/pokeranalytics/android/util/data/Realm+Dao.kt
  30. 5
      app/src/main/res/color/chips_background_states.xml
  31. 7
      app/src/main/res/font/roboto_medium.xml
  32. 7
      app/src/main/res/font/roboto_mono_medium.xml
  33. 62
      app/src/main/res/layout/bottom_sheet_game_list.xml
  34. 23
      app/src/main/res/layout/fragment_editable_data.xml
  35. 92
      app/src/main/res/layout/fragment_session.xml
  36. 7
      app/src/main/res/layout/row_session_view.xml
  37. 17
      app/src/main/res/menu/editable_data.xml
  38. 2
      app/src/main/res/values/preloaded_fonts.xml
  39. 29
      app/src/main/res/values/styles.xml

@ -34,6 +34,10 @@ android {
} }
} }
configurations {
all*.exclude group: 'com.google.guava', module: 'listenablefuture'
}
} }
dependencies { dependencies {
@ -47,6 +51,9 @@ dependencies {
implementation 'androidx.constraintlayout:constraintlayout:1.1.3' implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
implementation 'androidx.lifecycle:lifecycle-extensions:2.0.0' implementation 'androidx.lifecycle:lifecycle-extensions:2.0.0'
// Places
implementation 'com.google.android.libraries.places:places:1.0.0'
// Firebase // Firebase
implementation 'com.google.firebase:firebase-core:16.0.7' implementation 'com.google.firebase:firebase-core:16.0.7'

@ -2,6 +2,9 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="net.pokeranalytics.android"> package="net.pokeranalytics.android">
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<application <application
android:allowBackup="true" android:allowBackup="true"
android:icon="@mipmap/ic_launcher" android:icon="@mipmap/ic_launcher"

@ -5,6 +5,7 @@ import io.realm.Realm
import io.realm.RealmConfiguration import io.realm.RealmConfiguration
import io.realm.RealmResults import io.realm.RealmResults
import io.realm.kotlin.where import io.realm.kotlin.where
import net.pokeranalytics.android.model.Limit
import net.pokeranalytics.android.model.realm.Game import net.pokeranalytics.android.model.realm.Game
import net.pokeranalytics.android.model.realm.Session import net.pokeranalytics.android.model.realm.Session
import net.pokeranalytics.android.util.PokerAnalyticsLogs import net.pokeranalytics.android.util.PokerAnalyticsLogs
@ -52,6 +53,8 @@ class PokerAnalyticsApplication : Application() {
*/ */
} }
Limit.init(this)
if (BuildConfig.DEBUG) { if (BuildConfig.DEBUG) {
// Logs // Logs
Timber.plant(PokerAnalyticsLogs()) Timber.plant(PokerAnalyticsLogs())

@ -0,0 +1,26 @@
package net.pokeranalytics.android.model
import android.content.Context
import net.pokeranalytics.android.R
class Limit {
companion object {
private val values = ArrayList<String>()
fun init(context: Context) {
values.clear()
values.addAll(context.resources.getStringArray(R.array.limit_short_name))
}
/**
* Get a limit name
*/
fun get(index: Int) : String? {
if (index >= 0 && index < values.size) {
return values[index]
}
return ""
}
}
}

@ -16,6 +16,8 @@ interface ObjectSavable {
fun isValidForSave(): Boolean { fun isValidForSave(): Boolean {
return true return true
} }
fun uniqueIdentifier(): String
} }
/** /**
@ -64,8 +66,8 @@ enum class LiveData : Localizable {
} }
} }
fun deleteData(realm:Realm, data:LiveDataDataSource) { fun deleteData(realm:Realm, data:ObjectSavable) {
realm.where(this.relatedEntity).equalTo("id", data.primaryKey).findAll().deleteAllFromRealm() realm.where(this.relatedEntity).equalTo("id", data.uniqueIdentifier()).findAll().deleteAllFromRealm()
} }
fun updateOrCreate(realm:Realm, primaryKey:String?): RealmObject { fun updateOrCreate(realm:Realm, primaryKey:String?): RealmObject {

@ -8,15 +8,12 @@ import net.pokeranalytics.android.model.ObjectSavable
import net.pokeranalytics.android.ui.adapter.components.LiveDataDataSource import net.pokeranalytics.android.ui.adapter.components.LiveDataDataSource
import net.pokeranalytics.android.ui.adapter.components.RowRepresentableDataSource import net.pokeranalytics.android.ui.adapter.components.RowRepresentableDataSource
import net.pokeranalytics.android.ui.fragment.components.bottomsheet.BottomSheetData import net.pokeranalytics.android.ui.fragment.components.bottomsheet.BottomSheetData
import net.pokeranalytics.android.ui.view.BankrollRow import net.pokeranalytics.android.ui.view.*
import net.pokeranalytics.android.ui.view.RowEditable
import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.SimpleRow
import java.util.* import java.util.*
import kotlin.collections.ArrayList import kotlin.collections.ArrayList
open class Bankroll(name: String = "") : RealmObject(), RowRepresentableDataSource, LiveDataDataSource, open class Bankroll(name: String = "") : RealmObject(), RowRepresentableDataSource,
RowEditable, ObjectSavable { RowEditable, ObjectSavable, RowRepresentable {
companion object { companion object {
fun newInstance() : Bankroll { fun newInstance() : Bankroll {
@ -42,8 +39,13 @@ open class Bankroll(name: String = "") : RealmObject(), RowRepresentableDataSour
// @todo rate management // @todo rate management
override val title: String get() = this.name override fun getDisplayName(): String {
override val primaryKey: String get() = this.id return this.name
}
override fun uniqueIdentifier(): String {
return this.id
}
override fun adapterRows(): ArrayList<RowRepresentable> { override fun adapterRows(): ArrayList<RowRepresentable> {
val rows = ArrayList<RowRepresentable>() val rows = ArrayList<RowRepresentable>()

@ -4,16 +4,15 @@ import android.text.InputType
import io.realm.RealmObject import io.realm.RealmObject
import io.realm.annotations.PrimaryKey import io.realm.annotations.PrimaryKey
import net.pokeranalytics.android.model.ObjectSavable import net.pokeranalytics.android.model.ObjectSavable
import net.pokeranalytics.android.ui.adapter.components.DisplayableDelegate
import net.pokeranalytics.android.ui.adapter.components.LiveDataDataSource import net.pokeranalytics.android.ui.adapter.components.LiveDataDataSource
import net.pokeranalytics.android.ui.adapter.components.RowRepresentableDataSource import net.pokeranalytics.android.ui.adapter.components.RowRepresentableDataSource
import net.pokeranalytics.android.ui.fragment.components.bottomsheet.BottomSheetData import net.pokeranalytics.android.ui.fragment.components.bottomsheet.BottomSheetData
import net.pokeranalytics.android.ui.view.GameRow import net.pokeranalytics.android.ui.view.*
import net.pokeranalytics.android.ui.view.RowEditable
import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.SimpleRow
import java.util.* import java.util.*
open class Game : RealmObject(), RowRepresentableDataSource, LiveDataDataSource, RowEditable, ObjectSavable { open class Game : RealmObject(), RowRepresentableDataSource, RowEditable, ObjectSavable,
RowRepresentable {
@PrimaryKey @PrimaryKey
var id = UUID.randomUUID().toString() var id = UUID.randomUUID().toString()
@ -24,8 +23,13 @@ open class Game : RealmObject(), RowRepresentableDataSource, LiveDataDataSource,
// A shorter name for the game // A shorter name for the game
var shortName: String? = null var shortName: String? = null
override val title: String get() = this.name override fun getDisplayName(): String {
override val primaryKey: String get() = this.id return this.name
}
override fun uniqueIdentifier(): String {
return this.id
}
override fun adapterRows(): ArrayList<RowRepresentable> { override fun adapterRows(): ArrayList<RowRepresentable> {
val rows = ArrayList<RowRepresentable>() val rows = ArrayList<RowRepresentable>()

@ -13,7 +13,7 @@ import net.pokeranalytics.android.ui.view.SimpleRow
import java.util.* import java.util.*
open class Location : RealmObject(), RowRepresentableDataSource, LiveDataDataSource, RowEditable, ObjectSavable { open class Location : RealmObject(), RowRepresentableDataSource, RowEditable, ObjectSavable, RowRepresentable {
@PrimaryKey @PrimaryKey
var id = UUID.randomUUID().toString() var id = UUID.randomUUID().toString()
@ -27,8 +27,13 @@ open class Location : RealmObject(), RowRepresentableDataSource, LiveDataDataSou
// the latitude of the location // the latitude of the location
var latitude: Double? = null var latitude: Double? = null
override val title: String get() = this.name override fun getDisplayName(): String {
override val primaryKey: String get() = this.id return this.name
}
override fun uniqueIdentifier(): String {
return this.id
}
override fun adapterRows(): ArrayList<RowRepresentable> { override fun adapterRows(): ArrayList<RowRepresentable> {
val rows = ArrayList<RowRepresentable>() val rows = ArrayList<RowRepresentable>()

@ -1,28 +1,33 @@
package net.pokeranalytics.android.model.realm package net.pokeranalytics.android.model.realm
import android.content.Context
import android.text.InputType import android.text.InputType
import io.realm.* import io.realm.RealmList
import io.realm.RealmObject
import io.realm.annotations.Ignore import io.realm.annotations.Ignore
import io.realm.annotations.PrimaryKey import io.realm.annotations.PrimaryKey
import net.pokeranalytics.android.R import net.pokeranalytics.android.R
import net.pokeranalytics.android.calculus.SessionInterface import net.pokeranalytics.android.calculus.SessionInterface
import net.pokeranalytics.android.model.Limit
import net.pokeranalytics.android.model.LiveData import net.pokeranalytics.android.model.LiveData
import net.pokeranalytics.android.model.ObjectSavable
import net.pokeranalytics.android.model.extensions.SessionState import net.pokeranalytics.android.model.extensions.SessionState
import net.pokeranalytics.android.model.extensions.getState import net.pokeranalytics.android.model.extensions.getState
import net.pokeranalytics.android.ui.adapter.components.LiveDataDataSource
import net.pokeranalytics.android.ui.adapter.components.RowRepresentableDataSource import net.pokeranalytics.android.ui.adapter.components.RowRepresentableDataSource
import net.pokeranalytics.android.ui.fragment.components.bottomsheet.BottomSheetData import net.pokeranalytics.android.ui.fragment.components.bottomsheet.BottomSheetData
import net.pokeranalytics.android.ui.view.RowEditable import net.pokeranalytics.android.ui.view.RowEditable
import net.pokeranalytics.android.ui.view.RowRepresentable import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.SessionRow import net.pokeranalytics.android.ui.view.SessionRow
import net.pokeranalytics.android.util.data.sessionDao import net.pokeranalytics.android.util.getDuration
import net.pokeranalytics.android.util.round
import net.pokeranalytics.android.util.short import net.pokeranalytics.android.util.short
import net.pokeranalytics.android.util.toCurrency import net.pokeranalytics.android.util.toCurrency
import timber.log.Timber
import java.util.* import java.util.*
import kotlin.collections.ArrayList import kotlin.collections.ArrayList
open class Session : RealmObject(), SessionInterface, RowRepresentableDataSource, LiveDataDataSource, open class Session : RealmObject(), SessionInterface, RowRepresentableDataSource,
RowEditable { RowEditable, RowRepresentable, ObjectSavable {
@PrimaryKey @PrimaryKey
var id = UUID.randomUUID().toString() var id = UUID.randomUUID().toString()
@ -138,6 +143,22 @@ open class Session : RealmObject(), SessionInterface, RowRepresentableDataSource
} }
} }
/**
* Return the duration of the current session
*/
fun getDuration(context: Context): String {
val startDate = timeFrame?.startDate ?: Date()
val enDate = timeFrame?.endDate ?: Date()
return startDate.getDuration(context, enDate)
}
/**
* Return the formatted blinds
*/
fun getBlinds(): String {
return if (cgSmallBlind == null) "--" else "$${cgSmallBlind?.round()}/${cgBigBlind?.round()}"
}
/** /**
* Delete the object from realm * Delete the object from realm
* TODO: Cascade delete? * TODO: Cascade delete?
@ -179,13 +200,13 @@ open class Session : RealmObject(), SessionInterface, RowRepresentableDataSource
*/ */
fun getGameTitle(): String { fun getGameTitle(): String {
var gameTitle = "" var gameTitle = ""
if (limit != null) { limit?.let {
gameTitle += limit gameTitle += Limit.get(it) + " "
} }
if (game != null) { if (game != null) {
gameTitle += game?.title gameTitle += game?.name
} }
return gameTitle return if (gameTitle.isNotBlank()) gameTitle else "--"
} }
companion object { companion object {
@ -237,6 +258,14 @@ open class Session : RealmObject(), SessionInterface, RowRepresentableDataSource
return 0.0 return 0.0
} }
override fun uniqueIdentifier(): String {
return this.id
}
override fun getDisplayName(): String {
return "session ${this.creationDate}"
}
override fun adapterRows(): ArrayList<RowRepresentable> { override fun adapterRows(): ArrayList<RowRepresentable> {
val rows = ArrayList<RowRepresentable>() val rows = ArrayList<RowRepresentable>()
rows.addAll(SessionRow.getRowsForState(getState())) rows.addAll(SessionRow.getRowsForState(getState()))
@ -251,9 +280,9 @@ open class Session : RealmObject(), SessionInterface, RowRepresentableDataSource
return when (row) { return when (row) {
SessionRow.BUY_IN -> buyin.toCurrency() SessionRow.BUY_IN -> buyin.toCurrency()
SessionRow.BLINDS -> if (cgSmallBlind != null && cgBigBlind != null) "$cgSmallBlind / $cgBigBlind" else "--" SessionRow.BLINDS -> if (cgSmallBlind != null && cgBigBlind != null) "$cgSmallBlind / $cgBigBlind" else "--"
SessionRow.GAME -> game?.title ?: "--" SessionRow.GAME -> getGameTitle()
SessionRow.LOCATION -> location?.title ?: "--" SessionRow.LOCATION -> location?.name ?: "--"
SessionRow.BANKROLL -> bankroll?.title ?: "--" SessionRow.BANKROLL -> bankroll?.name ?: "--"
SessionRow.TABLE_SIZE -> tableSize?.toString() ?: "--" SessionRow.TABLE_SIZE -> tableSize?.toString() ?: "--"
SessionRow.START_DATE -> if (timeFrame != null) timeFrame?.startDate?.short() ?: "--" else "--" SessionRow.START_DATE -> if (timeFrame != null) timeFrame?.startDate?.short() ?: "--" else "--"
SessionRow.END_DATE -> if (timeFrame != null) timeFrame?.endDate?.short() ?: "--" else "--" SessionRow.END_DATE -> if (timeFrame != null) timeFrame?.endDate?.short() ?: "--" else "--"
@ -271,12 +300,6 @@ open class Session : RealmObject(), SessionInterface, RowRepresentableDataSource
} }
} }
override var title: String = "Change that: $creationDate"
override val primaryKey: String get() = this.id
override fun getBottomSheetData(row: RowRepresentable): ArrayList<BottomSheetData> { override fun getBottomSheetData(row: RowRepresentable): ArrayList<BottomSheetData> {
val data = ArrayList<BottomSheetData>() val data = ArrayList<BottomSheetData>()
@ -288,8 +311,21 @@ open class Session : RealmObject(), SessionInterface, RowRepresentableDataSource
data.add(BottomSheetData(100.0 * (cgBigBlind ?: 0.0))) data.add(BottomSheetData(100.0 * (cgBigBlind ?: 0.0)))
data.add(BottomSheetData(200.0 * (cgBigBlind ?: 0.0))) data.add(BottomSheetData(200.0 * (cgBigBlind ?: 0.0)))
data.add(BottomSheetData(buyin)) data.add(BottomSheetData(buyin))
data.add(BottomSheetData("",inputType = InputType.TYPE_CLASS_NUMBER or InputType.TYPE_NUMBER_FLAG_DECIMAL)) data.add(
data.add(BottomSheetData("",inputType = InputType.TYPE_CLASS_NUMBER or InputType.TYPE_NUMBER_FLAG_DECIMAL)) BottomSheetData(
"",
inputType = InputType.TYPE_CLASS_NUMBER or InputType.TYPE_NUMBER_FLAG_DECIMAL
)
)
data.add(
BottomSheetData(
"",
inputType = InputType.TYPE_CLASS_NUMBER or InputType.TYPE_NUMBER_FLAG_DECIMAL
)
)
}
SessionRow.CASHED_OUT -> {
data.add(BottomSheetData(result?.cashout, inputType = InputType.TYPE_CLASS_NUMBER))
} }
SessionRow.TIPS -> { SessionRow.TIPS -> {
// Disable the buttons with value = 0, add current value & set the 2 edit texts // Disable the buttons with value = 0, add current value & set the 2 edit texts
@ -300,7 +336,9 @@ open class Session : RealmObject(), SessionInterface, RowRepresentableDataSource
data.add(BottomSheetData("", inputType = InputType.TYPE_CLASS_NUMBER)) data.add(BottomSheetData("", inputType = InputType.TYPE_CLASS_NUMBER))
data.add(BottomSheetData("", inputType = InputType.TYPE_CLASS_NUMBER)) data.add(BottomSheetData("", inputType = InputType.TYPE_CLASS_NUMBER))
} }
SessionRow.TABLE_SIZE -> {data.add(BottomSheetData(tableSize))} SessionRow.TABLE_SIZE -> {
data.add(BottomSheetData(tableSize))
}
SessionRow.GAME -> { SessionRow.GAME -> {
// Add current game & games list // Add current game & games list
data.add(BottomSheetData(limit)) data.add(BottomSheetData(limit))
@ -329,14 +367,33 @@ open class Session : RealmObject(), SessionInterface, RowRepresentableDataSource
override fun updateValue(value: Any?, row: RowRepresentable) { override fun updateValue(value: Any?, row: RowRepresentable) {
realm.beginTransaction() realm.beginTransaction()
when (row) { when (row) {
SessionRow.BUY_IN -> { SessionRow.BUY_IN -> {
val localResult = if (result != null) result as Result else realm.createObject(Result::class.java) val localResult = if (result != null) result as Result else realm.createObject(Result::class.java)
localResult.buyin = value as Double localResult.buyin = value as Double?
result = localResult
}
SessionRow.CASHED_OUT -> {
val localResult = if (result != null) result as Result else realm.createObject(Result::class.java)
localResult.cashout = if (value == null) null else (value as String).toDouble()
result = localResult result = localResult
} }
SessionRow.TABLE_SIZE -> tableSize = value as Int? SessionRow.TABLE_SIZE -> tableSize = value as Int?
SessionRow.GAME -> game = value as Game? SessionRow.GAME -> {
if (value is ArrayList<*>) {
Timber.d("${value[0]}")
Timber.d("${value[1]}")
limit = try {
(value[0] as Int?)
} catch (e: Exception) {
null
}
game = try {
(value[1] as Game?)
} catch (e: Exception) {
null
}
}
}
SessionRow.BANKROLL -> bankroll = value as Bankroll? SessionRow.BANKROLL -> bankroll = value as Bankroll?
SessionRow.LOCATION -> location = value as Location? SessionRow.LOCATION -> location = value as Location?
SessionRow.COMMENT -> comment = value as String? ?: "" SessionRow.COMMENT -> comment = value as String? ?: ""
@ -351,20 +408,28 @@ open class Session : RealmObject(), SessionInterface, RowRepresentableDataSource
} catch (e: Exception) { } catch (e: Exception) {
null null
} }
cgBigBlind?.let {
if (cgSmallBlind == null || cgSmallBlind == 0.0) {
cgSmallBlind = it / 2.0
}
}
} }
//TODO: Update //TODO: Update
SessionRow.START_DATE -> if (value is Date?) { SessionRow.START_DATE -> if (value is Date?) {
if (value == null) { if (value == null) {
timeFrame = null timeFrame = null
} else { } else {
val timeFrameToUpdate = if (timeFrame != null) timeFrame as TimeFrame else realm.createObject(TimeFrame::class.java) val timeFrameToUpdate =
if (timeFrame != null) timeFrame as TimeFrame else realm.createObject(TimeFrame::class.java)
timeFrameToUpdate.setDate(value, null) timeFrameToUpdate.setDate(value, null)
timeFrame = timeFrameToUpdate timeFrame = timeFrameToUpdate
} }
} }
//TODO: Update //TODO: Update
SessionRow.END_DATE -> if (value is Date?) { SessionRow.END_DATE -> if (value is Date?) {
val timeFrameToUpdate = if (timeFrame != null) timeFrame as TimeFrame else realm.createObject(TimeFrame::class.java) val timeFrameToUpdate =
if (timeFrame != null) timeFrame as TimeFrame else realm.createObject(TimeFrame::class.java)
timeFrameToUpdate.setDate(null, value) timeFrameToUpdate.setDate(null, value)
timeFrame = timeFrameToUpdate timeFrame = timeFrameToUpdate
} }
@ -378,70 +443,3 @@ enum class TournamentKind {
MTT, MTT,
SNG SNG
} }
/**
* Session Dao
*/
class SessionDao(realmDb: Realm) {
var realm: Realm = realmDb
/**
* Create or update session
*/
fun createOrUpdateSession(session: Session): Session {
realm.beginTransaction()
val sessionToSave = realm.copyToRealmOrUpdate(session)
realm.commitTransaction()
return realm.copyFromRealm(sessionToSave)
}
/**
* Create or update sessions
*/
fun createOrUpdateSessions(sessions: List<Session>): List<Session> {
realm.beginTransaction()
// Update
val sessionsToSave = realm.copyToRealmOrUpdate(sessions)
realm.commitTransaction()
return realm.copyFromRealm(sessionsToSave)
}
/**
* Find all sessions
*/
fun findAllSessions(): RealmResults<Session> {
return realm.where(Session::class.java).findAll().sort("creationDate", Sort.DESCENDING)
}
/**
* Find session by id
*/
fun findSessionById(sessionId: Int): Session? {
return realm.copyFromRealm(realm.where(Session::class.java).equalTo("id", sessionId).findFirst())
}
/**
* Delete session
*/
fun deleteSession(sessionId: Int) {
realm.beginTransaction()
realm.sessionDao().findSessionById(sessionId)?.deleteFromRealm()
realm.commitTransaction()
}
/**
* Delete all sessions
*/
fun deleteAllSessions() {
realm.beginTransaction()
realm.sessionDao().findAllSessions().deleteAllFromRealm()
realm.commitTransaction()
}
}

@ -12,7 +12,7 @@ import net.pokeranalytics.android.ui.view.SimpleRow
import net.pokeranalytics.android.ui.view.TournamentFeatureRow import net.pokeranalytics.android.ui.view.TournamentFeatureRow
import java.util.* import java.util.*
open class TournamentFeature : RealmObject(), RowRepresentableDataSource, LiveDataDataSource, RowEditable, ObjectSavable { open class TournamentFeature : RealmObject(), RowRepresentableDataSource, RowEditable, ObjectSavable, RowRepresentable {
@PrimaryKey @PrimaryKey
var id = UUID.randomUUID().toString() var id = UUID.randomUUID().toString()
@ -20,8 +20,13 @@ open class TournamentFeature : RealmObject(), RowRepresentableDataSource, LiveDa
// The name of the feature // The name of the feature
var name: String = "" var name: String = ""
override val title: String get() = this.name override fun getDisplayName(): String {
override val primaryKey: String get() = this.id return this.name
}
override fun uniqueIdentifier(): String {
return this.id
}
override fun adapterRows(): ArrayList<RowRepresentable> { override fun adapterRows(): ArrayList<RowRepresentable> {
val rows = ArrayList<RowRepresentable>() val rows = ArrayList<RowRepresentable>()

@ -13,7 +13,7 @@ import net.pokeranalytics.android.ui.view.TransactionTypeRow
import java.util.* import java.util.*
open class TransactionType : RealmObject(), RowRepresentableDataSource, LiveDataDataSource, RowEditable, ObjectSavable { open class TransactionType : RealmObject(), RowRepresentableDataSource, RowEditable, ObjectSavable, RowRepresentable {
@PrimaryKey @PrimaryKey
var id = UUID.randomUUID().toString() var id = UUID.randomUUID().toString()
@ -30,8 +30,13 @@ open class TransactionType : RealmObject(), RowRepresentableDataSource, LiveData
// The predefined kind, if necessary, like: Withdrawal, deposit, or tips // The predefined kind, if necessary, like: Withdrawal, deposit, or tips
var kind: Int? = null var kind: Int? = null
override val title: String get() = this.name override fun getDisplayName(): String {
override val primaryKey: String get() = this.id return this.name
}
override fun uniqueIdentifier(): String {
return this.id
}
override fun adapterRows(): ArrayList<RowRepresentable> { override fun adapterRows(): ArrayList<RowRepresentable> {
val rows = ArrayList<RowRepresentable>() val rows = ArrayList<RowRepresentable>()

@ -3,6 +3,7 @@ package net.pokeranalytics.android.ui.activity
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.os.Bundle import android.os.Bundle
import androidx.fragment.app.Fragment
import com.google.android.material.bottomnavigation.BottomNavigationView import com.google.android.material.bottomnavigation.BottomNavigationView
import kotlinx.android.synthetic.main.activity_home.* import kotlinx.android.synthetic.main.activity_home.*
import net.pokeranalytics.android.R import net.pokeranalytics.android.R
@ -68,7 +69,7 @@ class HomeActivity : PokerAnalyticsActivity() {
else -> "" else -> ""
} }
val fragment = when(index) { val fragment: Fragment = when(index) {
0 -> HistoryFragment() 0 -> HistoryFragment()
1 -> StatsFragment() 1 -> StatsFragment()
else -> SettingsFragment() else -> SettingsFragment()

@ -21,6 +21,7 @@ class LimitTypesAdapter(private var tableSizes: ArrayList<String>) : RecyclerVie
itemView.title.text = tableSize itemView.title.text = tableSize
itemView.container.setOnClickListener { itemView.container.setOnClickListener {
onClickOnItem?.invoke(adapterPosition) onClickOnItem?.invoke(adapterPosition)
} }
} }
} }

@ -9,9 +9,13 @@ import androidx.recyclerview.widget.RecyclerView
import net.pokeranalytics.android.R import net.pokeranalytics.android.R
import net.pokeranalytics.android.ui.view.RowViewType import net.pokeranalytics.android.ui.view.RowViewType
enum class LiveDataViewType {
DATA,
BOTTOM_SHEET_DATA
}
interface LiveDataDataSource { interface LiveDataDataSource {
val title: String val title: String
val primaryKey: String
} }
interface LiveDataDelegate { interface LiveDataDelegate {
@ -20,17 +24,20 @@ interface LiveDataDelegate {
fun size() : Int fun size() : Int
} }
class LiveDataAdapter(var adapterDelegate: LiveDataDelegate, var layout: Int? = null) : RecyclerView.Adapter<RecyclerView.ViewHolder>() { class LiveDataAdapter(var adapterDelegate: LiveDataDelegate, var liveDataViewType: LiveDataViewType? = LiveDataViewType.DATA) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
inner class DataViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { inner class DataViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
fun bind(row: LiveDataDataSource, listener: View.OnClickListener) { fun bind(row: LiveDataDataSource, listener: View.OnClickListener) {
try { when(liveDataViewType) {
LiveDataViewType.DATA -> {
itemView.findViewById<AppCompatTextView>(R.id.rowTitle_title).text = row.title
itemView.findViewById<ConstraintLayout>(R.id.rowTitle_container).setOnClickListener(listener)
}
LiveDataViewType.BOTTOM_SHEET_DATA -> {
itemView.findViewById<AppCompatTextView>(R.id.title).text = row.title itemView.findViewById<AppCompatTextView>(R.id.title).text = row.title
itemView.findViewById<ConstraintLayout>(R.id.container).setOnClickListener(listener) itemView.findViewById<ConstraintLayout>(R.id.container).setOnClickListener(listener)
} catch (e: Exception) {
e.printStackTrace()
} }
}
} }
} }
@ -39,7 +46,15 @@ class LiveDataAdapter(var adapterDelegate: LiveDataDelegate, var layout: Int? =
} }
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
val layoutToInflate = layout ?: R.layout.row_title val layoutToInflate = when(liveDataViewType) {
LiveDataViewType.DATA -> {
R.layout.row_title
}
LiveDataViewType.BOTTOM_SHEET_DATA -> {
R.layout.row_bottom_sheet_title
}
else -> R.layout.row_title
}
return DataViewHolder(LayoutInflater.from(parent.context).inflate(layoutToInflate, parent, false)) return DataViewHolder(LayoutInflater.from(parent.context).inflate(layoutToInflate, parent, false))
} }

@ -6,18 +6,45 @@ import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import net.pokeranalytics.android.ui.view.BindableHolder import net.pokeranalytics.android.ui.view.BindableHolder
import net.pokeranalytics.android.ui.view.RowRepresentable import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.RowRepresentableDiffCallback
import net.pokeranalytics.android.ui.view.RowViewType import net.pokeranalytics.android.ui.view.RowViewType
interface RowRepresentableDataSource : DisplayableDataSource {
fun rowRepresentableForPosition(position:Int): RowRepresentable {
if (this.numberOfRows() > position) {
return this.adapterRows()[position]
} else {
throw IllegalStateException("Need to implement Data Source")
}
}
fun numberOfRows(): Int {
return this.adapterRows().size
}
fun viewTypeForPosition(position:Int): Int {
return this.rowRepresentableForPosition(position).viewType
}
fun indexForRow(row:RowRepresentable): Int {
return this.adapterRows().indexOf(row)
}
}
interface RowRepresentableDelegate : DisplayableDelegate {
fun onIndexSelected(position: Int) {}
}
/** /**
* An interface used to provide RowRepresentableAdapter content and value in the form of rows * An interface used to provide RowRepresentableAdapter content and value in the form of rows
*/ */
interface RowRepresentableDataSource { interface DisplayableDataSource {
/** /**
* Returns a list of rows * Returns a list of rows
*/ */
fun adapterRows(): ArrayList<RowRepresentable> fun adapterRows(): ArrayList<RowRepresentable> {
return ArrayList()
}
/** /**
* Returns a boolean for a specific row * Returns a boolean for a specific row
@ -48,39 +75,29 @@ interface RowRepresentableDataSource {
* - switch (bool) * - switch (bool)
* - static content * - static content
* */ * */
} }
/** /**
* A delegate used to propagate UI actions * A delegate used to propagate UI actions
*/ */
interface RowRepresentableDelegate { interface DisplayableDelegate {
fun onRowSelected(row: RowRepresentable) {} fun onRowSelected(row: RowRepresentable) {}
fun onActionSelected(row: RowRepresentable) {} fun onActionSelected(row: RowRepresentable) {}
} }
/** /**
* An adapter capable of displaying a list of RowRepresentables * An adapter capable of displaying a list of RowRepresentables
* @param rowRepresentableDataSource the datasource providing rows * @param dataSource the datasource providing rows
* @param rowRepresentableDelegate the delegate, notified of UI actions * @param delegate the delegate, notified of UI actions
*/ */
class RowRepresentableAdapter( class RowRepresentableAdapter(
var rowRepresentableDataSource: RowRepresentableDataSource, var dataSource: RowRepresentableDataSource,
var rowRepresentableDelegate: RowRepresentableDelegate? = null var delegate: RowRepresentableDelegate? = null
) : ) :
RecyclerView.Adapter<RecyclerView.ViewHolder>() { RecyclerView.Adapter<RecyclerView.ViewHolder>() {
/**
* The list of rows to display
*/
private var rows: ArrayList<RowRepresentable> = ArrayList()
init {
this.rows = rowRepresentableDataSource.adapterRows()
}
override fun getItemViewType(position: Int): Int { override fun getItemViewType(position: Int): Int {
return this.rows[position].viewType return this.dataSource.viewTypeForPosition(position)
} }
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
@ -89,28 +106,29 @@ class RowRepresentableAdapter(
} }
override fun getItemCount(): Int { override fun getItemCount(): Int {
return this.rows.size return this.dataSource.numberOfRows()
} }
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
val dynamicRow = this.rows[position] val dynamicRow = this.dataSource.rowRepresentableForPosition(position)
val listener = View.OnClickListener { val listener = View.OnClickListener {
rowRepresentableDelegate?.onRowSelected(dynamicRow) delegate?.onRowSelected(dynamicRow)
delegate?.onIndexSelected(position)
} }
val actionListener = View.OnClickListener { val actionListener = View.OnClickListener {
rowRepresentableDelegate?.onActionSelected(dynamicRow) delegate?.onActionSelected(dynamicRow)
} }
(holder as BindableHolder).bind(dynamicRow, this.rowRepresentableDataSource, listener, actionListener) (holder as BindableHolder).bind(dynamicRow, this.dataSource, listener, actionListener)
} }
/** /**
* Refresh the row in the adapter * Refresh the row in the adapter
*/ */
fun refreshRow(row: RowRepresentable) { fun refreshRow(row: RowRepresentable) {
val index = rows.indexOf(row) val index = this.dataSource.indexForRow(row)
if (index >= 0) { if (index >= 0) {
notifyItemChanged(index) notifyItemChanged(index)
} }
@ -119,9 +137,7 @@ class RowRepresentableAdapter(
/** /**
* Update UI * Update UI
*/ */
fun updateRows(newRows: ArrayList<RowRepresentable>) { fun updateRows(diffResult: DiffUtil.DiffResult) {
val diffResult = DiffUtil.calculateDiff(RowRepresentableDiffCallback(newRows, rows, rowRepresentableDataSource))
this.rows = newRows
diffResult.dispatchUpdatesTo(this) diffResult.dispatchUpdatesTo(this)
} }

@ -5,17 +5,21 @@ import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import io.realm.ObjectChangeSet
import io.realm.Realm import io.realm.Realm
import io.realm.RealmResults import io.realm.RealmResults
import kotlinx.android.synthetic.main.fragment_data_list.* import kotlinx.android.synthetic.main.fragment_data_list.*
import net.pokeranalytics.android.R import net.pokeranalytics.android.R
import net.pokeranalytics.android.model.ObjectSavable
import net.pokeranalytics.android.ui.activity.EditableDataActivity import net.pokeranalytics.android.ui.activity.EditableDataActivity
import net.pokeranalytics.android.ui.adapter.components.* import net.pokeranalytics.android.ui.adapter.components.*
import net.pokeranalytics.android.ui.fragment.components.PokerAnalyticsFragment 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.SettingRow import net.pokeranalytics.android.ui.view.SettingRow
import timber.log.Timber import timber.log.Timber
class DataListFragment : PokerAnalyticsFragment(), LiveDataDelegate { class DataListFragment : PokerAnalyticsFragment(), RowRepresentableDataSource, RowRepresentableDelegate{
private lateinit var dataType: SettingRow private lateinit var dataType: SettingRow
@ -31,18 +35,26 @@ class DataListFragment : PokerAnalyticsFragment(), LiveDataDelegate {
initUI() initUI()
} }
override fun data(position: Int): LiveDataDataSource { override fun rowRepresentableForPosition(position: Int): RowRepresentable {
return (items[position] as LiveDataDataSource) return this.items[position] as RowRepresentable
} }
override fun onRowSelected(position: Int) { override fun numberOfRows(): Int {
this.dataType.relatedResultsRepresentable?.let { return this.items.size
EditableDataActivity.newInstance(requireContext(), it.ordinal, this.data(position).primaryKey) }
override fun viewTypeForPosition(position: Int): Int {
return RowViewType.DATA.ordinal
} }
override fun indexForRow(row: RowRepresentable): Int {
return this.items.indexOf(row)
} }
override fun size(): Int { override fun onIndexSelected(position: Int) {
return items.size this.dataType.relatedResultsRepresentable?.let {
EditableDataActivity.newInstance(requireContext(), it.ordinal, (this.items[position] as ObjectSavable).uniqueIdentifier())
}
} }
private fun initData() { private fun initData() {
@ -54,7 +66,7 @@ class DataListFragment : PokerAnalyticsFragment(), LiveDataDelegate {
private fun initUI() { private fun initUI() {
val viewManager = LinearLayoutManager(requireContext()) val viewManager = LinearLayoutManager(requireContext())
val dataListAdapter = LiveDataAdapter(this) val dataListAdapter = RowRepresentableAdapter(this, this)
recyclerView.apply { recyclerView.apply {
setHasFixedSize(true) setHasFixedSize(true)

@ -1,10 +1,7 @@
package net.pokeranalytics.android.ui.fragment package net.pokeranalytics.android.ui.fragment
import android.content.DialogInterface
import android.os.Bundle import android.os.Bundle
import android.view.LayoutInflater import android.view.*
import android.view.View
import android.view.ViewGroup
import android.widget.Toast import android.widget.Toast
import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AlertDialog
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
@ -28,6 +25,7 @@ class EditableDataFragment : PokerAnalyticsFragment(), RowRepresentableDelegate,
private lateinit var item: RealmObject private lateinit var item: RealmObject
private lateinit var liveDataType: LiveData private lateinit var liveDataType: LiveData
private lateinit var rowRepresentableAdapter: RowRepresentableAdapter private lateinit var rowRepresentableAdapter: RowRepresentableAdapter
private var editableMenu: Menu? = null
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.fragment_editable_data, container, false) return inflater.inflate(R.layout.fragment_editable_data, container, false)
@ -39,6 +37,22 @@ class EditableDataFragment : PokerAnalyticsFragment(), RowRepresentableDelegate,
initUI() initUI()
} }
override fun onCreateOptionsMenu(menu: Menu?, inflater: MenuInflater?) {
inflater?.inflate(R.menu.editable_data, menu)
this.editableMenu = menu
updateMenuUI()
super.onCreateOptionsMenu(menu, inflater)
}
override fun onOptionsItemSelected(item: MenuItem?): Boolean {
when (item!!.itemId) {
R.id.save -> saveData()
R.id.delete -> deleteData()
}
return true
}
override fun onRowSelected(row: RowRepresentable) { override fun onRowSelected(row: RowRepresentable) {
BottomSheetFragment.create(fragmentManager, row, this, (this.item as RowEditable).getBottomSheetData(row)) BottomSheetFragment.create(fragmentManager, row, this, (this.item as RowEditable).getBottomSheetData(row))
} }
@ -49,16 +63,16 @@ class EditableDataFragment : PokerAnalyticsFragment(), RowRepresentableDelegate,
override fun clickOnClear(row: RowRepresentable) { override fun clickOnClear(row: RowRepresentable) {
Toast.makeText(requireContext(), "Clear: $row", Toast.LENGTH_SHORT).show() Toast.makeText(requireContext(), "Clear: $row", Toast.LENGTH_SHORT).show()
(this.item as RowEditable).updateValue(null, row)
this.getRealm().executeTransaction { this.getRealm().executeTransaction {
(this.item as RowEditable).updateValue(null, row)
it.copyToRealmOrUpdate(this.item) it.copyToRealmOrUpdate(this.item)
} }
rowRepresentableAdapter.refreshRow(row) rowRepresentableAdapter.refreshRow(row)
} }
override fun setValue(value: Any?, row: RowRepresentable) { override fun setValue(value: Any?, row: RowRepresentable) {
(this.item as RowEditable).updateValue(value, row)
this.getRealm().executeTransaction { this.getRealm().executeTransaction {
(this.item as RowEditable).updateValue(value, row)
it.copyToRealmOrUpdate(this.item) it.copyToRealmOrUpdate(this.item)
} }
rowRepresentableAdapter.refreshRow(row) rowRepresentableAdapter.refreshRow(row)
@ -74,6 +88,7 @@ class EditableDataFragment : PokerAnalyticsFragment(), RowRepresentableDelegate,
val activity = activity as PokerAnalyticsActivity val activity = activity as PokerAnalyticsActivity
activity.setSupportActionBar(toolbar) activity.setSupportActionBar(toolbar)
activity.supportActionBar?.setDisplayHomeAsUpEnabled(true) activity.supportActionBar?.setDisplayHomeAsUpEnabled(true)
setHasOptionsMenu(true)
val viewManager = LinearLayoutManager(requireContext()) val viewManager = LinearLayoutManager(requireContext())
@ -81,38 +96,49 @@ class EditableDataFragment : PokerAnalyticsFragment(), RowRepresentableDelegate,
setHasFixedSize(true) setHasFixedSize(true)
layoutManager = viewManager layoutManager = viewManager
} }
}
this.saveButton.text = this.saveButton.context.getString(R.string.save) /**
this.saveButton.setOnClickListener { * Update menu UI
*/
private fun updateMenuUI() {
editableMenu?.findItem(R.id.delete)?.isVisible = item.isManaged
editableMenu?.findItem(R.id.save)?.isVisible = true
}
/**
* Save data
*/
private fun saveData() {
if ((this.item as ObjectSavable).isValidForSave()) { if ((this.item as ObjectSavable).isValidForSave()) {
this.getRealm().executeTransaction { this.getRealm().executeTransaction {
it.copyToRealmOrUpdate(this.item) it.copyToRealmOrUpdate(this.item)
} }
this.activity?.let { activity?.finish()
it.finish()
}
} else { } else {
val builder = AlertDialog.Builder(it.context) val builder = AlertDialog.Builder(requireContext())
.setMessage(R.string.empty_name_for_br_error) .setMessage(R.string.empty_name_for_br_error)
.setNegativeButton(R.string.ok, null) .setNegativeButton(R.string.ok, null)
builder.show() builder.show()
} }
} }
this.deleteButton.text = this.deleteButton.context.getString(R.string.delete) /**
this.deleteButton.setOnClickListener { * Delete data
val builder = AlertDialog.Builder(it.context) */
private fun deleteData() {
val builder = AlertDialog.Builder(requireContext())
builder.setTitle(R.string.warning) builder.setTitle(R.string.warning)
.setMessage(R.string.are_you_sure_you_want_to_do_that_) .setMessage(R.string.are_you_sure_you_want_to_do_that_)
.setNeutralButton(R.string.no, null) .setNegativeButton(R.string.no, null)
.setNegativeButton(R.string.yes, DialogInterface.OnClickListener { dialog, id -> .setPositiveButton(R.string.yes) { dialog, id ->
if (this.item.isManaged) { if (this.item.isManaged) {
Toast.makeText(requireContext(), "isManaged", Toast.LENGTH_SHORT).show() Toast.makeText(requireContext(), "isManaged", Toast.LENGTH_SHORT).show()
Timber.d("is managed") Timber.d("is managed")
this.getRealm().executeTransaction { this.getRealm().executeTransaction {
this.liveDataType.deleteData(it, (this.item as LiveDataDataSource)) this.liveDataType.deleteData(it, (this.item as ObjectSavable))
} }
} else { } else {
Toast.makeText(requireContext(), "isNotManaged", Toast.LENGTH_SHORT).show() Toast.makeText(requireContext(), "isNotManaged", Toast.LENGTH_SHORT).show()
@ -121,9 +147,9 @@ class EditableDataFragment : PokerAnalyticsFragment(), RowRepresentableDelegate,
this.activity?.let { this.activity?.let {
it.finish() it.finish()
} }
})
builder.show()
} }
builder.show()
} }
/** /**

@ -7,15 +7,21 @@ import android.view.ViewGroup
import android.widget.Toast import android.widget.Toast
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import io.realm.RealmResults import io.realm.RealmResults
import io.realm.Sort
import io.realm.kotlin.where
import kotlinx.android.synthetic.main.fragment_history.* import kotlinx.android.synthetic.main.fragment_history.*
import net.pokeranalytics.android.R import net.pokeranalytics.android.R
import net.pokeranalytics.android.model.ObjectSavable
import net.pokeranalytics.android.model.realm.Session import net.pokeranalytics.android.model.realm.Session
import net.pokeranalytics.android.ui.activity.SessionActivity import net.pokeranalytics.android.ui.activity.SessionActivity
import net.pokeranalytics.android.ui.adapter.HistoryAdapter import net.pokeranalytics.android.ui.adapter.components.RowRepresentableAdapter
import net.pokeranalytics.android.ui.adapter.components.RowRepresentableDataSource
import net.pokeranalytics.android.ui.adapter.components.RowRepresentableDelegate
import net.pokeranalytics.android.ui.fragment.components.PokerAnalyticsFragment import net.pokeranalytics.android.ui.fragment.components.PokerAnalyticsFragment
import net.pokeranalytics.android.util.data.sessionDao import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.RowViewType
class HistoryFragment : PokerAnalyticsFragment() { class HistoryFragment : PokerAnalyticsFragment(), RowRepresentableDataSource, RowRepresentableDelegate {
companion object { companion object {
fun newInstance(): HistoryFragment { fun newInstance(): HistoryFragment {
@ -26,8 +32,8 @@ class HistoryFragment : PokerAnalyticsFragment() {
} }
} }
private lateinit var historyAdapter: HistoryAdapter private lateinit var historyAdapter: RowRepresentableAdapter
private var realmSessions: RealmResults<Session>? = null private lateinit var realmSessions: RealmResults<Session>
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.fragment_history, container, false) return inflater.inflate(R.layout.fragment_history, container, false)
@ -41,7 +47,12 @@ class HistoryFragment : PokerAnalyticsFragment() {
override fun onDestroyView() { override fun onDestroyView() {
super.onDestroyView() super.onDestroyView()
realmSessions?.removeAllChangeListeners() realmSessions.removeAllChangeListeners()
}
override fun onResume() {
super.onResume()
historyAdapter.notifyDataSetChanged()
} }
/** /**
@ -70,28 +81,34 @@ class HistoryFragment : PokerAnalyticsFragment() {
* Init data * Init data
*/ */
private fun initData() { private fun initData() {
realmSessions = getRealm().where<Session>().findAll().sort("timeFrame.startDate", Sort.DESCENDING)
realmSessions = getRealm().sessionDao().findAllSessions()
realmSessions?.let {
val viewManager = LinearLayoutManager(requireContext()) val viewManager = LinearLayoutManager(requireContext())
historyAdapter = HistoryAdapter(it) historyAdapter = RowRepresentableAdapter(this, this)
recyclerView.apply { recyclerView.apply {
setHasFixedSize(true) setHasFixedSize(true)
layoutManager = viewManager layoutManager = viewManager
adapter = historyAdapter adapter = historyAdapter
} }
}
historyAdapter.onClickOnSession = {position, session -> override fun rowRepresentableForPosition(position: Int): RowRepresentable {
SessionActivity.newInstance(requireContext(), sessionId = session.id) return this.realmSessions[position] as RowRepresentable
} }
it.addChangeListener { newSessions -> override fun numberOfRows(): Int {
historyAdapter.notifyDataSetChanged() return this.realmSessions.size
} }
override fun viewTypeForPosition(position: Int): Int {
return RowViewType.ROW_SESSION.ordinal
} }
override fun indexForRow(row: RowRepresentable): Int {
return this.realmSessions.indexOf(row)
} }
override fun onRowSelected(row: RowRepresentable) {
SessionActivity.newInstance(requireContext(), sessionId = (row as ObjectSavable).uniqueIdentifier())
}
} }

@ -4,7 +4,9 @@ import android.os.Bundle
import android.view.* import android.view.*
import android.view.animation.OvershootInterpolator import android.view.animation.OvershootInterpolator
import android.widget.Toast import android.widget.Toast
import androidx.core.content.ContextCompat
import androidx.interpolator.view.animation.FastOutSlowInInterpolator import androidx.interpolator.view.animation.FastOutSlowInInterpolator
import androidx.recyclerview.widget.DiffUtil
import io.realm.kotlin.where import io.realm.kotlin.where
import kotlinx.android.synthetic.main.fragment_session.* import kotlinx.android.synthetic.main.fragment_session.*
import net.pokeranalytics.android.R import net.pokeranalytics.android.R
@ -21,8 +23,10 @@ import net.pokeranalytics.android.ui.fragment.components.PokerAnalyticsFragment
import net.pokeranalytics.android.ui.fragment.components.bottomsheet.BottomSheetDelegate import net.pokeranalytics.android.ui.fragment.components.bottomsheet.BottomSheetDelegate
import net.pokeranalytics.android.ui.fragment.components.bottomsheet.BottomSheetFragment import net.pokeranalytics.android.ui.fragment.components.bottomsheet.BottomSheetFragment
import net.pokeranalytics.android.ui.view.RowRepresentable import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.RowRepresentableDiffCallback
import net.pokeranalytics.android.ui.view.SessionRow import net.pokeranalytics.android.ui.view.SessionRow
import net.pokeranalytics.android.ui.view.SmoothScrollLinearLayoutManager import net.pokeranalytics.android.ui.view.SmoothScrollLinearLayoutManager
import net.pokeranalytics.android.util.px
import net.pokeranalytics.android.util.toast import net.pokeranalytics.android.util.toast
import timber.log.Timber import timber.log.Timber
import java.util.* import java.util.*
@ -32,7 +36,7 @@ class SessionFragment : PokerAnalyticsFragment(), RowRepresentableDelegate, Bott
private lateinit var currentSession: Session private lateinit var currentSession: Session
private lateinit var sessionAdapter: RowRepresentableAdapter private lateinit var sessionAdapter: RowRepresentableAdapter
private var sessionMenu: Menu? = null private var sessionMenu: Menu? = null
private val oldRows: ArrayList<RowRepresentable> = ArrayList()
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.fragment_session, container, false) return inflater.inflate(R.layout.fragment_session, container, false)
@ -145,7 +149,6 @@ class SessionFragment : PokerAnalyticsFragment(), RowRepresentableDelegate, Bott
floatingActionButton.setOnClickListener { floatingActionButton.setOnClickListener {
manageSessionState() manageSessionState()
} }
} }
/** /**
@ -156,42 +159,89 @@ class SessionFragment : PokerAnalyticsFragment(), RowRepresentableDelegate, Bott
when (currentSession.getState()) { when (currentSession.getState()) {
SessionState.PENDING -> { SessionState.PENDING -> {
state.text = "WAITING"
state.setTextColor(ContextCompat.getColor(requireContext(), R.color.white))
sessionMenu?.findItem(R.id.restart)?.isVisible = false sessionMenu?.findItem(R.id.restart)?.isVisible = false
floatingActionButton.setImageResource(R.drawable.ic_outline_play) floatingActionButton.setImageResource(R.drawable.ic_outline_play)
bottomAppBar.menu.findItem(R.id.stop).isVisible = false bottomAppBar.menu.findItem(R.id.stop).isVisible = false
floatingActionButton.animate().scaleX(1f).scaleY(1f).alpha(1f) floatingActionButton.animate().scaleX(1f).scaleY(1f).alpha(1f)
.setInterpolator(OvershootInterpolator()).start() .setInterpolator(OvershootInterpolator()).start()
sessionData.animate().translationY(-(72f.px)).alpha(1f)
.setInterpolator(FastOutSlowInInterpolator()).setDuration(500).start()
recyclerView.animate().translationY(-(72f.px))
.setInterpolator(FastOutSlowInInterpolator()).setDuration(500).start()
} }
SessionState.STARTED -> { SessionState.STARTED -> {
state.text = "PLAYING"
state.setTextColor(ContextCompat.getColor(requireContext(), R.color.green))
sessionMenu?.findItem(R.id.restart)?.isVisible = true sessionMenu?.findItem(R.id.restart)?.isVisible = true
floatingActionButton.setImageResource(R.drawable.ic_outline_pause) floatingActionButton.setImageResource(R.drawable.ic_outline_pause)
bottomAppBar.menu.findItem(R.id.stop).isVisible = true bottomAppBar.menu.findItem(R.id.stop).isVisible = true
floatingActionButton.animate().scaleX(1f).scaleY(1f).alpha(1f) floatingActionButton.animate().scaleX(1f).scaleY(1f).alpha(1f)
.setInterpolator(OvershootInterpolator()).start() .setInterpolator(OvershootInterpolator()).start()
sessionData.animate().translationY(0f).alpha(1f)
.setInterpolator(FastOutSlowInInterpolator()).setDuration(500).start()
recyclerView.animate().translationY(0f.px)
.setInterpolator(FastOutSlowInInterpolator()).setDuration(500).start()
} }
SessionState.PAUSED -> { SessionState.PAUSED -> {
state.text = "BREAK"
state.setTextColor(ContextCompat.getColor(requireContext(), R.color.blue))
sessionMenu?.findItem(R.id.restart)?.isVisible = true sessionMenu?.findItem(R.id.restart)?.isVisible = true
floatingActionButton.setImageResource(R.drawable.ic_outline_play) floatingActionButton.setImageResource(R.drawable.ic_outline_play)
bottomAppBar.menu.findItem(R.id.stop).isVisible = true bottomAppBar.menu.findItem(R.id.stop).isVisible = true
floatingActionButton.animate().scaleX(1f).scaleY(1f).alpha(1f) floatingActionButton.animate().scaleX(1f).scaleY(1f).alpha(1f)
.setInterpolator(OvershootInterpolator()).start() .setInterpolator(OvershootInterpolator()).start()
sessionData.animate().translationY(0f).alpha(1f)
.setInterpolator(FastOutSlowInInterpolator()).setDuration(500).start()
recyclerView.animate().translationY(0f.px)
.setInterpolator(FastOutSlowInInterpolator()).setDuration(500).start()
} }
SessionState.FINISHED -> { SessionState.FINISHED -> {
state.text = "FINISHED"
state.setTextColor(ContextCompat.getColor(requireContext(), R.color.white))
sessionMenu?.findItem(R.id.restart)?.isVisible = true sessionMenu?.findItem(R.id.restart)?.isVisible = true
bottomAppBar.menu.findItem(R.id.stop).isVisible = false bottomAppBar.menu.findItem(R.id.stop).isVisible = false
floatingActionButton.animate().scaleX(0f).scaleY(0f).alpha(0f) floatingActionButton.animate().scaleX(0f).scaleY(0f).alpha(0f)
.setInterpolator(FastOutSlowInInterpolator()).start() .setInterpolator(FastOutSlowInInterpolator()).start()
sessionData.animate().translationY(0f).alpha(1f)
.setInterpolator(FastOutSlowInInterpolator()).setDuration(500).start()
recyclerView.animate().translationY(0f.px)
.setInterpolator(FastOutSlowInInterpolator()).setDuration(500).start()
}
} }
updateAdapterUI(true)
} }
sessionAdapter.updateRows(currentSession.adapterRows()) /**
* Update adapter UI
*/
private fun updateAdapterUI(scrollToTop: Boolean) {
val diffResult = DiffUtil.calculateDiff(RowRepresentableDiffCallback(currentSession.adapterRows(), oldRows))
sessionAdapter.updateRows(diffResult)
oldRows.clear()
oldRows.addAll(currentSession.adapterRows())
if (scrollToTop) {
recyclerView.smoothScrollToPosition(0) recyclerView.smoothScrollToPosition(0)
}
} }
/** /**
* Update the state of the session (start / pause) * Update the state of the session (start / pause)
*/ */
private fun manageSessionState() { private fun manageSessionState() {
Timber.d("oldRows: $oldRows")
when (currentSession.getState()) { when (currentSession.getState()) {
SessionState.PENDING -> { SessionState.PENDING -> {
currentSession.startSession() currentSession.startSession()

@ -8,15 +8,14 @@ import io.realm.RealmResults
import kotlinx.android.synthetic.main.bottom_sheet_list.* import kotlinx.android.synthetic.main.bottom_sheet_list.*
import kotlinx.android.synthetic.main.fragment_bottom_sheet.view.* import kotlinx.android.synthetic.main.fragment_bottom_sheet.view.*
import net.pokeranalytics.android.R import net.pokeranalytics.android.R
import net.pokeranalytics.android.model.realm.Game import net.pokeranalytics.android.ui.adapter.components.*
import net.pokeranalytics.android.ui.adapter.components.LiveDataAdapter import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.adapter.components.LiveDataDataSource import net.pokeranalytics.android.ui.view.RowViewType
import net.pokeranalytics.android.ui.adapter.components.LiveDataDelegate
class BottomSheetListFragment : BottomSheetFragment(), LiveDataDelegate { class BottomSheetListFragment : BottomSheetFragment(), RowRepresentableDataSource, RowRepresentableDelegate {
private var realmData: RealmResults<*>? = null private var realmData: RealmResults<*>? = null
private lateinit var dataAdapter: LiveDataAdapter private lateinit var dataAdapter: RowRepresentableAdapter
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
@ -29,15 +28,32 @@ class BottomSheetListFragment : BottomSheetFragment(), LiveDataDelegate {
dataAdapter.notifyDataSetChanged() dataAdapter.notifyDataSetChanged()
} }
override fun data(position: Int): LiveDataDataSource { override fun rowRepresentableForPosition(position: Int): RowRepresentable {
realmData?.let { realmData?.let {
return it[position] as LiveDataDataSource return it[position] as RowRepresentable
} }
//TODO: Change that return super.rowRepresentableForPosition(position)
return Game()
} }
override fun onRowSelected(position: Int) { override fun numberOfRows(): Int {
realmData?.let {
return it.size
}
return super.numberOfRows()
}
override fun viewTypeForPosition(position: Int): Int {
return RowViewType.BOTTOM_SHEET_DATA.ordinal
}
override fun indexForRow(row: RowRepresentable): Int {
realmData?.let {
return it.indexOf(row)
}
return super.indexForRow(row)
}
override fun onIndexSelected(position: Int) {
realmData?.let { realmData?.let {
val selectedData = it[position] val selectedData = it[position]
selectedData?.let {data -> selectedData?.let {data ->
@ -45,10 +61,7 @@ class BottomSheetListFragment : BottomSheetFragment(), LiveDataDelegate {
dismiss() dismiss()
} }
} }
} super.onIndexSelected(position)
override fun size(): Int {
return realmData?.size ?: 0
} }
/** /**
@ -69,7 +82,7 @@ class BottomSheetListFragment : BottomSheetFragment(), LiveDataDelegate {
LayoutInflater.from(requireContext()).inflate(R.layout.bottom_sheet_list, view?.bottomSheetContainer, true) LayoutInflater.from(requireContext()).inflate(R.layout.bottom_sheet_list, view?.bottomSheetContainer, true)
val viewManager = LinearLayoutManager(requireContext()) val viewManager = LinearLayoutManager(requireContext())
dataAdapter = LiveDataAdapter(this, R.layout.row_bottom_sheet_title) dataAdapter = RowRepresentableAdapter(this, this)
reyclerView.apply { reyclerView.apply {
setHasFixedSize(true) setHasFixedSize(true)

@ -4,22 +4,24 @@ import android.os.Bundle
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import com.google.android.material.chip.Chip
import io.realm.RealmResults import io.realm.RealmResults
import kotlinx.android.synthetic.main.bottom_sheet_game_list.* import kotlinx.android.synthetic.main.bottom_sheet_game_list.*
import kotlinx.android.synthetic.main.fragment_bottom_sheet.view.* import kotlinx.android.synthetic.main.fragment_bottom_sheet.view.*
import net.pokeranalytics.android.R import net.pokeranalytics.android.R
import net.pokeranalytics.android.model.realm.Game import net.pokeranalytics.android.ui.adapter.components.RowRepresentableAdapter
import net.pokeranalytics.android.ui.adapter.LimitTypesAdapter import net.pokeranalytics.android.ui.adapter.components.RowRepresentableDataSource
import net.pokeranalytics.android.ui.adapter.components.LiveDataAdapter import net.pokeranalytics.android.ui.adapter.components.RowRepresentableDelegate
import net.pokeranalytics.android.ui.adapter.components.LiveDataDataSource import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.adapter.components.LiveDataDelegate import net.pokeranalytics.android.ui.view.RowViewType
import timber.log.Timber import timber.log.Timber
class BottomSheetListGameFragment : BottomSheetFragment(), LiveDataDelegate { class BottomSheetListGameFragment : BottomSheetFragment(), RowRepresentableDataSource, RowRepresentableDelegate {
private var realmData: RealmResults<*>? = null private var realmData: RealmResults<*>? = null
private lateinit var dataAdapter: LiveDataAdapter private lateinit var dataAdapter: RowRepresentableAdapter
private val values = ArrayList<Any?>()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
@ -32,29 +34,45 @@ class BottomSheetListGameFragment : BottomSheetFragment(), LiveDataDelegate {
dataAdapter.notifyDataSetChanged() dataAdapter.notifyDataSetChanged()
} }
override fun data(position: Int): LiveDataDataSource { override fun getValue(): Any? {
return values
}
override fun rowRepresentableForPosition(position: Int): RowRepresentable {
realmData?.let { realmData?.let {
return it[position] as LiveDataDataSource return it[position] as RowRepresentable
} }
//TODO: Change that return super.rowRepresentableForPosition(position)
return Game()
} }
override fun onRowSelected(position: Int) { override fun numberOfRows(): Int {
realmData?.let { realmData?.let {
val selectedData = it[position] return it.size
selectedData?.let {data ->
bottomSheetDelegate.setValue(data, row)
dismiss()
}
} }
return super.numberOfRows()
} }
override fun size(): Int { override fun viewTypeForPosition(position: Int): Int {
return RowViewType.BOTTOM_SHEET_DATA.ordinal
}
Timber.d("Games: ${realmData?.size}") override fun indexForRow(row: RowRepresentable): Int {
realmData?.let {
return it.indexOf(row)
}
return super.indexForRow(row)
}
return realmData?.size ?: 0 override fun onIndexSelected(position: Int) {
realmData?.let {
val selectedData = it[position]
selectedData?.let { data ->
values[1] = data
bottomSheetDelegate.setValue(values, row)
dismiss()
}
}
super.onIndexSelected(position)
} }
/** /**
@ -74,23 +92,28 @@ class BottomSheetListGameFragment : BottomSheetFragment(), LiveDataDelegate {
LayoutInflater.from(requireContext()).inflate(R.layout.bottom_sheet_game_list, view?.bottomSheetContainer, true) LayoutInflater.from(requireContext()).inflate(R.layout.bottom_sheet_game_list, view?.bottomSheetContainer, true)
values.add(0, null)
values.add(1, null)
val limits = ArrayList<String>() val limits = ArrayList<String>()
limits.addAll(resources.getStringArray(R.array.limit_short_name)) limits.addAll(resources.getStringArray(R.array.limit_short_name))
chipGroup.removeAllViews()
for ((index, limit) in limits.withIndex()) {
val chip = Chip(requireContext())
chip.text = limit
chip.id = index
chipGroup.addView(chip)
}
val viewManager1 = LinearLayoutManager(requireContext()) chipGroup.setOnCheckedChangeListener { chipGroup, i ->
val gameDataAdapter1 = LimitTypesAdapter(limits) Timber.d("Chip selected: $i")
values[0] = i
recyclerView1.apply {
setHasFixedSize(true)
layoutManager = viewManager1
adapter = gameDataAdapter1
isNestedScrollingEnabled = false
} }
val viewManager2 = LinearLayoutManager(requireContext()) val viewManager2 = LinearLayoutManager(requireContext())
dataAdapter = LiveDataAdapter(this, R.layout.row_bottom_sheet_title) dataAdapter = RowRepresentableAdapter(this, this)
recyclerView2.apply { recyclerView2.apply {
setHasFixedSize(true) setHasFixedSize(true)

@ -1,16 +1,131 @@
package net.pokeranalytics.android.ui.fragment.components.bottomsheet package net.pokeranalytics.android.ui.fragment.components.bottomsheet
import android.content.Context
import android.os.Bundle import android.os.Bundle
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.GridLayoutManager
import kotlinx.android.synthetic.main.bottom_sheet_grid.* import kotlinx.android.synthetic.main.bottom_sheet_grid.*
import kotlinx.android.synthetic.main.fragment_bottom_sheet.view.* import kotlinx.android.synthetic.main.fragment_bottom_sheet.view.*
import net.pokeranalytics.android.ui.adapter.TableSizeGridAdapter import net.pokeranalytics.android.R
import net.pokeranalytics.android.ui.adapter.components.*
import net.pokeranalytics.android.ui.view.GridSpacingItemDecoration import net.pokeranalytics.android.ui.view.GridSpacingItemDecoration
import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.RowViewType
import net.pokeranalytics.android.util.px import net.pokeranalytics.android.util.px
class TableSize(var numberOfPlayer:Int): RowRepresentable {
companion object {
val all = Array(8, init =
{ index -> TableSize(index+2)})
}
override val resId: Int?
get() {
return if (this.numberOfPlayer == 2) {
R.string.heads_up
} else {
R.string.max
}
}
override fun localizedTitle(context: Context): String {
this.resId?.let {
return if (this.numberOfPlayer == 2) {
context.getString(it)
} else {
"$this.numberOfPlayer$context.getString(it)"
}
}
return super.localizedTitle(context)
}
override val viewType: Int
get() = RowViewType.TITLE_GRID.ordinal
}
class BottomSheetTableSizeGridFragment : BottomSheetFragment(), RowRepresentableDataSource, RowRepresentableDelegate {
private lateinit var dataAdapter: RowRepresentableAdapter
private var defaultSize: Int? = null
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
initData()
initUI()
}
override fun onResume() {
super.onResume()
dataAdapter.notifyDataSetChanged()
}
override fun getValue(): Any? {
return defaultSize
}
/**
* Init data
*/
private fun initData() {
val bottomSheetData = getData()
if (bottomSheetData.isNotEmpty() && bottomSheetData.first().defaultValue != null) {
defaultSize = bottomSheetData.first().defaultValue as Int?
}
}
/**
* Init UI
*/
private fun initUI() {
setAddButtonVisible(false)
LayoutInflater.from(requireContext())
.inflate(net.pokeranalytics.android.R.layout.bottom_sheet_grid, view?.bottomSheetContainer, true)
val viewManager = GridLayoutManager(requireContext(), 3)
dataAdapter = RowRepresentableAdapter(this, this)
val spanCount = 3
val spacing = 2.px
val includeEdge = false
reyclerView.apply {
setHasFixedSize(true)
layoutManager = viewManager
adapter = dataAdapter
addItemDecoration(GridSpacingItemDecoration(spanCount, spacing, includeEdge))
}
}
override fun rowRepresentableForPosition(position: Int): RowRepresentable {
return TableSize.all[position]
}
override fun indexForRow(row: RowRepresentable): Int {
return TableSize.all.indexOf(row)
}
override fun numberOfRows(): Int {
return TableSize.all.size
}
override fun onRowSelected(row: RowRepresentable) {
bottomSheetDelegate.setValue((this.row as TableSize).numberOfPlayer, this.row)
dismiss()
}
override fun stringForRow(row: RowRepresentable): String {
this.context?.let {
return row.localizedTitle(it)
}
return "UNKNOWN CONTEXT FOR ROW $row"
}
}
/*
class BottomSheetTableSizeGridFragment : BottomSheetFragment() { class BottomSheetTableSizeGridFragment : BottomSheetFragment() {
private var dataList: ArrayList<String> = ArrayList() private var dataList: ArrayList<String> = ArrayList()
@ -80,3 +195,5 @@ class BottomSheetTableSizeGridFragment : BottomSheetFragment() {
} }
} }
*/

@ -29,11 +29,17 @@ interface Localizable {
} }
} }
interface RowRepresentable : Displayable {
fun getDisplayName(): String {
return "UNKNOWN NAME"
}
}
/** /**
* An interface used so that enums values can be represented visually * An interface used so that enums values can be represented visually
* as rows in RecyclerViews * as rows in RecyclerViews
*/ */
interface RowRepresentable : Localizable { interface Displayable: Localizable {
/** /**
* The type of view associated with the row * The type of view associated with the row
*/ */

@ -2,12 +2,8 @@ package net.pokeranalytics.android.ui.view
import androidx.annotation.Nullable import androidx.annotation.Nullable
import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.DiffUtil
import net.pokeranalytics.android.ui.adapter.components.RowRepresentableDataSource
class RowRepresentableDiffCallback( class RowRepresentableDiffCallback(var newRows: List<RowRepresentable>, var oldRows: List<RowRepresentable>) :
var newRows: List<RowRepresentable>, var oldRows: List<RowRepresentable>,
var rowRepresentableDataSource: RowRepresentableDataSource
) :
DiffUtil.Callback() { DiffUtil.Callback() {
override fun getOldListSize(): Int { override fun getOldListSize(): Int {

@ -3,12 +3,18 @@ package net.pokeranalytics.android.ui.view
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.appcompat.widget.AppCompatTextView
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import kotlinx.android.synthetic.main.row_bottom_sheet_grid_title.view.*
import kotlinx.android.synthetic.main.row_header_title_value.view.* import kotlinx.android.synthetic.main.row_header_title_value.view.*
import kotlinx.android.synthetic.main.row_history_session.view.*
import kotlinx.android.synthetic.main.row_title.view.* import kotlinx.android.synthetic.main.row_title.view.*
import kotlinx.android.synthetic.main.row_title_value.view.* import kotlinx.android.synthetic.main.row_title_value.view.*
import kotlinx.android.synthetic.main.row_title_value_action.view.* import kotlinx.android.synthetic.main.row_title_value_action.view.*
import net.pokeranalytics.android.R import net.pokeranalytics.android.R
import net.pokeranalytics.android.model.realm.Session
import net.pokeranalytics.android.ui.adapter.TableSizeGridAdapter
import net.pokeranalytics.android.ui.adapter.components.RowRepresentableDataSource import net.pokeranalytics.android.ui.adapter.components.RowRepresentableDataSource
/** /**
@ -26,7 +32,11 @@ enum class RowViewType {
EDIT_TEXT, EDIT_TEXT,
TITLE, TITLE,
TITLE_VALUE, TITLE_VALUE,
TITLE_VALUE_ACTION; TITLE_VALUE_ACTION,
DATA,
BOTTOM_SHEET_DATA,
TITLE_GRID,
ROW_SESSION;
inner class FakeViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView), inner class FakeViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView),
BindableHolder { BindableHolder {
@ -34,6 +44,35 @@ enum class RowViewType {
} }
} }
inner class RowSessionViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView),
BindableHolder {
override fun bind(row: RowRepresentable, rowRepresentableDataSource: RowRepresentableDataSource?, listener: View.OnClickListener, actionListener: View.OnClickListener?) {
itemView.sessionRow.setData(row as Session)
itemView.sessionRow.setOnClickListener(listener)
}
}
inner class CellSessionViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView), BindableHolder {
override fun bind(row: RowRepresentable, rowRepresentableDataSource: RowRepresentableDataSource?, listener: View.OnClickListener, actionListener: View.OnClickListener?) {
itemView.title.text = row.localizedTitle(itemView.context)
itemView.container.setOnClickListener(listener)
}
}
inner class DataViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView), BindableHolder {
override fun bind(row: RowRepresentable, rowRepresentableDataSource: RowRepresentableDataSource?, listener: View.OnClickListener, actionListener: View.OnClickListener?) {
itemView.findViewById<AppCompatTextView>(R.id.rowTitle_title).text = row.getDisplayName()
itemView.findViewById<ConstraintLayout>(R.id.rowTitle_container).setOnClickListener(listener)
}
}
inner class BottomSheetDataViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView), BindableHolder {
override fun bind(row: RowRepresentable, rowRepresentableDataSource: RowRepresentableDataSource?, listener: View.OnClickListener, actionListener: View.OnClickListener?) {
itemView.findViewById<AppCompatTextView>(R.id.title).text = row.getDisplayName()
itemView.findViewById<ConstraintLayout>(R.id.container).setOnClickListener(listener)
}
}
inner class TitleViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView), inner class TitleViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView),
BindableHolder { BindableHolder {
override fun bind(row: RowRepresentable, rowRepresentableDataSource: RowRepresentableDataSource?, listener: View.OnClickListener, actionListener: View.OnClickListener?) { override fun bind(row: RowRepresentable, rowRepresentableDataSource: RowRepresentableDataSource?, listener: View.OnClickListener, actionListener: View.OnClickListener?) {
@ -115,7 +154,32 @@ enum class RowViewType {
false false
) )
) )
DATA -> DataViewHolder(
LayoutInflater.from(parent.context).inflate(
R.layout.row_title,
parent,
false
)
)
BOTTOM_SHEET_DATA -> BottomSheetDataViewHolder(
LayoutInflater.from(parent.context).inflate(
R.layout.row_bottom_sheet_title,
parent,
false
)
)
TITLE_GRID -> CellSessionViewHolder(
LayoutInflater.from(parent.context).inflate(
R.layout.row_bottom_sheet_grid_title,
parent,
false)
)
ROW_SESSION -> RowSessionViewHolder(
LayoutInflater.from(parent.context).inflate(
R.layout.row_history_session,
parent,
false)
)
else -> FakeViewHolder(parent) else -> FakeViewHolder(parent)
} }
} }

@ -10,6 +10,7 @@ import net.pokeranalytics.android.R
import net.pokeranalytics.android.model.realm.Session import net.pokeranalytics.android.model.realm.Session
import net.pokeranalytics.android.util.getDayNumber import net.pokeranalytics.android.util.getDayNumber
import net.pokeranalytics.android.util.getShortDayName import net.pokeranalytics.android.util.getShortDayName
import net.pokeranalytics.android.util.toCurrency
class SessionRowView : FrameLayout { class SessionRowView : FrameLayout {
@ -55,17 +56,9 @@ class SessionRowView : FrameLayout {
rowHistorySession.dateDay.text = session.creationDate.getShortDayName() rowHistorySession.dateDay.text = session.creationDate.getShortDayName()
rowHistorySession.dateNumber.text = session.creationDate.getDayNumber() rowHistorySession.dateNumber.text = session.creationDate.getDayNumber()
// TODO rowHistorySession.gameType.text = session.getGameTitle()
rowHistorySession.gameInfo.text = session.getDuration(context)
var gameTitle = session.getGameTitle() rowHistorySession.gameResult.text = session.result?.netResult?.toCurrency() ?: "$0"
if (gameTitle.isEmpty()) {
gameTitle = "Game title here"
}
rowHistorySession.gameType.text = gameTitle
rowHistorySession.gameInfo.text = "Game info: duration, table size, ..."
rowHistorySession.gameResult.text = "$ 0"
} }

@ -1,5 +1,6 @@
package net.pokeranalytics.android.util package net.pokeranalytics.android.util
import android.content.Context
import android.content.res.Resources import android.content.res.Resources
import android.widget.Toast import android.widget.Toast
import net.pokeranalytics.android.ui.activity.components.PokerAnalyticsActivity import net.pokeranalytics.android.ui.activity.components.PokerAnalyticsActivity
@ -9,6 +10,8 @@ import java.text.DecimalFormat
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.* import java.util.*
// Sizes // Sizes
val Int.dp: Int val Int.dp: Int
get() = (this / Resources.getSystem().displayMetrics.density).toInt() get() = (this / Resources.getSystem().displayMetrics.density).toInt()
@ -55,6 +58,20 @@ fun Date.getDayNumber() : String {
fun Date.getShortDayName() : String { fun Date.getShortDayName() : String {
return SimpleDateFormat("EE", Locale.getDefault()).format(this) return SimpleDateFormat("EE", Locale.getDefault()).format(this)
} }
// Return the duration between two dates
fun Date.getDuration(context: Context, toDate: Date) : String {
val difference = (toDate.time - this.time).toInt()
val numOfDays = (difference / (1000 * 60 * 60 * 24))
val hours = (difference / (1000 * 60 * 60))
val minutes = (difference / (1000 * 60)) % 60
val seconds = (difference / 1000) % 60
val hoursStr = if (hours < 10) "0$hours" else "$hours"
val minutesStr = if (minutes < 10) "0$minutes" else "$minutes"
val secondsStr = if (seconds < 10) "0$seconds" else "$seconds"
return "$hoursStr:$minutesStr:$secondsStr"
}
// Toast // Toast

@ -1,21 +0,0 @@
package net.pokeranalytics.android.util.data
import androidx.lifecycle.LiveData
import io.realm.RealmChangeListener
import io.realm.RealmModel
import io.realm.RealmResults
class LiveRealmData<T : RealmModel>(private val results: RealmResults<T>) : LiveData<RealmResults<T>>() {
private val listener = RealmChangeListener<RealmResults<T>> { results -> value = results }
override fun onActive() {
results.addChangeListener(listener)
value = results
}
override fun onInactive() {
results.removeChangeListener(listener)
}
}

@ -1,11 +0,0 @@
@file:JvmName("RealmUtils") // pretty name for utils class if called from
package net.pokeranalytics.android.util.data
import io.realm.Realm
import io.realm.RealmModel
import io.realm.RealmResults
import net.pokeranalytics.android.model.realm.SessionDao
fun Realm.sessionDao(): SessionDao = SessionDao(this)
fun <T:RealmModel> RealmResults<T>.asLiveData() = LiveRealmData(this)

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="@color/colorAccent" android:state_checked="true" />
<item android:color="@android:color/transparent" />
</selector>

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<font-family xmlns:app="http://schemas.android.com/apk/res-auto"
app:fontProviderAuthority="com.google.android.gms.fonts"
app:fontProviderPackage="com.google.android.gms"
app:fontProviderQuery="name=Roboto&amp;weight=500"
app:fontProviderCerts="@array/com_google_android_gms_fonts_certs">
</font-family>

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<font-family xmlns:app="http://schemas.android.com/apk/res-auto"
app:fontProviderAuthority="com.google.android.gms.fonts"
app:fontProviderPackage="com.google.android.gms"
app:fontProviderQuery="name=Roboto Mono&amp;weight=500"
app:fontProviderCerts="@array/com_google_android_gms_fonts_certs">
</font-family>

@ -2,16 +2,62 @@
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="240dp"
android:orientation="horizontal"> android:orientation="horizontal">
<androidx.recyclerview.widget.RecyclerView <FrameLayout
android:id="@+id/recyclerView1" android:id="@+id/chips"
android:layout_width="80dp" android:layout_width="0dp"
android:paddingTop="8dp"
android:paddingBottom="8dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" /> app:layout_constraintTop_toTopOf="parent">
<com.google.android.material.chip.ChipGroup
android:id="@+id/chipGroup"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:orientation="horizontal"
app:chipSpacingHorizontal="16dp"
app:singleSelection="true">
<!--
<com.google.android.material.chip.Chip
android:id="@+id/chip1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="NL" />
<com.google.android.material.chip.Chip
android:id="@+id/chip2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="PL" />
<com.google.android.material.chip.Chip
android:id="@+id/chip3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="FL" />
<com.google.android.material.chip.Chip
android:id="@+id/chip4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="SL" />
<com.google.android.material.chip.Chip
android:id="@+id/chip5"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="ML" />
-->
</com.google.android.material.chip.ChipGroup>
</FrameLayout>
<androidx.recyclerview.widget.RecyclerView <androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerView2" android:id="@+id/recyclerView2"
@ -19,7 +65,7 @@
android:layout_height="0dp" android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/recyclerView1" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" /> app:layout_constraintTop_toBottomOf="@+id/chips" />
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>

@ -6,10 +6,11 @@
android:layout_height="match_parent"> android:layout_height="match_parent">
<androidx.core.widget.NestedScrollView <androidx.core.widget.NestedScrollView
android:id="@+id/nestedScrollView"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:fillViewport="true" android:fillViewport="true"
app:layout_behavior="@string/appbar_scrolling_view_behavior" android:id="@+id/nestedScrollView"> app:layout_behavior="@string/appbar_scrolling_view_behavior">
<androidx.constraintlayout.widget.ConstraintLayout <androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent" android:layout_width="match_parent"
@ -38,37 +39,23 @@
android:id="@+id/collapsingToolbar" android:id="@+id/collapsingToolbar"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
app:collapsedTitleTextAppearance="@style/PokerAnalyticsTheme.Toolbar.CollapsedTitleAppearance"
app:contentScrim="?attr/colorPrimary" app:contentScrim="?attr/colorPrimary"
app:expandedTitleGravity="bottom" app:expandedTitleGravity="bottom"
app:expandedTitleMarginStart="72dp" app:expandedTitleMarginStart="72dp"
app:expandedTitleTextAppearance="@style/PokerAnalyticsTheme.Toolbar.ExpandedTitleAppearance" app:expandedTitleTextAppearance="@style/PokerAnalyticsTheme.Toolbar.ExpandedTitleAppearance"
app:collapsedTitleTextAppearance="@style/PokerAnalyticsTheme.Toolbar.CollapsedTitleAppearance"
app:layout_scrollFlags="scroll|exitUntilCollapsed|snap"> app:layout_scrollFlags="scroll|exitUntilCollapsed|snap">
<androidx.appcompat.widget.Toolbar <androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar" android:id="@+id/toolbar"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize" android:layout_height="?attr/actionBarSize"
app:layout_collapseMode="pin"
app:title="Poker Analytics" app:title="Poker Analytics"
app:titleTextColor="@color/white" app:titleTextColor="@color/white" />
app:layout_collapseMode="pin"/>
</com.google.android.material.appbar.CollapsingToolbarLayout> </com.google.android.material.appbar.CollapsingToolbarLayout>
</com.google.android.material.appbar.AppBarLayout> </com.google.android.material.appbar.AppBarLayout>
<Button
tools:text="Save"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/saveButton"
app:layout_anchorGravity="right|top"
app:layout_anchor="@+id/appBar"/>
<Button
tools:text="Delete"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/deleteButton"
app:layout_anchorGravity="bottom|right"
app:layout_anchor="@+id/nestedScrollView"/>
</androidx.coordinatorlayout.widget.CoordinatorLayout> </androidx.coordinatorlayout.widget.CoordinatorLayout>

@ -15,16 +15,99 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content"> android:layout_height="wrap_content">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/sessionData"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/gray_darker"
android:elevation="4dp"
android:translationY="-72dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:translationY="0dp">
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/sinceTitle"
style="@style/PokerAnalyticsTheme.TextView.RowTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginBottom="16dp"
android:text="Since"
android:textAllCaps="true"
android:textSize="12sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/sinceValue"
style="@style/PokerAnalyticsTheme.TextView.RowTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginBottom="16dp"
android:text="-"
android:textSize="24sp"
app:fontFamily="@font/roboto_bold"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/sinceTitle" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/resultTitle"
style="@style/PokerAnalyticsTheme.TextView.RowTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:layout_marginBottom="16dp"
android:text="Result"
android:textAllCaps="true"
android:textSize="12sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/appCompatTextView"
style="@style/PokerAnalyticsTheme.TextView.RowTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="16dp"
android:layout_marginBottom="16dp"
android:text="-"
android:textColor="@color/green"
android:textSize="28sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@+id/resultTitle" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/state"
style="@style/PokerAnalyticsTheme.TextView.RowTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="PLAYING"
android:textColor="@color/colorAccent"
android:textSize="12sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
<androidx.recyclerview.widget.RecyclerView <androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerView" android:id="@+id/recyclerView"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="0dp" android:layout_height="0dp"
android:paddingBottom="96dp"
android:clipToPadding="false" android:clipToPadding="false"
android:paddingBottom="96dp"
android:translationY="-72dp"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" /> app:layout_constraintTop_toBottomOf="@+id/sessionData"
tools:translationY="0dp" />
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>
@ -55,6 +138,7 @@
app:titleTextColor="@color/white" app:titleTextColor="@color/white"
tools:title="Poker Analytics" /> tools:title="Poker Analytics" />
</com.google.android.material.appbar.CollapsingToolbarLayout> </com.google.android.material.appbar.CollapsingToolbarLayout>
</com.google.android.material.appbar.AppBarLayout> </com.google.android.material.appbar.AppBarLayout>
@ -63,10 +147,10 @@
android:id="@+id/bottomAppBar" android:id="@+id/bottomAppBar"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
app:fabAlignmentMode="center" android:layout_gravity="bottom"
android:background="@color/red" android:background="@color/red"
android:theme="@style/PokerAnalyticsTheme.BottomAppBar" android:theme="@style/PokerAnalyticsTheme.BottomAppBar"
android:layout_gravity="bottom" /> app:fabAlignmentMode="center" />
<com.google.android.material.floatingactionbutton.FloatingActionButton <com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/floatingActionButton" android:id="@+id/floatingActionButton"

@ -9,10 +9,12 @@
<androidx.appcompat.widget.AppCompatTextView <androidx.appcompat.widget.AppCompatTextView
android:id="@+id/dateDay" android:id="@+id/dateDay"
style="@style/PokerAnalyticsTheme.TextView.SessionRow.Date" style="@style/PokerAnalyticsTheme.TextView.SessionRow.Date"
android:layout_width="wrap_content" android:layout_width="32dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="8dp" android:layout_marginTop="8dp"
android:gravity="center"
android:textAllCaps="true" android:textAllCaps="true"
app:fontFamily="@font/roboto_mono_medium"
app:layout_constraintBottom_toTopOf="@+id/dateNumber" app:layout_constraintBottom_toTopOf="@+id/dateNumber"
app:layout_constraintStart_toStartOf="@+id/guidelineStart" app:layout_constraintStart_toStartOf="@+id/guidelineStart"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent"
@ -22,9 +24,10 @@
<androidx.appcompat.widget.AppCompatTextView <androidx.appcompat.widget.AppCompatTextView
android:id="@+id/dateNumber" android:id="@+id/dateNumber"
style="@style/PokerAnalyticsTheme.TextView.SessionRow.DateNumber" style="@style/PokerAnalyticsTheme.TextView.SessionRow.DateNumber"
android:layout_width="wrap_content" android:layout_width="32dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginBottom="8dp" android:layout_marginBottom="8dp"
android:gravity="center"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="@+id/dateDay" app:layout_constraintEnd_toEndOf="@+id/dateDay"
app:layout_constraintHorizontal_bias="0.5" app:layout_constraintHorizontal_bias="0.5"

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/delete"
android:icon="@drawable/ic_outline_delete"
android:title="@string/delete"
app:showAsAction="ifRoom" />
<item
android:id="@+id/save"
android:title="@string/save"
android:icon="@drawable/ic_check"
app:showAsAction="ifRoom" />
</menu>

@ -5,5 +5,7 @@
<item>@font/roboto_black</item> <item>@font/roboto_black</item>
<item>@font/roboto_bold</item> <item>@font/roboto_bold</item>
<item>@font/roboto_light</item> <item>@font/roboto_light</item>
<item>@font/roboto_medium</item>
<item>@font/roboto_mono_medium</item>
</array> </array>
</resources> </resources>

@ -2,7 +2,7 @@
<!-- PokerAnalytics application theme --> <!-- PokerAnalytics application theme -->
<style name="PokerAnalyticsTheme" parent="Theme.MaterialComponents.Light.NoActionBar"> <style name="PokerAnalyticsTheme" parent="Theme.MaterialComponents.Light.NoActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">@color/colorPrimary</item> <item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item> <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item> <item name="colorAccent">@color/colorAccent</item>
@ -14,7 +14,8 @@
<item name="bottomAppBarStyle">@style/PokerAnalyticsTheme.BottomAppBar</item> <item name="bottomAppBarStyle">@style/PokerAnalyticsTheme.BottomAppBar</item>
<item name="editTextStyle">@style/PokerAnalyticsTheme.EditText</item> <item name="editTextStyle">@style/PokerAnalyticsTheme.EditText</item>
<item name="android:textViewStyle">@style/PokerAnalyticsTheme.TextView</item> <item name="android:textViewStyle">@style/PokerAnalyticsTheme.TextView</item>
<item name="alertDialogTheme">@style/PokerAnalyticsTheme.AlertDialog</item>
<item name="chipStyle">@style/PokerAnalyticsTheme.Chip</item>
</style> </style>
@ -105,24 +106,29 @@
<item name="android:maxLines">1</item> <item name="android:maxLines">1</item>
<item name="android:ellipsize">end</item> <item name="android:ellipsize">end</item>
</style> </style>
<style name="PokerAnalyticsTheme.TextView.SessionRow.Date"> <style name="PokerAnalyticsTheme.TextView.SessionRow.Date">
<item name="android:textSize">12sp</item> <item name="android:textSize">12sp</item>
<item name="android:fontFamily">@font/roboto</item>r <item name="android:fontFamily">@font/roboto</item>
</style> </style>
<style name="PokerAnalyticsTheme.TextView.SessionRow.DateNumber"> <style name="PokerAnalyticsTheme.TextView.SessionRow.DateNumber">
<item name="android:textSize">18sp</item> <item name="android:textSize">18sp</item>
<item name="android:fontFamily">@font/roboto_black</item> <item name="android:fontFamily">@font/roboto_black</item>
<item name="android:letterSpacing">0.05</item> <item name="android:letterSpacing">0.05</item>
</style> </style>
<style name="PokerAnalyticsTheme.TextView.SessionRow.Title"> <style name="PokerAnalyticsTheme.TextView.SessionRow.Title">
<item name="android:textSize">16sp</item> <item name="android:textSize">16sp</item>
<item name="android:fontFamily">@font/roboto</item> <item name="android:fontFamily">@font/roboto</item>
</style> </style>
<style name="PokerAnalyticsTheme.TextView.SessionRow.Subtitle"> <style name="PokerAnalyticsTheme.TextView.SessionRow.Subtitle">
<item name="android:textSize">12sp</item> <item name="android:textSize">12sp</item>
<item name="android:fontFamily">@font/roboto</item> <item name="android:fontFamily">@font/roboto</item>
<item name="android:textColor">@color/kaki_lighter</item> <item name="android:textColor">@color/kaki_lighter</item>
</style> </style>
<style name="PokerAnalyticsTheme.TextView.SessionRow.Result"> <style name="PokerAnalyticsTheme.TextView.SessionRow.Result">
<item name="android:textSize">20sp</item> <item name="android:textSize">20sp</item>
<item name="android:fontFamily">@font/roboto_light</item> <item name="android:fontFamily">@font/roboto_light</item>
@ -130,8 +136,15 @@
</style> </style>
<!-- EditText --> <!-- Alert Dialog -->
<style name="PokerAnalyticsTheme.AlertDialog" parent="Theme.MaterialComponents.Dialog">
<item name="colorAccent">@color/green</item>
<item name="android:textColorPrimary">@color/white</item>
<item name="android:background">@color/gray_dark</item>
</style>
<!-- EditText -->
<style name="PokerAnalyticsTheme.EditText" parent="Widget.AppCompat.EditText"> <style name="PokerAnalyticsTheme.EditText" parent="Widget.AppCompat.EditText">
<item name="android:textColor">@color/white</item> <item name="android:textColor">@color/white</item>
<item name="android:fontFamily">@font/roboto</item> <item name="android:fontFamily">@font/roboto</item>
@ -147,5 +160,13 @@
<item name="android:fontFamily">@font/roboto_bold</item> <item name="android:fontFamily">@font/roboto_bold</item>
</style> </style>
<!-- Chip -->
<style name="PokerAnalyticsTheme.Chip" parent="Widget.MaterialComponents.Chip.Choice">
<item name="chipBackgroundColor">@color/chips_background_states</item>
<item name="android:textColor">@color/white</item>
<item name="chipStrokeColor">@color/colorAccent</item>
<item name="chipStrokeWidth">1dp</item>
</style>
</resources> </resources>

Loading…
Cancel
Save