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

feature/top10
Razmig Sarkissian 7 years ago
commit 5b11883a4a
  1. 10
      app/src/main/AndroidManifest.xml
  2. 2
      app/src/main/java/net/pokeranalytics/android/PokerAnalyticsApplication.kt
  3. 15
      app/src/main/java/net/pokeranalytics/android/calculus/Calculator.kt
  4. 86
      app/src/main/java/net/pokeranalytics/android/calculus/Report.kt
  5. 18
      app/src/main/java/net/pokeranalytics/android/calculus/Stat.kt
  6. 37
      app/src/main/java/net/pokeranalytics/android/ui/extensions/UIExtensions.kt
  7. 4
      app/src/main/java/net/pokeranalytics/android/ui/fragment/CalendarDetailsFragment.kt
  8. 123
      app/src/main/java/net/pokeranalytics/android/ui/fragment/GraphFragment.kt
  9. 1
      app/src/main/java/net/pokeranalytics/android/ui/fragment/ReportsFragment.kt
  10. 5
      app/src/main/java/net/pokeranalytics/android/ui/fragment/SessionFragment.kt
  11. 10
      app/src/main/java/net/pokeranalytics/android/ui/fragment/SettingsFragment.kt
  12. 7
      app/src/main/java/net/pokeranalytics/android/ui/graph/ChartDataSet.kt
  13. 43
      app/src/main/java/net/pokeranalytics/android/ui/view/RowViewType.kt
  14. 2
      app/src/main/java/net/pokeranalytics/android/util/FakeDataManager.kt
  15. 39
      app/src/main/res/layout/fragment_loader.xml
  16. 6
      app/src/main/res/xml/provider_paths.xml

@ -98,6 +98,16 @@
android:name="preloaded_fonts" android:name="preloaded_fonts"
android:resource="@array/preloaded_fonts" /> android:resource="@array/preloaded_fonts" />
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.fileprovider"
android:grantUriPermissions="true"
android:exported="false">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/provider_paths" />
</provider>
</application> </application>
</manifest> </manifest>

