diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro index baeaae1c..e4b45cbc 100644 --- a/app/proguard-rules.pro +++ b/app/proguard-rules.pro @@ -57,4 +57,7 @@ # Guava -dontwarn com.google.j2objc.annotations.** --keep class com.google.j2objc.annotations.** { *; } \ No newline at end of file +-keep class com.google.j2objc.annotations.** { *; } + +# Enum +-optimizations !class/unboxing/enum \ No newline at end of file diff --git a/app/src/main/java/net/pokeranalytics/android/PokerAnalyticsApplication.kt b/app/src/main/java/net/pokeranalytics/android/PokerAnalyticsApplication.kt index 60b02421..be1d6117 100644 --- a/app/src/main/java/net/pokeranalytics/android/PokerAnalyticsApplication.kt +++ b/app/src/main/java/net/pokeranalytics/android/PokerAnalyticsApplication.kt @@ -27,7 +27,7 @@ class PokerAnalyticsApplication : Application() { Realm.init(this) val realmConfiguration = RealmConfiguration.Builder() .name(Realm.DEFAULT_REALM_NAME) - .schemaVersion(2) + .schemaVersion(3) .migration(PokerAnalyticsMigration()) .initialData(Seed(this)) .build() diff --git a/app/src/main/java/net/pokeranalytics/android/calculus/Calculator.kt b/app/src/main/java/net/pokeranalytics/android/calculus/Calculator.kt index f3cb17b3..2617ae13 100644 --- a/app/src/main/java/net/pokeranalytics/android/calculus/Calculator.kt +++ b/app/src/main/java/net/pokeranalytics/android/calculus/Calculator.kt @@ -60,7 +60,7 @@ class Calculator { companion object { - fun computeStatsWithFilters(realm: Realm, filters: List, options: Options): List { + fun computeStatsWithFilters(realm: Realm, filters: List, options: Options): Report { var computableGroups: MutableList = mutableListOf() filters.forEach { filter -> @@ -75,9 +75,9 @@ class Calculator { /** * Computes all stats for list of Session sessionGroup */ - fun computeGroups(realm: Realm, groups: List, options: Options): List { + fun computeGroups(realm: Realm, groups: List, options: Options): Report { - val computedResults = mutableListOf() + val report = Report() groups.forEach { group -> val s = Date() @@ -96,7 +96,7 @@ class Calculator { } results.finalize(options) // later treatment, such as evolution numericValues sorting - computedResults.add(results) + report.addResults(results) val e = Date() val duration = (e.time - s.time) / 1000.0 @@ -104,7 +104,7 @@ class Calculator { } - return computedResults + return report } /** diff --git a/app/src/main/java/net/pokeranalytics/android/calculus/ComputableGroup.kt b/app/src/main/java/net/pokeranalytics/android/calculus/Report.kt similarity index 83% rename from app/src/main/java/net/pokeranalytics/android/calculus/ComputableGroup.kt rename to app/src/main/java/net/pokeranalytics/android/calculus/Report.kt index b1fdf74f..de8c329f 100644 --- a/app/src/main/java/net/pokeranalytics/android/calculus/ComputableGroup.kt +++ b/app/src/main/java/net/pokeranalytics/android/calculus/Report.kt @@ -10,6 +10,54 @@ import net.pokeranalytics.android.model.realm.ComputableResult import net.pokeranalytics.android.model.realm.Filter import net.pokeranalytics.android.model.realm.SessionSet +/** + * The class returned after performing calculation in the Calculator object + */ +class Report() { + + private var _results: MutableList = mutableListOf() + + val results: List = this._results + +// private var groups: MutableList = mutableListOf() +// +// var options: Calculator.Options = options +// +// fun addGroup(group: ComputableGroup) { +// this.groups.add(group) +// } +// +// fun addGroups(groups: Collection) { +// this.groups.addAll(groups) +// } + + fun addResults(result: ComputedResults) { + this._results.add(result) + } + + fun barEntries(stat: Stat): List { + val entries = mutableListOf() + + this._results.forEachIndexed { index, results -> + val cs = results.computedStat(stat) + cs?.let { computedStat -> + entries.add(Entry(index.toFloat(), computedStat.value.toFloat(), results.group)) + } + } + return entries + } + + fun multiLineEntries(stat: Stat): List> { + val entries = mutableListOf>() + this._results.forEach { result -> + val entryList = result.singleLineEntries(stat) + entries.add(entryList) + } + return entries + } + +} + /** * A sessionGroup of computable items identified by a name */ diff --git a/app/src/main/java/net/pokeranalytics/android/calculus/Stat.kt b/app/src/main/java/net/pokeranalytics/android/calculus/Stat.kt index 01b652b1..1b111ecf 100644 --- a/app/src/main/java/net/pokeranalytics/android/calculus/Stat.kt +++ b/app/src/main/java/net/pokeranalytics/android/calculus/Stat.kt @@ -23,6 +23,28 @@ interface StatBase : RealmModel { } +enum class GraphType { + LINE, + BAR, +} + +enum class AggregationType { + SESSION, + MONTH, + YEAR, + DURATION; + + val resId: Int + get() { + return when (this) { + SESSION -> R.string.session + MONTH -> R.string.month + YEAR -> R.string.year + DURATION -> R.string.duration + } + } +} + /** * An enum representing all the types of Session statistics */ @@ -150,7 +172,7 @@ enum class Stat(var underlyingClass: Class? = null) : RowRepresentabl fun cumulativeLabelResId(context: Context) : String { val resId = when (this) { - AVERAGE, AVERAGE_DURATION, NETRESULT, NET_BB_PER_100_HANDS, + AVERAGE, AVERAGE_DURATION, NET_BB_PER_100_HANDS, HOURLY_RATE_BB, AVERAGE_NET_BB, ROI, WIN_RATIO, HOURLY_RATE -> R.string.average NETRESULT, DURATION -> R.string.total STANDARD_DEVIATION -> R.string.net_result @@ -165,6 +187,22 @@ enum class Stat(var underlyingClass: Class? = null) : RowRepresentabl } } + val graphType: GraphType + get() { + return when (this) { + NUMBER_OF_SETS, NUMBER_OF_GAMES -> GraphType.BAR + else -> GraphType.LINE + } + } + + val aggregationTypes: List + get() { + return when (this) { + NETRESULT -> listOf(AggregationType.SESSION, AggregationType.MONTH, AggregationType.YEAR, AggregationType.DURATION) + else -> listOf(AggregationType.SESSION, AggregationType.MONTH, AggregationType.YEAR, AggregationType.DURATION) + } + } + override val viewType: Int = RowViewType.TITLE_VALUE.ordinal } @@ -191,11 +229,4 @@ class ComputedStat(var stat: Stat, var value: Double, var currency: Currency? = return this.stat.format(this.value, this.currency, context) } - /** - * Returns a TextFormat instance for an evolution value located at the specified [index] - */ - fun evolutionValueFormat(index: Int): TextFormat { - return TextFormat("undef ${index}") - } - } diff --git a/app/src/main/java/net/pokeranalytics/android/calculus/Format.kt b/app/src/main/java/net/pokeranalytics/android/calculus/TextFormat.kt similarity index 100% rename from app/src/main/java/net/pokeranalytics/android/calculus/Format.kt rename to app/src/main/java/net/pokeranalytics/android/calculus/TextFormat.kt diff --git a/app/src/main/java/net/pokeranalytics/android/model/filter/QueryCondition.kt b/app/src/main/java/net/pokeranalytics/android/model/filter/QueryCondition.kt index bc8c118b..48f541d5 100644 --- a/app/src/main/java/net/pokeranalytics/android/model/filter/QueryCondition.kt +++ b/app/src/main/java/net/pokeranalytics/android/model/filter/QueryCondition.kt @@ -4,6 +4,7 @@ import io.realm.RealmQuery import net.pokeranalytics.android.exceptions.PokerAnalyticsException import net.pokeranalytics.android.model.realm.FilterCondition import net.pokeranalytics.android.model.realm.Session +import net.pokeranalytics.android.util.Preferences import net.pokeranalytics.android.util.extensions.endOfDay import net.pokeranalytics.android.util.extensions.startOfDay import java.util.* @@ -71,6 +72,8 @@ enum class QueryCondition(var operator: Operator? = null) { PAST_DAYS, MORE_THAN_DURATION(Operator.MORE), LESS_THAN_DURATION(Operator.LESS), + STARTED_FROM_TIME, + ENDED_TO_TIME, COMMENT, diff --git a/app/src/main/java/net/pokeranalytics/android/model/migrations/PokerAnalyticsMigration.kt b/app/src/main/java/net/pokeranalytics/android/model/migrations/PokerAnalyticsMigration.kt index 4588fd95..29e15c3b 100644 --- a/app/src/main/java/net/pokeranalytics/android/model/migrations/PokerAnalyticsMigration.kt +++ b/app/src/main/java/net/pokeranalytics/android/model/migrations/PokerAnalyticsMigration.kt @@ -46,6 +46,13 @@ class PokerAnalyticsMigration : RealmMigration { currentVersion++ } + // Migrate to version 2 + if (currentVersion == 2) { + Timber.d("*** Running migration ${currentVersion + 1}") + schema.rename("Report", "ReportSetup") + currentVersion++ + } + } override fun equals(other: Any?): Boolean { diff --git a/app/src/main/java/net/pokeranalytics/android/model/realm/FilterCondition.kt b/app/src/main/java/net/pokeranalytics/android/model/realm/FilterCondition.kt index 6742969c..0aabc19c 100644 --- a/app/src/main/java/net/pokeranalytics/android/model/realm/FilterCondition.kt +++ b/app/src/main/java/net/pokeranalytics/android/model/realm/FilterCondition.kt @@ -115,7 +115,7 @@ open class FilterCondition() : RealmObject() { */ fun getFilterConditionValue(filterElementRow: FilterElementRow): Any? { return when (filterElementRow) { - is From, is To -> dateValue //TODO: Probably change by 'date' (doesn't work now because the value isn't correctly saved + is DateFilterElementRow -> date is PastDays -> values else -> throw PokerAnalyticsException.FilterElementTypeMissing(filterElementRow) } diff --git a/app/src/main/java/net/pokeranalytics/android/model/realm/Report.kt b/app/src/main/java/net/pokeranalytics/android/model/realm/ReportSetup.kt similarity index 94% rename from app/src/main/java/net/pokeranalytics/android/model/realm/Report.kt rename to app/src/main/java/net/pokeranalytics/android/model/realm/ReportSetup.kt index abf711a9..2edad050 100644 --- a/app/src/main/java/net/pokeranalytics/android/model/realm/Report.kt +++ b/app/src/main/java/net/pokeranalytics/android/model/realm/ReportSetup.kt @@ -11,7 +11,7 @@ enum class ReportDisplay { MAP } -open class Report : RealmObject() { +open class ReportSetup : RealmObject() { @PrimaryKey var id = UUID.randomUUID().toString() diff --git a/app/src/main/java/net/pokeranalytics/android/model/utils/Seed.kt b/app/src/main/java/net/pokeranalytics/android/model/utils/Seed.kt index 274dbde6..9672f3fa 100644 --- a/app/src/main/java/net/pokeranalytics/android/model/utils/Seed.kt +++ b/app/src/main/java/net/pokeranalytics/android/model/utils/Seed.kt @@ -3,9 +3,14 @@ package net.pokeranalytics.android.model.utils import android.content.Context import io.realm.Realm import io.realm.kotlin.where -import net.pokeranalytics.android.R -import net.pokeranalytics.android.model.realm.* +import net.pokeranalytics.android.model.realm.Bankroll import net.pokeranalytics.android.model.realm.Currency +<<<<<<< HEAD +======= +import net.pokeranalytics.android.model.realm.Game +import net.pokeranalytics.android.model.realm.TournamentFeature +import net.pokeranalytics.android.util.CurrencyUtils +>>>>>>> 7fce9661594eb0faba91337d78c6cc1e880e49a1 import java.util.* @@ -19,7 +24,7 @@ class Seed(var context:Context) : Realm.Transaction { } private fun createDefaultTournamentFeatures(realm: Realm) { - context.resources.getStringArray(R.array.seed_tournament_features).forEach { + context.resources.getStringArray(net.pokeranalytics.android.R.array.seed_tournament_features).forEach { val tournamentFeature = TournamentFeature() tournamentFeature.id = UUID.randomUUID().toString() tournamentFeature.name = it @@ -37,8 +42,13 @@ class Seed(var context:Context) : Realm.Transaction { } private fun createDefaultCurrencyAndBankroll(realm: Realm) { + // Currency +<<<<<<< HEAD val localeCurrency = localeCurrency +======= + val localeCurrency = CurrencyUtils.getLocaleCurrency() +>>>>>>> 7fce9661594eb0faba91337d78c6cc1e880e49a1 val defaultCurrency = Currency() defaultCurrency.code = localeCurrency.currencyCode realm.insertOrUpdate(defaultCurrency) @@ -52,8 +62,8 @@ class Seed(var context:Context) : Realm.Transaction { } private fun createDefaultGames(realm: Realm) { - val gamesName = context.resources.getStringArray(R.array.seed_games) - val gamesShortName = context.resources.getStringArray(R.array.seed_games_short_name) + val gamesName = context.resources.getStringArray(net.pokeranalytics.android.R.array.seed_games) + val gamesShortName = context.resources.getStringArray(net.pokeranalytics.android.R.array.seed_games_short_name) for ((index, name) in gamesName.withIndex()) { val game = Game() game.id = UUID.randomUUID().toString() diff --git a/app/src/main/java/net/pokeranalytics/android/ui/activity/GraphActivity.kt b/app/src/main/java/net/pokeranalytics/android/ui/activity/GraphActivity.kt index 8f815c9c..e0a840d9 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/activity/GraphActivity.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/activity/GraphActivity.kt @@ -41,7 +41,7 @@ class GraphActivity : PokerAnalyticsActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - setContentView(R.layout.activity_editable_data) + setContentView(R.layout.activity_graph) initUI() } diff --git a/app/src/main/java/net/pokeranalytics/android/ui/fragment/FilterDetailsFragment.kt b/app/src/main/java/net/pokeranalytics/android/ui/fragment/FilterDetailsFragment.kt index 042ecb95..40a5f226 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/fragment/FilterDetailsFragment.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/fragment/FilterDetailsFragment.kt @@ -27,12 +27,13 @@ import net.pokeranalytics.android.ui.view.rowrepresentable.FilterElementRow import net.pokeranalytics.android.ui.view.rowrepresentable.FilterSectionRow import net.pokeranalytics.android.util.NULL_TEXT import net.pokeranalytics.android.util.extensions.shortDate +import net.pokeranalytics.android.util.extensions.shortTime import net.pokeranalytics.android.util.extensions.toMinutes import timber.log.Timber import java.util.* import kotlin.collections.ArrayList -open class FilterDetailsFragment : PokerAnalyticsFragment(), StaticRowRepresentableDataSource, RowRepresentableDelegate { +open class FilterDetailsFragment : PokerAnalyticsFragment(), StaticRowRepresentableDataSource, RowRepresentableDelegate { lateinit var parentActivity: PokerAnalyticsActivity lateinit var rowRepresentableAdapter: RowRepresentableAdapter @@ -69,7 +70,7 @@ open class FilterDetailsFragment : PokerAnalyticsFragment(), StaticRowRepresenta Timber.d("Row: $row") when (row) { - is FilterElementRow.DateFilterElementRow -> DateTimePickerManager.create(requireContext(), row, this, row.dateValue, onlyDate = true) + is FilterElementRow.DateFilterElementRow -> DateTimePickerManager.create(requireContext(), row, this, row.dateValue, onlyDate = !row.showTime, onlyTime = row.showTime) is FilterElementRow.PastDays -> { val pastDays = if (row.lastDays > 0) row.lastDays.toString() else "" val data = row.editingDescriptors(mapOf("pastDays" to pastDays)) @@ -107,7 +108,7 @@ open class FilterDetailsFragment : PokerAnalyticsFragment(), StaticRowRepresenta is FilterElementRow.PastDays -> if (row.lastDays > 0) row.lastDays.toString() else NULL_TEXT is FilterElementRow.LastGames -> if (row.lastGames > 0) row.lastGames.toString() else NULL_TEXT is FilterElementRow.LastSessions -> if (row.lastSessions > 0) row.lastSessions.toString() else NULL_TEXT - is FilterElementRow.DateFilterElementRow -> row.dateValue.shortDate() + is FilterElementRow.DateFilterElementRow -> if (row.showTime) row.dateValue.shortTime() else row.dateValue.shortDate() is FilterElementRow.AmountFilterElement -> if (row.amount > 0) row.amount.toString() else NULL_TEXT is FilterElementRow.DurationFilterElement -> row.minutes.toMinutes(requireContext()) else -> super.stringForRow(row) @@ -243,7 +244,7 @@ open class FilterDetailsFragment : PokerAnalyticsFragment(), StaticRowRepresenta private fun saveData() { //TODO: Save currentFilter details data Timber.d("Save data for filter: ${currentFilter?.id}") - selectedRows?.forEach { + selectedRows.forEach { Timber.d("Selected rows: $it") } diff --git a/app/src/main/java/net/pokeranalytics/android/ui/fragment/GraphFragment.kt b/app/src/main/java/net/pokeranalytics/android/ui/fragment/GraphFragment.kt index a126610a..5cfb9755 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/fragment/GraphFragment.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/fragment/GraphFragment.kt @@ -4,16 +4,24 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import com.github.mikephil.charting.charts.BarChart +import com.github.mikephil.charting.charts.BarLineChartBase +import com.github.mikephil.charting.charts.LineChart import com.github.mikephil.charting.data.Entry import com.github.mikephil.charting.data.LineData import com.github.mikephil.charting.data.LineDataSet import com.github.mikephil.charting.highlight.Highlight import com.github.mikephil.charting.listener.OnChartValueSelectedListener -import kotlinx.android.synthetic.main.fragment_graph.* +import com.google.android.material.chip.Chip +import kotlinx.android.synthetic.main.fragment_evograph.* import net.pokeranalytics.android.R +import net.pokeranalytics.android.calculus.GraphType import net.pokeranalytics.android.calculus.Stat +import net.pokeranalytics.android.ui.activity.components.PokerAnalyticsActivity import net.pokeranalytics.android.ui.fragment.components.PokerAnalyticsFragment import net.pokeranalytics.android.ui.graph.setStyle +import net.pokeranalytics.android.ui.view.LegendView +import net.pokeranalytics.android.util.extensions.px interface GraphDataSource { @@ -22,13 +30,16 @@ interface GraphDataSource { class GraphFragment : PokerAnalyticsFragment(), OnChartValueSelectedListener { + private lateinit var parentActivity: PokerAnalyticsActivity lateinit var dataSource: GraphDataSource lateinit var stat: Stat lateinit var entries: List - companion object { + lateinit var legendView: LegendView + lateinit var chartView: BarLineChartBase<*> + companion object { } @@ -38,7 +49,7 @@ class GraphFragment : PokerAnalyticsFragment(), OnChartValueSelectedListener { } override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { - return inflater.inflate(R.layout.fragment_graph, container, false) + return inflater.inflate(R.layout.fragment_evograph, container, false) } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { @@ -46,18 +57,63 @@ class GraphFragment : PokerAnalyticsFragment(), OnChartValueSelectedListener { initUI() } + /** + * Init UI + */ private fun initUI() { + parentActivity = activity as PokerAnalyticsActivity + + this.legendView = LegendView(requireContext()) + this.legendContainer.addView(this.legendView) + this.legendView.prepareWithStat(this.stat) + + // Avoid a bug during setting the title + toolbar.title = "" + + parentActivity.setSupportActionBar(toolbar) + parentActivity.supportActionBar?.setDisplayHomeAsUpEnabled(true) + setHasOptionsMenu(true) + + toolbar.title = stat.localizedTitle(requireContext()) + val dataSet = LineDataSet(this.entries, this.stat.name) val colors = arrayOf(R.color.green_light).toIntArray() dataSet.setColors(colors, context) + dataSet.setDrawCircles(false) val lineData = LineData(listOf(dataSet)) - this.chart.setStyle() + this.chartView = when (stat.graphType) { + GraphType.LINE -> { + val lineChart = LineChart(context) + lineChart.data = lineData + lineChart + } + GraphType.BAR -> { + val barChart = BarChart(context) + barChart + } + } + + this.chartContainer.addView(this.chartView) + + this.chartView.setStyle(requireContext()) + this.chartView.setOnChartValueSelectedListener(this) - this.chart.data = lineData - this.chart.setOnChartValueSelectedListener(this) + this.stat.aggregationTypes.forEach { type -> + val chip = Chip(requireContext()) + chip.id = type.ordinal + chip.text = requireContext().getString(type.resId) + chip.chipStartPadding = 8f.px + chip.chipEndPadding = 8f.px + this.chipGroup.addView(chip) + } + + this.chipGroup.setOnCheckedChangeListener { group, i -> + + } + this.chipGroup.check(this.stat.aggregationTypes.first().ordinal) } // OnChartValueSelectedListener @@ -85,7 +141,7 @@ class GraphFragment : PokerAnalyticsFragment(), OnChartValueSelectedListener { } - this.text.text = "" +// this.text.text = "" diff --git a/app/src/main/java/net/pokeranalytics/android/ui/fragment/StatsFragment.kt b/app/src/main/java/net/pokeranalytics/android/ui/fragment/StatsFragment.kt index 000e43de..65cb1378 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/fragment/StatsFragment.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/fragment/StatsFragment.kt @@ -37,7 +37,7 @@ class StatsFragment : SessionObserverFragment(), StaticRowRepresentableDataSourc private var stringTournament = "" private lateinit var statsAdapter: RowRepresentableAdapter - private var computedResults : List? = null + private var report : Report? = null companion object { @@ -137,31 +137,31 @@ class StatsFragment : SessionObserverFragment(), StaticRowRepresentableDataSourc GlobalScope.launch(coroutineContext) { - var results = listOf() + var r = Report() val test = GlobalScope.async { val s = Date() Timber.d(">>> start...") val realm = Realm.getDefaultInstance() - results = createSessionGroupsAndStartCompute(realm) - computedResults = results + r = createSessionGroupsAndStartCompute(realm) + report = r realm.close() val e = Date() val duration = (e.time - s.time) / 1000.0 - Timber.d(">>> ended in ${duration} seconds") + Timber.d(">>> ended in $duration seconds") } test.await() if (!isDetached) { - showResults(results) + showResults(r) } } } - private fun createSessionGroupsAndStartCompute(realm: Realm) : List { + private fun createSessionGroupsAndStartCompute(realm: Realm) : Report { val allStats: List = listOf(Stat.NETRESULT, Stat.HOURLY_RATE, Stat.AVERAGE, Stat.NUMBER_OF_SETS, Stat.AVERAGE_DURATION, Stat.DURATION) val allSessionGroup = ComputableGroup(stringAll, listOf(), allStats) @@ -176,16 +176,16 @@ class StatsFragment : SessionObserverFragment(), StaticRowRepresentableDataSourc } - private fun showResults(results: List) { - this.rowRepresentables = this.convertResultsIntoRepresentables(results) + private fun showResults(report: Report) { + this.rowRepresentables = this.convertReportIntoRepresentables(report) statsAdapter.notifyDataSetChanged() } - private fun convertResultsIntoRepresentables(results: List) : ArrayList { + private fun convertReportIntoRepresentables(report: Report) : ArrayList { val rows: ArrayList = ArrayList() - results.forEach { result -> + report.results.forEach { result -> rows.add(CustomizableRowRepresentable(title = result.group.name)) result.group.stats?.forEach { stat -> rows.add(StatRepresentable(stat, result.computedStat(stat), result.group.name)) @@ -202,7 +202,7 @@ class StatsFragment : SessionObserverFragment(), StaticRowRepresentableDataSourc if (row is StatRepresentable) { // filter groups - val groupResults = this.computedResults?.filter { + val groupResults = this.report?.results?.filter { it.group.name == row.groupName } @@ -217,7 +217,7 @@ class StatsFragment : SessionObserverFragment(), StaticRowRepresentableDataSourc GlobalScope.launch(coroutineContext) { - var results = listOf() + var report = Report() val test = GlobalScope.async { val s = Date() Timber.d(">>> start...") @@ -225,18 +225,18 @@ class StatsFragment : SessionObserverFragment(), StaticRowRepresentableDataSourc val realm = Realm.getDefaultInstance() val options = Calculator.Options() options.evolutionValues = Calculator.Options.EvolutionValues.STANDARD - results = Calculator.computeGroups(realm, listOf(computableGroup), options) + report = Calculator.computeGroups(realm, listOf(computableGroup), options) realm.close() val e = Date() val duration = (e.time - s.time) / 1000.0 - Timber.d(">>> ended in ${duration} seconds") + Timber.d(">>> ended in $duration seconds") } test.await() if (!isDetached) { - results.firstOrNull()?.defaultStatEntries(stat)?.let { entries -> + report.results.firstOrNull()?.defaultStatEntries(stat)?.let { entries -> GraphActivity.newInstance(requireContext(), stat, entries) } } diff --git a/app/src/main/java/net/pokeranalytics/android/ui/graph/GraphExtensions.kt b/app/src/main/java/net/pokeranalytics/android/ui/graph/GraphExtensions.kt index 56cd4dda..ee94423e 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/graph/GraphExtensions.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/graph/GraphExtensions.kt @@ -1,25 +1,35 @@ package net.pokeranalytics.android.ui.graph -import com.github.mikephil.charting.charts.BarChart +import android.content.Context +import androidx.core.content.ContextCompat import com.github.mikephil.charting.charts.BarLineChartBase -import com.github.mikephil.charting.charts.LineChart +import com.github.mikephil.charting.components.XAxis +import net.pokeranalytics.android.R +import net.pokeranalytics.android.util.extensions.px -fun BarChart.setStyle() { - GraphHelper.setStyle(this) -} +//fun BarChart.setStyle(context: Context) { +// GraphHelper.setStyle(this, context) +//} -fun LineChart.setStyle() { - GraphHelper.setStyle(this) +fun BarLineChartBase<*>.setStyle(context: Context) { + GraphHelper.setStyle(this, context) } class GraphHelper { companion object { - fun setStyle(chart: BarLineChartBase<*>) { + fun setStyle(chart: BarLineChartBase<*>, context: Context) { + + chart.xAxis.axisLineColor = ContextCompat.getColor(context, R.color.chart_default) + chart.xAxis.enableGridDashedLine(3.0f.px, 5.0f.px, 1.0f.px) + chart.xAxis.textColor = ContextCompat.getColor(context, R.color.chart_default) + chart.xAxis.labelCount = 4 + chart.xAxis.position = XAxis.XAxisPosition.BOTTOM + + chart.axisLeft.enableGridDashedLine(3.0f.px, 5.0f.px, 1.0f.px) -// this.xAxis.axisLineColor = ContextCompat.getColor(context, R.color.) ChartAppearance.defaultColor -// this.xAxis.axisLineWidth = ChartAppearance.lineWidth +// this.xAxis.axisLineWidth = ChartAppearance.lineWidth // this.xAxis.enableGridDashedLine(3.0f, 5.0f, 1.0f) // // this.xAxis.labelTextColor = ChartAppearance.defaultColor @@ -27,7 +37,7 @@ class GraphHelper { // this.xAxis.labelCount = 4 // this.xAxis.labelPosition = .bottom // -// this.xAxis.drawLabelsEnabled = true +// this.xAxis.drawLabelsEnabled = true // this.xAxis.drawGridLinesEnabled = true // this.xAxis.granularity = 1.0 // this.xAxis.granularityEnabled = true diff --git a/app/src/main/java/net/pokeranalytics/android/ui/helpers/DateTimePickerManager.kt b/app/src/main/java/net/pokeranalytics/android/ui/helpers/DateTimePickerManager.kt index eea9bd32..d5e26d36 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/helpers/DateTimePickerManager.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/helpers/DateTimePickerManager.kt @@ -23,6 +23,7 @@ class DateTimePickerManager : DatePickerDialog.OnDateSetListener, private lateinit var calendar: Calendar private var minimumDate: Date? = null private var onlyDate: Boolean = false + private var onlyTime: Boolean = false private var isClearable: Boolean = true companion object { @@ -33,6 +34,7 @@ class DateTimePickerManager : DatePickerDialog.OnDateSetListener, date: Date?, minimumDate: Date? = null, onlyDate: Boolean? = false, + onlyTime: Boolean? = false, isClearable: Boolean? = true ): DateTimePickerManager { @@ -46,9 +48,14 @@ class DateTimePickerManager : DatePickerDialog.OnDateSetListener, dateTimePickerManager.calendar = calendar dateTimePickerManager.minimumDate = minimumDate dateTimePickerManager.onlyDate = onlyDate ?: false + dateTimePickerManager.onlyTime = onlyTime ?: false dateTimePickerManager.isClearable = isClearable ?: true - dateTimePickerManager.showDatePicker() + if (dateTimePickerManager.onlyTime) { + dateTimePickerManager.showTimePicker() + } else { + dateTimePickerManager.showDatePicker() + } return dateTimePickerManager } diff --git a/app/src/main/java/net/pokeranalytics/android/ui/view/LegendView.kt b/app/src/main/java/net/pokeranalytics/android/ui/view/LegendView.kt new file mode 100644 index 00000000..a5d4ad1b --- /dev/null +++ b/app/src/main/java/net/pokeranalytics/android/ui/view/LegendView.kt @@ -0,0 +1,69 @@ +package net.pokeranalytics.android.ui.view + +import android.content.Context +import android.util.AttributeSet +import android.view.LayoutInflater +import android.widget.FrameLayout +import androidx.constraintlayout.widget.ConstraintLayout +import kotlinx.android.synthetic.main.layout_legend_default.view.* +import net.pokeranalytics.android.R +import net.pokeranalytics.android.calculus.Stat +import net.pokeranalytics.android.model.realm.Session + + +/** + * Display a row session + */ +class LegendView : FrameLayout { + + private lateinit var legendLayout: ConstraintLayout + + /** + * Constructors + */ + constructor(context: Context) : super(context) { + init() + } + + constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) { + init() + } + + constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) { + init() + } + + /** + * Init + */ + private fun init() { + val layoutInflater = LayoutInflater.from(context) + legendLayout = layoutInflater.inflate(R.layout.layout_legend_default, this, false) as ConstraintLayout + val layoutParams = FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT) + addView(legendLayout, layoutParams) + } + + /** + * Set the stat data to the view + */ + fun prepareWithStat(stat: Stat) { + + this.stat1Name.text = stat.localizedTitle(context) + this.stat2Name.text = stat.cumulativeLabelResId(context) + + //TODO: Set real data + this.title.text = "11/04/2019" + this.stat1Value.text = "$521" + this.stat2Value.text = "$15,051" + this.counter.text = "21 Sessions" + + } + + /** + * + */ + fun setData(session: Session) { + + } + +} \ No newline at end of file diff --git a/app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/FilterElementRow.kt b/app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/FilterElementRow.kt index 1c715ed8..5217f486 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/FilterElementRow.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/FilterElementRow.kt @@ -11,6 +11,10 @@ import net.pokeranalytics.android.ui.fragment.components.bottomsheet.BottomSheet import net.pokeranalytics.android.ui.view.RowRepresentable import net.pokeranalytics.android.ui.view.RowRepresentableEditDescriptor import net.pokeranalytics.android.ui.view.RowViewType +import net.pokeranalytics.android.util.CurrencyUtils +import net.pokeranalytics.android.util.NULL_TEXT +import net.pokeranalytics.android.util.extensions.formatted +import net.pokeranalytics.android.util.extensions.round import java.text.DateFormatSymbols import java.util.* import java.util.prefs.Preferences @@ -26,7 +30,7 @@ sealed class FilterElementRow : RowRepresentable { interface LessOperator : Operator open class BoolFilterElementRow : FilterElementRow() - open class DateFilterElementRow(var dateValue: Date = Date()) : FilterElementRow() + open class DateFilterElementRow(var dateValue: Date = Date(), var showTime: Boolean = false) : FilterElementRow() open class NumericFilterElementRow(open val doubleValue: Double = 0.0) : FilterElementRow() open class StringFilterElementRow(val stringValue: String = "") : FilterElementRow() @@ -84,6 +88,10 @@ sealed class FilterElementRow : RowRepresentable { object From : DateFilterElementRow() object To : DateFilterElementRow() + object FromTime : DateFilterElementRow(showTime = true) + object ToTime : DateFilterElementRow(showTime = true) + + // Data classes - holding value object ResultMoreThan : AmountFilterElement(), MoreOperator @@ -144,6 +152,8 @@ sealed class FilterElementRow : RowRepresentable { is Stake -> QueryCondition.STAKE is From -> QueryCondition.STARTED_FROM_DATE is To -> QueryCondition.ENDED_TO_DATE + is FromTime -> QueryCondition.STARTED_FROM_TIME + is ToTime -> QueryCondition.ENDED_TO_TIME is Month -> QueryCondition.MONTH is Day -> QueryCondition.DAY_OF_WEEK is Year -> QueryCondition.YEAR @@ -171,7 +181,6 @@ sealed class FilterElementRow : RowRepresentable { is DurationMoreThan -> QueryCondition.MORE_THAN_DURATION is DurationLessThan -> QueryCondition.LESS_THAN_DURATION - //TODO: Check the conditions is LastGames -> QueryCondition.LAST_GAMES is LastSessions -> QueryCondition.LAST_SESSIONS @@ -206,8 +215,8 @@ sealed class FilterElementRow : RowRepresentable { is CurrentWeek -> R.string.current_week is CurrentMonth -> R.string.current_month is CurrentYear -> R.string.current_year - is From -> R.string.from - is To -> R.string.to + is From, FromTime -> R.string.from + is To, ToTime -> R.string.to is Live -> R.string.live is Online -> R.string.online is Weekday -> R.string.week_days @@ -226,7 +235,7 @@ sealed class FilterElementRow : RowRepresentable { override val viewType: Int get() { return when (this) { - is PastDays, is From, is To, is LastGames, is LastSessions, is ReBuyMoreThan, is ReBuyLessThan, + is PastDays, is From, is To, is FromTime, is ToTime, is LastGames, is LastSessions, is ReBuyMoreThan, is ReBuyLessThan, is DurationMoreThan, is DurationLessThan -> RowViewType.TITLE_VALUE_CHECK.ordinal else -> RowViewType.TITLE_CHECK.ordinal } @@ -333,22 +342,4 @@ sealed class FilterElementRow : RowRepresentable { return null } - /* - override fun editingDescriptors(map: Map): ArrayList? { - when (this) { - PAST_DAYS -> { - val defaultValue: String? by map - val data = arrayListOf() - data.add( - RowRepresentableEditDescriptor( - defaultValue, - inputType = InputType.TYPE_CLASS_NUMBER - ) - ) - } - } - - return super.editingDescriptors(map) - } - */ } \ No newline at end of file diff --git a/app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/FilterSectionRow.kt b/app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/FilterSectionRow.kt index d3542e8b..4f634007 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/FilterSectionRow.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/FilterSectionRow.kt @@ -9,6 +9,8 @@ import net.pokeranalytics.android.model.realm.Session import net.pokeranalytics.android.ui.view.RowRepresentable import net.pokeranalytics.android.ui.view.RowViewType import net.pokeranalytics.android.ui.view.rowrepresentable.FilterElementRow.* +import net.pokeranalytics.android.util.extensions.endOfDay +import net.pokeranalytics.android.util.extensions.startOfDay import java.text.DateFormatSymbols import java.util.* @@ -86,7 +88,8 @@ enum class FilterSectionRow(override val resId: Int?) : RowRepresentable { TABLE_SIZE -> { val tableSizes = arrayListOf() val realm = Realm.getDefaultInstance() - val distinctTableSizes = realm.where().distinct("tableSize").findAll().sort("tableSize", Sort.ASCENDING) + val distinctTableSizes = + realm.where().distinct("tableSize").findAll().sort("tableSize", Sort.ASCENDING) distinctTableSizes.forEach { session -> session.tableSize?.let { tableSize -> tableSizes.add(TableSize(net.pokeranalytics.android.model.TableSize(tableSize))) @@ -110,7 +113,8 @@ enum class FilterSectionRow(override val resId: Int?) : RowRepresentable { YEAR -> { val years = arrayListOf() val realm = Realm.getDefaultInstance() - val distinctYears = realm.where().distinct("year").findAll().sort("year", Sort.DESCENDING) + val distinctYears = + realm.where().distinct("year").findAll().sort("year", Sort.DESCENDING) distinctYears.forEach { session -> session.year?.let { year -> years.add(Year(year)) @@ -140,8 +144,17 @@ enum class FilterSectionRow(override val resId: Int?) : RowRepresentable { } // Duration - SESSION_DURATION -> arrayListOf(DurationMoreThan as FilterElementRow, DurationLessThan as FilterElementRow) - RANGE -> arrayListOf(From, To) + SESSION_DURATION -> arrayListOf( + DurationMoreThan as FilterElementRow, + DurationLessThan as FilterElementRow + ) + RANGE -> { + val fromTime = FromTime + fromTime.dateValue = Date().startOfDay() + val toTime = ToTime + toTime.dateValue = Date().endOfDay() + arrayListOf(fromTime, toTime) + } // Sessions SESSIONS -> arrayListOf(LastGames(0), LastSessions(0)) @@ -158,7 +171,10 @@ enum class FilterSectionRow(override val resId: Int?) : RowRepresentable { realm.close() stakes } - CASH_RE_BUY_COUNT -> arrayListOf(ReBuyMoreThan as FilterElementRow, ReBuyLessThan as FilterElementRow) + CASH_RE_BUY_COUNT -> arrayListOf( + ReBuyMoreThan as FilterElementRow, + ReBuyLessThan as FilterElementRow + ) // Tournament TOURNAMENT_TYPE -> arrayListOf() diff --git a/app/src/main/java/net/pokeranalytics/android/util/CurrencyUtils.kt b/app/src/main/java/net/pokeranalytics/android/util/CurrencyUtils.kt index 861ada82..2aa76778 100644 --- a/app/src/main/java/net/pokeranalytics/android/util/CurrencyUtils.kt +++ b/app/src/main/java/net/pokeranalytics/android/util/CurrencyUtils.kt @@ -13,7 +13,7 @@ class CurrencyUtils { * return the currency associated with this bankroll */ fun getCurrency(bankroll: Bankroll? = null) : Currency { - val currencyCode = bankroll?.currency?.code ?: Currency.getInstance(Locale.getDefault()).currencyCode + val currencyCode = bankroll?.currency?.code ?: CurrencyUtils.getLocaleCurrency().currencyCode return Currency.getInstance(currencyCode) } @@ -40,6 +40,25 @@ class CurrencyUtils { return currencyFormatter } + /** + * Return the locale currency, or en_US if there + */ + fun getLocaleCurrency() : Currency { + return try { + Currency.getInstance(Locale.getDefault()) + } catch (ex: Exception) { + when (Locale.getDefault().language) { + "en" -> Currency.getInstance(Locale("en", "US")) + "fr" -> Currency.getInstance(Locale("fr", "FR")) + "es" -> Currency.getInstance(Locale("es", "ES")) + "de" -> Currency.getInstance(Locale("de", "DE")) + "ja" -> Currency.getInstance(Locale("ja", "JP")) + "zh" -> Currency.getInstance(Locale("zh", "CN")) + else -> Currency.getInstance(Locale("en", "US")) + } + } + } + } } \ No newline at end of file diff --git a/app/src/main/res/layout/activity_graph.xml b/app/src/main/res/layout/activity_graph.xml index 70454fb9..b1ce6c7a 100644 --- a/app/src/main/res/layout/activity_graph.xml +++ b/app/src/main/res/layout/activity_graph.xml @@ -1,7 +1,8 @@ - + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_evograph.xml b/app/src/main/res/layout/fragment_evograph.xml new file mode 100644 index 00000000..eba9d9ac --- /dev/null +++ b/app/src/main/res/layout/fragment_evograph.xml @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_graph.xml b/app/src/main/res/layout/fragment_graph.xml deleted file mode 100644 index cf58c3d3..00000000 --- a/app/src/main/res/layout/fragment_graph.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/layout_legend_default.xml b/app/src/main/res/layout/layout_legend_default.xml new file mode 100644 index 00000000..4d65f59a --- /dev/null +++ b/app/src/main/res/layout/layout_legend_default.xml @@ -0,0 +1,94 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index b0cd3cbe..65d61cb7 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -37,4 +37,6 @@ #8e35c8 + #5c7258 + diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index 43246d76..4853c382 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -1,7 +1,7 @@ - + + + + + + + + + + + + + + + + + + + + + + + + +