dev_raz_wip
Razmig Sarkissian 7 years ago
commit 22d0459436
  1. 118
      app/src/main/java/net/pokeranalytics/android/calculus/Calculator.kt
  2. 4
      app/src/main/java/net/pokeranalytics/android/calculus/Computable.kt
  3. 35
      app/src/main/java/net/pokeranalytics/android/calculus/Stat.kt
  4. 2
      app/src/main/java/net/pokeranalytics/android/model/realm/Result.kt
  5. 73
      app/src/main/java/net/pokeranalytics/android/model/realm/Session.kt
  6. 61
      app/src/main/java/net/pokeranalytics/android/model/realm/TimeFrame.kt
  7. 15
      app/src/main/java/net/pokeranalytics/android/model/realm/TimeFrameGroup.kt
  8. 2
      app/src/main/java/net/pokeranalytics/android/ui/adapter/components/DynamicListAdapter.kt
  9. 137
      app/src/main/java/net/pokeranalytics/android/ui/fragment/BottomSheetFragment.kt
  10. 11
      app/src/main/java/net/pokeranalytics/android/ui/fragment/NewSessionFragment.kt
  11. 4
      app/src/main/java/net/pokeranalytics/android/ui/fragment/SettingsFragment.kt
  12. 13
      app/src/main/java/net/pokeranalytics/android/ui/fragment/components/BottomSheetType.kt
  13. 26
      app/src/main/java/net/pokeranalytics/android/util/DatePickerFragment.kt
  14. 3
      app/src/main/java/net/pokeranalytics/android/util/PokerAnalyticsFragment.kt
  15. 26
      app/src/main/java/net/pokeranalytics/android/util/TimePickerFragment.kt
  16. 5
      app/src/main/res/drawable/ic_add_white_24dp.xml
  17. 5
      app/src/main/res/drawable/ic_check_white_24dp.xml
  18. 5
      app/src/main/res/drawable/ic_close_white_24dp.xml
  19. 5
      app/src/main/res/drawable/ic_delete_white_24dp.xml
  20. 13
      app/src/main/res/layout/bottom_sheet_bankroll.xml
  21. 59
      app/src/main/res/layout/bottom_sheet_blinds.xml
  22. 32
      app/src/main/res/layout/bottom_sheet_date.xml
  23. 19
      app/src/main/res/layout/bottom_sheet_game.xml
  24. 13
      app/src/main/res/layout/bottom_sheet_location.xml
  25. 13
      app/src/main/res/layout/bottom_sheet_table_size.xml
  26. 28
      app/src/main/res/layout/fragment_bottom_sheet.xml
  27. 45
      app/src/main/res/layout/fragment_bottom_sheet_container.xml
  28. 23
      app/src/main/res/menu/bottom_sheet_menu.xml
  29. 6
      app/src/main/res/values/styles.xml
  30. 43
      app/src/test/java/net/pokeranalytics/android/ExampleUnitTest.kt

