Grid calendar + hands count CSV management

blinds
Laurent 5 years ago
parent 5f2ffdb306
commit 4044cee176
  1. 5
      app/src/main/AndroidManifest.xml
  2. 6
      app/src/main/java/net/pokeranalytics/android/ui/adapter/RowRepresentableAdapter.kt
  3. 10
      app/src/main/java/net/pokeranalytics/android/ui/modules/calendar/CalendarFragment.kt
  4. 60
      app/src/main/java/net/pokeranalytics/android/ui/modules/calendar/GridCalendarFragment.kt
  5. 223
      app/src/main/java/net/pokeranalytics/android/ui/modules/calendar/GridCalendarViewModel.kt
  6. 2
      app/src/main/java/net/pokeranalytics/android/ui/modules/handhistory/views/KeyboardActionView.kt
  7. 2
      app/src/main/java/net/pokeranalytics/android/ui/view/RowRepresentable.kt
  8. 105
      app/src/main/java/net/pokeranalytics/android/ui/view/RowViewType.kt
  9. 1
      app/src/main/java/net/pokeranalytics/android/util/csv/PACSVDescriptor.kt
  10. 1
      app/src/main/java/net/pokeranalytics/android/util/csv/ProductCSVDescriptors.kt
  11. 1
      app/src/main/java/net/pokeranalytics/android/util/csv/SessionCSVDescriptor.kt
  12. 5
      app/src/main/java/net/pokeranalytics/android/util/csv/SessionField.kt
  13. 19
      app/src/main/java/net/pokeranalytics/android/util/extensions/DateExtension.kt
  14. 6
      app/src/main/java/net/pokeranalytics/android/util/extensions/RealmExtensions.kt
  15. 6
      app/src/main/res/drawable/rounded_grey_rect.xml
  16. 16
      app/src/main/res/layout-sw320dp/fragment_calendar.xml
  17. 16
      app/src/main/res/layout-sw400dp/fragment_calendar.xml
  18. 2
      app/src/main/res/layout/activity_grid_calendar.xml
  19. 29
      app/src/main/res/layout/cell_calendar_grid.xml
  20. 8
      app/src/main/res/layout/cell_calendar_time_unit.xml
  21. 16
      app/src/main/res/layout/fragment_calendar.xml
  22. 73
      app/src/main/res/layout/fragment_grid_calendar.xml

@ -183,6 +183,11 @@
android:launchMode="singleTop" android:launchMode="singleTop"
android:screenOrientation="portrait" /> android:screenOrientation="portrait" />
<activity
android:name="net.pokeranalytics.android.ui.modules.calendar.GridCalendarActivity"
android:launchMode="singleTop"
android:screenOrientation="portrait" />
<!-- No screenOrientation="portrait" to fix Oreo crash --> <!-- No screenOrientation="portrait" to fix Oreo crash -->
<activity <activity
android:name="net.pokeranalytics.android.ui.activity.ColorPickerActivity" android:name="net.pokeranalytics.android.ui.activity.ColorPickerActivity"

@ -1,6 +1,5 @@
package net.pokeranalytics.android.ui.adapter package net.pokeranalytics.android.ui.adapter
import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
@ -65,4 +64,9 @@ class RowRepresentableAdapter(
diffResult.dispatchUpdatesTo(this) diffResult.dispatchUpdatesTo(this)
} }
fun changeDataSource(dataSource: RowRepresentableDataSource) {
this.dataSource = dataSource
}
} }

