Merge remote-tracking branch 'origin/dev' into dev

feature/top10
Razmig Sarkissian 7 years ago
commit 61d6d0a0bb
  1. 4
      app/src/main/java/net/pokeranalytics/android/model/comparison/Comparator.kt
  2. 220
      app/src/main/java/net/pokeranalytics/android/ui/fragment/CalendarFragment.kt
  3. 24
      app/src/main/java/net/pokeranalytics/android/util/extensions/DateExtension.kt
  4. 51
      app/src/main/res/layout/fragment_calendar.xml
  5. 2
      app/src/main/res/values-es/strings.xml
  6. 2
      app/src/main/res/values-fr/strings.xml
  7. 2
      app/src/main/res/values-it/strings.xml
  8. 2
      app/src/main/res/values-pt/strings.xml
  9. 2
      app/src/main/res/values/strings.xml

@ -17,6 +17,8 @@ enum class Comparator {
MONTH, MONTH,
YEAR, YEAR,
BLIND, BLIND,
CASH,
TOURNAMENT,
; ;
val queryConditions: List<QueryCondition> val queryConditions: List<QueryCondition>
@ -38,6 +40,8 @@ enum class Comparator {
realm.close() realm.close()
years years
} }
CASH -> listOf(QueryCondition.CASH)
TOURNAMENT -> listOf(QueryCondition.TOURNAMENT)
else -> throw PokerAnalyticsException.QueryTypeUnhandled else -> throw PokerAnalyticsException.QueryTypeUnhandled
} }
} }