@ -1,5 +1,6 @@
package net.pokeranalytics.android.calculus package net.pokeranalytics.android.calculus
import net.pokeranalytics.android.calculus.Stat.*
import net.pokeranalytics.android.model.realm.TimeFrameGroup import net.pokeranalytics.android.model.realm.TimeFrameGroup
@ -25,6 +26,15 @@ class Calculator {
var evolutionValues: EvolutionValues = EvolutionValues.NONE var evolutionValues: EvolutionValues = EvolutionValues.NONE
var displayedStats: List<Stat> = listOf() var displayedStats: List<Stat> = listOf()
fun shouldComputeStandardDeviation() : Boolean {
this.displayedStats.forEach { stat ->
when (stat) {
STANDARD_DEVIATION, STANDARD_DEVIATION_HOURLY, STANDARD_DEVIATION_BB_PER_100_HANDS -> return true
}
}
return false
}
// var aggregation: Aggregation? = null // var aggregation: Aggregation? = null
} }
@ -62,43 +72,113 @@ class Calculator {
fun compute(group: SessionGroup, options: Options) : ComputedResults { fun compute(group: SessionGroup, options: Options) : ComputedResults {
val sessions: List<SessionInterface> = group.sessionGroup val sessions: List<SessionInterface> = group.sessionGroup
val series: Set<TimeFrameGroup> = setOf() // @todo get unique list of serie val sessionGroups: Set<TimeFrameGroup> = setOf() // @todo get unique list of serie
var results: ComputedResults = ComputedResults() var results: ComputedResults = ComputedResults()
var sum: Double = 0.0 var sum: Double = 0.0
var duration: Double = 0.0 var totalHands: Double = 0.0
var bbSum: Double = 0.0
var bbSessionCount: Int = 0
var winningSessionCount: Int = 0
var totalBuyin: Double = 0.0
// @todo add all stats // @todo add all stats
// Compute for each session // Compute for each session
sessions.forEach { item -> var index: Int = 0
sum += item.value sessions.forEach { s ->
index++;
when (options.evolutionValues) {
Options.EvolutionValues.STANDARD -> { bbSessionCount += s.bigBlindSessionCount
results.addEvolutionValue(sum, Stat.NETRESULT) if (s.value >= 0) {
} winningSessionCount++
Options.EvolutionValues.DATED -> { }
results.addEvolutionValue(sum, duration, Stat.NETRESULT) totalBuyin += s.buyin
}
if (options.evolutionValues != Options.EvolutionValues.NONE) {
sum += s.value
totalHands += s.estimatedHands
bbSum += s.bbNetResult
results.addEvolutionValue(sum / index, AVERAGE)
results.addEvolutionValue(index.toDouble(), NUMBER_OF_GAMES)
results.addEvolutionValue(bbSum / bbSessionCount, AVERAGE_NET_BB)
results.addEvolutionValue((winningSessionCount / index).toDouble(), WIN_RATIO)
results.addEvolutionValue(totalBuyin / index, AVERAGE_BUYIN)
results.addEvolutionValue(Stat.returnOnInvestment(sum, totalBuyin), ROI)
} }
} }
// Compute for each serie // Compute for each serie
series.forEach { serie -> var duration: Double = 0.0
duration += serie.duration var hourlyRate: Double = 0.0; var hourlyRateBB: Double = 0.0
index = 0; sum = 0.0; totalHands = 0.0; bbSum = 0.0;
sessionGroups.forEach { group ->
index++
duration += group.duration
sum += group.netResult
totalHands += group.estimatedHands
bbSum += group.bbNetResult
hourlyRate = sum / duration * 3600.0
hourlyRateBB = bbSum / duration * 3600.0
if (options.evolutionValues != Options.EvolutionValues.NONE) { if (options.evolutionValues != Options.EvolutionValues.NONE) {
results.addEvolutionValue(duration, Stat.DURATION) results.addEvolutionValue(sum, duration, NETRESULT)
results.addEvolutionValue(sum / duration * 3600.0, duration, HOURLY_RATE)
results.addEvolutionValue(Stat.netBBPer100Hands(bbSum, totalHands), duration, NET_BB_PER_100_HANDS)
results.addEvolutionValue(hourlyRate, duration, HOURLY_RATE)
results.addEvolutionValue(index.toDouble(), duration, NUMBER_OF_GROUPS)
results.addEvolutionValue(group.duration, duration, DURATION)
results.addEvolutionValue(duration / index, duration, AVERAGE_DURATION)
results.addEvolutionValue(hourlyRateBB, duration, HOURLY_RATE_BB)
} }
} }
val average: Double = sum / sessions.size
// Create stats // Create stats
results.addStats(setOf( results.addStats(setOf(
ComputedStat(Stat.NETRESULT, sum), ComputedStat(NETRESULT, sum),
ComputedStat(Stat.AVERAGE,sum / sessions.size), ComputedStat(HOURLY_RATE, hourlyRate),
ComputedStat(Stat.DURATION, duration) ComputedStat(AVERAGE, average),
)) ComputedStat(DURATION, duration),
ComputedStat(NUMBER_OF_GROUPS, sessionGroups.size.toDouble()),
ComputedStat(NUMBER_OF_GAMES, sessions.size.toDouble()),
ComputedStat(AVERAGE_DURATION, (duration / 3600.0) / sessions.size),
ComputedStat(NET_BB_PER_100_HANDS, Stat.netBBPer100Hands(bbSum, totalHands)),
ComputedStat(HOURLY_RATE_BB, bbSum / duration * 3600.0),
ComputedStat(AVERAGE_NET_BB, bbSum / bbSessionCount),
ComputedStat(WIN_RATIO, (winningSessionCount / sessions.size).toDouble()),
ComputedStat(AVERAGE_BUYIN, totalBuyin / sessions.size),
ComputedStat(ROI, Stat.returnOnInvestment(sum, totalBuyin))
))
// Standard Deviation
if (options.shouldComputeStandardDeviation()) {
var stdSum: Double = 0.0
sessions.forEach { s ->
stdSum += Math.pow(s.value - average, 2.0)
}
val standardDeviation: Double = Math.sqrt(stdSum / sessions.size)
var hourlyStdSum: Double = 0.0
sessionGroups.forEach { sg ->
hourlyStdSum += Math.pow(sg.hourlyRate - hourlyRate, 2.0)
}
val hourlyStandardDeviation: Double = Math.sqrt(hourlyStdSum / sessionGroups.size)
results.addStats(setOf(
ComputedStat(STANDARD_DEVIATION, standardDeviation),
ComputedStat(Stat.STANDARD_DEVIATION_HOURLY, hourlyStandardDeviation)
))
}
return results return results
} }

@ -10,6 +10,10 @@ interface Summable {
// An interface describing some class that can be computed // An interface describing some class that can be computed
interface SessionInterface : Summable { interface SessionInterface : Summable {
var serie: TimeFrameGroup var serie: TimeFrameGroup
var estimatedHands: Double
var bbNetResult: Double
var bigBlindSessionCount: Int // 0 or 1
var buyin: Double
} }
/** /**

@ -7,25 +7,48 @@ interface AnyStat {
enum class Stat : AnyStat { enum class Stat : AnyStat {
NETRESULT, NETRESULT,
HOURLYRATE, HOURLY_RATE,
DURATION,
AVERAGE, AVERAGE,
STANDARDDEVIATION, NUMBER_OF_GROUPS,
HOURLYSTANDARDDEVIATION; NUMBER_OF_GAMES,
DURATION,
AVERAGE_DURATION,
NET_BB_PER_100_HANDS,
HOURLY_RATE_BB,
AVERAGE_NET_BB,
WIN_RATIO,
AVERAGE_BUYIN,
ROI,
STANDARD_DEVIATION,
STANDARD_DEVIATION_HOURLY,
STANDARD_DEVIATION_BB_PER_100_HANDS;
fun label() : String = when (this) { fun label() : String = when (this) {
NETRESULT -> "" NETRESULT -> ""
HOURLYRATE -> "" HOURLY_RATE -> ""
else -> throw IllegalArgumentException("Label not defined") else -> throw IllegalArgumentException("Label not defined")
} }
fun hasDistributionSorting() : Boolean { fun hasDistributionSorting() : Boolean {
when (this) { when (this) {
STANDARDDEVIATION, HOURLYSTANDARDDEVIATION -> return true STANDARD_DEVIATION, STANDARD_DEVIATION_HOURLY, STANDARD_DEVIATION_BB_PER_100_HANDS -> return true
else -> return false else -> return false
} }
} }
companion object {
fun returnOnInvestment(netResult: Double, buyin: Double) : Double {
return netResult / buyin
}
fun netBBPer100Hands(netBB: Double, numberOfHands: Double) : Double {
return netBB / numberOfHands * 100
}
}
} }
enum class CashSessionStat : AnyStat { enum class CashSessionStat : AnyStat {

@ -36,7 +36,7 @@ open class Result : RealmObject() {
} }
// The net (readonly) // The net (readonly)
var net: Double? = null var net: Double = 0.0
// The transactions associated with the Result, impacting the result // The transactions associated with the Result, impacting the result
var transactions: RealmList<Transaction> = RealmList() var transactions: RealmList<Transaction> = RealmList()

@ -1,18 +1,13 @@
package net.pokeranalytics.android.model.realm package net.pokeranalytics.android.model.realm
import io.realm.RealmList import io.realm.*
import io.realm.Realm import io.realm.annotations.Ignore
import io.realm.RealmObject
import io.realm.RealmResults
import io.realm.Sort
import io.realm.annotations.PrimaryKey import io.realm.annotations.PrimaryKey
import net.pokeranalytics.android.*
import net.pokeranalytics.android.ui.adapter.components.DynamicRowDelegate import net.pokeranalytics.android.ui.adapter.components.DynamicRowDelegate
import net.pokeranalytics.android.ui.adapter.components.DynamicRowInterface import net.pokeranalytics.android.ui.adapter.components.DynamicRowInterface
import net.pokeranalytics.android.ui.adapter.components.SessionRow import net.pokeranalytics.android.ui.adapter.components.SessionRow
import net.pokeranalytics.android.util.data.sessionDao import net.pokeranalytics.android.util.data.sessionDao
import java.util.* import java.util.*
import java.util.UUID.randomUUID
import kotlin.collections.ArrayList import kotlin.collections.ArrayList
@ -21,6 +16,9 @@ open class Session(comment: String = "") : RealmObject(), DynamicRowDelegate {
@PrimaryKey @PrimaryKey
var id = UUID.randomUUID().toString() var id = UUID.randomUUID().toString()
// The result of the main user
var result: Result? = null
// The time frame of the Session, i.e. the start & end date // The time frame of the Session, i.e. the start & end date
var timeFrame: TimeFrame? = null var timeFrame: TimeFrame? = null
@ -30,30 +28,27 @@ open class Session(comment: String = "") : RealmObject(), DynamicRowDelegate {
// the date of creation of the app // the date of creation of the app
var creationDate: Date = Date() var creationDate: Date = Date()
// The bankroll hosting the results
var bankroll: Bankroll? = null
// The limit type: NL, PL... // The limit type: NL, PL...
var limit: Int? = null var limit: Int? = null
// The number of tables played at the same time // The game played during the Session
var numberOfTables: Int = 1 var game: Game? = null
// The number of players at the table // The number of players at the table
var tableSize: Int? = null var tableSize: Int? = null
// The game played during the Session // the location where the session is played
var game: Game? = null var location: Location? = null
// The bankroll hosting the results // The number of tables played at the same time
var bankroll: Bankroll? = null var numberOfTables: Int = 1
// The hands list associated with the Session // The hands list associated with the Session
var hands: RealmList<HandHistory> = RealmList() var hands: RealmList<HandHistory> = RealmList()
// the location where the session is played
var location: Location? = null
// The result of the main user
var result: Result? = null
// The list of opponents who participated to the session // The list of opponents who participated to the session
var opponents: RealmList<Player> = RealmList() var opponents: RealmList<Player> = RealmList()
@ -85,6 +80,46 @@ open class Session(comment: String = "") : RealmObject(), DynamicRowDelegate {
// 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 {
fun newInstance() : Session {
var session: Session = Session()
session.result = Result()
session.timeFrame = TimeFrame()
return session
}
}
@Ignore
var estimatedHands: Double = 0.0
@Ignore
var bbNetResult: Double = 0.0
get() {
this.cgBigBlind?.let { bb ->
this.result?.let { result ->
return result.net / bb
}
}
return 0.0
}
@Ignore
var bigBlindSessionCount: Int = if (this.cgBigBlind != null) 1 else 0
// get() = if (this.cgBigBlind != null) 1 else 0
@Ignore
var buyin: Double = 0.0
get() {
this.result?.let {
it.buyin?.let {
return it
}
}
return 0.0
}
override fun adapterRows(): ArrayList<DynamicRowInterface> { override fun adapterRows(): ArrayList<DynamicRowInterface> {
val rows = ArrayList<DynamicRowInterface>() val rows = ArrayList<DynamicRowInterface>()

@ -1,24 +1,79 @@
package net.pokeranalytics.android.model.realm package net.pokeranalytics.android.model.realm
import io.realm.RealmObject import io.realm.RealmObject
import io.realm.annotations.PrimaryKey import io.realm.RealmResults
import io.realm.annotations.LinkingObjects
import java.util.* import java.util.*
open class TimeFrame : RealmObject() { open class TimeFrame : RealmObject() {
// A start date // A start date
var startDate: Date = Date() var startDate: Date = Date()
set(value) {
field = value
this.computeDuration()
if (this.session != null) {
this.notifyDateChange()
}
}
// An end date // An end date
var endDate: Date? = null var endDate: Date? = null
set(value) {
field = value
this.computeDuration()
if (this.session != null) {
this.notifyDateChange()
}
}
// The break duration // The break duration
var breakDuration: Double = 0.0 var breakDuration: Long = 0L
set(value) {
field = value
this.computeDuration()
}
// the total duration // the total duration
var duration: Double = 0.0 var duration: Long = 0L
private set
// indicates a state of pause // indicates a state of pause
var paused: Boolean = false var paused: Boolean = false
@LinkingObjects("timeFrame")
private val session: RealmResults<Session>? = null
@LinkingObjects("timeFrame")
private val group: RealmResults<TimeFrameGroup>? = null
private fun computeDuration() {
var endDate: Date
if (this.endDate != null) {
endDate = this.endDate!!
} else {
endDate = Date()
}
this.duration = endDate.time - startDate.time - this.breakDuration
}
private fun notifyDateChange() {
// val realm = Realm.getDefaultInstance()
//
// var query: RealmQuery<TimeFrame> = realm.where(TimeFrame::class.java)
// query.greaterThan("startDate", this.startDate.time)
//
// this.endDate?.let { endDate ->
// query.or()
// .greaterThan("startDate", endDate.time)
// .lessThan("endDate", endDate.time)
// }
//
//
// realm.close()
}
} }

@ -3,8 +3,6 @@ package net.pokeranalytics.android.model.realm
import io.realm.RealmList import io.realm.RealmList
import io.realm.RealmObject import io.realm.RealmObject
import io.realm.annotations.Ignore import io.realm.annotations.Ignore
import io.realm.annotations.PrimaryKey
import java.util.*
open class TimeFrameGroup() : RealmObject() { open class TimeFrameGroup() : RealmObject() {
@ -13,10 +11,21 @@ open class TimeFrameGroup() : RealmObject() {
var timeFrame: TimeFrame? = null var timeFrame: TimeFrame? = null
// The list of Session played within the group, i.e. played within the same time frame // The list of Session played within the group, i.e. played within the same time frame
var timeFrames: RealmList<Session> = RealmList() var sessions: RealmList<Session> = RealmList()
@Ignore // a duration shortcut @Ignore // a duration shortcut
var duration: Double = 0.0 var duration: Double = 0.0
@Ignore // a netResult shortcut
var netResult: Double = 0.0
@Ignore // a duration shortcut
var hourlyRate: Double = 0.0
@Ignore
var estimatedHands: Double = 0.0
@Ignore
var bbNetResult: Double = 0.0
} }

@ -6,7 +6,7 @@ import android.widget.Toast
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import io.realm.Realm.init import io.realm.Realm.init
interface EditableDataDelegate : DynamicRowDelegate { interface EditableDataDelegate {
fun setValue(value: Any, row: DynamicRowInterface) fun setValue(value: Any, row: DynamicRowInterface)
} }

@ -1,21 +1,76 @@
package net.pokeranalytics.android.ui.fragment package net.pokeranalytics.android.ui.fragment
import android.app.DatePickerDialog
import android.os.Bundle import android.os.Bundle
import com.google.android.material.bottomsheet.BottomSheetDialogFragment import com.google.android.material.bottomsheet.BottomSheetDialogFragment
import kotlinx.android.synthetic.main.fragment_bottom_sheet_container.*
import android.content.Context
import android.content.DialogInterface import android.content.DialogInterface
import android.view.* import android.view.*
import android.view.inputmethod.InputMethodManager import androidx.constraintlayout.widget.ConstraintLayout
import kotlinx.android.synthetic.main.bottom_sheet_blinds.*
import kotlinx.android.synthetic.main.bottom_sheet_date.*
import kotlinx.android.synthetic.main.fragment_bottom_sheet.*
import kotlinx.android.synthetic.main.fragment_bottom_sheet.view.*
import net.pokeranalytics.android.ui.adapter.components.DynamicRowInterface
import net.pokeranalytics.android.ui.adapter.components.EditableDataDelegate
import net.pokeranalytics.android.ui.fragment.components.BottomSheetType
import timber.log.Timber
import android.widget.DatePicker
import net.pokeranalytics.android.util.DatePickerFragment
import net.pokeranalytics.android.util.TimePickerFragment
import java.util.*
class BottomSheetFragment : BottomSheetDialogFragment() { class BottomSheetFragment : BottomSheetDialogFragment() {
private var row: DynamicRowInterface? = null
private var valueDelegate: EditableDataDelegate? = null
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
val view = inflater.inflate(
net.pokeranalytics.android.R.layout.fragment_bottom_sheet,
container,
false
) as ConstraintLayout
row?.let {
when (it.bottomSheetType) {
BottomSheetType.BANKROLL -> inflater.inflate(
net.pokeranalytics.android.R.layout.bottom_sheet_bankroll,
view.bottomSheetContainer,
true
)
BottomSheetType.BLINDS -> inflater.inflate(
net.pokeranalytics.android.R.layout.bottom_sheet_blinds,
view.bottomSheetContainer,
true
)
BottomSheetType.DATE -> inflater.inflate(
net.pokeranalytics.android.R.layout.bottom_sheet_date,
view.bottomSheetContainer,
true
)
BottomSheetType.GAME -> inflater.inflate(
net.pokeranalytics.android.R.layout.bottom_sheet_game,
view.bottomSheetContainer,
true
)
BottomSheetType.LOCATION -> inflater.inflate(
net.pokeranalytics.android.R.layout.bottom_sheet_location,
view.bottomSheetContainer,
true
)
BottomSheetType.TABLE_SIZE -> inflater.inflate(
net.pokeranalytics.android.R.layout.bottom_sheet_table_size,
view.bottomSheetContainer,
true
)
else -> {
}
}
}
return inflater.inflate(net.pokeranalytics.android.R.layout.fragment_bottom_sheet_container, container, false) return view
} }
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
@ -23,46 +78,80 @@ class BottomSheetFragment : BottomSheetDialogFragment() {
initUI() initUI()
} }
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
// To display correctly the keyboard
dialog?.window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE)
}
override fun onStart() { override fun onStart() {
super.onStart() super.onStart()
// Open the keyboard // Open the keyboard
/* row?.let {
val inputMethodManager = requireContext().getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager when (it.bottomSheetType) {
inputMethodManager.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0) BottomSheetType.BLINDS -> {
editText.requestFocus() smallBlind.requestFocus()
*/ }
else -> {
}
}
}
} }
/**
* Actions:
* - Add / Add ?
* - Clear / Garbage ?
* - Done / Check ?
* -
*/
override fun onDismiss(dialog: DialogInterface?) { override fun onDismiss(dialog: DialogInterface?) {
super.onDismiss(dialog) super.onDismiss(dialog)
val inputMethodManager = requireContext().getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
inputMethodManager.toggleSoftInput(InputMethodManager.HIDE_IMPLICIT_ONLY, 0) // Return the value
row?.let {
valueDelegate?.setValue("Test", it)
}
} }
/** /**
* Init UI * Init UI
*/ */
private fun initUI() { private fun initUI() {
close.setOnClickListener {
dismiss() row?.let {
//bottomSheetToolbar.title = row?.localizedTitle(requireContext())
bottomSheetToolbar.inflateMenu(net.pokeranalytics.android.R.menu.bottom_sheet_menu)
bottomSheetToolbar.setOnMenuItemClickListener {
false
}
}
row?.let {
when (it.bottomSheetType) {
BottomSheetType.DATE -> initDateUI()
else -> {}
}
} }
} }
/** /**
* * Init date UI
*/ */
fun displayDataForRow() { private fun initDateUI() {
startDate.setOnClickListener {
val dateFragment = DatePickerFragment()
dateFragment.show(fragmentManager, "datePicker")
}
endDate.setOnClickListener {
val timeFragment = TimePickerFragment()
timeFragment.show(fragmentManager, "timePicker")
}
} }
/**
* Init
*/
fun init(row: DynamicRowInterface, valueDelegate: EditableDataDelegate) {
this.row = row
this.valueDelegate = valueDelegate
}
} }