@ -198,6 +198,10 @@ class CalendarFragment : RealmFragment(), CoroutineScope, StaticRowRepresentable
*/ */
private fun initUI() { private fun initUI() {
this.binding.gridButton.setOnClickListener {
showGridCalendar()
}
CalendarTabs.values().forEach { CalendarTabs.values().forEach {
val tab = binding.tabs.newTab() val tab = binding.tabs.newTab()
tab.text = getString(it.resId) tab.text = getString(it.resId)
@ -564,10 +568,10 @@ class CalendarFragment : RealmFragment(), CoroutineScope, StaticRowRepresentable
Timber.d("Display data: ${System.currentTimeMillis() - startDate.time}ms") Timber.d("Display data: ${System.currentTimeMillis() - startDate.time}ms")
Timber.d("Rows: ${rows.size}") Timber.d("Rows: ${rows.size}")
calendarAdapter.notifyDataSetChanged() this.calendarAdapter.notifyDataSetChanged()
binding.progressBar.hideWithAnimation() this.binding.progressBar.hideWithAnimation()
binding.recyclerView.showWithAnimation() this.binding.recyclerView.showWithAnimation()
} }

@ -4,31 +4,85 @@ 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 net.pokeranalytics.android.databinding.FragmentDealtHandsConfigBinding import androidx.lifecycle.ViewModelProvider
import androidx.recyclerview.widget.GridLayoutManager
import net.pokeranalytics.android.R
import net.pokeranalytics.android.databinding.FragmentGridCalendarBinding
import net.pokeranalytics.android.ui.adapter.RowRepresentableAdapter
import net.pokeranalytics.android.ui.extensions.px
import net.pokeranalytics.android.ui.fragment.components.BaseFragment import net.pokeranalytics.android.ui.fragment.components.BaseFragment
import net.pokeranalytics.android.ui.view.GridSpacingItemDecoration
class GridCalendarFragment : BaseFragment() { class GridCalendarFragment : BaseFragment() {
private var _binding: FragmentDealtHandsConfigBinding? = null private val model: GridCalendarViewModel by lazy {
ViewModelProvider(this).get(GridCalendarViewModel::class.java)
}
private var _binding: FragmentGridCalendarBinding? = null
private val binding get() = _binding!! private val binding get() = _binding!!
private lateinit var dataAdapter: RowRepresentableAdapter
override fun onCreateView( override fun onCreateView(
inflater: LayoutInflater, inflater: LayoutInflater,
container: ViewGroup?, container: ViewGroup?,
savedInstanceState: Bundle? savedInstanceState: Bundle?
): View { ): View {
super.onCreateView(inflater, container, savedInstanceState) super.onCreateView(inflater, container, savedInstanceState)
_binding = FragmentDealtHandsConfigBinding.inflate(inflater, container, false) _binding = FragmentGridCalendarBinding.inflate(inflater, container, false)
return binding.root return binding.root
} }
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
initUI() initUI()
initData()
} }
private fun initUI() { private fun initUI() {
setDisplayHomeAsUpEnabled(true)
this.binding.dayUnit.text = getString(R.string.day).capitalize()
this.dataAdapter = RowRepresentableAdapter(this.model)
val spanCount = 2
val spacing = 8.px
val includeEdge = false
val viewManager = GridLayoutManager(context, spanCount)
this.binding.recyclerView.apply {
setHasFixedSize(true)
layoutManager = viewManager
adapter = dataAdapter
addItemDecoration(GridSpacingItemDecoration(spanCount, spacing, includeEdge))
}
this.binding.dayUnit.setOnCheckedChangeListener { _, isChecked ->
if (isChecked && this.model.selectedTimeUnit != TimeUnit.DAY) {
this.model.selectedTimeUnit = TimeUnit.DAY
this.launch()
}
}
this.binding.monthUnit.setOnCheckedChangeListener { _, isChecked ->
if (isChecked && this.model.selectedTimeUnit != TimeUnit.MONTH) {
this.model.selectedTimeUnit = TimeUnit.MONTH
this.launch()
}
}
}
private fun initData() {
this.launch()
}
private fun launch() {
this.model.buildDataStructure()
this.dataAdapter.notifyDataSetChanged()
} }
} }

