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

dev_raz_wip
Laurent 7 years ago
commit a51c01344e
  1. 46
      app/src/main/java/net/pokeranalytics/android/model/LiveData.kt
  2. 40
      app/src/main/java/net/pokeranalytics/android/model/extensions/SessionExtensions.kt
  3. 3
      app/src/main/java/net/pokeranalytics/android/model/realm/Bankroll.kt
  4. 10
      app/src/main/java/net/pokeranalytics/android/model/realm/Game.kt
  5. 96
      app/src/main/java/net/pokeranalytics/android/model/realm/Session.kt
  6. 10
      app/src/main/java/net/pokeranalytics/android/model/realm/TimeFrame.kt
  7. 13
      app/src/main/java/net/pokeranalytics/android/ui/activity/SessionActivity.kt
  8. 8
      app/src/main/java/net/pokeranalytics/android/ui/adapter/components/RowRepresentableAdapter.kt
  9. 48
      app/src/main/java/net/pokeranalytics/android/ui/fragment/EditableDataFragment.kt
  10. 111
      app/src/main/java/net/pokeranalytics/android/ui/fragment/SessionFragment.kt
  11. 143
      app/src/main/java/net/pokeranalytics/android/ui/view/RowRepresentable.kt
  12. 14
      app/src/main/java/net/pokeranalytics/android/util/Extensions.kt
  13. 0
      app/src/main/res/drawable/ic_add.xml
  14. 0
      app/src/main/res/drawable/ic_check.xml
  15. 0
      app/src/main/res/drawable/ic_close.xml
  16. 0
      app/src/main/res/drawable/ic_close_black.xml
  17. 9
      app/src/main/res/drawable/ic_dashboard_black_24dp.xml
  18. 5
      app/src/main/res/drawable/ic_delete_white_24dp.xml
  19. 9
      app/src/main/res/drawable/ic_home_black_24dp.xml
  20. 2
      app/src/main/res/drawable/ic_notifications.xml
  21. 2
      app/src/main/res/drawable/ic_outline_chart_bar.xml
  22. 2
      app/src/main/res/drawable/ic_outline_chart_show.xml
  23. 9
      app/src/main/res/drawable/ic_outline_delete.xml
  24. 2
      app/src/main/res/drawable/ic_outline_filter_list.xml
  25. 2
      app/src/main/res/drawable/ic_outline_history.xml
  26. 2
      app/src/main/res/drawable/ic_outline_pause.xml
  27. 2
      app/src/main/res/drawable/ic_outline_play.xml
  28. 9
      app/src/main/res/drawable/ic_outline_restart.xml
  29. 2
      app/src/main/res/drawable/ic_outline_settings.xml
  30. 2
      app/src/main/res/drawable/ic_outline_sort.xml
  31. 2
      app/src/main/res/drawable/ic_outline_stop.xml
  32. 2
      app/src/main/res/layout/fragment_data_list.xml
  33. 20
      app/src/main/res/layout/fragment_editable_data.xml
  34. 26
      app/src/main/res/layout/fragment_session.xml
  35. 42
      app/src/main/res/layout/row_session_view.xml
  36. 8
      app/src/main/res/layout/row_title_value.xml
  37. 2
      app/src/main/res/layout/row_title_value_action.xml
  38. 6
      app/src/main/res/menu/bottom_sheet_menu.xml
  39. 10
      app/src/main/res/menu/session_bottom_app_bar.xml
  40. 17
      app/src/main/res/menu/session_toolbar.xml
  41. 2
      app/src/main/res/values/strings.xml
  42. 17
      app/src/main/res/values/styles.xml