@ -52,7 +52,7 @@ class PokerAnalyticsApplication : Application() {
if (BuildConfig.DEBUG) { if (BuildConfig.DEBUG) {
Timber.d("UserPreferences.defaultCurrency: ${UserDefaults.currency.symbol}") Timber.d("UserPreferences.defaultCurrency: ${UserDefaults.currency.symbol}")
this.createFakeSessions() //this.createFakeSessions()
} }
Patcher.patchBreaks() Patcher.patchBreaks()

@ -177,7 +177,7 @@ class Calculator {
results.computeStatVariations(comparedResults) results.computeStatVariations(comparedResults)
} }
if (options.shouldManageMultiGroupProgressValues == true) { if (options.shouldManageMultiGroupProgressValues) {
group.comparedComputedResults = report.results.lastOrNull() group.comparedComputedResults = report.results.lastOrNull()
} }
@ -268,15 +268,15 @@ class Calculator {
// Iterate for each session // Iterate for each session
if (shouldIterateOverComputables) { if (shouldIterateOverComputables) {
var index: Int = 0 var index = 0
var tSum = 0.0 var tSum = 0.0
var tBBSum = 0.0 var tBBSum = 0.0
var tBBSessionCount = 0 var tBBSessionCount = 0
var tWinningSessionCount = 0 var tWinningSessionCount = 0
var tBuyinSum = 0.0 var tBuyinSum = 0.0
var tHands = 0.0 var tHands = 0.0
var longestWinStreak = 0; var longestWinStreak = 0
var longestLoseStreak = 0; var longestLoseStreak = 0
var currentStreak = 0 var currentStreak = 0
computables.forEach { computable -> computables.forEach { computable ->
@ -316,6 +316,7 @@ class Calculator {
data = session data = session
) )
results.addEvolutionValue(tBuyinSum / index, stat = AVERAGE_BUYIN, data = session) results.addEvolutionValue(tBuyinSum / index, stat = AVERAGE_BUYIN, data = session)
results.addEvolutionValue(computable.ratedNet, stat = STANDARD_DEVIATION, data = session)
Stat.netBBPer100Hands(tBBSum, tHands)?.let { netBB100 -> Stat.netBBPer100Hands(tBBSum, tHands)?.let { netBB100 ->
results.addEvolutionValue(netBB100, stat = NET_BB_PER_100_HANDS, data = session) results.addEvolutionValue(netBB100, stat = NET_BB_PER_100_HANDS, data = session)
@ -355,7 +356,7 @@ class Calculator {
} }
} }
val shouldIterateOverSets = computableGroup.conditions.size > 0 || val shouldIterateOverSets = computableGroup.conditions.isNotEmpty() ||
options.evolutionValues != Options.EvolutionValues.NONE || options.evolutionValues != Options.EvolutionValues.NONE ||
options.computeDaysPlayed options.computeDaysPlayed
@ -366,8 +367,8 @@ class Calculator {
var tRatedNetSum = 0.0 var tRatedNetSum = 0.0
var tBBSum = 0.0 var tBBSum = 0.0
var tTotalHands = 0.0 var tTotalHands = 0.0
var tHourlyRate = 0.0 var tHourlyRate: Double
var tHourlyRateBB = 0.0 var tHourlyRateBB: Double
val daysSet = mutableSetOf<Date>() val daysSet = mutableSetOf<Date>()
var tMaxDuration = 0.0 var tMaxDuration = 0.0

@ -1,15 +1,17 @@
package net.pokeranalytics.android.calculus package net.pokeranalytics.android.calculus
import android.content.Context import android.content.Context
import com.github.mikephil.charting.data.BarEntry import com.github.mikephil.charting.data.*
import com.github.mikephil.charting.data.Entry
import io.realm.Realm import io.realm.Realm
import io.realm.RealmResults import io.realm.RealmResults
import net.pokeranalytics.android.R
import net.pokeranalytics.android.model.filter.QueryCondition import net.pokeranalytics.android.model.filter.QueryCondition
import net.pokeranalytics.android.model.interfaces.Timed import net.pokeranalytics.android.model.interfaces.Timed
import net.pokeranalytics.android.model.realm.ComputableResult import net.pokeranalytics.android.model.realm.ComputableResult
import net.pokeranalytics.android.model.realm.Filter import net.pokeranalytics.android.model.realm.Filter
import net.pokeranalytics.android.model.realm.SessionSet import net.pokeranalytics.android.model.realm.SessionSet
import net.pokeranalytics.android.ui.graph.PALineDataSet
import kotlin.math.abs
/** /**
* The class returned after performing calculation in the Calculator object * The class returned after performing calculation in the Calculator object
@ -34,7 +36,7 @@ class Report(var options: Calculator.Options) {
* Returns the list of entries corresponding to the provided [stat] * Returns the list of entries corresponding to the provided [stat]
* One value will be returned by result * One value will be returned by result
*/ */
fun lineEntries(stat: Stat): List<Entry> { fun lineEntries(stat: Stat, context: Context): LineDataSet {
val entries = mutableListOf<Entry>() val entries = mutableListOf<Entry>()
this._results.forEachIndexed { index, results -> this._results.forEachIndexed { index, results ->
@ -42,11 +44,11 @@ class Report(var options: Calculator.Options) {
entries.add(Entry(index.toFloat(), progressValue.toFloat(), results)) entries.add(Entry(index.toFloat(), progressValue.toFloat(), results))
} }
} }
return entries return PALineDataSet(entries, stat.name, context)
} }
fun barEntries(stat: Stat? = null): List<Entry> { fun barEntries(stat: Stat? = null): BarDataSet {
val entries = mutableListOf<Entry>() val entries = mutableListOf<BarEntry>()
val statToUse = stat ?: options.displayedStats.firstOrNull() val statToUse = stat ?: options.displayedStats.firstOrNull()
statToUse?.let { statToUse?.let {
@ -59,16 +61,16 @@ class Report(var options: Calculator.Options) {
} }
} }
return entries return BarDataSet(entries, stat?.name)
} }
fun multiLineEntries(): List<List<Entry>> { fun multiLineEntries(context: Context): List<List<Entry>> {
val entries = mutableListOf<List<Entry>>() val entries = mutableListOf<List<Entry>>()
options.displayedStats.forEach { stat -> options.displayedStats.forEach { stat ->
this._results.forEach { result -> this._results.forEach { result ->
val entryList = result.singleLineEntries(stat) val dataSet = result.singleLineEntries(stat, context)
entries.add(entryList) // entries.add(entryList)
} }
} }
@ -328,48 +330,39 @@ class ComputedResults(group: ComputableGroup, shouldManageMultiGroupProgressValu
this.consolidateProgressStats() this.consolidateProgressStats()
if (options.evolutionValues != Calculator.Options.EvolutionValues.NONE) {
// Sort points as a distribution
this._computedStats.keys.filter { it.hasDistributionSorting() }.forEach { _ ->
// @todo sort
// var evolutionValues = this._evolutionValues[stat]
// evolutionValues.so
}
}
} }
// MPAndroidChart // MPAndroidChart
fun defaultStatEntries(stat: Stat): List<Entry> { fun defaultStatEntries(stat: Stat, context: Context): DataSet<out Entry> {
return when (stat) { return when (stat) {
Stat.NUMBER_OF_SETS, Stat.NUMBER_OF_GAMES -> this.barEntries(stat) Stat.NUMBER_OF_SETS, Stat.NUMBER_OF_GAMES -> this.barEntries(stat)
else -> this.singleLineEntries(stat) Stat.STANDARD_DEVIATION -> this.distributionEntries(stat, context)
else -> this.singleLineEntries(stat, context)
} }
} }
fun singleLineEntries(stat: Stat): List<Entry> { fun singleLineEntries(stat: Stat, context: Context): LineDataSet {
val entries = mutableListOf<Entry>() val entries = mutableListOf<Entry>()
this._evolutionValues[stat]?.let { points -> this._evolutionValues[stat]?.let { points ->
points.forEachIndexed { index, p -> points.forEachIndexed { index, p ->
entries.add(Entry(index.toFloat(), p.y.toFloat(), p.data)) entries.add(Entry(index.toFloat(), p.y.toFloat(), p.data))
} }
} }
return entries return PALineDataSet(entries, stat.name, context)
} }
fun durationEntries(stat: Stat): List<Entry> { fun durationEntries(stat: Stat, context: Context): LineDataSet {
val entries = mutableListOf<Entry>() val entries = mutableListOf<Entry>()
this._evolutionValues[stat]?.let { points -> this._evolutionValues[stat]?.let { points ->
points.forEach { p -> points.forEach { p ->
entries.add(Entry(p.x.toFloat(), p.y.toFloat(), p.data)) entries.add(Entry(p.x.toFloat(), p.y.toFloat(), p.data))
} }
} }
return entries return PALineDataSet(entries, stat.name, context)
} }
fun barEntries(stat: Stat): List<BarEntry> { fun barEntries(stat: Stat): BarDataSet {
val entries = mutableListOf<BarEntry>() val entries = mutableListOf<BarEntry>()
this._evolutionValues[stat]?.let { points -> this._evolutionValues[stat]?.let { points ->
@ -377,7 +370,44 @@ class ComputedResults(group: ComputableGroup, shouldManageMultiGroupProgressValu
entries.add(BarEntry(p.x.toFloat(), p.y.toFloat(), p.data)) entries.add(BarEntry(p.x.toFloat(), p.y.toFloat(), p.data))
} }
} }
return entries val dataSet = BarDataSet(entries, stat.name)
dataSet.setDrawValues(false)
return dataSet
}
fun distributionEntries(stat: Stat, context: Context): BarDataSet {
val colors = mutableListOf<Int>()
val entries = mutableListOf<BarEntry>()
this._evolutionValues[stat]?.let { points ->
val negative = mutableListOf<Point>()
val positive = mutableListOf<Point>()
points.sortByDescending { it.y }
points.forEach {
if (it.y < 0) {
negative.add(it)
} else {
positive.add(it)
}
}
negative.forEachIndexed { index, p ->
entries.add(BarEntry(index.toFloat(), abs(p.y.toFloat()), p.data))
colors.add(context.getColor(R.color.red))
}
positive.forEachIndexed { index, p ->
val x = negative.size + index.toFloat()
entries.add(BarEntry(x, p.y.toFloat(), p.data))
colors.add(context.getColor(R.color.green))
}
}
val dataSet = BarDataSet(entries, stat.name)
dataSet.colors = colors
dataSet.setDrawValues(false)
return dataSet
} }
val isEmpty: Boolean val isEmpty: Boolean

@ -94,16 +94,6 @@ enum class Stat : RowRepresentable {
TOTAL_BUYIN, TOTAL_BUYIN,
; ;
/**
* Returns whether the stat evolution numericValues requires a distribution sorting
*/
fun hasDistributionSorting(): Boolean {
return when (this) {
STANDARD_DEVIATION, STANDARD_DEVIATION_HOURLY, STANDARD_DEVIATION_BB_PER_100_HANDS -> true
else -> false
}
}
companion object { companion object {
fun returnOnInvestment(netResult: Double, buyin: Double): Double? { fun returnOnInvestment(netResult: Double, buyin: Double): Double? {
@ -224,14 +214,6 @@ enum class Stat : RowRepresentable {
} }
} }
val graphType: GraphType
get() {
return when (this) {
NUMBER_OF_SETS, NUMBER_OF_GAMES -> GraphType.BAR
else -> GraphType.LINE
}
}
val aggregationTypes: List<AggregationType> val aggregationTypes: List<AggregationType>
get() { get() {
return when (this) { return when (this) {

@ -11,6 +11,7 @@ import androidx.appcompat.app.AlertDialog
import androidx.appcompat.widget.AppCompatTextView import androidx.appcompat.widget.AppCompatTextView
import androidx.browser.customtabs.CustomTabsIntent import androidx.browser.customtabs.CustomTabsIntent
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.core.content.FileProvider
import androidx.core.view.isVisible import androidx.core.view.isVisible
import net.pokeranalytics.android.BuildConfig import net.pokeranalytics.android.BuildConfig
import net.pokeranalytics.android.R import net.pokeranalytics.android.R
@ -19,6 +20,11 @@ import net.pokeranalytics.android.ui.activity.components.PokerAnalyticsActivity
import net.pokeranalytics.android.ui.fragment.components.PokerAnalyticsFragment import net.pokeranalytics.android.ui.fragment.components.PokerAnalyticsFragment
import net.pokeranalytics.android.util.DeviceUtils import net.pokeranalytics.android.util.DeviceUtils
import net.pokeranalytics.android.util.URL import net.pokeranalytics.android.util.URL
import java.io.File
// Sizes // Sizes
@ -63,20 +69,33 @@ fun PokerAnalyticsActivity.openPlayStorePage() {
} }
// Open email for "Contact us" // Open email for "Contact us"
fun PokerAnalyticsActivity.openContactMail(subjectStringRes: Int) { fun PokerAnalyticsActivity.openContactMail(subjectStringRes: Int, filePath: String?= null) {
val info = "v${BuildConfig.VERSION_NAME}(${BuildConfig.VERSION_CODE}), Android ${android.os.Build.VERSION.SDK_INT}, ${DeviceUtils.getDeviceName()}" val info = "v${BuildConfig.VERSION_NAME}(${BuildConfig.VERSION_CODE}), Android ${android.os.Build.VERSION.SDK_INT}, ${DeviceUtils.getDeviceName()}"
val intent = Intent(Intent.ACTION_SENDTO)
intent.data = Uri.parse("mailto:${URL.SUPPORT_EMAIL.value}") val emailIntent = Intent(Intent.ACTION_SEND)
intent.putExtra(Intent.EXTRA_SUBJECT, getString(subjectStringRes))
intent.putExtra(Intent.EXTRA_EMAIL, URL.SUPPORT_EMAIL.value) filePath?.let {
intent.putExtra(Intent.EXTRA_TEXT, "\n\n$info") val databaseFile = File(it)
startActivity(Intent.createChooser(intent, getString(R.string.contact))) val contentUri = FileProvider.getUriForFile(this, "net.pokeranalytics.android.fileprovider", databaseFile)
if (contentUri != null) {
emailIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
emailIntent.setDataAndType(contentUri, contentResolver.getType(contentUri))
emailIntent.putExtra(Intent.EXTRA_STREAM, contentUri)
}
}
emailIntent.type = "message/rfc822"
emailIntent.putExtra(Intent.EXTRA_SUBJECT, getString(subjectStringRes))
emailIntent.putExtra(Intent.EXTRA_TEXT, "\n\n$info")
emailIntent.putExtra(Intent.EXTRA_EMAIL, arrayOf(URL.SUPPORT_EMAIL.value))
startActivity(Intent.createChooser(emailIntent, getString(R.string.contact)))
} }
// Open custom tab // Open custom tab
fun PokerAnalyticsActivity.openUrl(url: String) { fun PokerAnalyticsActivity.openUrl(url: String) {
val builder: CustomTabsIntent.Builder = CustomTabsIntent.Builder() val builder: CustomTabsIntent.Builder = CustomTabsIntent.Builder()
builder.setToolbarColor(ContextCompat.getColor(this, R.color.colorPrimary)) builder.setToolbarColor(ContextCompat.getColor(this, net.pokeranalytics.android.R.color.colorPrimary))
val customTabsIntent = builder.build() val customTabsIntent = builder.build()
customTabsIntent.launchUrl(this, Uri.parse(url)) customTabsIntent.launchUrl(this, Uri.parse(url))
} }
@ -102,7 +121,7 @@ fun showAlertDialog(context: Context, title: Int? = null, message: Int? = null)
message?.let { message?.let {
builder.setMessage(message) builder.setMessage(message)
} }
builder.setPositiveButton(R.string.ok, null) builder.setPositiveButton(net.pokeranalytics.android.R.string.ok, null)
builder.show() builder.show()
} }

@ -187,10 +187,10 @@ class CalendarDetailsFragment : PokerAnalyticsFragment(), StaticRowRepresentable
rowRepresentables.add(StatDoubleRow(it.computedStat(Stat.NET_RESULT), it.computedStat(Stat.HOURLY_RATE))) rowRepresentables.add(StatDoubleRow(it.computedStat(Stat.NET_RESULT), it.computedStat(Stat.HOURLY_RATE)))
rowRepresentables.add(StatDoubleRow(it.computedStat(Stat.LOCATIONS_PLAYED), it.computedStat(Stat.LONGEST_STREAKS))) rowRepresentables.add(StatDoubleRow(it.computedStat(Stat.LOCATIONS_PLAYED), it.computedStat(Stat.LONGEST_STREAKS)))
rowRepresentables.add(CustomizableRowRepresentable(RowViewType.HEADER_TITLE, resId = R.string.distribution)) rowRepresentables.add(CustomizableRowRepresentable(RowViewType.HEADER_TITLE, resId = R.string.distribution))
rowRepresentables.add(GraphRow(report, Stat.NET_RESULT)) rowRepresentables.add(GraphRow(report, Stat.STANDARD_DEVIATION))
rowRepresentables.add(StatDoubleRow(it.computedStat(Stat.WIN_RATIO), it.computedStat(Stat.MAXIMUM_NETRESULT))) rowRepresentables.add(StatDoubleRow(it.computedStat(Stat.WIN_RATIO), it.computedStat(Stat.MAXIMUM_NETRESULT)))
rowRepresentables.add(CustomizableRowRepresentable(RowViewType.HEADER_TITLE, resId = R.string.volume)) rowRepresentables.add(CustomizableRowRepresentable(RowViewType.HEADER_TITLE, resId = R.string.volume))
rowRepresentables.add(GraphRow(report, Stat.NET_RESULT)) rowRepresentables.add(GraphRow(report, Stat.DURATION))
rowRepresentables.add(StatDoubleRow(it.computedStat(Stat.DURATION), it.computedStat(Stat.AVERAGE_DURATION))) rowRepresentables.add(StatDoubleRow(it.computedStat(Stat.DURATION), it.computedStat(Stat.AVERAGE_DURATION)))
rowRepresentables.add(StatDoubleRow(it.computedStat(Stat.DAYS_PLAYED), it.computedStat(Stat.MAXIMUM_DURATION))) rowRepresentables.add(StatDoubleRow(it.computedStat(Stat.DAYS_PLAYED), it.computedStat(Stat.MAXIMUM_DURATION)))
} }

@ -17,7 +17,6 @@ import net.pokeranalytics.android.R
import net.pokeranalytics.android.calculus.* import net.pokeranalytics.android.calculus.*
import net.pokeranalytics.android.ui.activity.components.PokerAnalyticsActivity import net.pokeranalytics.android.ui.activity.components.PokerAnalyticsActivity
import net.pokeranalytics.android.ui.fragment.components.PokerAnalyticsFragment import net.pokeranalytics.android.ui.fragment.components.PokerAnalyticsFragment
import net.pokeranalytics.android.ui.graph.PALineDataSet
import net.pokeranalytics.android.ui.graph.setStyle import net.pokeranalytics.android.ui.graph.setStyle
import net.pokeranalytics.android.ui.view.LegendView import net.pokeranalytics.android.ui.view.LegendView
import kotlin.coroutines.CoroutineContext import kotlin.coroutines.CoroutineContext
@ -46,7 +45,7 @@ class GraphFragment : PokerAnalyticsFragment(), OnChartValueSelectedListener, Co
private lateinit var parentActivity: PokerAnalyticsActivity private lateinit var parentActivity: PokerAnalyticsActivity
private lateinit var selectedReport: Report private lateinit var selectedReport: Report
private lateinit var legendView: LegendView private lateinit var legendView: LegendView
private lateinit var chartView: BarLineChartBase<*> private var chartView: BarLineChartBase<*>? = null
private var stat: Stat = Stat.NET_RESULT private var stat: Stat = Stat.NET_RESULT
private var aggregationType: AggregationType = AggregationType.SESSION private var aggregationType: AggregationType = AggregationType.SESSION
@ -65,33 +64,20 @@ class GraphFragment : PokerAnalyticsFragment(), OnChartValueSelectedListener, Co
loadGraph() loadGraph()
} }
// OnChartValueSelectedListener /**
override fun onNothingSelected() { * Set data
// nothing to do */
} fun setData(report: Report, stat: Stat, aggregationType: AggregationType) {
override fun onValueSelected(e: Entry?, h: Highlight?) {
e?.let { entry ->
val statEntry = when (entry.data) {
is ObjectIdentifier -> {
val identifier = entry.data as ObjectIdentifier
getRealm().where(identifier.clazz).equalTo("id", identifier.id).findAll().firstOrNull()
}
is StatEntry -> entry.data as StatEntry?
else -> null
}
statEntry?.let {
val formattedDate = it.entryTitle this.selectedReport = report
val entryValue = it.formattedValue(this.stat, requireContext()) this.aggregationType = aggregationType
val totalStatValue = this.stat.format(entry.y.toDouble(), currency = null) this.stat = stat
this.legendView.setItemData(this.stat, formattedDate, entryValue, totalStatValue) if (isAdded && !isDetached) {
} loadGraph()
} }
} }
/** /**
* Init UI * Init UI
*/ */
@ -103,14 +89,6 @@ class GraphFragment : PokerAnalyticsFragment(), OnChartValueSelectedListener, Co
this.legendView = LegendView(requireContext()) this.legendView = LegendView(requireContext())
this.legendContainer.addView(this.legendView) this.legendContainer.addView(this.legendView)
this.chartView = when (stat.graphType) {
GraphType.LINE -> LineChart(context)
GraphType.BAR -> BarChart(context)
}
val axisFormatting = aggregationType.axisFormatting
this.chartView.setStyle(false, axisFormatting, requireContext())
this.chartContainer.addView(this.chartView)
} }
/** /**
@ -118,38 +96,41 @@ class GraphFragment : PokerAnalyticsFragment(), OnChartValueSelectedListener, Co
*/ */
private fun loadGraph() { private fun loadGraph() {
val graphEntries = when (aggregationType) { val ds = when (aggregationType) {
AggregationType.SESSION -> selectedReport.results.firstOrNull()?.defaultStatEntries(stat) AggregationType.SESSION -> selectedReport.results.firstOrNull()?.defaultStatEntries(stat, requireContext())
AggregationType.DURATION -> { AggregationType.DURATION -> {
selectedReport.results.firstOrNull()?.durationEntries(stat) selectedReport.results.firstOrNull()?.durationEntries(stat, requireContext())
} }
AggregationType.MONTH, AggregationType.YEAR -> { AggregationType.MONTH, AggregationType.YEAR -> {
when (this.stat) { when (this.stat) {
Stat.NUMBER_OF_GAMES, Stat.NUMBER_OF_SETS -> selectedReport.barEntries(this.stat) Stat.NUMBER_OF_GAMES, Stat.NUMBER_OF_SETS -> selectedReport.barEntries(this.stat)
else -> selectedReport.lineEntries(this.stat) else -> selectedReport.lineEntries(this.stat, requireContext())
} }
} }
} }
graphEntries?.let { entries -> ds?.let { dataSet ->
this.legendView.prepareWithStat(this.stat, entries.size) this.legendView.prepareWithStat(this.stat, dataSet.entryCount)
when (stat.graphType) { // initialize chart
GraphType.LINE -> { if (this.chartView == null) {
val lineChart: LineChart = this.chartView as LineChart this.chartView = when (dataSet) {
is LineDataSet -> LineChart(context)
is BarDataSet -> BarChart(context)
else -> null
}
this.chartContainer.addView(this.chartView)
}
val dataSet = PALineDataSet(entries, this.stat.name, requireContext()) when (dataSet) {
val colors = arrayOf(R.color.green_light).toIntArray() is LineDataSet -> {
dataSet.setColors(colors, context) val lineChart: LineChart = this.chartView as LineChart
dataSet.setDrawCircles(false)
val lineData = LineData(listOf(dataSet)) val lineData = LineData(listOf(dataSet))
lineChart.data = lineData lineChart.data = lineData
} }
GraphType.BAR -> { is BarDataSet -> {
val barChart = this.chartView as BarChart val barChart = this.chartView as BarChart
val dataSet = BarDataSet(entries as List<BarEntry>, this.stat.name)
val colors = arrayOf(R.color.green_light).toIntArray() val colors = arrayOf(R.color.green_light).toIntArray()
dataSet.setColors(colors, context) dataSet.setColors(colors, context)
val barData = BarData(listOf(dataSet)) val barData = BarData(listOf(dataSet))
@ -158,26 +139,48 @@ class GraphFragment : PokerAnalyticsFragment(), OnChartValueSelectedListener, Co
} }
val axisFormatting = aggregationType.axisFormatting val axisFormatting = aggregationType.axisFormatting
this.chartView.setStyle(false, axisFormatting, requireContext())
this.chartView.setOnChartValueSelectedListener(this)
this.chartView.highlightValue((entries.size - 1).toFloat(), 0) this.chartView?.let {
it.setStyle(false, axisFormatting, requireContext())
it.setOnChartValueSelectedListener(this)
}
this.selectValue(dataSet.getEntryForIndex(dataSet.entryCount - 1))
} }
} }
/** // OnChartValueSelectedListener
* Set data override fun onNothingSelected() {
*/ // nothing to do
fun setData(report: Report, stat: Stat, aggregationType: AggregationType) { }
this.selectedReport = report override fun onValueSelected(e: Entry?, h: Highlight?) {
this.aggregationType = aggregationType e?.let { entry ->
this.stat = stat this.selectValue(entry)
}
}
if (isAdded && !isDetached) { private fun selectValue(entry: Entry) {
loadGraph()
val statEntry = when (entry.data) {
is ObjectIdentifier -> {
val identifier = entry.data as ObjectIdentifier
getRealm().where(identifier.clazz).equalTo("id", identifier.id).findAll().firstOrNull()
}
is StatEntry -> entry.data as StatEntry?
else -> null
}
statEntry?.let {
val formattedDate = it.entryTitle
val entryValue = it.formattedValue(this.stat, requireContext())
val totalStatValue = this.stat.format(entry.y.toDouble(), currency = null)
this.legendView.setItemData(this.stat, formattedDate, entryValue, totalStatValue)
} }
} }
} }