@ -0,0 +1,223 @@
package net.pokeranalytics.android.ui.modules.calendar
import androidx.lifecycle.ViewModel
import io.realm.Realm
import net.pokeranalytics.android.R
import net.pokeranalytics.android.exceptions.PAIllegalStateException
import net.pokeranalytics.android.model.filter.Query
import net.pokeranalytics.android.model.filter.QueryCondition
import net.pokeranalytics.android.model.realm.Session
import net.pokeranalytics.android.ui.adapter.RowRepresentableDataSource
import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.RowViewType
import net.pokeranalytics.android.util.extensions.*
import java.util.*
import kotlin.collections.HashMap
class GridCalendarViewModel : ViewModel(), RowRepresentableDataSource {
var selectedTimeUnit: TimeUnit = TimeUnit.DAY
private var groups: TreeSet<Date> = TreeSet<Date>()
private var results: HashMap<Date, CalendarItemCell> = HashMap()
private fun addGroup(date: Date) {
this.groups.add(date)
}
private fun result(index: Int): CalendarItemCell {
val group = this.groups.elementAt(index)
return this.results[group] ?: throw PAIllegalStateException("item not found")
}
private fun addResult(group: Date, result: CellResult, unit: TimeUnit) {
this.addGroup(group)
this.results[group]?.add(result) ?: run {
this.results[group] = CalendarItemCell(group, result, unit)
}
}
private fun clear() {
this.groups.clear()
this.results.clear()
}
fun buildDataStructure() {
// Timber.d(">>> Start buildDataStructure: ${this.selectedTimeUnit}")
this.clear()
val realm = Realm.getDefaultInstance()
val query = Query(QueryCondition.DateNotNull, QueryCondition.EndDateNotNull)
val sessions = realm.findAll<Session>(query, "startDate")
val groupedSessions = when (this.selectedTimeUnit) {
TimeUnit.DAY -> sessions.groupBy { it.startDate!!.startOfDay() }
TimeUnit.MONTH -> sessions.groupBy { it.startDate!!.startOfMonth() }
}
val firstDate = sessions.firstOrNull()?.startDate?.startOf(this.selectedTimeUnit.groupingUnit)
val lastDate = sessions.lastOrNull()?.startDate?.endOf(this.selectedTimeUnit.groupingUnit)
// Timber.d("f = $firstDate, e = $lastDate")
if (firstDate != null && lastDate != null) {
var tmpDate: Date = firstDate.startOfDay()
val calendar = Calendar.getInstance()
while (tmpDate.time <= lastDate.time) {
val result = groupedSessions[tmpDate]?.let { bucket ->
if (bucket.sumByDouble {
it.result?.net ?: 0.0
} > 0.0) CellResult.POSITIVE else CellResult.NEGATIVE
} ?: run {
CellResult.EMPTY
}
val groupingDate = tmpDate.startOf(this.selectedTimeUnit.groupingUnit)
this.addResult(groupingDate, result, this.selectedTimeUnit)
// change tmp date
calendar.time = tmpDate
calendar.add(selectedTimeUnit.calendarUnit, 1)
tmpDate = calendar.time
}
}
}
// RowRepresentableDataSource
override fun adapterRows(): List<RowRepresentable> {
return this.groups.descendingSet().map { this.results[it]!! }
}
override fun rowRepresentableForPosition(position: Int): RowRepresentable {
return this.result(position)
}
override fun numberOfRows(): Int {
return this.results.size
}
override fun viewTypeForPosition(position: Int): Int {
return RowViewType.CALENDAR_GRID_CELL.ordinal
}
}
class CalendarItemCell(var date: Date, result: CellResult, var unit: TimeUnit) : RowRepresentable, RowRepresentableDataSource {
private var results: MutableList<CellResult> = mutableListOf(result)
private set
fun add(result: CellResult) {
this.results.add(result)
}
val size: Int = this.results.size
override val viewType: Int = RowViewType.CALENDAR_GRID_CELL.ordinal
val title: String
get() {
return when (unit) {
TimeUnit.DAY -> date.getMonthAndYear()
TimeUnit.MONTH -> date.getDateYear()
}
}
// RowRepresentableDataSource
override fun adapterRows(): List<RowRepresentable> {
return this.results
}
override fun rowRepresentableForPosition(position: Int): RowRepresentable {
return this.results[position]
}
override fun numberOfRows(): Int {
return this.results.size
}
override fun viewTypeForPosition(position: Int): Int {
return RowViewType.CALENDAR_TIME_UNIT_CELL.ordinal
}
}
enum class TimeUnit {
DAY,
MONTH;
val calendarUnit: Int
get() {
return when (this) {
DAY -> Calendar.DAY_OF_MONTH
MONTH -> Calendar.MONTH
}
}
val groupingUnit: Int
get() {
return when (this) {
DAY -> Calendar.MONTH
MONTH -> Calendar.YEAR
}
}
val spanCount: Int
get() {
return when (this) {
DAY -> 7
MONTH -> 4
}
}
}
enum class CellResult : RowRepresentable {
POSITIVE,
NEGATIVE,
EMPTY;
val background: Int
get() {
return when (this) {
POSITIVE -> R.drawable.rounded_green_rect
NEGATIVE -> R.drawable.rounded_red_rect
EMPTY -> R.drawable.rounded_grey_rect
}
}
override val viewType: Int = RowViewType.CALENDAR_TIME_UNIT_CELL.ordinal
}
private fun Date.startOf(unit: Int): Date {
return when (unit) {
Calendar.DAY_OF_MONTH -> this.startOfDay()
Calendar.MONTH -> this.startOfMonth()
Calendar.YEAR -> this.startOfYear()
else -> throw PAIllegalStateException("Un-managed case: $unit")
}
}
private fun Date.endOf(unit: Int): Date {
return when (unit) {
Calendar.DAY_OF_MONTH -> this.endOfDay()
Calendar.MONTH -> this.endOfMonth()
Calendar.YEAR -> this.endOfYear()
else -> throw PAIllegalStateException("Un-managed case: $unit")
}
}