@ -18,9 +18,10 @@ import net.pokeranalytics.android.ui.adapter.NewSessionAdapter
import net.pokeranalytics.android.ui.adapter.components.DynamicListAdapter import net.pokeranalytics.android.ui.adapter.components.DynamicListAdapter
import net.pokeranalytics.android.ui.adapter.components.DynamicRowCallback import net.pokeranalytics.android.ui.adapter.components.DynamicRowCallback
import net.pokeranalytics.android.ui.adapter.components.DynamicRowInterface import net.pokeranalytics.android.ui.adapter.components.DynamicRowInterface
import net.pokeranalytics.android.ui.adapter.components.EditableDataDelegate
import net.pokeranalytics.android.util.PokerAnalyticsFragment import net.pokeranalytics.android.util.PokerAnalyticsFragment
class NewSessionFragment : PokerAnalyticsFragment(), DynamicRowCallback { class NewSessionFragment : PokerAnalyticsFragment(), DynamicRowCallback, EditableDataDelegate {
private lateinit var newSession: Session private lateinit var newSession: Session
@ -30,13 +31,17 @@ class NewSessionFragment : PokerAnalyticsFragment(), DynamicRowCallback {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
initData() initData()
initUI() initUI()
} }
override fun onRowSelected(row: DynamicRowInterface) { override fun onRowSelected(row: DynamicRowInterface) {
val bottomSheetFragment = openBottomSheet(row) val bottomSheetFragment = openBottomSheet()
bottomSheetFragment.init(row, this)
}
override fun setValue(value: Any, row: DynamicRowInterface) {
Toast.makeText(requireContext(), "Callback for ${row.localizedTitle(requireContext())} ($value)", Toast.LENGTH_SHORT).show()
} }
private fun initData() { private fun initData() {

@ -4,6 +4,7 @@ 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 androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import kotlinx.android.synthetic.main.fragment_settings.* import kotlinx.android.synthetic.main.fragment_settings.*
import net.pokeranalytics.android.R import net.pokeranalytics.android.R
@ -39,11 +40,12 @@ class SettingsFragment : PokerAnalyticsFragment(), DynamicRowDelegate, DynamicRo
override fun adapterRows(): ArrayList<DynamicRowInterface> { override fun adapterRows(): ArrayList<DynamicRowInterface> {
val rows = ArrayList<DynamicRowInterface>() val rows = ArrayList<DynamicRowInterface>()
rows.addAll(DataObjectRowType.values()) rows.addAll(BusinessObjectRowType.values())
return rows return rows
} }
override fun onRowSelected(row: DynamicRowInterface) { override fun onRowSelected(row: DynamicRowInterface) {
val bottomSheetFragment = openBottomSheet(row)
} }
/** /**

@ -0,0 +1,13 @@
package net.pokeranalytics.android.ui.fragment.components
enum class BottomSheetType {
NONE,
GAME,
BLINDS,
LOCATION,
BANKROLL,
TABLE_SIZE,
DATE
}

@ -0,0 +1,26 @@
package net.pokeranalytics.android.util
import android.app.DatePickerDialog
import android.app.Dialog
import android.os.Bundle
import android.widget.DatePicker
import androidx.fragment.app.DialogFragment
import java.util.*
class DatePickerFragment : DialogFragment(), DatePickerDialog.OnDateSetListener {
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
// Use the current date as the default date in the picker
val c = Calendar.getInstance()
val year = c.get(Calendar.YEAR)
val month = c.get(Calendar.MONTH)
val day = c.get(Calendar.DAY_OF_MONTH)
// Create a new instance of DatePickerDialog and return it
return DatePickerDialog(activity, this, year, month, day)
}
override fun onDateSet(view: DatePicker, year: Int, month: Int, day: Int) {
// Do something with the date chosen by the user
}
}

@ -27,8 +27,7 @@ open class PokerAnalyticsFragment: Fragment() {
/** /**
* Open the bottom sheet * Open the bottom sheet
*/ */
fun openBottomSheet(row: DynamicRowInterface): BottomSheetFragment { fun openBottomSheet(): BottomSheetFragment {
//TODO: Give the data to display in the bottom sheet here
val bottomSheetFragment = BottomSheetFragment() val bottomSheetFragment = BottomSheetFragment()
bottomSheetFragment.show(fragmentManager, "bottomSheet") bottomSheetFragment.show(fragmentManager, "bottomSheet")
return bottomSheetFragment return bottomSheetFragment

@ -0,0 +1,26 @@
package net.pokeranalytics.android.util
import android.app.Dialog
import android.app.TimePickerDialog
import android.os.Bundle
import android.text.format.DateFormat
import android.widget.TimePicker
import androidx.fragment.app.DialogFragment
import java.util.*
class TimePickerFragment : DialogFragment(), TimePickerDialog.OnTimeSetListener {
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
// Use the current time as the default values for the picker
val c = Calendar.getInstance()
val hour = c.get(Calendar.HOUR_OF_DAY)
val minute = c.get(Calendar.MINUTE)
// Create a new instance of TimePickerDialog and return it
return TimePickerDialog(activity, this, hour, minute, DateFormat.is24HourFormat(activity))
}
override fun onTimeSet(view: TimePicker, hourOfDay: Int, minute: Int) {
// Do something with the time chosen by the user
}
}

@ -0,0 +1,5 @@
<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="M19,13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/>
</vector>

@ -0,0 +1,5 @@
<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="M9,16.17L4.83,12l-1.42,1.41L9,19 21,7l-1.41,-1.41z"/>
</vector>

@ -0,0 +1,5 @@
<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="M19,6.41L17.59,5 12,10.59 6.41,5 5,6.41 10.59,12 5,17.59 6.41,19 12,13.41 17.59,19 19,17.59 13.41,12z"/>
</vector>

@ -0,0 +1,5 @@
<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>

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/bankrollRecyclerView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="200dp" />
</LinearLayout>

@ -0,0 +1,59 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
tools:background="@color/gray_dark_1">
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/appCompatTextView"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:layout_marginEnd="8dp"
android:layout_marginBottom="16dp"
android:text="Blinds"
android:textColor="@color/white"
android:textSize="16sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/smallBlind"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<androidx.appcompat.widget.AppCompatEditText
android:id="@+id/smallBlind"
android:layout_width="96dp"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:layout_marginBottom="8dp"
android:gravity="end|center_vertical"
android:imeOptions="actionNext"
android:inputType="numberDecimal"
android:lines="1"
android:textColor="@color/white"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/bigBlind"
app:layout_constraintTop_toTopOf="parent" />
<androidx.appcompat.widget.AppCompatEditText
android:id="@+id/bigBlind"
android:layout_width="96dp"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:layout_marginBottom="8dp"
android:gravity="end|center_vertical"
android:imeOptions="actionDone"
android:inputType="numberDecimal"
android:lines="1"
android:textColor="@color/white"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

@ -0,0 +1,32 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<androidx.appcompat.widget.AppCompatButton
android:id="@+id/startDate"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:layout_marginBottom="16dp"
android:text="Set start date"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<androidx.appcompat.widget.AppCompatButton
android:id="@+id/endDate"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:layout_marginEnd="16dp"
android:layout_marginBottom="16dp"
android:text="Set end date"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/gameTypeRecyclerView"
android:layout_width="80dp"
android:layout_height="wrap_content"
android:minHeight="200dp" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/gameNameRecyclerView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="200dp" />
</LinearLayout>

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/locationRecyclerView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="200dp" />
</LinearLayout>

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/locationRecyclerView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="200dp" />
</LinearLayout>

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#222222">
<androidx.appcompat.widget.Toolbar
android:id="@+id/bottomSheetToolbar"
style="@style/BottomSheetToolbar"
android:layout_width="0dp"
android:layout_height="?actionBarSize"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:title="Test" />
<FrameLayout
android:id="@+id/bottomSheetContainer"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/bottomSheetToolbar" />
</androidx.constraintlayout.widget.ConstraintLayout>

@ -1,45 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#222222">
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/appCompatTextView"
android:layout_width="0dp"
android:layout_height="220dp"
android:gravity="center"
android:text="Bottom sheet fragment"
android:textColor="#FFFFFF"
android:textSize="18sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/close"
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:background="?selectableItemBackgroundBorderless"
android:scaleType="centerInside"
android:src="@drawable/ic_close_24dp"
android:tint="@color/white"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@+id/appCompatTextView" />
<androidx.appcompat.widget.AppCompatEditText
android:id="@+id/editText"
android:layout_width="180dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:textColor="@color/white"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

@ -0,0 +1,23 @@
<?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"
xmlns:tools="http://schemas.android.com/tools">
<item
android:id="@+id/actionClear"
android:orderInCategory="100"
android:title="@string/app_name"
android:icon="@drawable/ic_close_white_24dp"
app:showAsAction="always" />
<item
android:id="@+id/actionAdd"
android:icon="@drawable/ic_add_white_24dp"
android:orderInCategory="200"
android:title="Search"
app:showAsAction="ifRoom" />
<item
android:id="@+id/actionSave"
android:icon="@drawable/ic_check_white_24dp"
android:orderInCategory="300"
android:title="User"
app:showAsAction="ifRoom" />
</menu>

@ -8,4 +8,10 @@
<item name="colorAccent">@color/colorAccent</item> <item name="colorAccent">@color/colorAccent</item>
</style> </style>
<style name="BottomSheetToolbar" parent="AppTheme">
<item name="android:background">@color/gray_dark_1</item>
<item name="titleTextColor">@color/white</item>
</style>
</resources> </resources>

@ -1,17 +1,52 @@
package net.pokeranalytics.android package net.pokeranalytics.android
import net.pokeranalytics.android.calculus.*
import net.pokeranalytics.android.model.realm.TimeFrameGroup
import org.junit.Assert.fail
import org.junit.Test import org.junit.Test
import org.junit.Assert.*
/** /**
* Example local unit test, which will execute on the development machine (host). * Example local unit test, which will execute on the development machine (host).
* *
* See [testing documentation](http://d.android.com/tools/testing). * See [testing documentation](http://d.android.com/tools/testing).
*/ */
class ExampleUnitTest { class ExampleUnitTest {
class Grade(someValue: Double) : SessionInterface {
// override var serie: Serie = Serie(TimeFrame())
override var value: Double = someValue
override var serie: TimeFrameGroup = TimeFrameGroup()
override var estimatedHands: Double = 0.0
override var bbNetResult: Double = 0.0
override var bigBlindSessionCount: Int = 0 // 0 or 1
override var buyin: Double = 0.0
}
@Test @Test
fun addition_isCorrect() { fun testStats() {
assertEquals(4, 2 + 2)
val grades: List<Grade> = listOf(Grade(someValue = 10.0), Grade(someValue = 20.0))
val group = SessionGroup(name = "test", sessions = grades)
val results: ComputedResults = Calculator.compute(group, Calculator.Options())
val sum = results.computedStat(Stat.NETRESULT)
if (sum != null) {
assert(sum.value == 30.0)
} else {
fail("No Net result stat")
}
val average = results.computedStat(Stat.AVERAGE)
if (average != null) {
assert(average.value == 15.0)
} else {
fail("No AVERAGE stat")
}
} }
} }

Loading…
Cancel
Save