diff --git a/app/src/main/java/net/pokeranalytics/android/model/realm/Bankroll.kt b/app/src/main/java/net/pokeranalytics/android/model/realm/Bankroll.kt index 3a5910ef..072be84a 100644 --- a/app/src/main/java/net/pokeranalytics/android/model/realm/Bankroll.kt +++ b/app/src/main/java/net/pokeranalytics/android/model/realm/Bankroll.kt @@ -16,9 +16,15 @@ import net.pokeranalytics.android.model.interfaces.SaveValidityStatus import net.pokeranalytics.android.ui.view.RowRepresentable import net.pokeranalytics.android.ui.view.rowrepresentable.BankrollRow import net.pokeranalytics.android.ui.view.rowrepresentable.SimpleRow +import net.pokeranalytics.android.util.Preferences import net.pokeranalytics.android.util.UserDefaults import java.util.* +enum class ResultCaptureType { + BUYIN_CASHEDOUT, + NET_RESULT +} + open class Bankroll : RealmObject(), NameManageable, RowRepresentable { @PrimaryKey @@ -100,6 +106,15 @@ open class Bankroll : RealmObject(), NameManageable, RowRepresentable { } } + fun resultCaptureType(context: Context): ResultCaptureType { + return Preferences.getResultCaptureType(this, context) ?: run { + when (this.live) { + true -> ResultCaptureType.BUYIN_CASHEDOUT + else -> ResultCaptureType.NET_RESULT + } + } + } + companion object { fun getOrCreate(realm: Realm, name: String, live: Boolean = true, currencyCode: String? = null, currencyRate: Double? = null) : Bankroll { diff --git a/app/src/main/java/net/pokeranalytics/android/model/realm/Session.kt b/app/src/main/java/net/pokeranalytics/android/model/realm/Session.kt index 4050473c..1c24eaa7 100644 --- a/app/src/main/java/net/pokeranalytics/android/model/realm/Session.kt +++ b/app/src/main/java/net/pokeranalytics/android/model/realm/Session.kt @@ -13,7 +13,6 @@ import io.realm.annotations.LinkingObjects import io.realm.annotations.PrimaryKey import io.realm.kotlin.where import net.pokeranalytics.android.R -import net.pokeranalytics.android.calculus.ComputedStat import net.pokeranalytics.android.calculus.Stat import net.pokeranalytics.android.calculus.StatFormattingException import net.pokeranalytics.android.exceptions.ModelException @@ -30,12 +29,9 @@ import net.pokeranalytics.android.model.filter.QueryCondition.* import net.pokeranalytics.android.model.interfaces.* import net.pokeranalytics.android.model.realm.handhistory.HandHistory import net.pokeranalytics.android.model.utils.SessionSetManager -import net.pokeranalytics.android.ui.adapter.StaticRowRepresentableDataSource import net.pokeranalytics.android.ui.adapter.UnmanagedRowRepresentableException import net.pokeranalytics.android.ui.fragment.GraphFragment import net.pokeranalytics.android.ui.view.* -import net.pokeranalytics.android.ui.view.rowrepresentable.CustomizableRowRepresentable -import net.pokeranalytics.android.ui.view.rowrepresentable.SeparatorRow import net.pokeranalytics.android.ui.view.rowrepresentable.SessionRow import net.pokeranalytics.android.util.NULL_TEXT import net.pokeranalytics.android.util.TextFormat @@ -44,11 +40,10 @@ import net.pokeranalytics.android.util.extensions.* import java.text.DateFormat import java.util.* import java.util.Currency -import kotlin.collections.ArrayList typealias BB = Double -open class Session : RealmObject(), Savable, Editable, StaticRowRepresentableDataSource, RowRepresentable, Timed, +open class Session : RealmObject(), Savable, Editable, RowRepresentable, Timed, TimeFilterable, Filterable, DatedBankrollGraphEntry { enum class Type(val value: String) { @@ -252,7 +247,7 @@ open class Session : RealmObject(), Savable, Editable, StaticRowRepresentableDat override var pauseDate: Date? = null set(value) { field = value - this.updateRowRepresentation() +// this.updateRowRepresentation() } // The session set containing the sessions, which can contain multiple endedSessions @@ -266,7 +261,7 @@ open class Session : RealmObject(), Savable, Editable, StaticRowRepresentableDat set(value) { field = value this.formatBlinds() - this.updateRowRepresentation() +// this.updateRowRepresentation() } // The limit type: NL, PL... @@ -353,7 +348,7 @@ open class Session : RealmObject(), Savable, Editable, StaticRowRepresentableDat } else if (this.sessionSet != null) { SessionSetManager.removeFromTimeline(this) } - this.updateRowRepresentation() +// this.updateRowRepresentation() } /** @@ -465,7 +460,7 @@ open class Session : RealmObject(), Savable, Editable, StaticRowRepresentableDat return playerHandsPerHour / tableSize.toDouble() } - private val hourlyRate: Double + val hourlyRate: Double get() { this.result?.let { result -> return result.net / this.hourlyDuration @@ -706,273 +701,10 @@ open class Session : RealmObject(), Savable, Editable, StaticRowRepresentableDat @Ignore override val viewType: Int = RowViewType.ROW_SESSION.ordinal - // Override to surcharge custom field viewType - override fun viewTypeForPosition(position: Int): Int { - rowRepresentationForCurrentState[position].let { - if (it is CustomField) { - return RowViewType.TITLE_VALUE.ordinal - } - } - return super.viewTypeForPosition(position) - } - override fun getDisplayName(context: Context): String { return "Session ${this.creationDate}" } - @Ignore - private var rowRepresentationForCurrentState: List = mutableListOf() - - private fun updatedRowRepresentationForCurrentState(): List { - val rows = ArrayList() - - // Headers - when (getState()) { - SessionState.STARTED -> { - rows.add( - CustomizableRowRepresentable( - RowViewType.HEADER_TITLE_AMOUNT_BIG, - title = getFormattedDuration(), - valueTextFormat = ComputedStat(Stat.NET_RESULT, result?.net ?: 0.0, currency = currency).textFormat - ) - ) - rows.add(SeparatorRow()) - } - SessionState.PAUSED -> { - rows.add( - CustomizableRowRepresentable( - RowViewType.HEADER_TITLE_AMOUNT_BIG, - resId = R.string.pause, - valueTextFormat = ComputedStat(Stat.NET_RESULT, result?.net ?: 0.0, currency = currency).textFormat - ) - ) - rows.add(SeparatorRow()) - } - SessionState.FINISHED -> { - rows.add( - CustomizableRowRepresentable( - RowViewType.HEADER_TITLE_AMOUNT_BIG, - title = getFormattedDuration(), - valueTextFormat = ComputedStat(Stat.NET_RESULT, result?.net ?: 0.0, currency = currency).textFormat - ) - ) - rows.add( - CustomizableRowRepresentable( - RowViewType.HEADER_TITLE_AMOUNT, - resId = R.string.hour_rate_without_pauses, - valueTextFormat = ComputedStat(Stat.HOURLY_RATE, this.hourlyRate, currency = currency).textFormat - ) - ) - -// if (!isTournament()) { -// rows.add( -// CustomizableRowRepresentable( -// RowViewType.HEADER_TITLE_VALUE, -// resId = R.string.bankroll_variation, -// computedStat = ComputedStat(Stat.HOURLY_RATE, 0.0, CurrencyUtils.getCurrency(bankroll)) -// ) -// ) -// } - rows.add(SeparatorRow()) - } - else -> { - } - } - - // Rows - rows.addAll(SessionRow.getRows(this)) - - // Add custom fields - realm?.let { - rows.add(SeparatorRow()) - rows.addAll(it.sorted()) - } - - return rows - } - - fun updateRowRepresentation() { - this.rowRepresentationForCurrentState = this.updatedRowRepresentationForCurrentState() - } - - override fun adapterRows(): List? { - return this.rowRepresentationForCurrentState - } - - override fun boolForRow(row: RowRepresentable): Boolean { - return false - } - - override fun charSequenceForRow(row: RowRepresentable, context: Context): String { - return when (row) { - SessionRow.BANKROLL -> bankroll?.name ?: NULL_TEXT - SessionRow.BLINDS -> getFormattedBlinds() - SessionRow.BREAK_TIME -> if (this.breakDuration > 0.0) this.breakDuration.toMinutes() else NULL_TEXT - SessionRow.BUY_IN -> this.result?.buyin?.toCurrency(currency) ?: NULL_TEXT - SessionRow.CASHED_OUT, SessionRow.PRIZE -> this.result?.cashout?.toCurrency(currency) ?: NULL_TEXT - SessionRow.NET_RESULT -> this.result?.netResult?.toCurrency(currency) ?: NULL_TEXT - SessionRow.COMMENT -> if (this.comment.isNotEmpty()) this.comment else NULL_TEXT - SessionRow.END_DATE -> this.endDate?.shortDateTime() ?: NULL_TEXT - SessionRow.GAME -> getFormattedGame() - SessionRow.INITIAL_BUY_IN -> tournamentEntryFee?.toCurrency(currency) ?: NULL_TEXT - SessionRow.LOCATION -> location?.name ?: NULL_TEXT - SessionRow.PLAYERS -> tournamentNumberOfPlayers?.toString() ?: NULL_TEXT - SessionRow.POSITION -> result?.tournamentFinalPosition?.toString() ?: NULL_TEXT - SessionRow.START_DATE -> this.startDate?.shortDateTime() ?: NULL_TEXT - SessionRow.TABLE_SIZE -> this.tableSize?.let { TableSize(it).localizedTitle(context) } ?: NULL_TEXT - SessionRow.TIPS -> result?.tips?.toCurrency(currency) ?: NULL_TEXT - SessionRow.TOURNAMENT_TYPE -> { - this.tournamentType?.let { - TournamentType.values()[it].localizedTitle(context) - } ?: run { - NULL_TEXT - } - } - SessionRow.TOURNAMENT_FEATURE -> { - if (tournamentFeatures.size > 2) { - "${tournamentFeatures.subList(0, 2).joinToString { - it.name - }}, ..." - } else if (tournamentFeatures.size > 0) { - tournamentFeatures.joinToString { - it.name - } - } else { - NULL_TEXT - } - } - SessionRow.TOURNAMENT_NAME -> tournamentName?.name ?: NULL_TEXT - SessionRow.HANDS -> this.handHistories?.size.toString() - is CustomField -> { - customFieldEntries.find { it.customField?.id == row.id }?.let { customFieldEntry -> - return customFieldEntry.getFormattedValue(currency) - } - return NULL_TEXT - } - else -> throw UnmanagedRowRepresentableException("Unmanaged row = $row") - } - } - - override fun actionIconForRow(row: RowRepresentable): Int? { - return when (row) { - SessionRow.START_DATE, SessionRow.END_DATE -> { - R.drawable.ic_close - } - else -> null - } - } - - override fun editDescriptors(row: RowRepresentable): List? { - return when (row) { - SessionRow.BANKROLL -> row.editingDescriptors( - mapOf( - "defaultValue" to this.bankroll, - "data" to realm.sorted() // LiveData.Bankroll.items(realm) - ) - ) - SessionRow.GAME -> row.editingDescriptors( - mapOf( - "limit" to this.limit, - "defaultValue" to this.game, - "data" to realm.sorted() //LiveData.Game.items(realm) - ) - ) - SessionRow.LOCATION -> row.editingDescriptors( - mapOf( - "defaultValue" to this.location, - "data" to realm.sorted() // LiveData.Location.items(realm) - ) - ) - SessionRow.TOURNAMENT_FEATURE -> row.editingDescriptors( - mapOf( - "defaultValue" to this.tournamentFeatures, - "data" to realm.sorted() //LiveData.TournamentFeature.items(realm) - ) - ) - SessionRow.TOURNAMENT_NAME -> row.editingDescriptors( - mapOf( - "defaultValue" to this.tournamentName, - "data" to realm.sorted() //LiveData.TournamentName.items(realm) - ) - ) - SessionRow.TOURNAMENT_TYPE -> row.editingDescriptors( - mapOf( - "defaultValue" to this.tournamentType - ) - ) - SessionRow.TABLE_SIZE -> row.editingDescriptors( - mapOf( - "defaultValue" to this.tableSize - ) - ) - SessionRow.BLINDS -> row.editingDescriptors( - mapOf( - "sb" to cgSmallBlind?.round(), - "bb" to cgBigBlind?.round() - ) - ) - SessionRow.BUY_IN -> row.editingDescriptors( - mapOf( - "bb" to cgBigBlind, - "fee" to this.tournamentEntryFee, - "ratedBuyin" to result?.buyin - ) - ) - SessionRow.BREAK_TIME -> row.editingDescriptors(mapOf()) - SessionRow.CASHED_OUT, SessionRow.PRIZE -> row.editingDescriptors( - mapOf( - "defaultValue" to result?.cashout - ) - ) - SessionRow.NET_RESULT -> row.editingDescriptors( - mapOf( - "defaultValue" to result?.netResult - ) - ) - SessionRow.COMMENT -> row.editingDescriptors( - mapOf( - "defaultValue" to this.comment - ) - ) - SessionRow.INITIAL_BUY_IN -> row.editingDescriptors( - mapOf( - "defaultValue" to this.tournamentEntryFee - ) - ) - SessionRow.PLAYERS -> row.editingDescriptors( - mapOf( - "defaultValue" to this.tournamentNumberOfPlayers - ) - ) - SessionRow.POSITION -> row.editingDescriptors( - mapOf( - "defaultValue" to this.result?.tournamentFinalPosition - ) - ) - SessionRow.TIPS -> row.editingDescriptors( - mapOf( - "sb" to cgSmallBlind?.round(), - "bb" to cgBigBlind?.round(), - "tips" to result?.tips - ) - ) - is CustomField -> { - row.editingDescriptors( - when (row.type) { - CustomField.Type.LIST.uniqueIdentifier -> mapOf( - "defaultValue" to customFieldEntries.find { it.customField?.id == row.id }?.value, - "data" to row.entries - ) - else -> mapOf( - "defaultValue" to customFieldEntries.find { it.customField?.id == row.id }?.numericValue - ) - } - ) - } - else -> null - } - } - override fun updateValue(value: Any?, row: RowRepresentable) { when (row) { @@ -1005,7 +737,7 @@ open class Session : RealmObject(), Savable, Editable, StaticRowRepresentableDat SessionRow.BUY_IN -> { val localResult = getOrCreateResult() localResult.buyin = value as Double? - this.updateRowRepresentation() +// this.updateRowRepresentation() } SessionRow.CASHED_OUT, SessionRow.PRIZE -> { val localResult = getOrCreateResult() @@ -1210,4 +942,55 @@ open class Session : RealmObject(), Savable, Editable, StaticRowRepresentableDat @Ignore override val realmObjectClass: Class = Session::class.java + fun charSequenceForRow(row: RowRepresentable, context: Context): String { + + return when (row) { + SessionRow.BANKROLL -> bankroll?.name ?: NULL_TEXT + SessionRow.BLINDS -> getFormattedBlinds() + SessionRow.BREAK_TIME -> if (this.breakDuration > 0.0) this.breakDuration.toMinutes() else NULL_TEXT + SessionRow.BUY_IN -> this.result?.buyin?.toCurrency(currency) ?: NULL_TEXT + SessionRow.CASHED_OUT, SessionRow.PRIZE -> this.result?.cashout?.toCurrency(currency) ?: NULL_TEXT + SessionRow.NET_RESULT -> this.result?.netResult?.toCurrency(currency) ?: NULL_TEXT + SessionRow.COMMENT -> if (this.comment.isNotEmpty()) this.comment else NULL_TEXT + SessionRow.END_DATE -> this.endDate?.shortDateTime() ?: NULL_TEXT + SessionRow.GAME -> getFormattedGame() + SessionRow.INITIAL_BUY_IN -> tournamentEntryFee?.toCurrency(currency) ?: NULL_TEXT + SessionRow.LOCATION -> location?.name ?: NULL_TEXT + SessionRow.PLAYERS -> tournamentNumberOfPlayers?.toString() ?: NULL_TEXT + SessionRow.POSITION -> result?.tournamentFinalPosition?.toString() ?: NULL_TEXT + SessionRow.START_DATE -> this.startDate?.shortDateTime() ?: NULL_TEXT + SessionRow.TABLE_SIZE -> this.tableSize?.let { TableSize(it).localizedTitle(context) } ?: NULL_TEXT + SessionRow.TIPS -> result?.tips?.toCurrency(currency) ?: NULL_TEXT + SessionRow.TOURNAMENT_TYPE -> { + this.tournamentType?.let { + TournamentType.values()[it].localizedTitle(context) + } ?: run { + NULL_TEXT + } + } + SessionRow.TOURNAMENT_FEATURE -> { + if (tournamentFeatures.size > 2) { + "${tournamentFeatures.subList(0, 2).joinToString { + it.name + }}, ..." + } else if (tournamentFeatures.size > 0) { + tournamentFeatures.joinToString { + it.name + } + } else { + NULL_TEXT + } + } + SessionRow.TOURNAMENT_NAME -> tournamentName?.name ?: NULL_TEXT + SessionRow.HANDS -> this.handHistories?.size.toString() + is CustomField -> { + customFieldEntries.find { it.customField?.id == row.id }?.let { customFieldEntry -> + return customFieldEntry.getFormattedValue(currency) + } + return NULL_TEXT + } + else -> throw UnmanagedRowRepresentableException("Unmanaged row = $row") + } + } + } diff --git a/app/src/main/java/net/pokeranalytics/android/ui/modules/data/BankrollDataFragment.kt b/app/src/main/java/net/pokeranalytics/android/ui/modules/data/BankrollDataFragment.kt index 32f746fa..9d5a94a4 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/modules/data/BankrollDataFragment.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/modules/data/BankrollDataFragment.kt @@ -5,9 +5,12 @@ import android.content.Context import android.content.Intent import android.os.Bundle import android.view.View +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModelProvider import net.pokeranalytics.android.R import net.pokeranalytics.android.api.FreeConverterApi import net.pokeranalytics.android.model.realm.Bankroll +import net.pokeranalytics.android.model.realm.ResultCaptureType import net.pokeranalytics.android.ui.activity.CurrenciesActivity import net.pokeranalytics.android.ui.activity.components.RequestCode import net.pokeranalytics.android.ui.adapter.RowRepresentableDataSource @@ -19,24 +22,37 @@ import net.pokeranalytics.android.ui.view.RowViewType import net.pokeranalytics.android.ui.view.rowrepresentable.BankrollRow import net.pokeranalytics.android.ui.view.rowrepresentable.CustomizableRowRepresentable import net.pokeranalytics.android.ui.view.rowrepresentable.SimpleRow +import net.pokeranalytics.android.ui.viewmodel.DataManagerViewModel import net.pokeranalytics.android.util.NULL_TEXT +import net.pokeranalytics.android.util.Preferences import net.pokeranalytics.android.util.UserDefaults import net.pokeranalytics.android.util.extensions.toCurrency import net.pokeranalytics.android.util.extensions.toRate import java.util.* +class BankrollDataViewModel: DataManagerViewModel() { + + var selectedCaptureType: MutableLiveData = MutableLiveData(ResultCaptureType.BUYIN_CASHEDOUT) + +} /** * Custom EditableDataFragment to manage the Bankroll data */ class BankrollDataFragment : EditableDataFragment(), StaticRowRepresentableDataSource { + private val bankrollModel: BankrollDataViewModel by lazy { + ViewModelProvider(this).get(BankrollDataViewModel::class.java) + } + // Return the item as a Bankroll object private val bankroll: Bankroll get() { return this.model.item as Bankroll } + override val modelClass: Class = BankrollDataViewModel::class.java + private lateinit var defaultCurrency: Currency private val rows = ArrayList() private var isRefreshingRate = false @@ -55,6 +71,7 @@ class BankrollDataFragment : EditableDataFragment(), StaticRowRepresentableDataS shouldOpenKeyboard = false initData() + initUI() refreshRows() updateAdapterUI() } @@ -72,6 +89,33 @@ class BankrollDataFragment : EditableDataFragment(), StaticRowRepresentableDataS } } + /** + * Init data + */ + override fun initData() { + super.initData() + + defaultCurrency = UserDefaults.currency + + if (!deleteButtonShouldAppear) { + bankroll.currency = net.pokeranalytics.android.model.realm.Currency() + bankroll.currency?.code = defaultCurrency.currencyCode + bankroll.currency?.rate = 1.0 + } + + Preferences.getResultCaptureType(this.bankroll, requireContext())?.let { + this.bankrollModel.selectedCaptureType.value = it + } + + } + + private fun initUI() { + this.bankrollModel.selectedCaptureType.observeForever { + rowRepresentableAdapter.notifyDataSetChanged() + } + + } + override fun getDataSource(): RowRepresentableDataSource { return this } @@ -80,11 +124,15 @@ class BankrollDataFragment : EditableDataFragment(), StaticRowRepresentableDataS return rows } - override fun charSequenceForRow( - row: RowRepresentable, - context: Context, - tag: Int - ): CharSequence { + override fun isSelected(position: Int, row: RowRepresentable, tag: Int): Boolean { + return when (row) { + BankrollRow.CAPTURE_BUYIN_CASHEDOUT -> this.bankrollModel.selectedCaptureType.value == ResultCaptureType.BUYIN_CASHEDOUT + BankrollRow.CAPTURE_NET_RESULT -> this.bankrollModel.selectedCaptureType.value == ResultCaptureType.NET_RESULT + else -> false + } + } + + override fun charSequenceForRow(row: RowRepresentable, context: Context, tag: Int): CharSequence { return when (row) { SimpleRow.NAME -> if (bankroll.name.isNotEmpty()) bankroll.name else NULL_TEXT BankrollRow.CURRENCY -> { @@ -137,6 +185,8 @@ class BankrollDataFragment : EditableDataFragment(), StaticRowRepresentableDataS RequestCode.CURRENCY.value ) BankrollRow.REFRESH_RATE -> refreshRate() + BankrollRow.CAPTURE_BUYIN_CASHEDOUT -> this.bankrollModel.selectedCaptureType.value = ResultCaptureType.BUYIN_CASHEDOUT + BankrollRow.CAPTURE_NET_RESULT -> this.bankrollModel.selectedCaptureType.value = ResultCaptureType.NET_RESULT else -> super.onRowSelected(position, row, tag) } } @@ -154,21 +204,6 @@ class BankrollDataFragment : EditableDataFragment(), StaticRowRepresentableDataS updateAdapterUI() } - /** - * Init data - */ - override fun initData() { - super.initData() - - defaultCurrency = UserDefaults.currency - - if (!deleteButtonShouldAppear) { - bankroll.currency = net.pokeranalytics.android.model.realm.Currency() - bankroll.currency?.code = defaultCurrency.currencyCode - bankroll.currency?.rate = 1.0 - } - } - /** * Refresh rows */ @@ -184,6 +219,12 @@ class BankrollDataFragment : EditableDataFragment(), StaticRowRepresentableDataS rows.add(BankrollRow.RATE) rows.add(BankrollRow.REFRESH_RATE) } + + if (!this.bankroll.live) { + rows.add(CustomizableRowRepresentable(customViewType = RowViewType.HEADER_TITLE, resId = R.string.bankroll_capture_method)) + rows.add(BankrollRow.CAPTURE_BUYIN_CASHEDOUT) + rows.add(BankrollRow.CAPTURE_NET_RESULT) + } } /** @@ -221,34 +262,16 @@ class BankrollDataFragment : EditableDataFragment(), StaticRowRepresentableDataS rowRepresentableAdapter.refreshRow(BankrollRow.REFRESH_RATE) } -// val call = CurrencyConverterApi.getApi(requireContext())?.convert(currenciesConverterValue) -// call?.enqueue(object : retrofit2.Callback> { -// -// override fun onResponse(call: Call>, response: Response>) { -// response.body()?.let { -// it[currenciesConverterValue]?.value?.let { rate -> -// Timber.d("rate found = $rate") -// onRowValueChanged(rate, BankrollRow.RATE) -// } ?: run { -// Timber.d("no rate for $currenciesConverterValue") -// } -// } ?: run { -// Timber.d("onResponse> no body in ${response}") -// } -// -// isRefreshingRate = false -// rowRepresentableAdapter.refreshRow(BankrollRow.REFRESH_RATE) -// } -// -// override fun onFailure(call: Call>, t: Throwable) { -// Timber.d("api call failed: ${t.message}") -// isRefreshingRate = false -// rowRepresentableAdapter.refreshRow(BankrollRow.REFRESH_RATE) -// } -// }) - this.isRefreshingRate = true this.rowRepresentableAdapter.refreshRow(BankrollRow.REFRESH_RATE) } + override fun willSaveData() { + super.willSaveData() + this.bankrollModel.selectedCaptureType.value?.let { + Preferences.setResultCaptureType(this.bankroll, it, requireContext()) + } + + } + } \ No newline at end of file diff --git a/app/src/main/java/net/pokeranalytics/android/ui/modules/data/DataManagerFragment.kt b/app/src/main/java/net/pokeranalytics/android/ui/modules/data/DataManagerFragment.kt index 85928927..a7c78bd8 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/modules/data/DataManagerFragment.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/modules/data/DataManagerFragment.kt @@ -19,10 +19,12 @@ import net.pokeranalytics.android.ui.viewmodel.DataManagerViewModel open class DataManagerFragment : RealmFragment() { - protected val model: DataManagerViewModel by lazy { - ViewModelProvider(this).get(DataManagerViewModel::class.java) + protected open val model: DataManagerViewModel by lazy { + ViewModelProvider(this).get(modelClass) } + open val modelClass: Class = DataManagerViewModel::class.java + // lateinit var item: Deletable // protected lateinit var liveDataType: LiveData // protected var primaryKey: String? = null diff --git a/app/src/main/java/net/pokeranalytics/android/ui/modules/data/EditableDataFragment.kt b/app/src/main/java/net/pokeranalytics/android/ui/modules/data/EditableDataFragment.kt index 3049550f..4afb19aa 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/modules/data/EditableDataFragment.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/modules/data/EditableDataFragment.kt @@ -15,7 +15,6 @@ import net.pokeranalytics.android.model.interfaces.NameManageable import net.pokeranalytics.android.ui.adapter.RowRepresentableAdapter import net.pokeranalytics.android.ui.adapter.RowRepresentableDataSource import net.pokeranalytics.android.ui.adapter.RowRepresentableDelegate -import net.pokeranalytics.android.ui.fragment.components.bottomsheet.BottomSheetFragment import net.pokeranalytics.android.ui.view.RowRepresentable diff --git a/app/src/main/java/net/pokeranalytics/android/ui/modules/session/SessionFragment.kt b/app/src/main/java/net/pokeranalytics/android/ui/modules/session/SessionFragment.kt index 20f0d407..d9719611 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/modules/session/SessionFragment.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/modules/session/SessionFragment.kt @@ -1,5 +1,6 @@ package net.pokeranalytics.android.ui.modules.session +import android.content.Context import android.os.Bundle import android.os.Handler import android.view.* @@ -10,11 +11,14 @@ import androidx.interpolator.view.animation.FastOutSlowInInterpolator import androidx.lifecycle.ViewModelProvider import androidx.recyclerview.widget.DiffUtil import com.crashlytics.android.Crashlytics +import io.realm.annotations.Ignore import kotlinx.android.synthetic.main.fragment_session.* import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.async import kotlinx.coroutines.launch import net.pokeranalytics.android.R +import net.pokeranalytics.android.calculus.ComputedStat +import net.pokeranalytics.android.calculus.Stat import net.pokeranalytics.android.calculus.bankroll.BankrollReportManager import net.pokeranalytics.android.calculus.optimalduration.CashGameOptimalDurationCalculator import net.pokeranalytics.android.exceptions.PAIllegalStateException @@ -24,28 +28,26 @@ import net.pokeranalytics.android.model.extensions.cancelStopNotification import net.pokeranalytics.android.model.extensions.getState import net.pokeranalytics.android.model.extensions.scheduleStopNotification import net.pokeranalytics.android.model.interfaces.SaveValidityStatus -import net.pokeranalytics.android.model.realm.Location -import net.pokeranalytics.android.model.realm.Session +import net.pokeranalytics.android.model.realm.* import net.pokeranalytics.android.model.utils.FavoriteSessionFinder import net.pokeranalytics.android.ui.adapter.RowRepresentableAdapter import net.pokeranalytics.android.ui.adapter.RowRepresentableDelegate +import net.pokeranalytics.android.ui.adapter.StaticRowRepresentableDataSource import net.pokeranalytics.android.ui.fragment.components.RealmFragment import net.pokeranalytics.android.ui.helpers.DateTimePickerManager import net.pokeranalytics.android.ui.modules.data.EditableDataActivity import net.pokeranalytics.android.ui.modules.datalist.DataListActivity import net.pokeranalytics.android.ui.modules.handhistory.HandHistoryActivity -import net.pokeranalytics.android.ui.view.RowRepresentable -import net.pokeranalytics.android.ui.view.RowRepresentableDiffCallback -import net.pokeranalytics.android.ui.view.SmoothScrollLinearLayoutManager +import net.pokeranalytics.android.ui.view.* +import net.pokeranalytics.android.ui.view.rowrepresentable.CustomizableRowRepresentable +import net.pokeranalytics.android.ui.view.rowrepresentable.SeparatorRow import net.pokeranalytics.android.ui.view.rowrepresentable.SessionRow import net.pokeranalytics.android.util.Preferences -import net.pokeranalytics.android.util.extensions.findById -import net.pokeranalytics.android.util.extensions.formattedHourlyDuration -import net.pokeranalytics.android.util.extensions.getNextMinuteInMilliseconds +import net.pokeranalytics.android.util.extensions.* import timber.log.Timber import java.util.* -class SessionFragment : RealmFragment(), RowRepresentableDelegate { +class SessionFragment : RealmFragment(), RowRepresentableDelegate, StaticRowRepresentableDataSource { private lateinit var viewModel: SessionViewModel @@ -114,7 +116,7 @@ class SessionFragment : RealmFragment(), RowRepresentableDelegate { toolbar.title = if (currentSession.isTournament()) getString(R.string.tournament) else getString(R.string.cash_game) collapsingToolbar.title = toolbar.title - sessionAdapter = RowRepresentableAdapter(currentSession, this) + sessionAdapter = RowRepresentableAdapter(this, this) recyclerView.adapter = sessionAdapter updateSessionUI(true) @@ -216,7 +218,7 @@ class SessionFragment : RealmFragment(), RowRepresentableDelegate { val session = this.currentSession - val data = session.editDescriptors(row) + val data = this.editDescriptors(row) when (row) { SessionRow.START_DATE -> DateTimePickerManager.create(requireContext(), row, this, session.startDate) SessionRow.END_DATE -> { @@ -270,7 +272,7 @@ class SessionFragment : RealmFragment(), RowRepresentableDelegate { */ private fun updateSessionUI(firstDisplay: Boolean = false) { - this.currentSession.updateRowRepresentation() + this.updateRowRepresentation() handler.removeCallbacksAndMessages(null) @@ -340,7 +342,7 @@ class SessionFragment : RealmFragment(), RowRepresentableDelegate { * Update adapter UI */ private fun updateAdapterUI() { - currentSession.adapterRows()?.let { + this.adapterRows()?.let { val diffResult = DiffUtil.calculateDiff(RowRepresentableDiffCallback(it, oldRows)) sessionAdapter.updateRows(diffResult) @@ -460,4 +462,231 @@ class SessionFragment : RealmFragment(), RowRepresentableDelegate { } } + // Static Data Source + + + // Override to surcharge custom field viewType + override fun viewTypeForPosition(position: Int): Int { + rowRepresentationForCurrentState[position].let { + if (it is CustomField) { + return RowViewType.TITLE_VALUE.ordinal + } + } + return super.viewTypeForPosition(position) + } + + + @Ignore + private var rowRepresentationForCurrentState: List = mutableListOf() + + private fun updatedRowRepresentationForCurrentState(context: Context): List { + val rows = ArrayList() + val session = this.currentSession + val result = session.result + val currency = session.currency + + // Headers + when (this.currentSession.getState()) { + SessionState.STARTED -> { + rows.add( + CustomizableRowRepresentable( + RowViewType.HEADER_TITLE_AMOUNT_BIG, + title = session.getFormattedDuration(), + valueTextFormat = ComputedStat(Stat.NET_RESULT, result?.net ?: 0.0, currency = session.currency).textFormat + ) + ) + rows.add(SeparatorRow()) + } + SessionState.PAUSED -> { + rows.add( + CustomizableRowRepresentable( + RowViewType.HEADER_TITLE_AMOUNT_BIG, + resId = R.string.pause, + valueTextFormat = ComputedStat(Stat.NET_RESULT, result?.net ?: 0.0, currency = currency).textFormat + ) + ) + rows.add(SeparatorRow()) + } + SessionState.FINISHED -> { + rows.add( + CustomizableRowRepresentable( + RowViewType.HEADER_TITLE_AMOUNT_BIG, + title = session.getFormattedDuration(), + valueTextFormat = ComputedStat(Stat.NET_RESULT, result?.net ?: 0.0, currency = currency).textFormat + ) + ) + rows.add( + CustomizableRowRepresentable( + RowViewType.HEADER_TITLE_AMOUNT, + resId = R.string.hour_rate_without_pauses, + valueTextFormat = ComputedStat(Stat.HOURLY_RATE, session.hourlyRate, currency = currency).textFormat + ) + ) + +// if (!isTournament()) { +// rows.add( +// CustomizableRowRepresentable( +// RowViewType.HEADER_TITLE_VALUE, +// resId = R.string.bankroll_variation, +// computedStat = ComputedStat(Stat.HOURLY_RATE, 0.0, CurrencyUtils.getCurrency(bankroll)) +// ) +// ) +// } + rows.add(SeparatorRow()) + } + else -> { + } + } + + // Rows + rows.addAll(SessionRow.getRows(this.currentSession, requireContext())) + + // Add custom fields + getRealm().let { + rows.add(SeparatorRow()) + rows.addAll(it.sorted()) + } + + return rows + } + + fun updateRowRepresentation() { + this.rowRepresentationForCurrentState = this.updatedRowRepresentationForCurrentState(requireContext()) + } + + override fun adapterRows(): List? { + return this.rowRepresentationForCurrentState + } + + override fun boolForRow(row: RowRepresentable): Boolean { + return false + } + + override fun charSequenceForRow(row: RowRepresentable, context: Context): String { + return this.currentSession.charSequenceForRow(row, context) + } + + override fun actionIconForRow(row: RowRepresentable): Int? { + return when (row) { + SessionRow.START_DATE, SessionRow.END_DATE -> { + R.drawable.ic_close + } + else -> null + } + } + + override fun editDescriptors(row: RowRepresentable): List? { + + val session = this.currentSession + return when (row) { + SessionRow.BANKROLL -> row.editingDescriptors( + mapOf( + "defaultValue" to session.bankroll, + "data" to getRealm().sorted() // LiveData.Bankroll.items(realm) + ) + ) + SessionRow.GAME -> row.editingDescriptors( + mapOf( + "limit" to session.limit, + "defaultValue" to session.game, + "data" to getRealm().sorted() //LiveData.Game.items(realm) + ) + ) + SessionRow.LOCATION -> row.editingDescriptors( + mapOf( + "defaultValue" to session.location, + "data" to getRealm().sorted() // LiveData.Location.items(realm) + ) + ) + SessionRow.TOURNAMENT_FEATURE -> row.editingDescriptors( + mapOf( + "defaultValue" to session.tournamentFeatures, + "data" to getRealm().sorted() //LiveData.TournamentFeature.items(realm) + ) + ) + SessionRow.TOURNAMENT_NAME -> row.editingDescriptors( + mapOf( + "defaultValue" to session.tournamentName, + "data" to getRealm().sorted() //LiveData.TournamentName.items(realm) + ) + ) + SessionRow.TOURNAMENT_TYPE -> row.editingDescriptors( + mapOf( + "defaultValue" to session.tournamentType + ) + ) + SessionRow.TABLE_SIZE -> row.editingDescriptors( + mapOf( + "defaultValue" to session.tableSize + ) + ) + SessionRow.BLINDS -> row.editingDescriptors( + mapOf( + "sb" to session.cgSmallBlind?.round(), + "bb" to session.cgBigBlind?.round() + ) + ) + SessionRow.BUY_IN -> row.editingDescriptors( + mapOf( + "bb" to session.cgBigBlind, + "fee" to session.tournamentEntryFee, + "ratedBuyin" to session.result?.buyin + ) + ) + SessionRow.BREAK_TIME -> row.editingDescriptors(mapOf()) + SessionRow.CASHED_OUT, SessionRow.PRIZE -> row.editingDescriptors( + mapOf( + "defaultValue" to session.result?.cashout + ) + ) + SessionRow.NET_RESULT -> row.editingDescriptors( + mapOf( + "defaultValue" to session.result?.netResult + ) + ) + SessionRow.COMMENT -> row.editingDescriptors( + mapOf( + "defaultValue" to session.comment + ) + ) + SessionRow.INITIAL_BUY_IN -> row.editingDescriptors( + mapOf( + "defaultValue" to session.tournamentEntryFee + ) + ) + SessionRow.PLAYERS -> row.editingDescriptors( + mapOf( + "defaultValue" to session.tournamentNumberOfPlayers + ) + ) + SessionRow.POSITION -> row.editingDescriptors( + mapOf( + "defaultValue" to session.result?.tournamentFinalPosition + ) + ) + SessionRow.TIPS -> row.editingDescriptors( + mapOf( + "sb" to session.cgSmallBlind?.round(), + "bb" to session.cgBigBlind?.round(), + "tips" to session.result?.tips + ) + ) + is CustomField -> { + row.editingDescriptors( + when (row.type) { + CustomField.Type.LIST.uniqueIdentifier -> mapOf( + "defaultValue" to session.customFieldEntries.find { it.customField?.id == row.id }?.value, + "data" to row.entries + ) + else -> mapOf( + "defaultValue" to session.customFieldEntries.find { it.customField?.id == row.id }?.numericValue + ) + } + ) + } + else -> null + } + } + + } \ No newline at end of file diff --git a/app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/BankrollRow.kt b/app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/BankrollRow.kt index 1e3b3152..8551b2ae 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/BankrollRow.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/BankrollRow.kt @@ -14,7 +14,9 @@ enum class BankrollRow : RowRepresentable, DefaultEditDataSource { INITIAL_VALUE, CURRENCY, RATE, - REFRESH_RATE; + REFRESH_RATE, + CAPTURE_BUYIN_CASHEDOUT, + CAPTURE_NET_RESULT; override val resId: Int? get() { @@ -24,6 +26,8 @@ enum class BankrollRow : RowRepresentable, DefaultEditDataSource { CURRENCY -> R.string.currency RATE -> R.string.rate REFRESH_RATE -> R.string.refresh_rate + CAPTURE_BUYIN_CASHEDOUT -> R.string.stack_buy_in + CAPTURE_NET_RESULT -> R.string.net_result_only } } @@ -35,7 +39,9 @@ enum class BankrollRow : RowRepresentable, DefaultEditDataSource { CURRENCY -> RowViewType.TITLE_VALUE_ARROW.ordinal RATE -> RowViewType.TITLE_VALUE.ordinal REFRESH_RATE -> RowViewType.ROW_BUTTON.ordinal - } + CAPTURE_BUYIN_CASHEDOUT -> RowViewType.TITLE_CHECK.ordinal + CAPTURE_NET_RESULT -> RowViewType.TITLE_CHECK.ordinal + } } override val bottomSheetType: BottomSheetType @@ -46,7 +52,9 @@ enum class BankrollRow : RowRepresentable, DefaultEditDataSource { CURRENCY -> BottomSheetType.NONE RATE -> BottomSheetType.NUMERIC_TEXT REFRESH_RATE -> BottomSheetType.NONE - } + CAPTURE_BUYIN_CASHEDOUT -> BottomSheetType.NONE + CAPTURE_NET_RESULT -> BottomSheetType.NONE + } } override fun editingDescriptors(map: Map): ArrayList? { diff --git a/app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/SessionRow.kt b/app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/SessionRow.kt index e448218a..587845b3 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/SessionRow.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/SessionRow.kt @@ -1,11 +1,13 @@ package net.pokeranalytics.android.ui.view.rowrepresentable +import android.content.Context import android.text.InputType import io.realm.RealmResults import net.pokeranalytics.android.R import net.pokeranalytics.android.model.TournamentType import net.pokeranalytics.android.model.extensions.SessionState import net.pokeranalytics.android.model.extensions.getState +import net.pokeranalytics.android.model.realm.ResultCaptureType import net.pokeranalytics.android.model.realm.Session import net.pokeranalytics.android.ui.fragment.components.bottomsheet.BottomSheetType import net.pokeranalytics.android.ui.view.RowRepresentable @@ -44,7 +46,7 @@ enum class SessionRow : RowRepresentable { /** * Return the rows to display for the current session state */ - fun getRows(session: Session): List { + fun getRows(session: Session, context: Context): List { when (session.type) { Session.Type.TOURNAMENT.ordinal -> { return when (session.getState()) { @@ -102,10 +104,13 @@ enum class SessionRow : RowRepresentable { SessionState.STARTED, SessionState.PAUSED, SessionState.FINISHED -> { val fields = mutableListOf() - when { - session.hasBuyin -> fields.addAll(listOf(CASHED_OUT, BUY_IN, TIPS)) - session.hasNetResult -> fields.add(NET_RESULT) - session.isLive -> fields.addAll(listOf(CASHED_OUT, BUY_IN, TIPS)) + + when (session.bankroll?.resultCaptureType(context)) { + ResultCaptureType.BUYIN_CASHEDOUT -> fields.addAll(listOf(CASHED_OUT, BUY_IN, TIPS)) + ResultCaptureType.NET_RESULT -> fields.add(NET_RESULT) +// session.hasBuyin -> fields.addAll(listOf(CASHED_OUT, BUY_IN, TIPS)) +// session.hasNetResult -> fields.add(NET_RESULT) +// session.isLive -> fields.addAll(listOf(CASHED_OUT, BUY_IN, TIPS)) else -> fields.add(NET_RESULT) } fields.add(SeparatorRow()) diff --git a/app/src/main/java/net/pokeranalytics/android/ui/viewmodel/DataManagerViewModel.kt b/app/src/main/java/net/pokeranalytics/android/ui/viewmodel/DataManagerViewModel.kt index 6dff061c..e5787a94 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/viewmodel/DataManagerViewModel.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/viewmodel/DataManagerViewModel.kt @@ -5,7 +5,7 @@ import io.realm.Realm import net.pokeranalytics.android.model.LiveData import net.pokeranalytics.android.model.interfaces.Deletable -class DataManagerViewModel : ViewModel() { +open class DataManagerViewModel : ViewModel() { /*** * A deletable object diff --git a/app/src/main/java/net/pokeranalytics/android/util/Preferences.kt b/app/src/main/java/net/pokeranalytics/android/util/Preferences.kt index 154c1a3b..440822ce 100644 --- a/app/src/main/java/net/pokeranalytics/android/util/Preferences.kt +++ b/app/src/main/java/net/pokeranalytics/android/util/Preferences.kt @@ -7,6 +7,8 @@ import android.view.View import io.realm.Realm import net.pokeranalytics.android.PokerAnalyticsApplication import net.pokeranalytics.android.R +import net.pokeranalytics.android.model.realm.Bankroll +import net.pokeranalytics.android.model.realm.ResultCaptureType import net.pokeranalytics.android.model.realm.Session import net.pokeranalytics.android.ui.extensions.openUrl import net.pokeranalytics.android.util.extensions.count @@ -33,7 +35,8 @@ class Preferences { PATCH_BLINDS_FORMAT("patchBlindFormat"), SHOW_STOP_NOTIFICATIONS("showStopNotifications"), ADD_NEW_TRANSACTION_TYPES("addNewTransactionTypes"), - SHOW_VILLAIN_CARDS("showVillainCards") + SHOW_VILLAIN_CARDS("showVillainCards"), + BANKROLL_RESULT_CAPTURE_TYPE("bankrollResultCaptureType_") } enum class FeedMessage { @@ -110,6 +113,7 @@ class Preferences { return preferences.getBoolean(key.identifier, defaultValue ?: false) } + fun setShowVillainCards(show: Boolean, context: Context) { setBoolean(Keys.SHOW_VILLAIN_CARDS, show, context) } @@ -193,7 +197,23 @@ class Preferences { } } - } + fun setResultCaptureType(bankroll: Bankroll, type: ResultCaptureType, context: Context) { + val key = "${Keys.BANKROLL_RESULT_CAPTURE_TYPE}${bankroll.id}" + val preferences = PreferenceManager.getDefaultSharedPreferences(context) + val editor = preferences.edit() + editor.putInt(key, type.ordinal) + editor.apply() + } + + fun getResultCaptureType(bankroll: Bankroll, context: Context): ResultCaptureType? { + val key = "${Keys.BANKROLL_RESULT_CAPTURE_TYPE}${bankroll.id}" + val preferences = PreferenceManager.getDefaultSharedPreferences(context) + return when (val ordinal = preferences.getInt(key, -1)) { + -1 -> null + else -> ResultCaptureType.values()[ordinal] + } + } + } }