@ -41,12 +41,12 @@ class KeyboardActionView(context: Context) : AbstractKeyboardView(context),
// Action recycler // Action recycler
val spanCount = 3 val spanCount = 3
val viewManager = GridLayoutManager(context, spanCount)
this.dataAdapter = RowRepresentableAdapter(this, this) this.dataAdapter = RowRepresentableAdapter(this, this)
val spacing = 2.px val spacing = 2.px
val includeEdge = false val includeEdge = false
val viewManager = GridLayoutManager(context, spanCount)
actionRecyclerView.apply { actionRecyclerView.apply {
setHasFixedSize(true) setHasFixedSize(true)
layoutManager = viewManager layoutManager = viewManager

@ -2,7 +2,6 @@ package net.pokeranalytics.android.ui.view
import android.content.Context import android.content.Context
import net.pokeranalytics.android.model.LiveData import net.pokeranalytics.android.model.LiveData
import net.pokeranalytics.android.model.interfaces.Identifiable
import net.pokeranalytics.android.ui.fragment.components.bottomsheet.BottomSheetType import net.pokeranalytics.android.ui.fragment.components.bottomsheet.BottomSheetType
import net.pokeranalytics.android.util.NULL_TEXT import net.pokeranalytics.android.util.NULL_TEXT
@ -14,6 +13,7 @@ interface RowRepresentable : Displayable, EditDataSource, ImageDecorator {
fun getDisplayName(context: Context): String { fun getDisplayName(context: Context): String {
return NULL_TEXT return NULL_TEXT
} }
} }
interface EditDataSource { interface EditDataSource {

@ -7,14 +7,18 @@ import android.widget.FrameLayout
import androidx.appcompat.widget.AppCompatImageView import androidx.appcompat.widget.AppCompatImageView
import androidx.appcompat.widget.AppCompatTextView import androidx.appcompat.widget.AppCompatTextView
import androidx.constraintlayout.widget.ConstraintLayout import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.content.ContextCompat
import androidx.core.view.isVisible import androidx.core.view.isVisible
import androidx.core.widget.ContentLoadingProgressBar import androidx.core.widget.ContentLoadingProgressBar
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import com.github.mikephil.charting.charts.BarChart import com.github.mikephil.charting.charts.BarChart
import com.github.mikephil.charting.charts.LineChart import com.github.mikephil.charting.charts.LineChart
import com.github.mikephil.charting.data.* import com.github.mikephil.charting.data.*
import com.google.android.material.chip.Chip import com.google.android.material.chip.Chip
import com.google.android.material.chip.ChipGroup import com.google.android.material.chip.ChipGroup
import kotlinx.android.synthetic.main.cell_calendar_time_unit.view.*
import kotlinx.android.synthetic.main.row_recycler.view.*
import net.pokeranalytics.android.R import net.pokeranalytics.android.R
import net.pokeranalytics.android.calculus.ComputedStat import net.pokeranalytics.android.calculus.ComputedStat
import net.pokeranalytics.android.calculus.Stat import net.pokeranalytics.android.calculus.Stat
@ -27,12 +31,16 @@ import net.pokeranalytics.android.model.realm.Session
import net.pokeranalytics.android.model.realm.Transaction import net.pokeranalytics.android.model.realm.Transaction
import net.pokeranalytics.android.ui.adapter.BindableHolder import net.pokeranalytics.android.ui.adapter.BindableHolder
import net.pokeranalytics.android.ui.adapter.RecyclerAdapter import net.pokeranalytics.android.ui.adapter.RecyclerAdapter
import net.pokeranalytics.android.ui.adapter.RowRepresentableAdapter
import net.pokeranalytics.android.ui.extensions.ChipGroupExtension import net.pokeranalytics.android.ui.extensions.ChipGroupExtension
import net.pokeranalytics.android.ui.extensions.dp
import net.pokeranalytics.android.ui.extensions.px import net.pokeranalytics.android.ui.extensions.px
import net.pokeranalytics.android.ui.extensions.setTextFormat import net.pokeranalytics.android.ui.extensions.setTextFormat
import net.pokeranalytics.android.ui.graph.Graph import net.pokeranalytics.android.ui.graph.Graph
import net.pokeranalytics.android.ui.modules.bankroll.BankrollRowRepresentable import net.pokeranalytics.android.ui.modules.bankroll.BankrollRowRepresentable
import net.pokeranalytics.android.ui.graph.setStyle import net.pokeranalytics.android.ui.graph.setStyle
import net.pokeranalytics.android.ui.modules.calendar.CalendarItemCell
import net.pokeranalytics.android.ui.modules.calendar.CellResult
import net.pokeranalytics.android.ui.modules.handhistory.views.RowHandHistoryViewHolder import net.pokeranalytics.android.ui.modules.handhistory.views.RowHandHistoryViewHolder
import net.pokeranalytics.android.ui.view.holder.RowViewHolder import net.pokeranalytics.android.ui.view.holder.RowViewHolder
import net.pokeranalytics.android.ui.view.rows.* import net.pokeranalytics.android.ui.view.rows.*
@ -86,6 +94,8 @@ enum class RowViewType(private var layoutRes: Int) : ViewIdentifier {
ROW_PLAYER(R.layout.row_player), ROW_PLAYER(R.layout.row_player),
ROW_PLAYER_IMAGE(R.layout.row_player_image), ROW_PLAYER_IMAGE(R.layout.row_player_image),
HAND_HISTORY(R.layout.row_hand_history_view), HAND_HISTORY(R.layout.row_hand_history_view),
CALENDAR_GRID_CELL(R.layout.cell_calendar_grid),
CALENDAR_TIME_UNIT_CELL(R.layout.cell_calendar_time_unit),
// ROW_HAND_ACTION(R.layout.row_hand_action), // ROW_HAND_ACTION(R.layout.row_hand_action),
// ROW_HAND_STREET(R.layout.row_hand_cards), // ROW_HAND_STREET(R.layout.row_hand_cards),
@ -147,6 +157,9 @@ enum class RowViewType(private var layoutRes: Int) : ViewIdentifier {
// ROW_HAND_ACTION -> RowHandAction(layout) // ROW_HAND_ACTION -> RowHandAction(layout)
// ROW_HAND_STREET -> RowHandStreet(layout) // ROW_HAND_STREET -> RowHandStreet(layout)
CALENDAR_GRID_CELL -> CalendarGridCellHolder(layout)
CALENDAR_TIME_UNIT_CELL -> CalendarTimeUnitCellHolder(layout)
// Separator // Separator
SEPARATOR -> SeparatorViewHolder(layout) SEPARATOR -> SeparatorViewHolder(layout)
@ -526,7 +539,6 @@ enum class RowViewType(private var layoutRes: Int) : ViewIdentifier {
} }
} }
/** /**
* Display a player image view * Display a player image view
*/ */
@ -569,7 +581,6 @@ enum class RowViewType(private var layoutRes: Int) : ViewIdentifier {
} }
} }
/** /**
* Display a separator * Display a separator
*/ */
@ -579,4 +590,94 @@ enum class RowViewType(private var layoutRes: Int) : ViewIdentifier {
} }
} }
inner class CalendarGridCellHolder(itemView: View) : RecyclerView.ViewHolder(itemView),
BindableHolder {
private var spanCount = 7
init {
itemView.findViewById<RecyclerView?>(R.id.recyclerView)?.let { recyclerView ->
// val spanCount = row.unit.spanCount
val spacing = 4.px
val includeEdge = true
val viewManager = object : GridLayoutManager(itemView.context, spanCount) {
override fun checkLayoutParams(lp: RecyclerView.LayoutParams?): Boolean {
val side = width / this.spanCount - 4.px
lp?.let { params ->
params.width = side
params.height = side
}
return true
}
}
recyclerView.apply {
setHasFixedSize(true)
layoutManager = viewManager
addItemDecoration(GridSpacingItemDecoration(spanCount, spacing, includeEdge))
}
}
}
private fun setLayoutManager(spanCount: Int) {
itemView.findViewById<RecyclerView?>(R.id.recyclerView)?.let { recyclerView ->
val viewManager = object : GridLayoutManager(itemView.context, spanCount) {
override fun checkLayoutParams(lp: RecyclerView.LayoutParams?): Boolean {
val side = width / spanCount - 4.px
lp?.let { params ->
params.width = side
params.height = side
}
return true
}
}
recyclerView.layoutManager = viewManager
}
}
override fun onBind(position: Int, row: RowRepresentable, adapter: RecyclerAdapter) {
if (row is CalendarItemCell) {
val sc = row.unit.spanCount
if (this.spanCount != sc) {
setLayoutManager(sc)
this.spanCount = sc
}
itemView.findViewById<RecyclerView?>(R.id.recyclerView)?.let { recyclerView ->
if (recyclerView.adapter == null) {
recyclerView.adapter = RowRepresentableAdapter(row)
} else {
(recyclerView.adapter as RowRepresentableAdapter).changeDataSource(row)
}
recyclerView.adapter?.notifyDataSetChanged()
}
itemView.findViewById<AppCompatTextView?>(R.id.title)?.let { textView ->
textView.text = row.title
}
}
}
}
inner class CalendarTimeUnitCellHolder(itemView: View) : RecyclerView.ViewHolder(itemView),
BindableHolder {
override fun onBind(position: Int, row: RowRepresentable, adapter: RecyclerAdapter) {
if (row is CellResult) {
itemView.timeUnit.background = ContextCompat.getDrawable(itemView.context, row.background)
}
}
}
} }

