parent
baf755c4c8
commit
925ab12faf
@ -0,0 +1,217 @@ |
|||||||
|
package net.pokeranalytics.android.calculus |
||||||
|
|
||||||
|
import android.content.Context |
||||||
|
import android.os.CountDownTimer |
||||||
|
import io.realm.Realm |
||||||
|
import io.realm.RealmResults |
||||||
|
import kotlinx.coroutines.GlobalScope |
||||||
|
import kotlinx.coroutines.launch |
||||||
|
import net.pokeranalytics.android.model.realm.CustomField |
||||||
|
import net.pokeranalytics.android.model.realm.Performance |
||||||
|
import net.pokeranalytics.android.model.realm.Result |
||||||
|
import net.pokeranalytics.android.model.realm.Session |
||||||
|
import net.pokeranalytics.android.ui.view.rows.StaticReport |
||||||
|
import timber.log.Timber |
||||||
|
|
||||||
|
interface NewPerformanceListener { |
||||||
|
fun newBestPerformanceHandler() |
||||||
|
} |
||||||
|
|
||||||
|
class ReportWhistleBlower(var context: Context) { |
||||||
|
|
||||||
|
var sessions: RealmResults<Session>? = null |
||||||
|
var results: RealmResults<Result>? = null |
||||||
|
|
||||||
|
var timer: CountDownTimer? = null |
||||||
|
|
||||||
|
// private lateinit var realm: Realm |
||||||
|
|
||||||
|
private val currentNotifications: MutableList<String> = mutableListOf() |
||||||
|
|
||||||
|
private val listeners: MutableList<NewPerformanceListener> = mutableListOf() |
||||||
|
|
||||||
|
// companion object { |
||||||
|
// |
||||||
|
// @Volatile private var INSTANCE: ReportWhistleBlower? = null |
||||||
|
// |
||||||
|
// fun getInstance(context: Context, realm: Realm): ReportWhistleBlower = |
||||||
|
// INSTANCE ?: synchronized(this) { |
||||||
|
// INSTANCE ?: newInstance(context, realm).also { INSTANCE = it } |
||||||
|
// } |
||||||
|
// |
||||||
|
// private fun newInstance(context: Context, realm: Realm): ReportWhistleBlower { |
||||||
|
// return ReportWhistleBlower(context, realm) |
||||||
|
// } |
||||||
|
// |
||||||
|
// } |
||||||
|
|
||||||
|
init { |
||||||
|
|
||||||
|
val realm = Realm.getDefaultInstance() |
||||||
|
|
||||||
|
this.sessions = realm.where(Session::class.java).findAll() |
||||||
|
this.sessions?.addChangeListener { _ -> |
||||||
|
launchReports() |
||||||
|
} |
||||||
|
|
||||||
|
this.results = realm.where(Result::class.java).findAll() |
||||||
|
this.results?.addChangeListener { _ -> |
||||||
|
launchReports() |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
fun addListener(newPerformanceListener: NewPerformanceListener) { |
||||||
|
this.listeners.add(newPerformanceListener) |
||||||
|
} |
||||||
|
|
||||||
|
private fun requestReportLaunch() { |
||||||
|
|
||||||
|
synchronized(this) { |
||||||
|
this.timer?.cancel() |
||||||
|
|
||||||
|
this.timer = object : CountDownTimer(500L, 0L) { |
||||||
|
override fun onTick(p0: Long) { } |
||||||
|
override fun onFinish() { |
||||||
|
launchReports() |
||||||
|
timer = null |
||||||
|
} |
||||||
|
} |
||||||
|
this.timer?.start() |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
private fun launchReports() { |
||||||
|
|
||||||
|
// Basic |
||||||
|
for (basicReport in StaticReport.basicReports) { |
||||||
|
launchReport(basicReport) |
||||||
|
} |
||||||
|
|
||||||
|
val realm = Realm.getDefaultInstance() |
||||||
|
|
||||||
|
// CustomField |
||||||
|
val customFields = realm.where(CustomField::class.java) |
||||||
|
.equalTo("type", CustomField.Type.LIST.uniqueIdentifier).findAll() |
||||||
|
for (customField in customFields) { |
||||||
|
launchReport(StaticReport.CustomFieldList(customField)) |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
private fun launchReport(report: StaticReport) { |
||||||
|
|
||||||
|
Timber.d(">>> launch report = $report") |
||||||
|
|
||||||
|
val options = Calculator.Options( |
||||||
|
stats = report.stats, |
||||||
|
criterias = report.criteria |
||||||
|
) |
||||||
|
|
||||||
|
this.launchReportWithOptions(report, options) |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
private fun launchReportWithOptions(staticReport: StaticReport, options: Calculator.Options) { |
||||||
|
|
||||||
|
GlobalScope.launch { |
||||||
|
|
||||||
|
val realm = Realm.getDefaultInstance() |
||||||
|
// realm.refresh() |
||||||
|
|
||||||
|
val result = Calculator.computeStats(realm, options = options) |
||||||
|
analyseReport(realm, staticReport, result) |
||||||
|
|
||||||
|
realm.close() |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private fun analyseReport(realm: Realm, staticReport: StaticReport, result: Report) { |
||||||
|
|
||||||
|
when (staticReport.uniqueIdentifier) { |
||||||
|
StaticReport.OptimalDuration.uniqueIdentifier -> analyseOptimalDuration(staticReport, result) |
||||||
|
else -> analyseDefaultReport(realm, staticReport, result) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private fun analyseDefaultReport(realm: Realm, staticReport: StaticReport, result: Report) { |
||||||
|
|
||||||
|
for (stat in result.options.stats) { |
||||||
|
|
||||||
|
Timber.d("analyse stat: $stat for report: $staticReport") |
||||||
|
|
||||||
|
result.max(stat)?.let { computedResults -> |
||||||
|
|
||||||
|
val customField: CustomField? = |
||||||
|
(staticReport as? StaticReport.CustomFieldList)?.customField |
||||||
|
var query = realm.where(Performance::class.java) |
||||||
|
.equalTo("statId", stat.uniqueIdentifier) |
||||||
|
.equalTo("reportId", staticReport.uniqueIdentifier) |
||||||
|
|
||||||
|
customField?.let { |
||||||
|
query = query.equalTo("customFieldId", it.id) |
||||||
|
} |
||||||
|
val currentPerf = query.findFirst() |
||||||
|
|
||||||
|
var storePerf = true |
||||||
|
currentPerf?.let { |
||||||
|
Timber.d("cr name = ${computedResults.group.query.getName(this.context)}") |
||||||
|
currentPerf.name?.let { |
||||||
|
if (computedResults.group.query.defaultName == it) { |
||||||
|
storePerf = false |
||||||
|
} |
||||||
|
} |
||||||
|
Timber.d("cr objectId = ${computedResults.group.query.objectId}") |
||||||
|
currentPerf.objectId?.let { |
||||||
|
if (computedResults.group.query.objectId == it) { |
||||||
|
storePerf = false |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
if (storePerf) { |
||||||
|
realm.executeTransaction { |
||||||
|
currentPerf.name = computedResults.group.query.getName(this.context) |
||||||
|
currentPerf.objectId = computedResults.group.query.objectId |
||||||
|
currentPerf.customFieldId = customField?.id |
||||||
|
} |
||||||
|
this.notify(currentPerf) |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
if (currentPerf == null && storePerf) { |
||||||
|
val performance = Performance( |
||||||
|
staticReport, |
||||||
|
stat, |
||||||
|
computedResults.group.query.getName(this.context), |
||||||
|
computedResults.group.query.objectId, |
||||||
|
customField?.id, |
||||||
|
null |
||||||
|
) |
||||||
|
realm.executeTransaction { it.copyToRealm(performance) } |
||||||
|
this.notify(performance) |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
private fun analyseOptimalDuration(staticReport: StaticReport, result: Report) { |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
private fun notify(performance: Performance) { |
||||||
|
|
||||||
|
this.currentNotifications.add(performance.id) |
||||||
|
for (listener in this.listeners) { |
||||||
|
listener.newBestPerformanceHandler() |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
fun has(performanceId: String): Boolean { |
||||||
|
return this.currentNotifications.contains(performanceId) |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
@ -1,4 +1,4 @@ |
|||||||
package net.pokeranalytics.android.calcul |
package net.pokeranalytics.android.calculus.calcul |
||||||
|
|
||||||
import net.pokeranalytics.android.calculus.AggregationType |
import net.pokeranalytics.android.calculus.AggregationType |
||||||
import net.pokeranalytics.android.ui.graph.Graph |
import net.pokeranalytics.android.ui.graph.Graph |
||||||
@ -1,4 +1,4 @@ |
|||||||
package net.pokeranalytics.android.calcul |
package net.pokeranalytics.android.calculus.calcul |
||||||
|
|
||||||
import android.content.Context |
import android.content.Context |
||||||
import com.github.mikephil.charting.data.* |
import com.github.mikephil.charting.data.* |
||||||
@ -1,4 +1,4 @@ |
|||||||
package net.pokeranalytics.android.calcul |
package net.pokeranalytics.android.calculus.calcul |
||||||
|
|
||||||
import net.pokeranalytics.android.R |
import net.pokeranalytics.android.R |
||||||
import net.pokeranalytics.android.calculus.Calculator |
import net.pokeranalytics.android.calculus.Calculator |
||||||
@ -1,4 +1,4 @@ |
|||||||
package net.pokeranalytics.android.calcul |
package net.pokeranalytics.android.calculus.calcul |
||||||
|
|
||||||
import android.content.Context |
import android.content.Context |
||||||
import com.github.mikephil.charting.data.BarDataSet |
import com.github.mikephil.charting.data.BarDataSet |
||||||
@ -1,4 +1,4 @@ |
|||||||
package net.pokeranalytics.android.calcul |
package net.pokeranalytics.android.calculus.calcul |
||||||
|
|
||||||
import android.content.Context |
import android.content.Context |
||||||
import net.pokeranalytics.android.R |
import net.pokeranalytics.android.R |
||||||
@ -0,0 +1,67 @@ |
|||||||
|
package net.pokeranalytics.android.model.realm |
||||||
|
|
||||||
|
import io.realm.Realm |
||||||
|
import io.realm.RealmObject |
||||||
|
import net.pokeranalytics.android.calculus.Stat |
||||||
|
import net.pokeranalytics.android.ui.fragment.PerformanceKey |
||||||
|
import net.pokeranalytics.android.ui.view.RowRepresentable |
||||||
|
import net.pokeranalytics.android.ui.view.rows.StaticReport |
||||||
|
import net.pokeranalytics.android.util.NULL_TEXT |
||||||
|
import net.pokeranalytics.android.util.extensions.lookupForNameInAllTablesById |
||||||
|
import java.util.* |
||||||
|
|
||||||
|
open class Performance() : RealmObject(), RowRepresentable { |
||||||
|
|
||||||
|
var id: String = UUID.randomUUID().toString() |
||||||
|
|
||||||
|
constructor( |
||||||
|
report: StaticReport, |
||||||
|
stat: Stat, |
||||||
|
name: String? = null, |
||||||
|
objectId: String? = null, |
||||||
|
customFieldId: String? = null, |
||||||
|
value: Double? = null |
||||||
|
) : this() { |
||||||
|
|
||||||
|
this.reportId = report.uniqueIdentifier |
||||||
|
this.statId = stat.uniqueIdentifier |
||||||
|
this.name = name |
||||||
|
this.objectId = objectId |
||||||
|
this.customFieldId = customFieldId |
||||||
|
this.value = value |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
var reportId: Int = 0 |
||||||
|
var statId: Int = 0 |
||||||
|
var name: String? = null |
||||||
|
var objectId: String? = null |
||||||
|
var customFieldId: String? = null |
||||||
|
var value: Double? = null |
||||||
|
|
||||||
|
fun toStaticReport(realm: Realm): StaticReport { |
||||||
|
return StaticReport.newInstance(realm, this.reportId, this.customFieldId) |
||||||
|
} |
||||||
|
|
||||||
|
fun displayValue(realm: Realm): CharSequence { |
||||||
|
this.name?.let { return it } |
||||||
|
this.objectId?.let { realm.lookupForNameInAllTablesById(it) } |
||||||
|
return NULL_TEXT |
||||||
|
} |
||||||
|
|
||||||
|
val performanceKey: PerformanceKey |
||||||
|
get() { |
||||||
|
return Stat.valueByIdentifier(this.statId) |
||||||
|
} |
||||||
|
|
||||||
|
val stat: Stat |
||||||
|
get() { |
||||||
|
return Stat.valueByIdentifier(this.statId) |
||||||
|
} |
||||||
|
|
||||||
|
override val resId: Int? |
||||||
|
get() { |
||||||
|
return this.performanceKey.resId |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
@ -1,63 +0,0 @@ |
|||||||
package net.pokeranalytics.android.ui.view.rows |
|
||||||
|
|
||||||
import net.pokeranalytics.android.R |
|
||||||
import net.pokeranalytics.android.model.Criteria |
|
||||||
import net.pokeranalytics.android.ui.view.RowRepresentable |
|
||||||
import net.pokeranalytics.android.ui.view.RowViewType |
|
||||||
|
|
||||||
/** |
|
||||||
* An enum managing the report rows |
|
||||||
*/ |
|
||||||
enum class ReportRow : RowRepresentable { |
|
||||||
BLINDS, |
|
||||||
BUY_IN, |
|
||||||
DAY_OF_WEEKS, |
|
||||||
GENERAL, |
|
||||||
LOCATIONS, |
|
||||||
//NUMBER_OF_TABLES, |
|
||||||
TOURNAMENT_TYPES, |
|
||||||
GAME; |
|
||||||
|
|
||||||
companion object { |
|
||||||
/** |
|
||||||
* Return the report rows |
|
||||||
*/ |
|
||||||
fun getRows(): ArrayList<RowRepresentable> { |
|
||||||
val rows = ArrayList<RowRepresentable>() |
|
||||||
rows.add(CustomizableRowRepresentable(customViewType = RowViewType.HEADER_TITLE, resId = R.string.comparison)) |
|
||||||
rows.addAll(values()) |
|
||||||
return rows |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
override val resId: Int? |
|
||||||
get() { |
|
||||||
return when (this) { |
|
||||||
BLINDS -> R.string.blinds |
|
||||||
BUY_IN -> R.string.buyin |
|
||||||
DAY_OF_WEEKS -> R.string.day_of_the_week |
|
||||||
GENERAL -> R.string.general |
|
||||||
LOCATIONS -> R.string.locations |
|
||||||
//NUMBER_OF_TABLES -> R.string.number_of_tables |
|
||||||
TOURNAMENT_TYPES -> R.string.tournament_type_complete |
|
||||||
GAME -> R.string.game |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
override val viewType: Int = RowViewType.TITLE_ARROW.ordinal |
|
||||||
|
|
||||||
val criteria: List<Criteria> |
|
||||||
get() { |
|
||||||
return when (this) { |
|
||||||
BLINDS -> listOf(Criteria.Stakes) |
|
||||||
BUY_IN -> listOf(Criteria.TournamentFees) |
|
||||||
DAY_OF_WEEKS -> listOf(Criteria.DaysOfWeek) |
|
||||||
GENERAL -> listOf(Criteria.SessionTypes, Criteria.BankrollTypes) |
|
||||||
LOCATIONS -> listOf(Criteria.Locations) |
|
||||||
//NUMBER_OF_TABLES -> listOf() //TODO |
|
||||||
TOURNAMENT_TYPES -> listOf(Criteria.TournamentTypes) |
|
||||||
GAME -> listOf(Criteria.Games) |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
||||||
@ -0,0 +1,117 @@ |
|||||||
|
package net.pokeranalytics.android.ui.view.rows |
||||||
|
|
||||||
|
import android.content.Context |
||||||
|
import io.realm.Realm |
||||||
|
import net.pokeranalytics.android.R |
||||||
|
import net.pokeranalytics.android.calculus.Stat |
||||||
|
import net.pokeranalytics.android.exceptions.PAIllegalStateException |
||||||
|
import net.pokeranalytics.android.model.Criteria |
||||||
|
import net.pokeranalytics.android.model.realm.CustomField |
||||||
|
import net.pokeranalytics.android.ui.view.RowRepresentable |
||||||
|
import net.pokeranalytics.android.ui.view.RowViewType |
||||||
|
import net.pokeranalytics.android.util.NULL_TEXT |
||||||
|
import net.pokeranalytics.android.util.enumerations.IntIdentifiable |
||||||
|
|
||||||
|
/** |
||||||
|
* The list of possible static reports |
||||||
|
*/ |
||||||
|
sealed class StaticReport(override var uniqueIdentifier: Int) : RowRepresentable, IntIdentifiable { |
||||||
|
object General : StaticReport(1) |
||||||
|
object Blinds : StaticReport(2) |
||||||
|
object TournamentBuyin : StaticReport(3) |
||||||
|
object DayOfWeek : StaticReport(4) |
||||||
|
object Location : StaticReport(5) |
||||||
|
object TournamentType : StaticReport(6) |
||||||
|
object Game : StaticReport(7) |
||||||
|
object TableSize : StaticReport(8) |
||||||
|
object Duration : StaticReport(9) |
||||||
|
object OptimalDuration : StaticReport(10) |
||||||
|
|
||||||
|
data class CustomFieldList(var customField: CustomField) : StaticReport(11) |
||||||
|
|
||||||
|
companion object { |
||||||
|
|
||||||
|
fun newInstance(realm: Realm, reportIdentifier: Int, customFieldId: String?): StaticReport { |
||||||
|
|
||||||
|
return when (reportIdentifier) { |
||||||
|
1 -> General |
||||||
|
2 -> Blinds |
||||||
|
3 -> TournamentBuyin |
||||||
|
4 -> DayOfWeek |
||||||
|
5 -> Location |
||||||
|
6 -> TournamentType |
||||||
|
7 -> Game |
||||||
|
8 -> TableSize |
||||||
|
9 -> Duration |
||||||
|
10 -> OptimalDuration |
||||||
|
11 -> { |
||||||
|
customFieldId?.let { id -> |
||||||
|
realm.where(CustomField::class.java).equalTo("id", customFieldId).findFirst()?.let { customField -> |
||||||
|
CustomFieldList(customField) |
||||||
|
} ?: run { throw PAIllegalStateException("Custom field not found: $id") } |
||||||
|
} ?: run { throw PAIllegalStateException("Missing custom field id") } |
||||||
|
} |
||||||
|
else -> throw PAIllegalStateException("Can't create StaticReport. id = $reportIdentifier, cfid = $customFieldId") |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
val basicReports: Set<StaticReport> = setOf(Blinds) // setOf(General, Blinds, TournamentBuyin, |
||||||
|
// DayOfWeek, Location, TournamentType, Game, TableSize, Duration, OptimalDuration) |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
override fun getDisplayName(context: Context): String { |
||||||
|
return when (this) { |
||||||
|
is CustomFieldList -> this.customField.getDisplayName(context) |
||||||
|
else -> this.resId?.let { context.getString(it) } ?: NULL_TEXT |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
override val resId: Int? |
||||||
|
get() { |
||||||
|
return when (this) { |
||||||
|
Blinds -> R.string.blinds |
||||||
|
TournamentBuyin -> R.string.buyin |
||||||
|
DayOfWeek -> R.string.day_of_the_week |
||||||
|
General -> R.string.general |
||||||
|
Location -> R.string.locations |
||||||
|
//NUMBER_OF_TABLES -> R.string.number_of_tables |
||||||
|
TournamentType -> R.string.tournament_type_complete |
||||||
|
Game -> R.string.game |
||||||
|
TableSize -> R.string.table_size |
||||||
|
Duration -> R.string.duration |
||||||
|
OptimalDuration -> R.string.optimal_duration |
||||||
|
is CustomFieldList -> null |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
override val viewType: Int = RowViewType.TITLE_ARROW.ordinal |
||||||
|
|
||||||
|
val criteria: List<Criteria> |
||||||
|
get() { |
||||||
|
return when (this) { |
||||||
|
Blinds -> listOf(Criteria.Stakes) |
||||||
|
TournamentBuyin -> listOf(Criteria.TournamentFees) |
||||||
|
DayOfWeek -> listOf(Criteria.DaysOfWeek) |
||||||
|
General -> listOf(Criteria.SessionTypes, Criteria.BankrollTypes) |
||||||
|
Location -> listOf(Criteria.Locations) |
||||||
|
//NUMBER_OF_TABLES -> listOf() //TODO |
||||||
|
TournamentType -> listOf(Criteria.TournamentTypes) |
||||||
|
Game -> listOf(Criteria.Games) |
||||||
|
TableSize -> listOf(Criteria.TableSizes) |
||||||
|
Duration -> listOf(Criteria.Duration) |
||||||
|
OptimalDuration -> listOf() |
||||||
|
is CustomFieldList -> listOf(Criteria.ListCustomFields(this.customField.id)) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
val stats: List<Stat> |
||||||
|
get() { |
||||||
|
return when (this) { |
||||||
|
OptimalDuration -> listOf(Stat.AVERAGE_NET_BB) |
||||||
|
else -> listOf(Stat.NET_RESULT, Stat.HOURLY_RATE) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
@ -0,0 +1,11 @@ |
|||||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android" |
||||||
|
android:shape="oval"> |
||||||
|
|
||||||
|
<solid android:color="@color/red" /> |
||||||
|
|
||||||
|
<size |
||||||
|
android:width="12dp" |
||||||
|
android:height="12dp" /> |
||||||
|
|
||||||
|
</shape> |
||||||
@ -0,0 +1,70 @@ |
|||||||
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" |
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto" |
||||||
|
xmlns:tools="http://schemas.android.com/tools" |
||||||
|
android:id="@+id/container" |
||||||
|
android:layout_width="match_parent" |
||||||
|
android:layout_height="48dp" |
||||||
|
android:background="?selectableItemBackground"> |
||||||
|
|
||||||
|
<androidx.appcompat.widget.AppCompatTextView |
||||||
|
android:id="@+id/title" |
||||||
|
style="@style/PokerAnalyticsTheme.TextView.RowTitle" |
||||||
|
android:layout_width="wrap_content" |
||||||
|
android:layout_height="wrap_content" |
||||||
|
android:layout_marginTop="16dp" |
||||||
|
android:layout_marginBottom="16dp" |
||||||
|
app:layout_constraintBottom_toBottomOf="parent" |
||||||
|
app:layout_constraintStart_toStartOf="@+id/guidelineStart" |
||||||
|
app:layout_constraintTop_toTopOf="parent" |
||||||
|
tools:text="Title" /> |
||||||
|
|
||||||
|
<androidx.appcompat.widget.AppCompatImageView |
||||||
|
android:id="@+id/badge" |
||||||
|
android:visibility="invisible" |
||||||
|
android:layout_width="8dp" |
||||||
|
android:layout_height="8dp" |
||||||
|
android:src="@drawable/circle_red" |
||||||
|
android:layout_marginEnd="8dp" |
||||||
|
app:layout_constraintBottom_toBottomOf="parent" |
||||||
|
app:layout_constraintEnd_toStartOf="@+id/value" |
||||||
|
app:layout_constraintTop_toTopOf="parent" /> |
||||||
|
|
||||||
|
<androidx.appcompat.widget.AppCompatTextView |
||||||
|
android:id="@+id/value" |
||||||
|
style="@style/PokerAnalyticsTheme.TextView.RowValue" |
||||||
|
android:layout_width="0dp" |
||||||
|
android:layout_height="wrap_content" |
||||||
|
android:layout_marginStart="16dp" |
||||||
|
android:ellipsize="end" |
||||||
|
android:gravity="end" |
||||||
|
android:maxLines="1" |
||||||
|
app:layout_constraintBottom_toBottomOf="parent" |
||||||
|
app:layout_constraintEnd_toStartOf="@+id/nextArrow" |
||||||
|
app:layout_constraintTop_toTopOf="parent" |
||||||
|
tools:text="Value" /> |
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.Guideline |
||||||
|
android:id="@+id/guidelineStart" |
||||||
|
android:layout_width="wrap_content" |
||||||
|
android:layout_height="wrap_content" |
||||||
|
android:orientation="vertical" |
||||||
|
app:layout_constraintGuide_begin="16dp" /> |
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.Guideline |
||||||
|
android:id="@+id/guidelineEnd" |
||||||
|
android:layout_width="wrap_content" |
||||||
|
android:layout_height="wrap_content" |
||||||
|
android:orientation="vertical" |
||||||
|
app:layout_constraintGuide_end="8dp" /> |
||||||
|
|
||||||
|
<androidx.appcompat.widget.AppCompatImageView |
||||||
|
android:id="@+id/nextArrow" |
||||||
|
android:layout_width="24dp" |
||||||
|
android:layout_height="24dp" |
||||||
|
android:src="@drawable/ic_arrow_right" |
||||||
|
android:tint="@color/grey_light" |
||||||
|
app:layout_constraintBottom_toBottomOf="parent" |
||||||
|
app:layout_constraintEnd_toEndOf="@+id/guidelineEnd" |
||||||
|
app:layout_constraintTop_toTopOf="parent" /> |
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout> |
||||||
Loading…
Reference in new issue