@ -27,7 +27,10 @@ import net.pokeranalytics.android.ui.view.CalendarTabs
import net.pokeranalytics.android.ui.view.RowRepresentable import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.RowViewType import net.pokeranalytics.android.ui.view.RowViewType
import net.pokeranalytics.android.ui.view.rowrepresentable.CustomizableRowRepresentable 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 timber.log.Timber
import java.util.* import java.util.*
import kotlin.coroutines.CoroutineContext import kotlin.coroutines.CoroutineContext
@ -35,6 +38,14 @@ import kotlin.coroutines.CoroutineContext
class CalendarFragment : SessionObserverFragment(), CoroutineScope, StaticRowRepresentableDataSource, RowRepresentableDelegate { class CalendarFragment : SessionObserverFragment(), CoroutineScope, StaticRowRepresentableDataSource, RowRepresentableDelegate {
private enum class SessionType {
ALL, CASH, TOURNAMENT
}
private enum class TimeFilter {
MONTH, YEAR
}
companion object { companion object {
/** /**
@ -58,6 +69,10 @@ class CalendarFragment : SessionObserverFragment(), CoroutineScope, StaticRowRep
private var sortedMonthlyReports: SortedMap<Date, ComputedResults> = HashMap<Date, ComputedResults>().toSortedMap() private var sortedMonthlyReports: SortedMap<Date, ComputedResults> = HashMap<Date, ComputedResults>().toSortedMap()
private var sortedYearlyReports: SortedMap<Date, ComputedResults> = HashMap<Date, ComputedResults>().toSortedMap() private var sortedYearlyReports: SortedMap<Date, ComputedResults> = HashMap<Date, ComputedResults>().toSortedMap()
private var currentSessionType = SessionType.ALL
private var currentTimeFilter = TimeFilter.MONTH
private var currentStat = Stat.NETRESULT
// Life Cycle // Life Cycle
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
@ -76,6 +91,10 @@ class CalendarFragment : SessionObserverFragment(), CoroutineScope, StaticRowRep
return rows return rows
} }
override fun onRowSelected(position: Int, row: RowRepresentable, fromAction: Boolean) {
//toast("Open $row")
}
// Business // Business
@ -98,16 +117,17 @@ class CalendarFragment : SessionObserverFragment(), CoroutineScope, StaticRowRep
tabs.addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener { tabs.addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener {
override fun onTabSelected(tab: TabLayout.Tab) { override fun onTabSelected(tab: TabLayout.Tab) {
when(tab.position) { when (tab.position) {
0 -> displayData(Stat.NETRESULT) 0 -> currentStat = Stat.NETRESULT
1 -> displayData(Stat.HOURLY_RATE) 1 -> currentStat = Stat.HOURLY_RATE
2 -> displayData(Stat.NUMBER_OF_GAMES) 2 -> currentStat = Stat.NUMBER_OF_GAMES
3 -> displayData(Stat.WIN_RATIO) 3 -> currentStat = Stat.WIN_RATIO
4 -> displayData(Stat.STANDARD_DEVIATION_HOURLY) 4 -> currentStat = Stat.STANDARD_DEVIATION_HOURLY
5 -> displayData(Stat.AVERAGE) 5 -> currentStat = Stat.AVERAGE
6 -> displayData(Stat.AVERAGE_DURATION) 6 -> currentStat = Stat.AVERAGE_DURATION
7 -> displayData(Stat.DURATION) 7 -> currentStat = Stat.DURATION
} }
displayData()
} }
override fun onTabUnselected(tab: TabLayout.Tab) { override fun onTabUnselected(tab: TabLayout.Tab) {
@ -115,8 +135,61 @@ class CalendarFragment : SessionObserverFragment(), CoroutineScope, StaticRowRep
override fun onTabReselected(tab: TabLayout.Tab) { 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()) val viewManager = LinearLayoutManager(requireContext())
calendarAdapter = RowRepresentableAdapter(this, this) calendarAdapter = RowRepresentableAdapter(this, this)
@ -137,31 +210,28 @@ class CalendarFragment : SessionObserverFragment(), CoroutineScope, StaticRowRep
GlobalScope.launch { GlobalScope.launch {
val calendar = Calendar.getInstance() val calendar = Calendar.getInstance()
calendar.set(Calendar.DAY_OF_MONTH, 1) calendar.time = Date().startOfMonth()
calendar.set(Calendar.HOUR_OF_DAY, 0)
calendar.set(Calendar.MINUTE, 0)
calendar.set(Calendar.SECOND, 0)
calendar.set(Calendar.MILLISECOND, 0)
val startDate = Date() val startDate = Date()
val realm = Realm.getDefaultInstance() val realm = Realm.getDefaultInstance()
val montlyReports: HashMap<Date, ComputedResults> = HashMap() val monthlyReports: HashMap<Date, ComputedResults> = HashMap()
val yearlyReports: HashMap<Date, ComputedResults> = HashMap() val yearlyReports: HashMap<Date, ComputedResults> = HashMap()
// Compute data per YEAR x MONTH // Compute data per YEAR and MONTH
val conditions = listOf(Comparator.YEAR, Comparator.MONTH_OF_YEAR).combined()
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()) monthConditions.forEach {conditions ->
//Timber.d("======> report results: ${report.results.size}") val report = Calculator.computeStatsWithComparators(realm, conditions = conditions, options = Calculator.Options())
report.results.forEach { computedResults -> report.results.forEach { computedResults ->
//Timber.d("======> computedResults empty: ${computedResults.isEmpty}")
if (!computedResults.isEmpty) { if (!computedResults.isEmpty) {
// Set date data // Set date data
it.forEach { condition -> conditions.forEach { condition ->
condition.valueMap?.get("year")?.let { year -> condition.valueMap?.get("year")?.let { year ->
calendar.set(Calendar.YEAR, year as Int) 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 calendar.time = Date().startOfYear()
val yearConditions = Comparator.YEAR.queryConditions
// compute at index
yearConditions.forEach { condition ->
// 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()) yearConditions.forEach { conditions ->
//Timber.d("======> report results: ${report.results.size}") val report = Calculator.computeStatsWithComparators(realm, conditions = conditions, options = Calculator.Options())
report.results.forEach { computedResults -> report.results.forEach { computedResults ->
//Timber.d("======> computedResults empty: ${computedResults.isEmpty}")
if (!computedResults.isEmpty) { if (!computedResults.isEmpty) {
calendar.set(Calendar.MONTH, 0)
// Set date data // Set date data
condition.valueMap?.get("year")?.let { year -> conditions.forEach { condition ->
calendar.set(Calendar.YEAR, year as Int) condition.valueMap?.get("year")?.let { year ->
calendar.set(Calendar.YEAR, year as Int)
}
} }
yearlyReports[calendar.time] = computedResults yearlyReports[calendar.time] = computedResults
} }
} }
} }
sortedMonthlyReports = monthlyReports.toSortedMap(compareByDescending { it })
sortedYearlyReports = yearlyReports.toSortedMap(compareByDescending { it })
Timber.d("Computation: ${System.currentTimeMillis() - startDate.time}ms") Timber.d("Computation: ${System.currentTimeMillis() - startDate.time}ms")
// Logs
/*
Timber.d("========== YEAR x MONTH") Timber.d("========== YEAR x MONTH")
sortedMonthlyReports = montlyReports.toSortedMap(compareByDescending { it })
sortedMonthlyReports.keys.forEach { sortedMonthlyReports.keys.forEach {
Timber.d("$it => ${sortedMonthlyReports[it]?.computedStat(Stat.NETRESULT)?.value}") Timber.d("$it => ${sortedMonthlyReports[it]?.computedStat(Stat.NETRESULT)?.value}")
} }
Timber.d("========== YEARLY") Timber.d("========== YEARLY")
sortedYearlyReports = yearlyReports.toSortedMap(compareByDescending { it })
sortedYearlyReports.keys.forEach { sortedYearlyReports.keys.forEach {
Timber.d("$it => ${sortedYearlyReports[it]?.computedStat(Stat.NETRESULT)?.value}") Timber.d("$it => ${sortedYearlyReports[it]?.computedStat(Stat.NETRESULT)?.value}")
} }
*/
GlobalScope.launch(Dispatchers.Main) { GlobalScope.launch(Dispatchers.Main) {
displayData(Stat.NETRESULT) displayData()
} }
} }
} }
/** /**
* Display data * Display data
*/ */
private fun displayData(stat: Stat) { private fun displayData() {
val startDate = Date()
rows.clear() rows.clear()
// Create yearly reports when (currentTimeFilter) {
sortedYearlyReports.keys.forEach {
Timber.d("$it => ${sortedYearlyReports[it]?.computedStat(Stat.NETRESULT)?.value}") // Create monthly reports
sortedYearlyReports[it]?.computedStat(stat)?.let { computedStat -> TimeFilter.MONTH -> {
rows.add( val years: ArrayList<String> = ArrayList()
CustomizableRowRepresentable( sortedMonthlyReports.keys.forEach { date ->
customViewType = RowViewType.TITLE_VALUE_ARROW, if (!years.contains(date.getDateYear())) {
title = it.shortDate(), years.add(date.getDateYear())
value = computedStat.format(requireContext()).text 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}") Timber.d("Rows: ${rows.size}")
calendarAdapter.notifyDataSetChanged() calendarAdapter.notifyDataSetChanged()

@ -79,6 +79,14 @@ fun Date.getDayNumber() : String {
fun Date.getShortDayName() : String { fun Date.getShortDayName() : String {
return SimpleDateFormat("EEE", Locale.getDefault()).format(this) 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 // Return the month & year of the date
fun Date.getMonthAndYear(): String { fun Date.getMonthAndYear(): String {
return SimpleDateFormat("MMMM yyyy", Locale.getDefault()).format(this).capitalize() 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.SECOND, 59)
calendar.set(Calendar.MILLISECOND, 999) calendar.set(Calendar.MILLISECOND, 999)
return calendar.time 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
} }

@ -14,6 +14,57 @@
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"> app:layout_constraintTop_toTopOf="parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="horizontal">
<com.google.android.material.chip.ChipGroup
android:id="@+id/filters"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="8dp"
app:singleSelection="false"
app:chipSpacing="6dp">
<com.google.android.material.chip.Chip
android:id="@+id/filterSessionAll"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checked="true"
android:text="@string/all"/>
<com.google.android.material.chip.Chip
android:id="@+id/filterSessionCash"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/cash_game"/>
<com.google.android.material.chip.Chip
android:id="@+id/filterSessionTournament"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/tournament"/>
<com.google.android.material.chip.Chip
android:id="@+id/filterTimeMonth"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="8dp"
android:checked="true"
android:text="@string/month"/>
<com.google.android.material.chip.Chip
android:id="@+id/filterTimeYear"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/year"/>
</com.google.android.material.chip.ChipGroup>
</LinearLayout>
<com.google.android.material.tabs.TabLayout <com.google.android.material.tabs.TabLayout
android:id="@+id/tabs" android:id="@+id/tabs"
android:layout_width="match_parent" android:layout_width="match_parent"

@ -281,7 +281,7 @@
<string name="mins">m</string> <string name="mins">m</string>
<string name="minus">Menos</string> <string name="minus">Menos</string>
<string name="modify_current_filter">Modificar&#8230;</string> <string name="modify_current_filter">Modificar&#8230;</string>
<string name="month">mes</string> <string name="month">Mes</string>
<string name="month_of_the_year">Mes del año</string> <string name="month_of_the_year">Mes del año</string>
<string name="months">meses</string> <string name="months">meses</string>
<string name="more_info">más infos</string> <string name="more_info">más infos</string>

@ -302,7 +302,7 @@
<string name="mins">mins</string> <string name="mins">mins</string>
<string name="minus">Moins</string> <string name="minus">Moins</string>
<string name="modify_current_filter">Modifier&#8230;</string> <string name="modify_current_filter">Modifier&#8230;</string>
<string name="month">mois</string> <string name="month">Mois</string>
<string name="month_of_the_year">Mois de l\'année</string> <string name="month_of_the_year">Mois de l\'année</string>
<string name="months">mois</string> <string name="months">mois</string>
<string name="more_info">plus d\'infos</string> <string name="more_info">plus d\'infos</string>

@ -280,7 +280,7 @@
<string name="mins">min</string> <string name="mins">min</string>
<string name="minus">Meno</string> <string name="minus">Meno</string>
<string name="modify_current_filter">Modifica&#8230;</string> <string name="modify_current_filter">Modifica&#8230;</string>
<string name="month">mese</string> <string name="month">Mese</string>
<string name="month_of_the_year">Mese dell\'anno</string> <string name="month_of_the_year">Mese dell\'anno</string>
<string name="months">mesi</string> <string name="months">mesi</string>
<string name="more_info">altre info</string> <string name="more_info">altre info</string>

@ -280,7 +280,7 @@
<string name="mins">mín.</string> <string name="mins">mín.</string>
<string name="minus">Menos</string> <string name="minus">Menos</string>
<string name="modify_current_filter">Modificar&#8230;</string> <string name="modify_current_filter">Modificar&#8230;</string>
<string name="month">mês</string> <string name="month">Mês</string>
<string name="month_of_the_year">Mês do ano</string> <string name="month_of_the_year">Mês do ano</string>
<string name="months">meses</string> <string name="months">meses</string>
<string name="more_info">mais informações</string> <string name="more_info">mais informações</string>

@ -307,7 +307,7 @@
<string name="mins">mins</string> <string name="mins">mins</string>
<string name="minus">Minus</string> <string name="minus">Minus</string>
<string name="modify_current_filter">Modify&#8230;</string> <string name="modify_current_filter">Modify&#8230;</string>
<string name="month">month</string> <string name="month">Month</string>
<string name="month_of_the_year">Month of the year</string> <string name="month_of_the_year">Month of the year</string>
<string name="months">months</string> <string name="months">months</string>
<string name="more_info">more infos</string> <string name="more_info">more infos</string>

Loading…
Cancel
Save