diff --git a/app/src/main/java/net/pokeranalytics/android/model/comparison/Comparator.kt b/app/src/main/java/net/pokeranalytics/android/model/comparison/Comparator.kt index ab2a614c..5b570fd8 100644 --- a/app/src/main/java/net/pokeranalytics/android/model/comparison/Comparator.kt +++ b/app/src/main/java/net/pokeranalytics/android/model/comparison/Comparator.kt @@ -17,6 +17,8 @@ enum class Comparator { MONTH, YEAR, BLIND, + CASH, + TOURNAMENT, ; val queryConditions: List @@ -38,6 +40,8 @@ enum class Comparator { realm.close() years } + CASH -> listOf(QueryCondition.CASH) + TOURNAMENT -> listOf(QueryCondition.TOURNAMENT) else -> throw PokerAnalyticsException.QueryTypeUnhandled } } diff --git a/app/src/main/java/net/pokeranalytics/android/ui/fragment/CalendarFragment.kt b/app/src/main/java/net/pokeranalytics/android/ui/fragment/CalendarFragment.kt index 2a7e7101..40056063 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/fragment/CalendarFragment.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/fragment/CalendarFragment.kt @@ -27,7 +27,10 @@ import net.pokeranalytics.android.ui.view.CalendarTabs import net.pokeranalytics.android.ui.view.RowRepresentable import net.pokeranalytics.android.ui.view.RowViewType import net.pokeranalytics.android.ui.view.rowrepresentable.CustomizableRowRepresentable -import net.pokeranalytics.android.util.extensions.shortDate +import net.pokeranalytics.android.util.extensions.getDateMonth +import net.pokeranalytics.android.util.extensions.getDateYear +import net.pokeranalytics.android.util.extensions.startOfMonth +import net.pokeranalytics.android.util.extensions.startOfYear import timber.log.Timber import java.util.* import kotlin.coroutines.CoroutineContext @@ -35,6 +38,14 @@ import kotlin.coroutines.CoroutineContext class CalendarFragment : SessionObserverFragment(), CoroutineScope, StaticRowRepresentableDataSource, RowRepresentableDelegate { + private enum class SessionType { + ALL, CASH, TOURNAMENT + } + + private enum class TimeFilter { + MONTH, YEAR + } + companion object { /** @@ -58,6 +69,10 @@ class CalendarFragment : SessionObserverFragment(), CoroutineScope, StaticRowRep private var sortedMonthlyReports: SortedMap = HashMap().toSortedMap() private var sortedYearlyReports: SortedMap = HashMap().toSortedMap() + private var currentSessionType = SessionType.ALL + private var currentTimeFilter = TimeFilter.MONTH + private var currentStat = Stat.NETRESULT + // Life Cycle override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { @@ -76,6 +91,10 @@ class CalendarFragment : SessionObserverFragment(), CoroutineScope, StaticRowRep return rows } + override fun onRowSelected(position: Int, row: RowRepresentable, fromAction: Boolean) { + //toast("Open $row") + } + // Business @@ -98,16 +117,17 @@ class CalendarFragment : SessionObserverFragment(), CoroutineScope, StaticRowRep tabs.addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener { override fun onTabSelected(tab: TabLayout.Tab) { - when(tab.position) { - 0 -> displayData(Stat.NETRESULT) - 1 -> displayData(Stat.HOURLY_RATE) - 2 -> displayData(Stat.NUMBER_OF_GAMES) - 3 -> displayData(Stat.WIN_RATIO) - 4 -> displayData(Stat.STANDARD_DEVIATION_HOURLY) - 5 -> displayData(Stat.AVERAGE) - 6 -> displayData(Stat.AVERAGE_DURATION) - 7 -> displayData(Stat.DURATION) + when (tab.position) { + 0 -> currentStat = Stat.NETRESULT + 1 -> currentStat = Stat.HOURLY_RATE + 2 -> currentStat = Stat.NUMBER_OF_GAMES + 3 -> currentStat = Stat.WIN_RATIO + 4 -> currentStat = Stat.STANDARD_DEVIATION_HOURLY + 5 -> currentStat = Stat.AVERAGE + 6 -> currentStat = Stat.AVERAGE_DURATION + 7 -> currentStat = Stat.DURATION } + displayData() } override fun onTabUnselected(tab: TabLayout.Tab) { @@ -115,8 +135,61 @@ class CalendarFragment : SessionObserverFragment(), CoroutineScope, StaticRowRep override fun onTabReselected(tab: TabLayout.Tab) { } - }) + + // Manage session type filter + filterSessionAll.setOnCheckedChangeListener { buttonView, isChecked -> + if (isChecked) { + currentSessionType = SessionType.ALL + filterSessionCash.isChecked = false + filterSessionTournament.isChecked = false + launchStatComputation() + } else if (currentSessionType == SessionType.ALL) { + filterSessionAll.isChecked = true + } + } + filterSessionCash.setOnCheckedChangeListener { buttonView, isChecked -> + if (isChecked) { + currentSessionType = SessionType.CASH + filterSessionAll.isChecked = false + filterSessionTournament.isChecked = false + launchStatComputation() + } else if (currentSessionType == SessionType.CASH) { + filterSessionCash.isChecked = true + } + } + filterSessionTournament.setOnCheckedChangeListener { buttonView, isChecked -> + if (isChecked) { + currentSessionType = SessionType.TOURNAMENT + filterSessionAll.isChecked = false + filterSessionCash.isChecked = false + launchStatComputation() + } else if (currentSessionType == SessionType.TOURNAMENT) { + filterSessionTournament.isChecked = true + } + } + + // Manage time filter + filterTimeMonth.setOnCheckedChangeListener { buttonView, isChecked -> + if (isChecked) { + currentTimeFilter = TimeFilter.MONTH + filterTimeYear.isChecked = false + displayData() + } else if (currentTimeFilter == TimeFilter.MONTH) { + filterTimeMonth.isChecked = true + } + + } + filterTimeYear.setOnCheckedChangeListener { buttonView, isChecked -> + if (isChecked) { + currentTimeFilter = TimeFilter.YEAR + filterTimeMonth.isChecked = false + displayData() + } else if (currentTimeFilter == TimeFilter.YEAR) { + filterTimeYear.isChecked = true + } + } + val viewManager = LinearLayoutManager(requireContext()) calendarAdapter = RowRepresentableAdapter(this, this) @@ -137,31 +210,28 @@ class CalendarFragment : SessionObserverFragment(), CoroutineScope, StaticRowRep GlobalScope.launch { val calendar = Calendar.getInstance() - calendar.set(Calendar.DAY_OF_MONTH, 1) - calendar.set(Calendar.HOUR_OF_DAY, 0) - calendar.set(Calendar.MINUTE, 0) - calendar.set(Calendar.SECOND, 0) - calendar.set(Calendar.MILLISECOND, 0) + calendar.time = Date().startOfMonth() val startDate = Date() val realm = Realm.getDefaultInstance() - val montlyReports: HashMap = HashMap() + val monthlyReports: HashMap = HashMap() val yearlyReports: HashMap = HashMap() - // Compute data per YEAR x MONTH - val conditions = listOf(Comparator.YEAR, Comparator.MONTH_OF_YEAR).combined() + // Compute data per YEAR and MONTH - conditions.forEach { + val monthConditions = when(currentSessionType) { + SessionType.ALL -> listOf(Comparator.YEAR, Comparator.MONTH_OF_YEAR).combined() + SessionType.CASH -> listOf(Comparator.YEAR, Comparator.MONTH_OF_YEAR, Comparator.CASH).combined() + SessionType.TOURNAMENT -> listOf(Comparator.YEAR, Comparator.MONTH_OF_YEAR, Comparator.TOURNAMENT).combined() + } - val report = Calculator.computeStatsWithComparators(realm, conditions = it, options = Calculator.Options()) - //Timber.d("======> report results: ${report.results.size}") + monthConditions.forEach {conditions -> + val report = Calculator.computeStatsWithComparators(realm, conditions = conditions, options = Calculator.Options()) report.results.forEach { computedResults -> - //Timber.d("======> computedResults empty: ${computedResults.isEmpty}") if (!computedResults.isEmpty) { - // Set date data - it.forEach { condition -> + conditions.forEach { condition -> condition.valueMap?.get("year")?.let { year -> calendar.set(Calendar.YEAR, year as Int) } @@ -170,79 +240,115 @@ class CalendarFragment : SessionObserverFragment(), CoroutineScope, StaticRowRep } } - montlyReports[calendar.time] = computedResults + monthlyReports[calendar.time] = computedResults } } } - // Compute data per YEAR - val yearConditions = Comparator.YEAR.queryConditions - - // compute at index - yearConditions.forEach { condition -> + calendar.time = Date().startOfYear() + // Compute data per YEAR + val yearConditions = when(currentSessionType) { + SessionType.ALL -> listOf(Comparator.YEAR).combined() + SessionType.CASH -> listOf(Comparator.YEAR, Comparator.CASH).combined() + SessionType.TOURNAMENT -> listOf(Comparator.YEAR, Comparator.TOURNAMENT).combined() + } - val report = Calculator.computeStatsWithComparators(realm, conditions = listOf(condition), options = Calculator.Options()) - //Timber.d("======> report results: ${report.results.size}") + yearConditions.forEach { conditions -> + val report = Calculator.computeStatsWithComparators(realm, conditions = conditions, options = Calculator.Options()) report.results.forEach { computedResults -> - //Timber.d("======> computedResults empty: ${computedResults.isEmpty}") if (!computedResults.isEmpty) { - - calendar.set(Calendar.MONTH, 0) - // Set date data - condition.valueMap?.get("year")?.let { year -> - calendar.set(Calendar.YEAR, year as Int) + conditions.forEach { condition -> + condition.valueMap?.get("year")?.let { year -> + calendar.set(Calendar.YEAR, year as Int) + } } - yearlyReports[calendar.time] = computedResults } } } + sortedMonthlyReports = monthlyReports.toSortedMap(compareByDescending { it }) + sortedYearlyReports = yearlyReports.toSortedMap(compareByDescending { it }) + Timber.d("Computation: ${System.currentTimeMillis() - startDate.time}ms") + // Logs + /* Timber.d("========== YEAR x MONTH") - sortedMonthlyReports = montlyReports.toSortedMap(compareByDescending { it }) sortedMonthlyReports.keys.forEach { Timber.d("$it => ${sortedMonthlyReports[it]?.computedStat(Stat.NETRESULT)?.value}") } Timber.d("========== YEARLY") - sortedYearlyReports = yearlyReports.toSortedMap(compareByDescending { it }) sortedYearlyReports.keys.forEach { Timber.d("$it => ${sortedYearlyReports[it]?.computedStat(Stat.NETRESULT)?.value}") } + */ GlobalScope.launch(Dispatchers.Main) { - displayData(Stat.NETRESULT) + displayData() } - } - } /** * Display data */ - private fun displayData(stat: Stat) { + private fun displayData() { + + val startDate = Date() rows.clear() - // Create yearly reports - sortedYearlyReports.keys.forEach { - Timber.d("$it => ${sortedYearlyReports[it]?.computedStat(Stat.NETRESULT)?.value}") - sortedYearlyReports[it]?.computedStat(stat)?.let { computedStat -> - rows.add( - CustomizableRowRepresentable( - customViewType = RowViewType.TITLE_VALUE_ARROW, - title = it.shortDate(), - value = computedStat.format(requireContext()).text - ) - ) + when (currentTimeFilter) { + + // Create monthly reports + TimeFilter.MONTH -> { + val years: ArrayList = ArrayList() + sortedMonthlyReports.keys.forEach { date -> + if (!years.contains(date.getDateYear())) { + years.add(date.getDateYear()) + rows.add( + CustomizableRowRepresentable( + customViewType = RowViewType.HEADER_TITLE, + title = date.getDateYear() + ) + ) + } + + sortedMonthlyReports[date]?.computedStat(currentStat)?.let { computedStat -> + rows.add( + CustomizableRowRepresentable( + customViewType = RowViewType.TITLE_VALUE_ARROW, + title = date.getDateMonth(), + computedStat = computedStat, + isSelectable = true + ) + ) + } + } + } + + // Create yearly reports + TimeFilter.YEAR -> { + sortedYearlyReports.keys.forEach { date -> + sortedYearlyReports[date]?.computedStat(currentStat)?.let { computedStat -> + rows.add( + CustomizableRowRepresentable( + customViewType = RowViewType.TITLE_VALUE_ARROW, + title = date.getDateYear(), + computedStat = computedStat, + isSelectable = true + ) + ) + } + } } } + Timber.d("Display data: ${System.currentTimeMillis() - startDate.time}ms") Timber.d("Rows: ${rows.size}") calendarAdapter.notifyDataSetChanged() diff --git a/app/src/main/java/net/pokeranalytics/android/util/extensions/DateExtension.kt b/app/src/main/java/net/pokeranalytics/android/util/extensions/DateExtension.kt index 6a5a6d10..b60ba293 100644 --- a/app/src/main/java/net/pokeranalytics/android/util/extensions/DateExtension.kt +++ b/app/src/main/java/net/pokeranalytics/android/util/extensions/DateExtension.kt @@ -79,6 +79,14 @@ fun Date.getDayNumber() : String { fun Date.getShortDayName() : String { return SimpleDateFormat("EEE", Locale.getDefault()).format(this) } +// Return the month of the date +fun Date.getDateMonth(): String { + return SimpleDateFormat("MMMM", Locale.getDefault()).format(this).capitalize() +} +// Return the year of the date +fun Date.getDateYear(): String { + return SimpleDateFormat("yyyy", Locale.getDefault()).format(this).capitalize() +} // Return the month & year of the date fun Date.getMonthAndYear(): String { return SimpleDateFormat("MMMM yyyy", Locale.getDefault()).format(this).capitalize() @@ -117,4 +125,20 @@ fun Date.endOfDay() : Date { calendar.set(Calendar.SECOND, 59) calendar.set(Calendar.MILLISECOND, 999) return calendar.time +} + +// Return the date of the beginning of the current month +fun Date.startOfMonth() : Date { + val calendar = Calendar.getInstance() + calendar.time = this.startOfDay() + calendar.set(Calendar.DAY_OF_MONTH, 1) + return calendar.time +} + +// Return the date of the beginning of the current year +fun Date.startOfYear() : Date { + val calendar = Calendar.getInstance() + calendar.time = this.startOfMonth() + calendar.set(Calendar.MONTH, 0) + return calendar.time } \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_calendar.xml b/app/src/main/res/layout/fragment_calendar.xml index 50adf8b2..42d5029a 100644 --- a/app/src/main/res/layout/fragment_calendar.xml +++ b/app/src/main/res/layout/fragment_calendar.xml @@ -14,6 +14,57 @@ app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent"> + + + + + + + + + + + + + + + + + + m Menos Modificar… - mes + Mes Mes del año meses más infos diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index e1b0c1f1..f4c9a0be 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -302,7 +302,7 @@ mins Moins Modifier… - mois + Mois Mois de l\'année mois plus d\'infos diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index bc2ca2d0..b435206f 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -280,7 +280,7 @@ min Meno Modifica… - mese + Mese Mese dell\'anno mesi altre info diff --git a/app/src/main/res/values-pt/strings.xml b/app/src/main/res/values-pt/strings.xml index de814433..b00b78df 100644 --- a/app/src/main/res/values-pt/strings.xml +++ b/app/src/main/res/values-pt/strings.xml @@ -280,7 +280,7 @@ mín. Menos Modificar… - mês + Mês Mês do ano meses mais informações diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 3e35818b..11fadf0a 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -307,7 +307,7 @@ mins Minus Modify… - month + Month Month of the year months more infos