@ -18,7 +18,6 @@ import net.pokeranalytics.android.ui.activity.ReportDetailsActivity
import net.pokeranalytics.android.ui.adapter.RowRepresentableAdapter import net.pokeranalytics.android.ui.adapter.RowRepresentableAdapter
import net.pokeranalytics.android.ui.adapter.RowRepresentableDelegate import net.pokeranalytics.android.ui.adapter.RowRepresentableDelegate
import net.pokeranalytics.android.ui.adapter.StaticRowRepresentableDataSource import net.pokeranalytics.android.ui.adapter.StaticRowRepresentableDataSource
import net.pokeranalytics.android.ui.fragment.components.LoaderDialogFragment
import net.pokeranalytics.android.ui.fragment.components.PokerAnalyticsFragment import net.pokeranalytics.android.ui.fragment.components.PokerAnalyticsFragment
import net.pokeranalytics.android.ui.view.RowRepresentable import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.rowrepresentable.ReportRow import net.pokeranalytics.android.ui.view.rowrepresentable.ReportRow

@ -43,8 +43,9 @@ class SessionFragment : PokerAnalyticsFragment(), RowRepresentableDelegate {
private val refreshTimer: Runnable = object : Runnable { private val refreshTimer: Runnable = object : Runnable {
override fun run() { override fun run() {
// Refresh header each 30 seconds // Refresh header each 30 seconds
currentSession.updateRowRepresentation()
sessionAdapter.notifyItemChanged(0) sessionAdapter.notifyItemChanged(0)
handler.postDelayed(this, 30000) handler.postDelayed(this, 60000)
} }
} }
@ -181,7 +182,7 @@ class SessionFragment : PokerAnalyticsFragment(), RowRepresentableDelegate {
floatingActionButton.animate().scaleX(1f).scaleY(1f).alpha(1f) floatingActionButton.animate().scaleX(1f).scaleY(1f).alpha(1f)
.setDuration(animationDuration) .setDuration(animationDuration)
.setInterpolator(OvershootInterpolator()).start() .setInterpolator(OvershootInterpolator()).start()
handler.postDelayed(refreshTimer, 30000) handler.postDelayed(refreshTimer, 60000)
} }
SessionState.PAUSED -> { SessionState.PAUSED -> {
sessionMenu?.findItem(R.id.restart)?.isVisible = true sessionMenu?.findItem(R.id.restart)?.isVisible = true

@ -11,7 +11,6 @@ import io.realm.Realm
import kotlinx.android.synthetic.main.fragment_settings.* import kotlinx.android.synthetic.main.fragment_settings.*
import net.pokeranalytics.android.BuildConfig import net.pokeranalytics.android.BuildConfig
import net.pokeranalytics.android.R import net.pokeranalytics.android.R
import net.pokeranalytics.android.model.realm.Bankroll
import net.pokeranalytics.android.model.realm.Session import net.pokeranalytics.android.model.realm.Session
import net.pokeranalytics.android.ui.activity.CurrenciesActivity import net.pokeranalytics.android.ui.activity.CurrenciesActivity
import net.pokeranalytics.android.ui.activity.DataListActivity import net.pokeranalytics.android.ui.activity.DataListActivity
@ -20,15 +19,15 @@ import net.pokeranalytics.android.ui.activity.components.PokerAnalyticsActivity
import net.pokeranalytics.android.ui.adapter.RowRepresentableAdapter import net.pokeranalytics.android.ui.adapter.RowRepresentableAdapter
import net.pokeranalytics.android.ui.adapter.RowRepresentableDelegate import net.pokeranalytics.android.ui.adapter.RowRepresentableDelegate
import net.pokeranalytics.android.ui.adapter.StaticRowRepresentableDataSource import net.pokeranalytics.android.ui.adapter.StaticRowRepresentableDataSource
import net.pokeranalytics.android.ui.extensions.openContactMail
import net.pokeranalytics.android.ui.extensions.openPlayStorePage
import net.pokeranalytics.android.ui.extensions.openUrl
import net.pokeranalytics.android.ui.fragment.components.PokerAnalyticsFragment import net.pokeranalytics.android.ui.fragment.components.PokerAnalyticsFragment
import net.pokeranalytics.android.ui.view.RowRepresentable import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.rowrepresentable.SettingRow import net.pokeranalytics.android.ui.view.rowrepresentable.SettingRow
import net.pokeranalytics.android.util.Preferences import net.pokeranalytics.android.util.Preferences
import net.pokeranalytics.android.util.URL import net.pokeranalytics.android.util.URL
import net.pokeranalytics.android.util.UserDefaults import net.pokeranalytics.android.util.UserDefaults
import net.pokeranalytics.android.ui.extensions.openContactMail
import net.pokeranalytics.android.ui.extensions.openPlayStorePage
import net.pokeranalytics.android.ui.extensions.openUrl
import java.util.* import java.util.*
@ -98,11 +97,10 @@ class SettingsFragment : PokerAnalyticsFragment(), RowRepresentableDelegate, Sta
} }
override fun onRowSelected(position: Int, row: RowRepresentable, fromAction: Boolean) { override fun onRowSelected(position: Int, row: RowRepresentable, fromAction: Boolean) {
when (row) { when (row) {
SettingRow.RATE_APP -> parentActivity.openPlayStorePage() SettingRow.RATE_APP -> parentActivity.openPlayStorePage()
SettingRow.CONTACT_US -> parentActivity.openContactMail(R.string.contact) SettingRow.CONTACT_US -> parentActivity.openContactMail(R.string.contact)
SettingRow.BUG_REPORT -> parentActivity.openContactMail(R.string.bug_report_subject) SettingRow.BUG_REPORT -> parentActivity.openContactMail(R.string.bug_report_subject, Realm.getDefaultInstance().path)
SettingRow.CURRENCY -> CurrenciesActivity.newInstanceForResult(this@SettingsFragment, REQUEST_CODE_CURRENCY) SettingRow.CURRENCY -> CurrenciesActivity.newInstanceForResult(this@SettingsFragment, REQUEST_CODE_CURRENCY)
SettingRow.FOLLOW_US -> { SettingRow.FOLLOW_US -> {
when (position) { when (position) {

@ -10,10 +10,17 @@ class PALineDataSet(yVals: List<Entry>, label: String, context: Context) : LineD
init { init {
this.highLightColor = context.getColor(R.color.chart_highlight_indicator) this.highLightColor = context.getColor(R.color.chart_highlight_indicator)
this.setDrawValues(false) this.setDrawValues(false)
this.setDrawCircles(false)
val colors = arrayOf(R.color.green_light).toIntArray()
this.setColors(colors, context)
} }
} }
//class PABarDataSet(yVals: List<BarEntry>, label: String, context: Context) : BarDataSet(yVals, label) { //class PABarDataSet(yVals: List<BarEntry>, label: String, context: Context) : BarDataSet(yVals, label) {
// //
// init { // init {

@ -13,17 +13,18 @@ import androidx.core.widget.ContentLoadingProgressBar
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import com.github.mikephil.charting.charts.BarChart import com.github.mikephil.charting.charts.BarChart
import com.github.mikephil.charting.charts.LineChart import com.github.mikephil.charting.charts.LineChart
import com.github.mikephil.charting.data.BarData
import com.github.mikephil.charting.data.BarDataSet
import com.github.mikephil.charting.data.LineData import com.github.mikephil.charting.data.LineData
import com.github.mikephil.charting.data.LineDataSet
import kotlinx.android.synthetic.main.row_history_session.view.* import kotlinx.android.synthetic.main.row_history_session.view.*
import kotlinx.android.synthetic.main.row_transaction.view.* import kotlinx.android.synthetic.main.row_transaction.view.*
import net.pokeranalytics.android.R import net.pokeranalytics.android.R
import net.pokeranalytics.android.calculus.GraphType
import net.pokeranalytics.android.model.realm.Session import net.pokeranalytics.android.model.realm.Session
import net.pokeranalytics.android.model.realm.Transaction import net.pokeranalytics.android.model.realm.Transaction
import net.pokeranalytics.android.ui.adapter.RowRepresentableAdapter import net.pokeranalytics.android.ui.adapter.RowRepresentableAdapter
import net.pokeranalytics.android.ui.extensions.setTextFormat import net.pokeranalytics.android.ui.extensions.setTextFormat
import net.pokeranalytics.android.ui.graph.AxisFormatting import net.pokeranalytics.android.ui.graph.AxisFormatting
import net.pokeranalytics.android.ui.graph.PALineDataSet
import net.pokeranalytics.android.ui.graph.setStyle import net.pokeranalytics.android.ui.graph.setStyle
import net.pokeranalytics.android.ui.view.rowrepresentable.CustomizableRowRepresentable import net.pokeranalytics.android.ui.view.rowrepresentable.CustomizableRowRepresentable
import net.pokeranalytics.android.ui.view.rowrepresentable.GraphRow import net.pokeranalytics.android.ui.view.rowrepresentable.GraphRow
@ -149,9 +150,7 @@ enum class RowViewType(private var layoutRes: Int) {
val listener = View.OnClickListener { val listener = View.OnClickListener {
adapter.delegate?.onRowSelected(position, row) adapter.delegate?.onRowSelected(position, row)
} }
itemView.findViewById<View?>(R.id.container)?.let { itemView.findViewById<View?>(R.id.container)?.setOnClickListener(listener)
it.setOnClickListener(listener)
}
} }
} }
@ -189,9 +188,7 @@ enum class RowViewType(private var layoutRes: Int) {
} }
} }
itemView.findViewById<View?>(R.id.container)?.let { itemView.findViewById<View?>(R.id.container)?.setOnClickListener(listener)
it.setOnClickListener(listener)
}
} }
// Switch // Switch
@ -318,31 +315,24 @@ enum class RowViewType(private var layoutRes: Int) {
BindableHolder { BindableHolder {
override fun bind(position: Int, row: RowRepresentable, adapter: RowRepresentableAdapter) { override fun bind(position: Int, row: RowRepresentable, adapter: RowRepresentableAdapter) {
//TODO: Implementation
if (row is GraphRow) { if (row is GraphRow) {
row.report.results.firstOrNull()?.defaultStatEntries(row.stat)?.let { entries -> row.report.results.firstOrNull()?.defaultStatEntries(row.stat, itemView.context)?.let { dataSet ->
val context = itemView.context val context = itemView.context
val dataSet = PALineDataSet(entries, row.stat.name, context) val chartView = when (dataSet) {
val colors = arrayOf(R.color.green_light).toIntArray() is LineDataSet -> {
dataSet.setColors(colors, context)
dataSet.setDrawCircles(false)
dataSet.setDrawValues(false)
val lineData = LineData(listOf(dataSet))
val chartView = when (row.stat.graphType) {
GraphType.LINE -> {
val lineChart = LineChart(context) val lineChart = LineChart(context)
lineChart.data = lineData lineChart.data = LineData(dataSet)
lineChart lineChart
} }
GraphType.BAR -> { is BarDataSet -> {
val barChart = BarChart(context) val barChart = BarChart(context)
barChart.data = BarData(dataSet)
barChart barChart
} }
else -> null
} }
itemView.findViewById<FrameLayout?>(R.id.chartContainer)?.let { itemView.findViewById<FrameLayout?>(R.id.chartContainer)?.let {
@ -350,9 +340,12 @@ enum class RowViewType(private var layoutRes: Int) {
it.addView(chartView) it.addView(chartView)
} }
chartView.setStyle(true, AxisFormatting.DEFAULT, context) chartView?.let {
chartView.setTouchEnabled(false) chartView.setStyle(true, AxisFormatting.DEFAULT, context)
chartView.highlightValue((entries.size - 1).toFloat(), 0) chartView.setTouchEnabled(false)
}
// chartView.highlightValue((entries.size - 1).toFloat(), 0)
} }
} }

@ -77,7 +77,7 @@ class FakeDataManager {
session.result?.let { result -> session.result?.let { result ->
val buyin = buyinList.random() val buyin = buyinList.random()
result.buyin = buyinList.random() result.buyin = buyinList.random()
result.netResult = resultsList.random() + buyin result.cashout = resultsList.random() + buyin
} }
} }

@ -1,18 +1,11 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="wrap_content" xmlns:tools="http://schemas.android.com/tools"
android:layout_height="wrap_content" android:layout_width="256dp"
android:layout_gravity="center"> android:layout_height="128dp"
android:layout_gravity="center"
<View android:background="@color/colorPrimary">
android:layout_width="128dp"
android:layout_height="128dp"
android:background="@color/colorPrimary"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<androidx.core.widget.ContentLoadingProgressBar <androidx.core.widget.ContentLoadingProgressBar
android:id="@+id/progressBar" android:id="@+id/progressBar"
@ -20,12 +13,30 @@
android:layout_width="32dp" android:layout_width="32dp"
android:layout_height="32dp" android:layout_height="32dp"
android:layout_marginStart="8dp" android:layout_marginStart="8dp"
android:layout_marginTop="8dp" android:layout_marginEnd="8dp"
app:layout_constraintBottom_toTopOf="@+id/loadingMessage"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_chainStyle="packed" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/loadingMessage"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="16dp"
android:layout_marginEnd="8dp" android:layout_marginEnd="8dp"
android:layout_marginBottom="8dp" android:layout_marginBottom="8dp"
android:fontFamily="@font/roboto"
android:textSize="16sp"
android:text="@string/calculating_please_wait_"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" /> app:layout_constraintTop_toBottomOf="@+id/progressBar"
app:layout_constraintVertical_chainStyle="packed" />
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<files-path
name="files"
path="." />
</paths>
Loading…
Cancel
Save