@ -4,14 +4,25 @@ import io.realm.Realm
import io.realm.RealmObject import io.realm.RealmObject
import io.realm.RealmResults import io.realm.RealmResults
import io.realm.Sort import io.realm.Sort
import net.pokeranalytics.android.R
import net.pokeranalytics.android.model.realm.* import net.pokeranalytics.android.model.realm.*
import java.util.* import net.pokeranalytics.android.ui.view.Localizable
enum class LiveData { /**
* An interface to easily handle the validity of any object we want to save
*/
interface ObjectSavable {
fun isValidForSave(): Boolean { return true }
}
/**
* An enum managing the business objects related to a realm results
*/
enum class LiveData : Localizable {
BANKROLL, BANKROLL,
GAME, GAME,
LOCATION, LOCATION,
TOURNAMENT_TYPE, TOURNAMENT_FEATURE,
TRANSACTION_TYPE; TRANSACTION_TYPE;
fun items(realm: Realm, fieldName: String? = null, sortOrder: Sort? = null): RealmResults<*> { fun items(realm: Realm, fieldName: String? = null, sortOrder: Sort? = null): RealmResults<*> {
@ -28,11 +39,21 @@ enum class LiveData {
BANKROLL -> Bankroll::class.java BANKROLL -> Bankroll::class.java
GAME -> Game::class.java GAME -> Game::class.java
LOCATION -> Location::class.java LOCATION -> Location::class.java
TOURNAMENT_TYPE -> TournamentFeature::class.java TOURNAMENT_FEATURE -> TournamentFeature::class.java
TRANSACTION_TYPE -> TransactionType::class.java TRANSACTION_TYPE -> TransactionType::class.java
} }
} }
fun newEntity(): RealmObject {
return when (this) {
BANKROLL -> Bankroll()
GAME -> Game()
LOCATION -> Location()
TOURNAMENT_FEATURE -> TournamentFeature()
TRANSACTION_TYPE -> TransactionType()
}
}
fun getData(realm:Realm, primaryKey:String?): RealmObject? { fun getData(realm:Realm, primaryKey:String?): RealmObject? {
var proxyItem: RealmObject? = null var proxyItem: RealmObject? = null
primaryKey?.let { primaryKey?.let {
@ -49,13 +70,24 @@ enum class LiveData {
proxyItem?.let { proxyItem?.let {
return realm.copyFromRealm(it) return realm.copyFromRealm(it)
} ?: run { } ?: run {
realm.beginTransaction() return this.newEntity()
/* realm.beginTransaction()
val t = realm.createObject(this.relatedEntity, UUID.randomUUID().toString()) val t = realm.createObject(this.relatedEntity, UUID.randomUUID().toString())
realm.commitTransaction() realm.commitTransaction()
return realm.copyFromRealm(t) return realm.copyFromRealm(t)*/
} }
} }
}
override val resId: Int?
get() {
return when (this) {
BANKROLL -> R.string.bankroll
GAME -> R.string.game
LOCATION -> R.string.location
TOURNAMENT_FEATURE -> R.string.tournament_type
TRANSACTION_TYPE -> R.string.operation_types
}
}}
/* /*
interface ListableDataSource { interface ListableDataSource {

@ -0,0 +1,40 @@
package net.pokeranalytics.android.model.extensions
import net.pokeranalytics.android.model.realm.Session
import java.util.*
enum class SessionState {
PENDING,
STARTED,
PAUSED,
FINISHED,
INVALID;
}
/**
* Return the current state of a session
* For example: STARTED, PAUSED, FINISHED
*/
fun Session.getState(): SessionState {
if (timeFrame == null) {
return SessionState.PENDING
}
val endDate = timeFrame?.endDate
timeFrame?.let {sessionTimeFrame ->
timeFrame?.startDate?.let {startDate ->
if (startDate > Date()) {
return SessionState.PENDING
} else if (endDate != null) {
return SessionState.FINISHED
} else if (sessionTimeFrame.paused) {
return SessionState.PAUSED
} else {
return SessionState.STARTED
}
}
}
return SessionState.INVALID
}

@ -4,6 +4,7 @@ import android.text.InputType
import io.realm.RealmList import io.realm.RealmList
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.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
@ -15,7 +16,7 @@ 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, LiveDataDataSource,
RowEditable { RowEditable, ObjectSavable {
companion object { companion object {
fun newInstance() : Bankroll { fun newInstance() : Bankroll {

@ -3,6 +3,7 @@ package net.pokeranalytics.android.model.realm
import android.text.InputType 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.ui.adapter.components.* import net.pokeranalytics.android.ui.adapter.components.*
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
@ -11,7 +12,7 @@ import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.SimpleRow import net.pokeranalytics.android.ui.view.SimpleRow
import java.util.* import java.util.*
open class Game : RealmObject(), RowRepresentableDataSource, LiveDataDataSource, RowEditable { open class Game : RealmObject(), RowRepresentableDataSource, LiveDataDataSource, RowEditable, ObjectSavable {
@PrimaryKey @PrimaryKey
var id = UUID.randomUUID().toString() var id = UUID.randomUUID().toString()
@ -35,6 +36,7 @@ open class Game : RealmObject(), RowRepresentableDataSource, LiveDataDataSource,
override fun stringForRow(row: RowRepresentable): String { override fun stringForRow(row: RowRepresentable): String {
return when (row) { return when (row) {
SimpleRow.NAME -> this.name SimpleRow.NAME -> this.name
GameRow.SHORT_NAME -> this.shortName?:""
else -> return super.stringForRow(row) else -> return super.stringForRow(row)
} }
} }
@ -43,6 +45,7 @@ open class Game : RealmObject(), RowRepresentableDataSource, LiveDataDataSource,
val data = java.util.ArrayList<BottomSheetData>() val data = java.util.ArrayList<BottomSheetData>()
when (row) { when (row) {
SimpleRow.NAME -> data.add(BottomSheetData(this.name, SimpleRow.NAME.resId, InputType.TYPE_CLASS_TEXT)) SimpleRow.NAME -> data.add(BottomSheetData(this.name, SimpleRow.NAME.resId, InputType.TYPE_CLASS_TEXT))
GameRow.SHORT_NAME -> data.add(BottomSheetData(this.shortName, GameRow.SHORT_NAME.resId, InputType.TYPE_CLASS_TEXT))
} }
return data return data
} }
@ -50,6 +53,11 @@ open class Game : RealmObject(), RowRepresentableDataSource, LiveDataDataSource,
override fun updateValue(value: Any?, row: RowRepresentable) { override fun updateValue(value: Any?, row: RowRepresentable) {
when (row) { when (row) {
SimpleRow.NAME -> this.name = value as String? ?: "" SimpleRow.NAME -> this.name = value as String? ?: ""
GameRow.SHORT_NAME -> this.shortName = value as String
} }
} }
override fun isValidForSave(): Boolean {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
} }

@ -7,6 +7,8 @@ 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.LiveData import net.pokeranalytics.android.model.LiveData
import net.pokeranalytics.android.model.extensions.SessionState
import net.pokeranalytics.android.model.extensions.getState
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
@ -88,15 +90,70 @@ open class Session : RealmObject(), SessionInterface, RowRepresentableDataSource
// The features of the tournament, like Knockout, Shootout, Turbo... // The features of the tournament, like Knockout, Shootout, Turbo...
var tournamentFeatures: RealmList<TournamentFeature> = RealmList() var tournamentFeatures: RealmList<TournamentFeature> = RealmList()
companion object { /**
* Start a session
*/
fun startSession() {
realm.executeTransaction {
when (getState()) {
SessionState.PENDING -> {
val sessionTimeFrame = this.timeFrame ?: realm.createObject(TimeFrame::class.java)
sessionTimeFrame.setDate(Date(), null)
this.timeFrame = sessionTimeFrame
}
SessionState.PAUSED -> {
this.timeFrame?.paused = false
}
else -> {
}
}
}
}
/**
* Pause a session
*/
fun pauseSession() {
realm.executeTransaction {
when (getState()) {
SessionState.STARTED -> {
this.timeFrame?.paused = true
}
}
}
}
/**
* Stop a session
*/
fun stopSession() {
realm.executeTransaction {
when (getState()) {
SessionState.STARTED, SessionState.PAUSED -> {
this.timeFrame?.paused = false
this.timeFrame?.setDate(null, Date())
}
}
}
}
/**
* Delete the object from realm
* TODO: Cascade delete?
*/
fun delete() {
realm.executeTransaction {
deleteFromRealm()
}
}
companion object {
fun newInstance(): Session { fun newInstance(): Session {
var session: Session = Session() var session: Session = Session()
session.result = Result() session.result = Result()
session.timeFrame = TimeFrame() session.timeFrame = TimeFrame()
return session return session
} }
} }
@Ignore // SessionInterface value @Ignore // SessionInterface value
@ -161,7 +218,7 @@ open class Session : RealmObject(), SessionInterface, RowRepresentableDataSource
override fun adapterRows(): ArrayList<RowRepresentable> { override fun adapterRows(): ArrayList<RowRepresentable> {
val rows = ArrayList<RowRepresentable>() val rows = ArrayList<RowRepresentable>()
rows.addAll(SessionRow.values()) rows.addAll(SessionRow.getRowsForState(getState()))
return rows return rows
} }
@ -185,7 +242,7 @@ open class Session : RealmObject(), SessionInterface, RowRepresentableDataSource
override fun actionIconForRow(row: RowRepresentable): Int? { override fun actionIconForRow(row: RowRepresentable): Int? {
return when (row) { return when (row) {
SessionRow.START_DATE, SessionRow.END_DATE -> { SessionRow.START_DATE, SessionRow.END_DATE -> {
R.drawable.ic_close_white_24dp R.drawable.ic_close
} }
else -> null else -> null
} }
@ -204,10 +261,22 @@ open class Session : RealmObject(), SessionInterface, RowRepresentableDataSource
data.add(BottomSheetData(game, inputType = InputType.TYPE_NULL, data = LiveData.GAME.items(realm))) data.add(BottomSheetData(game, inputType = InputType.TYPE_NULL, data = LiveData.GAME.items(realm)))
} }
SessionRow.LOCATION -> { SessionRow.LOCATION -> {
data.add(BottomSheetData(location, inputType = InputType.TYPE_NULL, data = LiveData.LOCATION.items(realm))) data.add(
BottomSheetData(
location,
inputType = InputType.TYPE_NULL,
data = LiveData.LOCATION.items(realm)
)
)
} }
SessionRow.BANKROLL -> { SessionRow.BANKROLL -> {
data.add(BottomSheetData(bankroll, inputType = InputType.TYPE_NULL, data = LiveData.BANKROLL.items(realm))) data.add(
BottomSheetData(
bankroll,
inputType = InputType.TYPE_NULL,
data = LiveData.BANKROLL.items(realm)
)
)
} }
SessionRow.BLINDS -> { SessionRow.BLINDS -> {
data.add(BottomSheetData(cgSmallBlind, R.string.smallblind, InputType.TYPE_CLASS_NUMBER)) data.add(BottomSheetData(cgSmallBlind, R.string.smallblind, InputType.TYPE_CLASS_NUMBER))
@ -223,14 +292,22 @@ 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.GAME -> game = value as Game? SessionRow.GAME -> game = value as Game?
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? ?: ""
SessionRow.BLINDS -> if (value is ArrayList<*>) { SessionRow.BLINDS -> if (value is ArrayList<*>) {
cgSmallBlind = try {(value[0] as String? ?: "0").toDouble()} catch (e:Exception) {null} cgSmallBlind = try {
cgBigBlind = try {(value[1] as String? ?: "0").toDouble()} catch (e:Exception) {null} (value[0] as String? ?: "0").toDouble()
} catch (e: Exception) {
null
}
cgBigBlind = try {
(value[1] as String? ?: "0").toDouble()
} catch (e: Exception) {
null
}
} }
//TODO: Update //TODO: Update
SessionRow.START_DATE -> if (value is Date) { SessionRow.START_DATE -> if (value is Date) {
@ -251,6 +328,7 @@ open class Session : RealmObject(), SessionInterface, RowRepresentableDataSource
} }
realm.commitTransaction() realm.commitTransaction()
} }
} }
enum class TournamentKind { enum class TournamentKind {

@ -51,7 +51,7 @@ open class TimeFrame : RealmObject() {
@Ignore @Ignore
var session: Session? = null var session: Session? = null
get() = this.sessions?.first() //get() = this.sessions?.first() ?: null
// Group // Group
@LinkingObjects("timeFrame") @LinkingObjects("timeFrame")
@ -61,8 +61,12 @@ open class TimeFrame : RealmObject() {
var set: SessionSet? = null var set: SessionSet? = null
get() = this.sets?.first() get() = this.sets?.first()
fun setDate(startDate: Date, endDate: Date?) { fun setDate(startDate: Date?, endDate: Date?) {
this.startDate = startDate
startDate?.let {
this.startDate = startDate
}
this.endDate = endDate this.endDate = endDate
this.computeDuration() this.computeDuration()

@ -10,16 +10,21 @@ import net.pokeranalytics.android.ui.fragment.SessionFragment
class SessionActivity: PokerAnalyticsActivity() { class SessionActivity: PokerAnalyticsActivity() {
enum class IntentKey(val keyName : String) {
IS_TOURNAMENT("IS_TOURNAMENT"),
SESSION_ID("SESSION_ID");
}
companion object { companion object {
fun newInstance(context: Context, isTournament: Boolean? = false, sessionId: String? = "") { fun newInstance(context: Context, isTournament: Boolean? = false, sessionId: String? = "") {
val intent = Intent(context, SessionActivity::class.java) val intent = Intent(context, SessionActivity::class.java)
isTournament?.let { isTournament?.let {
intent.putExtra("is_tournament", isTournament) intent.putExtra(IntentKey.IS_TOURNAMENT.keyName, isTournament)
} }
sessionId?.let { sessionId?.let {
intent.putExtra("session_id", sessionId) intent.putExtra(IntentKey.SESSION_ID.keyName, sessionId)
} }
context.startActivity(intent) context.startActivity(intent)
@ -38,8 +43,8 @@ class SessionActivity: PokerAnalyticsActivity() {
* Init UI * Init UI
*/ */
private fun initUI() { private fun initUI() {
val sessionId = intent.getStringExtra("session_id") val sessionId = intent.getStringExtra(IntentKey.SESSION_ID.keyName)
val isTournament = intent.getBooleanExtra("is_tournament", false) val isTournament = intent.getBooleanExtra(IntentKey.IS_TOURNAMENT.keyName, false)
val fragment = newSessionFragment as SessionFragment val fragment = newSessionFragment as SessionFragment
fragment.setData(isTournament, sessionId) fragment.setData(isTournament, sessionId)
} }

@ -111,4 +111,12 @@ class RowRepresentableAdapter(var rowRepresentableDataSource: RowRepresentableDa
} }
} }
/**
* Refresh all adapter rows
*/
fun refreshAllRows() {
this.rows = rowRepresentableDataSource.adapterRows()
notifyDataSetChanged()
}
} }

@ -1,17 +1,19 @@
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.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.Toast import android.widget.Toast
import androidx.appcompat.app.AlertDialog
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import io.realm.Realm
import io.realm.RealmObject import io.realm.RealmObject
import kotlinx.android.synthetic.main.fragment_editable_data.* import kotlinx.android.synthetic.main.fragment_editable_data.*
import kotlinx.android.synthetic.main.fragment_editable_data.view.* import kotlinx.android.synthetic.main.fragment_editable_data.view.*
import net.pokeranalytics.android.R import net.pokeranalytics.android.R
import net.pokeranalytics.android.model.LiveData import net.pokeranalytics.android.model.LiveData
import net.pokeranalytics.android.model.ObjectSavable
import net.pokeranalytics.android.ui.activity.components.PokerAnalyticsActivity import net.pokeranalytics.android.ui.activity.components.PokerAnalyticsActivity
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
@ -78,26 +80,56 @@ 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 {
if ((this.item as ObjectSavable).isValidForSave()) {
this.getRealm().executeTransaction {
it.copyToRealmOrUpdate(this.item)
}
this.activity?.let {
it.finish()
}
} else {
val builder = AlertDialog.Builder(it.context)
builder.setTitle(R.string.warning)
.setNegativeButton(R.string.ok, null)
builder.show()
}
}
this.deleteButton.text = this.deleteButton.context.getString(R.string.delete)
this.deleteButton.setOnClickListener {
val builder = AlertDialog.Builder(it.context)
builder.setTitle(R.string.warning)
.setMessage(R.string.are_you_sure_you_want_to_do_that_)
.setNeutralButton(R.string.no, null)
.setNegativeButton(R.string.yes, DialogInterface.OnClickListener { dialog, id ->
this.getRealm().executeTransaction {
this.item.deleteFromRealm()
}
this.activity?.let {
it.finish()
}
})
builder.show()
}
} }
/** /**
* Set fragment data * Set fragment data
*/ */
fun setData(dataType: Int, primaryKey: String?) { fun setData(dataType: Int, primaryKey: String?) {
this.liveDataType = LiveData.values()[dataType] this.liveDataType = LiveData.values()[dataType]
val realm = Realm.getDefaultInstance() var proxyItem : RealmObject? = this.liveDataType.getData(this.getRealm(), primaryKey)
var proxyItem : RealmObject? = this.liveDataType.getData(realm, primaryKey)
proxyItem?.let { proxyItem?.let {
this.appBar.toolbar.title = "Update ${this.liveDataType.name.toLowerCase().capitalize()}" this.appBar.toolbar.title = "Update ${this.liveDataType.name.toLowerCase().capitalize()}"
} ?: run { } ?: run {
this.appBar.toolbar.title = "New ${this.liveDataType.name.toLowerCase().capitalize()}" this.appBar.toolbar.title = "New ${this.liveDataType.name.toLowerCase().capitalize()}"
} }
this.item = this.liveDataType.updateOrCreate(this.getRealm(), primaryKey)
this.item = this.liveDataType.updateOrCreate(realm, primaryKey)
this.rowRepresentableAdapter = RowRepresentableAdapter((this.item as RowRepresentableDataSource), this) this.rowRepresentableAdapter = RowRepresentableAdapter((this.item as RowRepresentableDataSource), this)
this.recyclerView.adapter = rowRepresentableAdapter this.recyclerView.adapter = rowRepresentableAdapter
} }
} }

@ -1,15 +1,16 @@
package net.pokeranalytics.android.ui.fragment package net.pokeranalytics.android.ui.fragment
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.interpolator.view.animation.FastOutSlowInInterpolator
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import io.realm.kotlin.where import io.realm.kotlin.where
import kotlinx.android.synthetic.main.fragment_new_session.* import kotlinx.android.synthetic.main.fragment_session.*
import net.pokeranalytics.android.R import net.pokeranalytics.android.R
import net.pokeranalytics.android.model.LiveData import net.pokeranalytics.android.model.LiveData
import net.pokeranalytics.android.model.extensions.SessionState
import net.pokeranalytics.android.model.extensions.getState
import net.pokeranalytics.android.model.realm.Session import net.pokeranalytics.android.model.realm.Session
import net.pokeranalytics.android.ui.activity.EditableDataActivity import net.pokeranalytics.android.ui.activity.EditableDataActivity
import net.pokeranalytics.android.ui.activity.components.PokerAnalyticsActivity import net.pokeranalytics.android.ui.activity.components.PokerAnalyticsActivity
@ -21,15 +22,17 @@ import net.pokeranalytics.android.ui.fragment.components.bottomsheet.BottomSheet
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.SessionRow import net.pokeranalytics.android.ui.view.SessionRow
import net.pokeranalytics.android.util.toast
import timber.log.Timber
import java.util.* import java.util.*
class SessionFragment : PokerAnalyticsFragment(), RowRepresentableDelegate, BottomSheetDelegate { class SessionFragment : PokerAnalyticsFragment(), RowRepresentableDelegate, BottomSheetDelegate {
private lateinit var currentSession: Session private lateinit var currentSession: Session
private lateinit var sessionAdapter : RowRepresentableAdapter private lateinit var sessionAdapter: RowRepresentableAdapter
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_new_session, container, false) return inflater.inflate(R.layout.fragment_session, container, false)
} }
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
@ -37,6 +40,23 @@ class SessionFragment : PokerAnalyticsFragment(), RowRepresentableDelegate, Bott
initUI() initUI()
} }
override fun onCreateOptionsMenu(menu: Menu?, inflater: MenuInflater?) {
inflater?.inflate(R.menu.session_toolbar, menu)
super.onCreateOptionsMenu(menu, inflater)
}
override fun onOptionsItemSelected(item: MenuItem?): Boolean {
when (item!!.itemId) {
R.id.restart -> toast("Restard is clicked!")
R.id.delete -> {
currentSession.delete()
activity?.finish()
}
}
return true
}
override fun onRowSelected(row: RowRepresentable) { override fun onRowSelected(row: RowRepresentable) {
val data = currentSession.getBottomSheetData(row) val data = currentSession.getBottomSheetData(row)
when (row) { when (row) {
@ -84,8 +104,13 @@ class SessionFragment : PokerAnalyticsFragment(), RowRepresentableDelegate, Bott
private fun initUI() { private fun initUI() {
val activity = activity as PokerAnalyticsActivity val activity = activity as PokerAnalyticsActivity
// Avoid a bug during setting the title
toolbar.title = ""
activity.setSupportActionBar(toolbar) activity.setSupportActionBar(toolbar)
activity.supportActionBar?.setDisplayHomeAsUpEnabled(true) activity.supportActionBar?.setDisplayHomeAsUpEnabled(true)
setHasOptionsMenu(true)
val viewManager = LinearLayoutManager(requireContext()) val viewManager = LinearLayoutManager(requireContext())
@ -94,13 +119,83 @@ class SessionFragment : PokerAnalyticsFragment(), RowRepresentableDelegate, Bott
layoutManager = viewManager layoutManager = viewManager
} }
bottomAppBar.inflateMenu(R.menu.session_bottom_app_bar)
bottomAppBar.menu.findItem(R.id.stop).isVisible = false
bottomAppBar.setOnMenuItemClickListener { item ->
when (item.itemId) {
R.id.stop -> {
currentSession.stopSession()
updateSessionUI()
}
}
false
}
floatingActionButton.setExpanded(false)
floatingActionButton.setOnClickListener {
manageSessionState()
}
}
/**
* Update the UI with the session data
* Should be called after the initialization of the session
*/
private fun updateSessionUI() {
when (currentSession.getState()) {
SessionState.PENDING -> {
floatingActionButton.setImageResource(R.drawable.ic_outline_play)
bottomAppBar.menu.findItem(R.id.stop).isVisible = false
}
SessionState.STARTED -> {
floatingActionButton.setImageResource(R.drawable.ic_outline_pause)
bottomAppBar.menu.findItem(R.id.stop).isVisible = true
}
SessionState.PAUSED -> {
floatingActionButton.setImageResource(R.drawable.ic_outline_play)
bottomAppBar.menu.findItem(R.id.stop).isVisible = true
}
SessionState.FINISHED -> {
bottomAppBar.menu.findItem(R.id.stop).isVisible = false
floatingActionButton.animate()
.scaleX(0f)
.scaleY(0f)
.alpha(0f)
.setInterpolator(FastOutSlowInInterpolator())
.start()
}
}
sessionAdapter.refreshAllRows()
}
/**
* Update the state of the session (start / pause)
*/
private fun manageSessionState() {
when (currentSession.getState()) {
SessionState.PENDING -> {
currentSession.startSession()
}
SessionState.STARTED -> {
currentSession.pauseSession()
}
SessionState.PAUSED -> {
currentSession.startSession()
}
}
updateSessionUI()
} }
/** /**
* Set fragment data * Set fragment data
*/ */
fun setData(isTournament: Boolean, sessionId: String) { fun setData(isTournament: Boolean, sessionId: String) {
toolbar.title = if (isTournament) "Tournament" else "Cash game" toolbar.title = if (isTournament) getString(R.string.tournament) else getString(R.string.cash_game)
val realm = getRealm() val realm = getRealm()
val sessionRealm = realm.where<Session>().equalTo("id", sessionId).findFirst() val sessionRealm = realm.where<Session>().equalTo("id", sessionId).findFirst()
@ -115,6 +210,8 @@ class SessionFragment : PokerAnalyticsFragment(), RowRepresentableDelegate, Bott
sessionAdapter = RowRepresentableAdapter(currentSession, this) sessionAdapter = RowRepresentableAdapter(currentSession, this)
recyclerView.adapter = sessionAdapter recyclerView.adapter = sessionAdapter
updateSessionUI()
Timber.d("Session state: ${currentSession.getState()}")
} }
} }

@ -3,14 +3,13 @@ package net.pokeranalytics.android.ui.view
import android.content.Context import android.content.Context
import net.pokeranalytics.android.R import net.pokeranalytics.android.R
import net.pokeranalytics.android.model.LiveData import net.pokeranalytics.android.model.LiveData
import net.pokeranalytics.android.model.extensions.SessionState
import net.pokeranalytics.android.ui.fragment.components.bottomsheet.BottomSheetType import net.pokeranalytics.android.ui.fragment.components.bottomsheet.BottomSheetType
/** /**
* An interface used so that enums values can be represented visually * An interface to easily localize any object
* as rows in RecyclerViews
*/ */
interface RowRepresentable { interface Localizable {
/** /**
* The resource identifier of the localized title * The resource identifier of the localized title
*/ */
@ -28,12 +27,18 @@ interface RowRepresentable {
} }
return "LOCALISATION NOT FOUND" return "LOCALISATION NOT FOUND"
} }
}
/**
* An interface used so that enums values can be represented visually
* as rows in RecyclerViews
*/
interface RowRepresentable : Localizable {
/** /**
* The type of view associated with the row * The type of view associated with the row
*/ */
val viewType: Int val viewType: Int
get() { get() {
return 0 return 0
} }
@ -52,32 +57,89 @@ interface RowRepresentable {
} }
enum class SessionRow : RowRepresentable { enum class SessionRow : RowRepresentable {
DURATION,
NET_HOURLY_RATE,
BANKROLL_VARIATION,
CASHED_OUT,
BUY_IN,
TIPS,
GAME, GAME,
BLINDS, BLINDS,
LOCATION, LOCATION,
BANKROLL, BANKROLL,
TABLE_SIZE,
START_DATE, START_DATE,
END_DATE, END_DATE,
BREAK_TIME,
COMMENT; COMMENT;
companion object {
/**
* Return the rows to display for the current session state
*/
fun getRowsForState(sessionState: SessionState): ArrayList<RowRepresentable> {
return when (sessionState) {
SessionState.PENDING -> {
arrayListOf(GAME, BLINDS, LOCATION, BANKROLL, TABLE_SIZE, START_DATE, END_DATE)
}
SessionState.STARTED -> {
arrayListOf(
CASHED_OUT, BUY_IN, TIPS,
GAME, BLINDS, LOCATION, BANKROLL, TABLE_SIZE, START_DATE, END_DATE, BREAK_TIME, COMMENT
)
}
SessionState.PAUSED -> {
arrayListOf(
CASHED_OUT, BUY_IN, TIPS,
GAME, BLINDS, LOCATION, BANKROLL, TABLE_SIZE, START_DATE, END_DATE, BREAK_TIME, COMMENT
)
}
SessionState.FINISHED -> {
arrayListOf(
DURATION, NET_HOURLY_RATE, BANKROLL_VARIATION,
CASHED_OUT, BUY_IN, TIPS,
GAME, BLINDS, LOCATION, BANKROLL, TABLE_SIZE, START_DATE, END_DATE, BREAK_TIME, COMMENT
)
}
else -> arrayListOf()
}
}
}
override val resId: Int? override val resId: Int?
get() { get() {
return when (this) { return when (this) {
BLINDS -> R.string.blinds
DURATION -> R.string.duration
NET_HOURLY_RATE -> R.string.hour_rate_without_pauses
BANKROLL_VARIATION -> R.string.bankroll_variation
CASHED_OUT -> R.string.cashed_out
BUY_IN -> R.string.buyin
TIPS -> R.string.tips
GAME -> R.string.game GAME -> R.string.game
BLINDS -> R.string.blinds
LOCATION -> R.string.location LOCATION -> R.string.location
BANKROLL -> R.string.bankroll BANKROLL -> R.string.bankroll
COMMENT -> R.string.comment TABLE_SIZE -> R.string.table_size
START_DATE -> R.string.start_date START_DATE -> R.string.start_date
END_DATE -> R.string.end_date END_DATE -> R.string.end_date
BREAK_TIME -> R.string.break_time
COMMENT -> R.string.comment
} }
} }
override val viewType: Int override val viewType: Int
get() { get() {
return when (this) { return when (this) {
BLINDS, GAME, BANKROLL, LOCATION, COMMENT -> RowViewType.TITLE_VALUE.ordinal DURATION, NET_HOURLY_RATE, BANKROLL_VARIATION,
START_DATE, END_DATE -> RowViewType.TITLE_VALUE_ACTION.ordinal CASHED_OUT, BUY_IN, TIPS,
GAME, BLINDS, LOCATION, BANKROLL, TABLE_SIZE, COMMENT, START_DATE, END_DATE, BREAK_TIME -> RowViewType.TITLE_VALUE.ordinal
} }
} }
@ -96,6 +158,7 @@ enum class SessionRow : RowRepresentable {
enum class SimpleRow : RowRepresentable { enum class SimpleRow : RowRepresentable {
NAME; NAME;
override val resId: Int? = R.string.name override val resId: Int? = R.string.name
override val viewType: Int = RowViewType.TITLE_VALUE.ordinal override val viewType: Int = RowViewType.TITLE_VALUE.ordinal
override val bottomSheetType: BottomSheetType = BottomSheetType.EDIT_TEXT override val bottomSheetType: BottomSheetType = BottomSheetType.EDIT_TEXT
@ -130,9 +193,53 @@ enum class BankrollRow : RowRepresentable {
} }
enum class GameRow : RowRepresentable { enum class GameRow : RowRepresentable {
SHORT_NAME;
override val resId: Int?
get() {
return when (this) {
SHORT_NAME -> R.string.short_name
}
}
override val viewType: Int
get() {
return when (this) {
SHORT_NAME -> RowViewType.TITLE_VALUE.ordinal
}
}
override val bottomSheetType: BottomSheetType
get() {
return when (this) {
SHORT_NAME -> BottomSheetType.EDIT_TEXT
}
}
} }
enum class LocationRow : RowRepresentable { enum class LocationRow : RowRepresentable {
LOCATION_STATUS;
override val resId: Int?
get() {
return when (this) {
LOCATION_STATUS -> R.string.short_name
}
}
override val viewType: Int
get() {
return when (this) {
LOCATION_STATUS -> RowViewType.TITLE.ordinal
}
}
override val bottomSheetType: BottomSheetType
get() {
return when (this) {
LOCATION_STATUS -> BottomSheetType.NONE
}
}
} }
enum class TransactionTypeRow : RowRepresentable { enum class TransactionTypeRow : RowRepresentable {
@ -141,33 +248,31 @@ enum class TransactionTypeRow : RowRepresentable {
enum class TournamentFeatureRow : RowRepresentable { enum class TournamentFeatureRow : RowRepresentable {
} }
enum class SettingRow: RowRepresentable { enum class SettingRow : RowRepresentable {
BANKROLL, BANKROLL,
GAME, GAME,
LOCATION, LOCATION,
TOURNAMENT_TYPE, TOURNAMENT_FEATURE,
TRANSACTION_TYPE; TRANSACTION_TYPE;
override val resId: Int? override val resId: Int?
get() { get() {
return when (this) { this.relatedResultsRepresentable?. let {
BANKROLL -> R.string.bankroll return it.resId
GAME -> R.string.game } ?: run {
LOCATION -> R.string.location return super.resId
TOURNAMENT_TYPE -> R.string.tournament_type
TRANSACTION_TYPE -> R.string.operation_types
} }
} }
override val viewType: Int = RowViewType.TITLE.ordinal override val viewType: Int = RowViewType.TITLE.ordinal
override val relatedResultsRepresentable : LiveData? override val relatedResultsRepresentable: LiveData?
get() { get() {
return when (this) { return when (this) {
BANKROLL -> LiveData.BANKROLL BANKROLL -> LiveData.BANKROLL
GAME -> LiveData.GAME GAME -> LiveData.GAME
LOCATION -> LiveData.LOCATION LOCATION -> LiveData.LOCATION
TOURNAMENT_TYPE -> LiveData.TOURNAMENT_TYPE TOURNAMENT_FEATURE -> LiveData.TOURNAMENT_FEATURE
TRANSACTION_TYPE -> LiveData.TRANSACTION_TYPE TRANSACTION_TYPE -> LiveData.TRANSACTION_TYPE
} }
} }

@ -1,5 +1,8 @@
package net.pokeranalytics.android.util package net.pokeranalytics.android.util
import android.widget.Toast
import net.pokeranalytics.android.ui.activity.components.PokerAnalyticsActivity
import net.pokeranalytics.android.ui.fragment.components.PokerAnalyticsFragment
import java.text.DateFormat import java.text.DateFormat
import java.util.* import java.util.*
@ -18,4 +21,15 @@ fun Date.medium(): String {
fun Date.full(): String { fun Date.full(): String {
return DateFormat.getDateTimeInstance(DateFormat.FULL, DateFormat.FULL).format(this) return DateFormat.getDateTimeInstance(DateFormat.FULL, DateFormat.FULL).format(this)
}
// Toast
fun PokerAnalyticsActivity.toast(message: String) {
Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
}
fun PokerAnalyticsFragment.toast(message: String) {
Toast.makeText(requireContext(), message, Toast.LENGTH_SHORT).show()
} }

@ -1,9 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M3,13h8L11,3L3,3v10zM3,21h8v-6L3,15v6zM13,21h8L21,11h-8v10zM13,3v6h8L21,3h-8z"/>
</vector>

@ -1,5 +0,0 @@
<vector android:height="24dp" android:tint="#FFFFFF"
android:viewportHeight="24.0" android:viewportWidth="24.0"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#FF000000" android:pathData="M6,19c0,1.1 0.9,2 2,2h8c1.1,0 2,-0.9 2,-2V7H6v12zM19,4h-3.5l-1,-1h-5l-1,1H5v2h14V4z"/>
</vector>

@ -1,9 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M10,20v-6h4v6h5v-8h3L12,3 2,12h3v8z"/>
</vector>

@ -4,6 +4,6 @@
android:viewportWidth="24.0" android:viewportWidth="24.0"
android:viewportHeight="24.0"> android:viewportHeight="24.0">
<path <path
android:fillColor="#FF000000" android:fillColor="#FFFFFFFF"
android:pathData="M12,22c1.1,0 2,-0.9 2,-2h-4c0,1.1 0.89,2 2,2zM18,16v-5c0,-3.07 -1.64,-5.64 -4.5,-6.32L13.5,4c0,-0.83 -0.67,-1.5 -1.5,-1.5s-1.5,0.67 -1.5,1.5v0.68C7.63,5.36 6,7.92 6,11v5l-2,2v1h16v-1l-2,-2z"/> android:pathData="M12,22c1.1,0 2,-0.9 2,-2h-4c0,1.1 0.89,2 2,2zM18,16v-5c0,-3.07 -1.64,-5.64 -4.5,-6.32L13.5,4c0,-0.83 -0.67,-1.5 -1.5,-1.5s-1.5,0.67 -1.5,1.5v0.68C7.63,5.36 6,7.92 6,11v5l-2,2v1h16v-1l-2,-2z"/>
</vector> </vector>

@ -4,6 +4,6 @@
android:viewportWidth="24" android:viewportWidth="24"
android:viewportHeight="24"> android:viewportHeight="24">
<path <path
android:fillColor="#FF000000" android:fillColor="#FFFFFFFF"
android:pathData="M5,9.2h3L8,19L5,19L5,9.2zM10.6,5h2.8v14h-2.8L10.6,5zM16.2,13L19,13v6h-2.8v-6z"/> android:pathData="M5,9.2h3L8,19L5,19L5,9.2zM10.6,5h2.8v14h-2.8L10.6,5zM16.2,13L19,13v6h-2.8v-6z"/>
</vector> </vector>

@ -4,6 +4,6 @@
android:viewportWidth="24" android:viewportWidth="24"
android:viewportHeight="24"> android:viewportHeight="24">
<path <path
android:fillColor="#FF000000" android:fillColor="#FFFFFFFF"
android:pathData="M3.5,18.49l6,-6.01 4,4L22,6.92l-1.41,-1.41 -7.09,7.97 -4,-4L2,16.99l1.5,1.5z"/> android:pathData="M3.5,18.49l6,-6.01 4,4L22,6.92l-1.41,-1.41 -7.09,7.97 -4,-4L2,16.99l1.5,1.5z"/>
</vector> </vector>

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#FFFFFFFF"
android:pathData="M16,9v10H8V9h8m-1.5,-6h-5l-1,1H5v2h14V4h-3.5l-1,-1zM18,7H6v12c0,1.1 0.9,2 2,2h8c1.1,0 2,-0.9 2,-2V7z"/>
</vector>

@ -4,6 +4,6 @@
android:viewportWidth="24" android:viewportWidth="24"
android:viewportHeight="24"> android:viewportHeight="24">
<path <path
android:fillColor="#FF000000" android:fillColor="#FFFFFFFF"
android:pathData="M10,18h4v-2h-4v2zM3,6v2h18L21,6L3,6zM6,13h12v-2L6,11v2z"/> android:pathData="M10,18h4v-2h-4v2zM3,6v2h18L21,6L3,6zM6,13h12v-2L6,11v2z"/>
</vector> </vector>

@ -4,6 +4,6 @@
android:viewportWidth="24" android:viewportWidth="24"
android:viewportHeight="24"> android:viewportHeight="24">
<path <path
android:fillColor="#FF000000" android:fillColor="#FFFFFFFF"
android:pathData="M13,3c-4.97,0 -9,4.03 -9,9L1,12l3.89,3.89 0.07,0.14L9,12L6,12c0,-3.87 3.13,-7 7,-7s7,3.13 7,7 -3.13,7 -7,7c-1.93,0 -3.68,-0.79 -4.94,-2.06l-1.42,1.42C8.27,19.99 10.51,21 13,21c4.97,0 9,-4.03 9,-9s-4.03,-9 -9,-9zM12,8v5l4.25,2.52 0.77,-1.28 -3.52,-2.09L13.5,8z"/> android:pathData="M13,3c-4.97,0 -9,4.03 -9,9L1,12l3.89,3.89 0.07,0.14L9,12L6,12c0,-3.87 3.13,-7 7,-7s7,3.13 7,7 -3.13,7 -7,7c-1.93,0 -3.68,-0.79 -4.94,-2.06l-1.42,1.42C8.27,19.99 10.51,21 13,21c4.97,0 9,-4.03 9,-9s-4.03,-9 -9,-9zM12,8v5l4.25,2.52 0.77,-1.28 -3.52,-2.09L13.5,8z"/>
</vector> </vector>

@ -4,6 +4,6 @@
android:viewportWidth="24" android:viewportWidth="24"
android:viewportHeight="24"> android:viewportHeight="24">
<path <path
android:fillColor="#FF000000" android:fillColor="#FFFFFFFF"
android:pathData="M6,19h4L10,5L6,5v14zM14,5v14h4L18,5h-4z"/> android:pathData="M6,19h4L10,5L6,5v14zM14,5v14h4L18,5h-4z"/>
</vector> </vector>

@ -4,6 +4,6 @@
android:viewportWidth="24" android:viewportWidth="24"
android:viewportHeight="24"> android:viewportHeight="24">
<path <path
android:fillColor="#FF000000" android:fillColor="#FFFFFFFF"
android:pathData="M10,8.64L15.27,12 10,15.36V8.64M8,5v14l11,-7L8,5z"/> android:pathData="M10,8.64L15.27,12 10,15.36V8.64M8,5v14l11,-7L8,5z"/>
</vector> </vector>

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#FFFFFFFF"
android:pathData="M14,12c0,-1.1 -0.9,-2 -2,-2s-2,0.9 -2,2 0.9,2 2,2 2,-0.9 2,-2zM12,3c-4.97,0 -9,4.03 -9,9L0,12l4,4 4,-4L5,12c0,-3.87 3.13,-7 7,-7s7,3.13 7,7 -3.13,7 -7,7c-1.51,0 -2.91,-0.49 -4.06,-1.3l-1.42,1.44C8.04,20.3 9.94,21 12,21c4.97,0 9,-4.03 9,-9s-4.03,-9 -9,-9z"/>
</vector>

@ -4,6 +4,6 @@
android:viewportWidth="24" android:viewportWidth="24"
android:viewportHeight="24"> android:viewportHeight="24">
<path <path
android:fillColor="#FF000000" android:fillColor="#FFFFFFFF"
android:pathData="M19.43,12.98c0.04,-0.32 0.07,-0.64 0.07,-0.98 0,-0.34 -0.03,-0.66 -0.07,-0.98l2.11,-1.65c0.19,-0.15 0.24,-0.42 0.12,-0.64l-2,-3.46c-0.09,-0.16 -0.26,-0.25 -0.44,-0.25 -0.06,0 -0.12,0.01 -0.17,0.03l-2.49,1c-0.52,-0.4 -1.08,-0.73 -1.69,-0.98l-0.38,-2.65C14.46,2.18 14.25,2 14,2h-4c-0.25,0 -0.46,0.18 -0.49,0.42l-0.38,2.65c-0.61,0.25 -1.17,0.59 -1.69,0.98l-2.49,-1c-0.06,-0.02 -0.12,-0.03 -0.18,-0.03 -0.17,0 -0.34,0.09 -0.43,0.25l-2,3.46c-0.13,0.22 -0.07,0.49 0.12,0.64l2.11,1.65c-0.04,0.32 -0.07,0.65 -0.07,0.98 0,0.33 0.03,0.66 0.07,0.98l-2.11,1.65c-0.19,0.15 -0.24,0.42 -0.12,0.64l2,3.46c0.09,0.16 0.26,0.25 0.44,0.25 0.06,0 0.12,-0.01 0.17,-0.03l2.49,-1c0.52,0.4 1.08,0.73 1.69,0.98l0.38,2.65c0.03,0.24 0.24,0.42 0.49,0.42h4c0.25,0 0.46,-0.18 0.49,-0.42l0.38,-2.65c0.61,-0.25 1.17,-0.59 1.69,-0.98l2.49,1c0.06,0.02 0.12,0.03 0.18,0.03 0.17,0 0.34,-0.09 0.43,-0.25l2,-3.46c0.12,-0.22 0.07,-0.49 -0.12,-0.64l-2.11,-1.65zM17.45,11.27c0.04,0.31 0.05,0.52 0.05,0.73 0,0.21 -0.02,0.43 -0.05,0.73l-0.14,1.13 0.89,0.7 1.08,0.84 -0.7,1.21 -1.27,-0.51 -1.04,-0.42 -0.9,0.68c-0.43,0.32 -0.84,0.56 -1.25,0.73l-1.06,0.43 -0.16,1.13 -0.2,1.35h-1.4l-0.19,-1.35 -0.16,-1.13 -1.06,-0.43c-0.43,-0.18 -0.83,-0.41 -1.23,-0.71l-0.91,-0.7 -1.06,0.43 -1.27,0.51 -0.7,-1.21 1.08,-0.84 0.89,-0.7 -0.14,-1.13c-0.03,-0.31 -0.05,-0.54 -0.05,-0.74s0.02,-0.43 0.05,-0.73l0.14,-1.13 -0.89,-0.7 -1.08,-0.84 0.7,-1.21 1.27,0.51 1.04,0.42 0.9,-0.68c0.43,-0.32 0.84,-0.56 1.25,-0.73l1.06,-0.43 0.16,-1.13 0.2,-1.35h1.39l0.19,1.35 0.16,1.13 1.06,0.43c0.43,0.18 0.83,0.41 1.23,0.71l0.91,0.7 1.06,-0.43 1.27,-0.51 0.7,1.21 -1.07,0.85 -0.89,0.7 0.14,1.13zM12,8c-2.21,0 -4,1.79 -4,4s1.79,4 4,4 4,-1.79 4,-4 -1.79,-4 -4,-4zM12,14c-1.1,0 -2,-0.9 -2,-2s0.9,-2 2,-2 2,0.9 2,2 -0.9,2 -2,2z"/> android:pathData="M19.43,12.98c0.04,-0.32 0.07,-0.64 0.07,-0.98 0,-0.34 -0.03,-0.66 -0.07,-0.98l2.11,-1.65c0.19,-0.15 0.24,-0.42 0.12,-0.64l-2,-3.46c-0.09,-0.16 -0.26,-0.25 -0.44,-0.25 -0.06,0 -0.12,0.01 -0.17,0.03l-2.49,1c-0.52,-0.4 -1.08,-0.73 -1.69,-0.98l-0.38,-2.65C14.46,2.18 14.25,2 14,2h-4c-0.25,0 -0.46,0.18 -0.49,0.42l-0.38,2.65c-0.61,0.25 -1.17,0.59 -1.69,0.98l-2.49,-1c-0.06,-0.02 -0.12,-0.03 -0.18,-0.03 -0.17,0 -0.34,0.09 -0.43,0.25l-2,3.46c-0.13,0.22 -0.07,0.49 0.12,0.64l2.11,1.65c-0.04,0.32 -0.07,0.65 -0.07,0.98 0,0.33 0.03,0.66 0.07,0.98l-2.11,1.65c-0.19,0.15 -0.24,0.42 -0.12,0.64l2,3.46c0.09,0.16 0.26,0.25 0.44,0.25 0.06,0 0.12,-0.01 0.17,-0.03l2.49,-1c0.52,0.4 1.08,0.73 1.69,0.98l0.38,2.65c0.03,0.24 0.24,0.42 0.49,0.42h4c0.25,0 0.46,-0.18 0.49,-0.42l0.38,-2.65c0.61,-0.25 1.17,-0.59 1.69,-0.98l2.49,1c0.06,0.02 0.12,0.03 0.18,0.03 0.17,0 0.34,-0.09 0.43,-0.25l2,-3.46c0.12,-0.22 0.07,-0.49 -0.12,-0.64l-2.11,-1.65zM17.45,11.27c0.04,0.31 0.05,0.52 0.05,0.73 0,0.21 -0.02,0.43 -0.05,0.73l-0.14,1.13 0.89,0.7 1.08,0.84 -0.7,1.21 -1.27,-0.51 -1.04,-0.42 -0.9,0.68c-0.43,0.32 -0.84,0.56 -1.25,0.73l-1.06,0.43 -0.16,1.13 -0.2,1.35h-1.4l-0.19,-1.35 -0.16,-1.13 -1.06,-0.43c-0.43,-0.18 -0.83,-0.41 -1.23,-0.71l-0.91,-0.7 -1.06,0.43 -1.27,0.51 -0.7,-1.21 1.08,-0.84 0.89,-0.7 -0.14,-1.13c-0.03,-0.31 -0.05,-0.54 -0.05,-0.74s0.02,-0.43 0.05,-0.73l0.14,-1.13 -0.89,-0.7 -1.08,-0.84 0.7,-1.21 1.27,0.51 1.04,0.42 0.9,-0.68c0.43,-0.32 0.84,-0.56 1.25,-0.73l1.06,-0.43 0.16,-1.13 0.2,-1.35h1.39l0.19,1.35 0.16,1.13 1.06,0.43c0.43,0.18 0.83,0.41 1.23,0.71l0.91,0.7 1.06,-0.43 1.27,-0.51 0.7,1.21 -1.07,0.85 -0.89,0.7 0.14,1.13zM12,8c-2.21,0 -4,1.79 -4,4s1.79,4 4,4 4,-1.79 4,-4 -1.79,-4 -4,-4zM12,14c-1.1,0 -2,-0.9 -2,-2s0.9,-2 2,-2 2,0.9 2,2 -0.9,2 -2,2z"/>
</vector> </vector>

@ -4,6 +4,6 @@
android:viewportWidth="24" android:viewportWidth="24"
android:viewportHeight="24"> android:viewportHeight="24">
<path <path
android:fillColor="#FF000000" android:fillColor="#FFFFFFFF"
android:pathData="M3,18h6v-2L3,16v2zM3,6v2h18L21,6L3,6zM3,13h12v-2L3,11v2z"/> android:pathData="M3,18h6v-2L3,16v2zM3,6v2h18L21,6L3,6zM3,13h12v-2L3,11v2z"/>
</vector> </vector>

@ -4,6 +4,6 @@
android:viewportWidth="24" android:viewportWidth="24"
android:viewportHeight="24"> android:viewportHeight="24">
<path <path
android:fillColor="#FF000000" android:fillColor="#FFFFFFFF"
android:pathData="M16,8v8H8V8h8m2,-2H6v12h12V6z"/> android:pathData="M16,8v8H8V8h8m2,-2H6v12h12V6z"/>
</vector> </vector>

@ -33,7 +33,7 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginEnd="16dp" android:layout_marginEnd="16dp"
android:layout_marginBottom="16dp" android:layout_marginBottom="16dp"
android:src="@drawable/ic_add_white_24dp" android:src="@drawable/ic_add"
app:fabSize="normal" app:fabSize="normal"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" /> app:layout_constraintEnd_toEndOf="parent" />

@ -9,7 +9,7 @@
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"> app:layout_behavior="@string/appbar_scrolling_view_behavior" android:id="@+id/nestedScrollView">
<androidx.constraintlayout.widget.ConstraintLayout <androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent" android:layout_width="match_parent"
@ -22,7 +22,7 @@
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_toTopOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>
@ -51,10 +51,24 @@
android:layout_height="?attr/actionBarSize" android:layout_height="?attr/actionBarSize"
app:title="Poker Analytics" app:title="Poker Analytics"
app:titleTextColor="@color/white" app:titleTextColor="@color/white"
app:layout_collapseMode="pin" /> 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>

@ -19,6 +19,8 @@
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"
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"
@ -38,23 +40,41 @@
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:title="Poker Analytics" app:layout_collapseMode="pin"
app:titleTextColor="@color/white" app:titleTextColor="@color/white"
app:layout_collapseMode="pin" /> 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>
<com.google.android.material.bottomappbar.BottomAppBar
android:id="@+id/bottomAppBar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:fabAlignmentMode="center"
android:background="@color/red"
android:theme="@style/PokerAnalyticsTheme.BottomAppBar"
android:layout_gravity="bottom" />
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/floatingActionButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|center"
android:layout_marginBottom="28dp"
android:elevation="16dp"
android:src="@drawable/ic_outline_play" />
</androidx.coordinatorlayout.widget.CoordinatorLayout> </androidx.coordinatorlayout.widget.CoordinatorLayout>

@ -1,25 +1,25 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
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" xmlns:tools="http://schemas.android.com/tools"
xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
android:layout_width="match_parent" android:layout_height="wrap_content"
android:layout_height="wrap_content" android:background="?selectableItemBackground"
android:padding="16dp"> android:padding="16dp">
<androidx.appcompat.widget.AppCompatTextView <androidx.appcompat.widget.AppCompatTextView
android:id="@+id/date" android:id="@+id/date"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
app:layout_constraintEnd_toEndOf="parent" android:layout_marginStart="8dp"
android:layout_marginEnd="8dp" android:layout_marginTop="8dp"
android:layout_marginTop="8dp" android:layout_marginEnd="8dp"
android:textSize="16sp" android:layout_marginBottom="8dp"
tools:text="This date" android:textSize="16sp"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent"
android:layout_marginStart="8dp" app:layout_constraintStart_toStartOf="parent"
android:layout_marginBottom="8dp" app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"/> tools:text="This date" />
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>

@ -6,8 +6,8 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:background="?selectableItemBackground" android:background="?selectableItemBackground"
android:paddingStart="24dp" android:paddingStart="16dp"
android:paddingEnd="24dp"> android:paddingEnd="16dp">
<androidx.appcompat.widget.AppCompatTextView <androidx.appcompat.widget.AppCompatTextView
android:id="@+id/title" android:id="@+id/title"
@ -15,7 +15,7 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="16dp" android:layout_marginTop="16dp"
android:layout_marginBottom="16dp" android:layout_marginBottom="16dp"
android:textSize="18sp" style="@style/PokerAnalyticsTheme.TextView.RowTitle"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintHorizontal_bias="0.0" app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
@ -30,7 +30,7 @@
android:ellipsize="end" android:ellipsize="end"
android:gravity="end" android:gravity="end"
android:maxLines="1" android:maxLines="1"
android:textSize="14sp" style="@style/PokerAnalyticsTheme.TextView.RowValue"
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/title" app:layout_constraintStart_toEndOf="@+id/title"

@ -49,6 +49,6 @@
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toEndOf="@+id/value" app:layout_constraintStart_toEndOf="@+id/value"
tools:src="@drawable/ic_close_white_24dp" /> tools:src="@drawable/ic_close" />
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>

@ -6,17 +6,17 @@
android:id="@+id/actionClear" android:id="@+id/actionClear"
android:orderInCategory="100" android:orderInCategory="100"
android:title="@string/clear" android:title="@string/clear"
android:icon="@drawable/ic_close_white_24dp" android:icon="@drawable/ic_close"
app:showAsAction="always" /> app:showAsAction="always" />
<item <item
android:id="@+id/actionAdd" android:id="@+id/actionAdd"
android:icon="@drawable/ic_add_white_24dp" android:icon="@drawable/ic_add"
android:orderInCategory="200" android:orderInCategory="200"
android:title="@string/new_str" android:title="@string/new_str"
app:showAsAction="ifRoom" /> app:showAsAction="ifRoom" />
<item <item
android:id="@+id/actionCheck" android:id="@+id/actionCheck"
android:icon="@drawable/ic_check_white_24dp" android:icon="@drawable/ic_check"
android:orderInCategory="300" android:orderInCategory="300"
android:title="@string/done" android:title="@string/done"
app:showAsAction="ifRoom" /> app:showAsAction="ifRoom" />

@ -0,0 +1,10 @@
<?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/stop"
android:title="@string/stop"
app:showAsAction="always" />
</menu>

@ -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/restart"
android:title="@string/restart_timer"
android:icon="@drawable/ic_outline_restart"
app:showAsAction="withText" />
<item
android:id="@+id/delete"
android:icon="@drawable/ic_outline_delete"
android:title="@string/delete"
app:showAsAction="withText" />
</menu>

@ -18,6 +18,8 @@
<string name="standard_deviation_hourly">Standard deviation hourly</string> <string name="standard_deviation_hourly">Standard deviation hourly</string>
<string name="hands_played">Hands played</string> <string name="hands_played">Hands played</string>
<string name="save">Save</string>
<!-- <!--
<string name="bankroll">Bankroll</string> <string name="bankroll">Bankroll</string>
<string name="blinds">Blinds</string> <string name="blinds">Blinds</string>

@ -34,6 +34,7 @@
<item name="titleTextColor">@color/white</item> <item name="titleTextColor">@color/white</item>
<item name="titleTextAppearance">@style/PokerAnalyticsTheme.Toolbar.TitleAppearance</item> <item name="titleTextAppearance">@style/PokerAnalyticsTheme.Toolbar.TitleAppearance</item>
</style> </style>
+
<style name="PokerAnalyticsTheme.Toolbar.TitleAppearance"> <style name="PokerAnalyticsTheme.Toolbar.TitleAppearance">
<item name="android:textSize">20sp</item> <item name="android:textSize">20sp</item>
@ -53,6 +54,10 @@
<!-- Bottom App Bar --> <!-- Bottom App Bar -->
<style name="PokerAnalyticsTheme.BottomAppBar" parent="Widget.MaterialComponents.BottomAppBar"> <style name="PokerAnalyticsTheme.BottomAppBar" parent="Widget.MaterialComponents.BottomAppBar">
<item name="backgroundTint">@color/gray_darker</item> <item name="backgroundTint">@color/gray_darker</item>
<item name="android:colorPrimary">@color/white</item>
<item name="android:titleTextColor">@color/white</item>
<item name="popupTheme">@style/ThemeOverlay.AppCompat.Dark.ActionBar</item>
<item name="actionMenuTextColor">@color/white</item>
</style> </style>
<!-- TextView --> <!-- TextView -->
@ -75,13 +80,19 @@
<item name="android:paddingTop">8dp</item> <item name="android:paddingTop">8dp</item>
</style> </style>
<style name="PokerAnalyticsTheme.TextView.TitleRow"> <style name="PokerAnalyticsTheme.TextView.RowTitle">
<item name="android:textSize">16sp</item> <item name="android:textSize">16sp</item>
<item name="android:textColor">@color/gray_darker</item> <item name="android:textColor">@color/white</item>
<item name="android:fontFamily">@font/roboto</item>
</style>
<style name="PokerAnalyticsTheme.TextView.RowValue">
<item name="android:textSize">16sp</item>
<item name="android:textColor">@color/kaki_lighter</item>
<item name="android:fontFamily">@font/roboto</item> <item name="android:fontFamily">@font/roboto</item>
<item name="android:paddingTop">8dp</item>
</style> </style>
<!-- EditText --> <!-- 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>

Loading…
Cancel
Save