@ -121,6 +121,7 @@ abstract class PACSVDescriptor<T : Identifiable>(source: DataSource,
is SessionField.Addon -> additionalBuyins += field.parse(value) ?: 0.0 is SessionField.Addon -> additionalBuyins += field.parse(value) ?: 0.0
is SessionField.Rebuy -> additionalBuyins += field.parse(value) ?: 0.0 is SessionField.Rebuy -> additionalBuyins += field.parse(value) ?: 0.0
is SessionField.Tips -> session.result?.tips = field.parse(value) is SessionField.Tips -> session.result?.tips = field.parse(value)
is SessionField.HandsCount -> session.handsCount = field.parse(value)
is SessionField.Break -> { is SessionField.Break -> {
field.parse(value)?.let { field.parse(value)?.let {
session.breakDuration = it.toLong() session.breakDuration = it.toLong()

@ -220,6 +220,7 @@ class ProductCSVDescriptors {
SessionField.CashedOut("Cashed Out"), SessionField.CashedOut("Cashed Out"),
SessionField.NetResult("Online Net"), SessionField.NetResult("Online Net"),
SessionField.Tips("Tips"), SessionField.Tips("Tips"),
SessionField.HandsCount("Hands Count"),
SessionField.LimitType("Limit"), SessionField.LimitType("Limit"),
SessionField.Game("Game"), SessionField.Game("Game"),
SessionField.TableSize("Table Size"), SessionField.TableSize("Table Size"),

@ -51,6 +51,7 @@ class SessionCSVDescriptor(source: DataSource, isTournament: Boolean?, vararg el
is SessionField.CashedOut -> field.format(data.result?.cashout) is SessionField.CashedOut -> field.format(data.result?.cashout)
is SessionField.NetResult -> field.format(data.result?.netResult) is SessionField.NetResult -> field.format(data.result?.netResult)
is SessionField.Tips -> field.format(data.result?.tips) is SessionField.Tips -> field.format(data.result?.tips)
is SessionField.HandsCount -> field.format(data.handsCount)
is SessionField.LimitType -> { is SessionField.LimitType -> {
data.limit?.let { limit -> data.limit?.let { limit ->
Limit.values()[limit].longName Limit.values()[limit].longName

@ -121,6 +121,11 @@ sealed class SessionField {
override var callback: ((String) -> Double?)? = null override var callback: ((String) -> Double?)? = null
) : NumberCSVField ) : NumberCSVField
data class HandsCount(
override var header: String,
override var callback: ((String) -> Int?)? = null
) : IntCSVField
data class SmallBlind( data class SmallBlind(
override var header: String, override var header: String,
override var callback: ((String) -> Double?)? = null override var callback: ((String) -> Double?)? = null

@ -165,6 +165,16 @@ fun Date.startOfMonth(): Date {
return calendar.time return calendar.time
} }
// Return the date of the end of the current date
fun Date.endOfMonth(): Date {
val calendar = Calendar.getInstance()
calendar.time = this
calendar.add(Calendar.MONTH, 1)
calendar.set(Calendar.DAY_OF_MONTH, 1)
calendar.add(Calendar.DATE, -1)
return calendar.time
}
// Return the date of the beginning of the current year // Return the date of the beginning of the current year
fun Date.startOfYear(): Date { fun Date.startOfYear(): Date {
val calendar = Calendar.getInstance() val calendar = Calendar.getInstance()
@ -173,6 +183,15 @@ fun Date.startOfYear(): Date {
return calendar.time return calendar.time
} }
// Return the date of the end of the current date
fun Date.endOfYear(): Date {
val calendar = Calendar.getInstance()
calendar.time = this
calendar.set(Calendar.MONTH, 11)
calendar.set(Calendar.DAY_OF_MONTH, 31)
return calendar.time
}
// Return the number of seconds until the next minute // Return the number of seconds until the next minute
fun Date.getNextMinuteInseconds(): Int { fun Date.getNextMinuteInseconds(): Int {
return (getNextMinuteInMilliseconds() / 1000).toInt() return (getNextMinuteInMilliseconds() / 1000).toInt()

@ -1,6 +1,8 @@
package net.pokeranalytics.android.util.extensions package net.pokeranalytics.android.util.extensions
import io.realm.* import io.realm.*
import net.pokeranalytics.android.model.filter.Filterable
import net.pokeranalytics.android.model.filter.Query
import net.pokeranalytics.android.model.interfaces.UsageCountable import net.pokeranalytics.android.model.interfaces.UsageCountable
import net.pokeranalytics.android.model.interfaces.Identifiable import net.pokeranalytics.android.model.interfaces.Identifiable
import net.pokeranalytics.android.model.interfaces.NameManageable import net.pokeranalytics.android.model.interfaces.NameManageable
@ -120,3 +122,7 @@ fun < T : RealmModel> Realm.find(clazz: Class<T>, searchContent: String?) : Real
val resultSort = arrayOf(Sort.ASCENDING) val resultSort = arrayOf(Sort.ASCENDING)
return items.sort(sortField, resultSort) return items.sort(sortField, resultSort)
} }
inline fun <reified T : Filterable> Realm.findAll(query: Query, sortField: String? = null): RealmResults<T> {
return Filter.queryOn(this, query, sortField)
}

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="@color/grey"/>
<!-- <stroke android:width="3dp" android:color="#B1BCBE" />-->
<corners android:radius="8dp"/>
</shape>

@ -123,4 +123,20 @@
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/appBar" /> app:layout_constraintTop_toBottomOf="@+id/appBar" />
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/gridButton"
style="@style/PokerAnalyticsTheme.FloatingButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_marginEnd="16dp"
android:layout_marginBottom="16dp"
android:src="@drawable/ic_grid"
android:tint="@color/black"
android:transitionName="floating_action_button"
app:fabSize="normal"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:contentDescription="@string/calendar" />
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>

@ -123,4 +123,20 @@
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/appBar" /> app:layout_constraintTop_toBottomOf="@+id/appBar" />
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/gridButton"
style="@style/PokerAnalyticsTheme.FloatingButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_marginEnd="16dp"
android:layout_marginBottom="16dp"
android:src="@drawable/ic_grid"
android:tint="@color/black"
android:transitionName="floating_action_button"
app:fabSize="normal"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:contentDescription="@string/calendar" />
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>

@ -6,7 +6,7 @@
android:orientation="vertical"> android:orientation="vertical">
<androidx.fragment.app.FragmentContainerView <androidx.fragment.app.FragmentContainerView
android:id="@+id/currenciesFragment" android:id="@+id/fragment"
android:name="net.pokeranalytics.android.ui.modules.calendar.GridCalendarFragment" android:name="net.pokeranalytics.android.ui.modules.calendar.GridCalendarFragment"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"

@ -0,0 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto">
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/title"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:layout_marginBottom="16dp"
style="@style/PokerAnalyticsTheme.TextView.Header"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
/>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@id/title"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
/>
</androidx.constraintlayout.widget.ConstraintLayout>

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/timeUnit"
android:layout_width="16dp"
android:layout_height="16dp">
</androidx.constraintlayout.widget.ConstraintLayout>

@ -127,4 +127,20 @@
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/appBar" /> app:layout_constraintTop_toBottomOf="@+id/appBar" />
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/gridButton"
style="@style/PokerAnalyticsTheme.FloatingButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_marginEnd="16dp"
android:layout_marginBottom="16dp"
android:src="@drawable/ic_grid"
android:tint="@color/black"
android:transitionName="floating_action_button"
app:fabSize="normal"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:contentDescription="@string/calendar" />
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>

@ -1,6 +1,77 @@
<?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" android:layout_width="match_parent" 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="match_parent"> android:layout_height="match_parent">
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/appBar"
android:layout_width="match_parent"
android:layout_height="128dp"
android:theme="@style/PokerAnalyticsTheme.Toolbar.Session"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<com.google.android.material.appbar.CollapsingToolbarLayout
android:id="@+id/collapsingToolbar"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:collapsedTitleTextAppearance="@style/PokerAnalyticsTheme.Toolbar.CollapsedTitleAppearance"
app:contentScrim="?attr/colorPrimary"
app:expandedTitleGravity="bottom"
app:expandedTitleMarginStart="72dp"
app:expandedTitleTextAppearance="@style/PokerAnalyticsTheme.Toolbar.ExpandedTitleAppearance"
app:layout_scrollFlags="scroll|exitUntilCollapsed|snap">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_collapseMode="pin"
app:title="@string/calendar"
app:titleTextColor="@color/white" />
</com.google.android.material.appbar.CollapsingToolbarLayout>
</com.google.android.material.appbar.AppBarLayout>
<com.google.android.material.chip.ChipGroup
android:id="@+id/timeUnits"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@id/appBar"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:singleSelection="true"
app:selectionRequired="true"
app:chipSpacing="8dp">
<com.google.android.material.chip.Chip
android:id="@+id/dayUnit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/day"
android:checked="true" />
<com.google.android.material.chip.Chip
android:id="@+id/monthUnit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/month" />
</com.google.android.material.chip.ChipGroup>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="0dp"
android:padding="16dp"
app:layout_constraintTop_toBottomOf="@id/timeUnits"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
/>
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>
Loading…
Cancel
Save