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. 8
      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: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 -->
<activity
android:name="net.pokeranalytics.android.ui.activity.ColorPickerActivity"

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

@ -198,6 +198,10 @@ class CalendarFragment : RealmFragment(), CoroutineScope, StaticRowRepresentable
*/
private fun initUI() {
this.binding.gridButton.setOnClickListener {
showGridCalendar()
}
CalendarTabs.values().forEach {
val tab = binding.tabs.newTab()
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("Rows: ${rows.size}")
calendarAdapter.notifyDataSetChanged()
this.calendarAdapter.notifyDataSetChanged()
binding.progressBar.hideWithAnimation()
binding.recyclerView.showWithAnimation()
this.binding.progressBar.hideWithAnimation()
this.binding.recyclerView.showWithAnimation()
}

@ -4,31 +4,85 @@ import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
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.view.GridSpacingItemDecoration
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 lateinit var dataAdapter: RowRepresentableAdapter
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
super.onCreateView(inflater, container, savedInstanceState)
_binding = FragmentDealtHandsConfigBinding.inflate(inflater, container, false)
_binding = FragmentGridCalendarBinding.inflate(inflater, container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
initUI()
initData()
}
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
val spanCount = 3
val viewManager = GridLayoutManager(context, spanCount)
this.dataAdapter = RowRepresentableAdapter(this, this)
val spacing = 2.px
val includeEdge = false
val viewManager = GridLayoutManager(context, spanCount)
actionRecyclerView.apply {
setHasFixedSize(true)
layoutManager = viewManager

@ -2,7 +2,6 @@ package net.pokeranalytics.android.ui.view
import android.content.Context
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.util.NULL_TEXT
@ -14,6 +13,7 @@ interface RowRepresentable : Displayable, EditDataSource, ImageDecorator {
fun getDisplayName(context: Context): String {
return NULL_TEXT
}
}
interface EditDataSource {

@ -7,14 +7,18 @@ import android.widget.FrameLayout
import androidx.appcompat.widget.AppCompatImageView
import androidx.appcompat.widget.AppCompatTextView
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.content.ContextCompat
import androidx.core.view.isVisible
import androidx.core.widget.ContentLoadingProgressBar
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.github.mikephil.charting.charts.BarChart
import com.github.mikephil.charting.charts.LineChart
import com.github.mikephil.charting.data.*
import com.google.android.material.chip.Chip
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.calculus.ComputedStat
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.ui.adapter.BindableHolder
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.dp
import net.pokeranalytics.android.ui.extensions.px
import net.pokeranalytics.android.ui.extensions.setTextFormat
import net.pokeranalytics.android.ui.graph.Graph
import net.pokeranalytics.android.ui.modules.bankroll.BankrollRowRepresentable
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.view.holder.RowViewHolder
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_IMAGE(R.layout.row_player_image),
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_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_STREET -> RowHandStreet(layout)
CALENDAR_GRID_CELL -> CalendarGridCellHolder(layout)
CALENDAR_TIME_UNIT_CELL -> CalendarTimeUnitCellHolder(layout)
// Separator
SEPARATOR -> SeparatorViewHolder(layout)
@ -526,7 +539,6 @@ enum class RowViewType(private var layoutRes: Int) : ViewIdentifier {
}
}
/**
* Display a player image view
*/
@ -569,7 +581,6 @@ enum class RowViewType(private var layoutRes: Int) : ViewIdentifier {
}
}
/**
* 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.Rebuy -> additionalBuyins += field.parse(value) ?: 0.0
is SessionField.Tips -> session.result?.tips = field.parse(value)
is SessionField.HandsCount -> session.handsCount = field.parse(value)
is SessionField.Break -> {
field.parse(value)?.let {
session.breakDuration = it.toLong()

@ -220,6 +220,7 @@ class ProductCSVDescriptors {
SessionField.CashedOut("Cashed Out"),
SessionField.NetResult("Online Net"),
SessionField.Tips("Tips"),
SessionField.HandsCount("Hands Count"),
SessionField.LimitType("Limit"),
SessionField.Game("Game"),
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.NetResult -> field.format(data.result?.netResult)
is SessionField.Tips -> field.format(data.result?.tips)
is SessionField.HandsCount -> field.format(data.handsCount)
is SessionField.LimitType -> {
data.limit?.let { limit ->
Limit.values()[limit].longName

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

@ -165,6 +165,16 @@ fun Date.startOfMonth(): Date {
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
fun Date.startOfYear(): Date {
val calendar = Calendar.getInstance()
@ -173,6 +183,15 @@ fun Date.startOfYear(): Date {
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
fun Date.getNextMinuteInseconds(): Int {
return (getNextMinuteInMilliseconds() / 1000).toInt()

@ -1,6 +1,8 @@
package net.pokeranalytics.android.util.extensions
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.Identifiable
import net.pokeranalytics.android.model.interfaces.NameManageable
@ -119,4 +121,8 @@ fun < T : RealmModel> Realm.find(clazz: Class<T>, searchContent: String?) : Real
val sortField = arrayOf("name")
val resultSort = arrayOf(Sort.ASCENDING)
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_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>

@ -123,4 +123,20 @@
app:layout_constraintStart_toStartOf="parent"
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>

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

@ -1,6 +1,77 @@
<?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"
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">
<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>
Loading…
Cancel
Save