|
|
|
|
@ -1,5 +1,7 @@ |
|
|
|
|
package net.pokeranalytics.android.ui.modules.handhistory.model |
|
|
|
|
|
|
|
|
|
import androidx.lifecycle.MutableLiveData |
|
|
|
|
import androidx.lifecycle.ViewModel |
|
|
|
|
import net.pokeranalytics.android.R |
|
|
|
|
import net.pokeranalytics.android.exceptions.PAIllegalStateException |
|
|
|
|
import net.pokeranalytics.android.model.handhistory.HandSetup |
|
|
|
|
@ -8,7 +10,7 @@ import net.pokeranalytics.android.model.handhistory.Street |
|
|
|
|
import net.pokeranalytics.android.model.realm.handhistory.Action |
|
|
|
|
import net.pokeranalytics.android.model.realm.handhistory.Card |
|
|
|
|
import net.pokeranalytics.android.model.realm.handhistory.HandHistory |
|
|
|
|
import net.pokeranalytics.android.ui.modules.handhistory.HHSelection |
|
|
|
|
import net.pokeranalytics.android.ui.adapter.RowRepresentableDataSource |
|
|
|
|
import net.pokeranalytics.android.ui.modules.handhistory.HandRowType |
|
|
|
|
import net.pokeranalytics.android.ui.modules.handhistory.views.CardCentralizer |
|
|
|
|
import net.pokeranalytics.android.ui.modules.handhistory.views.CardsRow |
|
|
|
|
@ -19,27 +21,60 @@ import net.pokeranalytics.android.ui.view.rowrepresentable.CustomizableRowRepres |
|
|
|
|
import net.pokeranalytics.android.util.extensions.formatted |
|
|
|
|
import timber.log.Timber |
|
|
|
|
|
|
|
|
|
interface BuilderListener { |
|
|
|
|
fun rowRepresentablesCountChanged() |
|
|
|
|
enum class HHKeyboard { |
|
|
|
|
ACTION, |
|
|
|
|
AMOUNT, |
|
|
|
|
CARD; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
class HHBuilder : CardCentralizer, ActionListListener { |
|
|
|
|
class HHSelection(var index: Int, var keyboard: HHKeyboard) |
|
|
|
|
|
|
|
|
|
class HandHistoryViewModel : ViewModel(), RowRepresentableDataSource, CardCentralizer, ActionListListener { |
|
|
|
|
|
|
|
|
|
/*** |
|
|
|
|
* Indicates whether the hand history is being edited or not |
|
|
|
|
*/ |
|
|
|
|
var isEdited = true |
|
|
|
|
|
|
|
|
|
/*** |
|
|
|
|
* The user selection's live data inside the editor |
|
|
|
|
*/ |
|
|
|
|
var selectionLiveData: MutableLiveData<HHSelection> = MutableLiveData() |
|
|
|
|
|
|
|
|
|
/*** |
|
|
|
|
* The current selection |
|
|
|
|
*/ |
|
|
|
|
val currentSelection: HHSelection |
|
|
|
|
get() { return selectionLiveData.value ?: throw PAIllegalStateException("No selection") } |
|
|
|
|
|
|
|
|
|
/*** |
|
|
|
|
* The current amount edited by the user |
|
|
|
|
*/ |
|
|
|
|
var currentAmount: String? = null |
|
|
|
|
|
|
|
|
|
/*** |
|
|
|
|
* The action index |
|
|
|
|
*/ |
|
|
|
|
private val actionIndexForSelection: Int |
|
|
|
|
get() { |
|
|
|
|
return this.indexOfComputedAction(currentSelection.index) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/*** |
|
|
|
|
* The list of row representables, generated from the hand history actions |
|
|
|
|
*/ |
|
|
|
|
var rowRepresentables = mutableListOf<RowRepresentable>() |
|
|
|
|
private set |
|
|
|
|
private val rowRepresentables: List<RowRepresentable> |
|
|
|
|
get() { return this.rowsLiveData.value ?: throw PAIllegalStateException("Rows not set") } |
|
|
|
|
|
|
|
|
|
/*** |
|
|
|
|
* The live data object that contains the list of RowRepresentable |
|
|
|
|
*/ |
|
|
|
|
var rowsLiveData: MutableLiveData<MutableList<RowRepresentable>> = MutableLiveData() |
|
|
|
|
|
|
|
|
|
/*** |
|
|
|
|
* The hand history |
|
|
|
|
*/ |
|
|
|
|
private var handHistory: HandHistory |
|
|
|
|
set(value) { |
|
|
|
|
field = value |
|
|
|
|
setNumberOfPlayers(value.numberOfPlayers) |
|
|
|
|
load() |
|
|
|
|
} |
|
|
|
|
private lateinit var handHistory: HandHistory |
|
|
|
|
|
|
|
|
|
/*** |
|
|
|
|
* All actions sorted by index |
|
|
|
|
@ -57,40 +92,29 @@ class HHBuilder : CardCentralizer, ActionListListener { |
|
|
|
|
private var playerHandMaxCards: Int? = null |
|
|
|
|
set(value) { |
|
|
|
|
field = value |
|
|
|
|
this.rowRepresentables.filterIsInstance<PlayerCardsRow>().forEach { |
|
|
|
|
this.rowsLiveData.value?.filterIsInstance<PlayerCardsRow>()?.forEach { |
|
|
|
|
it.maxCards = value |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/*** |
|
|
|
|
* Creates a builder using a [handSetup] |
|
|
|
|
* Also creates a new Hand History and configures it according to the [handSetup] |
|
|
|
|
* Configures a new HandHistory object using a [handSetup] |
|
|
|
|
*/ |
|
|
|
|
constructor(handSetup: HandSetup) { |
|
|
|
|
fun configure(handSetup: HandSetup) { |
|
|
|
|
val handHistory = HandHistory() |
|
|
|
|
handHistory.configure(handSetup) |
|
|
|
|
this.playerHandMaxCards = handSetup.game?.playerHandMaxCards |
|
|
|
|
this.handHistory = handHistory |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/*** |
|
|
|
|
* Creates a builder using the parameter [handHistory] |
|
|
|
|
*/ |
|
|
|
|
constructor(handHistory: HandHistory) { |
|
|
|
|
this.handHistory = handHistory |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private var listener: BuilderListener? = null |
|
|
|
|
|
|
|
|
|
fun setBuilderListener(builderListener: BuilderListener) { |
|
|
|
|
this.listener = builderListener |
|
|
|
|
this.setHandHistory(handHistory) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/*** |
|
|
|
|
* Returns the action |
|
|
|
|
* Sets the hand history and loads it |
|
|
|
|
*/ |
|
|
|
|
private fun actionForIndex(index: Int) : ComputedAction { |
|
|
|
|
return this.sortedActions[index] |
|
|
|
|
fun setHandHistory(handHistory: HandHistory) { |
|
|
|
|
this.handHistory = handHistory |
|
|
|
|
setNumberOfPlayers(handHistory.numberOfPlayers) |
|
|
|
|
load() |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/*** |
|
|
|
|
@ -98,10 +122,7 @@ class HHBuilder : CardCentralizer, ActionListListener { |
|
|
|
|
* Pre-computes the potsizes for the video export |
|
|
|
|
*/ |
|
|
|
|
private fun load() { |
|
|
|
|
|
|
|
|
|
// this.boardManager = BoardManager(this.handHistory.board, this) |
|
|
|
|
this.sortedActions.load(this.handHistory) |
|
|
|
|
|
|
|
|
|
this.sortedActions.load(this.handHistory) |
|
|
|
|
this.createRowRepresentation() |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@ -109,77 +130,54 @@ class HHBuilder : CardCentralizer, ActionListListener { |
|
|
|
|
* Sets the number of players playing the hand |
|
|
|
|
* Defines the appropriate positions for this player count |
|
|
|
|
*/ |
|
|
|
|
fun setNumberOfPlayers(playerCount: Int) { |
|
|
|
|
private fun setNumberOfPlayers(playerCount: Int) { |
|
|
|
|
this.handHistory.numberOfPlayers = playerCount |
|
|
|
|
this.sortedActions.positions = Position.positionsPerPlayers(playerCount) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
fun availableActions(actionIndexForSelection: Int): Set<Action.Type> { |
|
|
|
|
return this.sortedActions.availableActions(actionIndexForSelection) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
fun selectAction(index: Int, actionType: Action.Type) { |
|
|
|
|
this.sortedActions.selectAction(index, actionType) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/*** |
|
|
|
|
* Sets the amount for the action at the provided [index] |
|
|
|
|
*/ |
|
|
|
|
fun setAmount(index: Int, amount: Double) { |
|
|
|
|
val computedAction = this.actionForIndex(index) |
|
|
|
|
Timber.d(">>> Sets $amount at index: $index, for action ${computedAction.action.type}") |
|
|
|
|
computedAction.setAmount(amount) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// /*** |
|
|
|
|
// * Creates a new street: |
|
|
|
|
// * - Adds a Street Header |
|
|
|
|
// * - Adds a Board if necessary |
|
|
|
|
// * - Adds empty actions for the remaining players |
|
|
|
|
// */ |
|
|
|
|
// private fun createStreet(street: Street) { |
|
|
|
|
// |
|
|
|
|
// val lastComputedAction = this.sortedActions.last() |
|
|
|
|
// val totalPotSize = lastComputedAction.totalPotSize |
|
|
|
|
// |
|
|
|
|
// addStreetHeader(this.rowRepresentables, street) |
|
|
|
|
// |
|
|
|
|
// val lastActionIndex = lastComputedAction.action.index |
|
|
|
|
// val isShowDown = street == Street.SUMMARY |
|
|
|
|
// activePositions(lastActionIndex, isShowDown).sortedBy { it.ordinal }.forEach { |
|
|
|
|
// |
|
|
|
|
// when (street) { |
|
|
|
|
// Street.SUMMARY -> { |
|
|
|
|
// this.rowRepresentables.add(PlayerCardsRow(it)) |
|
|
|
|
// } |
|
|
|
|
// else -> { |
|
|
|
|
// addNewEmptyAction(it, street, totalPotSize, lastRemainingStack(it, lastActionIndex)) |
|
|
|
|
// } |
|
|
|
|
// } |
|
|
|
|
// |
|
|
|
|
// } |
|
|
|
|
// } |
|
|
|
|
/*** |
|
|
|
|
* Returns the list of available actions at the selected index |
|
|
|
|
*/ |
|
|
|
|
fun availableActions() : Set<Action.Type> { |
|
|
|
|
return this.sortedActions.availableActions(this.actionIndexForSelection) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/*** |
|
|
|
|
* Sets an action at the selected index |
|
|
|
|
*/ |
|
|
|
|
fun actionSelected(action: Action.Type) { |
|
|
|
|
this.sortedActions.selectAction(this.actionIndexForSelection, action) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/*** |
|
|
|
|
* Returns a list of positions at the provided [index] |
|
|
|
|
*/ |
|
|
|
|
fun positionsAtIndex(index: Int): List<Position> { |
|
|
|
|
return this.sortedActions.positionsAtIndex(index) |
|
|
|
|
fun positionsForSelection(): List<Position> { |
|
|
|
|
return this.sortedActions.positionsAtIndex(this.actionIndexForSelection) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/*** |
|
|
|
|
* Returns the index of a ComputedAction given its [rowRepresentableIndex] |
|
|
|
|
*/ |
|
|
|
|
fun indexOfComputedAction(rowRepresentableIndex: Int) : Int { |
|
|
|
|
private fun indexOfComputedAction(rowRepresentableIndex: Int) : Int { |
|
|
|
|
val computedAction = this.rowRepresentables[rowRepresentableIndex] as ComputedAction |
|
|
|
|
return computedAction.action.index |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/*** |
|
|
|
|
* Looks for a row and a keyboard, i.e. a HHSelection, suitable for edition |
|
|
|
|
*/ |
|
|
|
|
fun findSelectionForEdition(index: Int): HHSelection? { |
|
|
|
|
val selection = this.getSelectionForFirstEditableRow(index) |
|
|
|
|
this.selectionLiveData.value = selection |
|
|
|
|
return selection |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/*** |
|
|
|
|
* Finds the index of the first incomplete action, if existing |
|
|
|
|
* If the same selection is the same than current, pass to the next row |
|
|
|
|
*/ |
|
|
|
|
fun findIndexForEdition(startIndex: Int): HHSelection? { |
|
|
|
|
private fun getSelectionForFirstEditableRow(startIndex: Int): HHSelection? { |
|
|
|
|
|
|
|
|
|
this.rowRepresentables.forEachIndexed { index, rowRepresentable -> |
|
|
|
|
|
|
|
|
|
@ -200,11 +198,10 @@ class HHBuilder : CardCentralizer, ActionListListener { |
|
|
|
|
* Returns the index, strictly superior to [actionIndexForSelection], |
|
|
|
|
* of the next action of the given [position] |
|
|
|
|
*/ |
|
|
|
|
fun nextActionIndex(actionIndexForSelection: Int, position: Position): Int { |
|
|
|
|
|
|
|
|
|
var i = actionIndexForSelection + 1 |
|
|
|
|
fun nextActionIndexForPosition(position: Position): Int { |
|
|
|
|
var i = this.actionIndexForSelection + 1 |
|
|
|
|
while (true) { |
|
|
|
|
val computedAction = this.actionForIndex(i) |
|
|
|
|
val computedAction = this.sortedActions[i] |
|
|
|
|
if (computedAction.position == position) { |
|
|
|
|
return this.rowRepresentables.indexOf(computedAction) |
|
|
|
|
} |
|
|
|
|
@ -213,12 +210,37 @@ class HHBuilder : CardCentralizer, ActionListListener { |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Amount |
|
|
|
|
|
|
|
|
|
/*** |
|
|
|
|
* Sets the typed amount in the relevant ComputedAction |
|
|
|
|
*/ |
|
|
|
|
fun amountValidated() { |
|
|
|
|
try { |
|
|
|
|
this.currentAmount?.toDouble()?.let { amount -> |
|
|
|
|
this.sortedActions.setAmount(this.actionIndexForSelection, amount) |
|
|
|
|
this.currentAmount = null |
|
|
|
|
} |
|
|
|
|
} catch (e: NumberFormatException) { |
|
|
|
|
Timber.w("Parsing exception: ${e.message}") |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/*** |
|
|
|
|
* Sets the current amount to null |
|
|
|
|
*/ |
|
|
|
|
fun clearAmount() { |
|
|
|
|
this.currentAmount = null |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Cards |
|
|
|
|
|
|
|
|
|
/*** |
|
|
|
|
* Adds a card with the selected [value] |
|
|
|
|
*/ |
|
|
|
|
fun cardValueSelected(value: Card.Value, currentSelection: HHSelection) { |
|
|
|
|
fun cardValueSelected(value: Card.Value) { |
|
|
|
|
this.lastValue = value |
|
|
|
|
val row = this.rowRepresentables[currentSelection.index] as CardsRow |
|
|
|
|
val row = this.rowRepresentables[this.currentSelection.index] as CardsRow |
|
|
|
|
row.valueSelected(value) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@ -226,9 +248,9 @@ class HHBuilder : CardCentralizer, ActionListListener { |
|
|
|
|
* Either affect the [suit] to the current card, |
|
|
|
|
* or create a Card with an empty value and the [suit] |
|
|
|
|
*/ |
|
|
|
|
fun cardSuitSelected(suit: Card.Suit, currentSelection: HHSelection) { |
|
|
|
|
fun cardSuitSelected(suit: Card.Suit) { |
|
|
|
|
|
|
|
|
|
val row = this.rowRepresentables[currentSelection.index] as CardsRow |
|
|
|
|
val row = this.rowRepresentables[this.currentSelection.index] as CardsRow |
|
|
|
|
row.suitSelected(suit) |
|
|
|
|
|
|
|
|
|
// TODO do we want to store the information right now ? |
|
|
|
|
@ -238,9 +260,9 @@ class HHBuilder : CardCentralizer, ActionListListener { |
|
|
|
|
/*** |
|
|
|
|
* Deletes all the card of the selected street |
|
|
|
|
*/ |
|
|
|
|
fun clearCards(currentSelection: HHSelection) { |
|
|
|
|
fun clearCards() { |
|
|
|
|
this.lastValue = null |
|
|
|
|
val row = this.rowRepresentables[currentSelection.index] as CardsRow |
|
|
|
|
val row = this.rowRepresentables[this.currentSelection.index] as CardsRow |
|
|
|
|
row.clear() |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@ -249,8 +271,8 @@ class HHBuilder : CardCentralizer, ActionListListener { |
|
|
|
|
* We don't want empty Card (value + suit), |
|
|
|
|
* so we delete the whole card if both information are null |
|
|
|
|
*/ |
|
|
|
|
fun deleteLastCardProperty(currentSelection: HHSelection) { |
|
|
|
|
val row = this.rowRepresentables[currentSelection.index] as CardsRow |
|
|
|
|
fun deleteLastCardProperty() { |
|
|
|
|
val row = this.rowRepresentables[this.currentSelection.index] as CardsRow |
|
|
|
|
row.deleteLastCardProperty() |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@ -258,7 +280,7 @@ class HHBuilder : CardCentralizer, ActionListListener { |
|
|
|
|
* When a card selection is ended, |
|
|
|
|
* sets the playerHandMaxCards with the number of cards set to the player |
|
|
|
|
*/ |
|
|
|
|
fun cardSelectionEnded(index: Int) { |
|
|
|
|
private fun cardSelectionEnded(index: Int) { |
|
|
|
|
val cardsRow = this.rowRepresentables[index] as CardsRow |
|
|
|
|
if (cardsRow is PlayerCardsRow) { |
|
|
|
|
this.playerHandMaxCards = cardsRow.cards.size |
|
|
|
|
@ -272,7 +294,7 @@ class HHBuilder : CardCentralizer, ActionListListener { |
|
|
|
|
*/ |
|
|
|
|
fun boardChanged(cards: List<Card>) { |
|
|
|
|
this.rowRepresentables.filterIsInstance<StreetCardsRow>().forEach { |
|
|
|
|
// it.cards = cards |
|
|
|
|
// it.cards = cards |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@ -283,6 +305,9 @@ class HHBuilder : CardCentralizer, ActionListListener { |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/*** |
|
|
|
|
* Uses the action list to create the list of RowRepresentables, displayed to the user |
|
|
|
|
*/ |
|
|
|
|
private fun createRowRepresentation() { |
|
|
|
|
val rows: MutableList<RowRepresentable> = mutableListOf() |
|
|
|
|
|
|
|
|
|
@ -314,11 +339,8 @@ class HHBuilder : CardCentralizer, ActionListListener { |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
this.rowRepresentables = rows |
|
|
|
|
this.listener?.rowRepresentablesCountChanged() |
|
|
|
|
this.rowsLiveData.value = rows |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/*** |
|
|
|
|
@ -382,9 +404,50 @@ class HHBuilder : CardCentralizer, ActionListListener { |
|
|
|
|
|
|
|
|
|
// Action List Listener |
|
|
|
|
|
|
|
|
|
/*** |
|
|
|
|
* Callback of the ActionListListener |
|
|
|
|
* Creates the row representation when the action list changes |
|
|
|
|
*/ |
|
|
|
|
override fun actionCountChanged() { |
|
|
|
|
this.createRowRepresentation() |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
fun amountChanged(amount: String?) { |
|
|
|
|
this.currentAmount = amount |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Row Representable Datasource |
|
|
|
|
|
|
|
|
|
override fun adapterRows(): List<RowRepresentable>? { |
|
|
|
|
return this.rowRepresentables |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
override fun rowRepresentableForPosition(position: Int): RowRepresentable? { |
|
|
|
|
return this.rowRepresentables[position] |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
override fun numberOfRows(): Int { |
|
|
|
|
return this.rowRepresentables.size |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
override fun viewTypeForPosition(position: Int): Int { |
|
|
|
|
return this.rowRepresentables[position].viewType |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
override fun isSelected(position: Int, row: RowRepresentable, tag: Int): Boolean { |
|
|
|
|
val currentSelection = this.selectionLiveData |
|
|
|
|
val isSelectedIndex = (position == currentSelection.value?.index) |
|
|
|
|
val isSelectedAction = (tag == currentSelection.value?.keyboard?.ordinal) |
|
|
|
|
return isSelectedIndex && isSelectedAction |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
fun cardSelectionEnded() { |
|
|
|
|
this.cardSelectionEnded(this.currentSelection.index) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// fun setBuilderListener(builderListener: BuilderListener) { |
|
|
|
|
// this.builder.setBuilderListener(builderListener) |
|
|
|
|
// } |
|
|
|
|
|
|
|
|
|
} |