diff --git a/app/src/main/java/net/pokeranalytics/android/model/handhistory/BoardManager.kt b/app/src/main/java/net/pokeranalytics/android/model/handhistory/BoardManager.kt new file mode 100644 index 00000000..3223452d --- /dev/null +++ b/app/src/main/java/net/pokeranalytics/android/model/handhistory/BoardManager.kt @@ -0,0 +1,49 @@ +package net.pokeranalytics.android.model.handhistory + +import net.pokeranalytics.android.exceptions.PAIllegalStateException +import net.pokeranalytics.android.model.realm.handhistory.Card + +interface BoardChangedListener { + fun boardChanged() +} + +class BoardManager(cards: List, var listener: BoardChangedListener) { + + private var sortedBoardCards: MutableList = mutableListOf() + + val allCards: List + get() { + return this.sortedBoardCards + } + + init { + this.sortedBoardCards = cards.sortedBy { it.index }.toMutableList() + } + + fun add(card: Card) { + + if (this.sortedBoardCards.size == 5) { + throw PAIllegalStateException("Can't add anymore cards") + } + + card.index = this.sortedBoardCards.size + + this.sortedBoardCards.add(card) + this.listener.boardChanged() + } + + fun clearStreet(street: Street) { + this.sortedBoardCards.removeAll { it.street == street } + this.listener.boardChanged() + } + + fun lastCard(street: Street) : Card? { + return this.sortedBoardCards.lastOrNull { it.street == street } + } + + fun remove(card: Card) { + this.sortedBoardCards.remove(card) + this.listener.boardChanged() + } + +} \ No newline at end of file diff --git a/app/src/main/java/net/pokeranalytics/android/model/handhistory/HHBuilder.kt b/app/src/main/java/net/pokeranalytics/android/model/handhistory/HHBuilder.kt index 0efd832e..2a1a0d6f 100644 --- a/app/src/main/java/net/pokeranalytics/android/model/handhistory/HHBuilder.kt +++ b/app/src/main/java/net/pokeranalytics/android/model/handhistory/HHBuilder.kt @@ -3,12 +3,14 @@ package net.pokeranalytics.android.model.handhistory import net.pokeranalytics.android.R import net.pokeranalytics.android.exceptions.PAIllegalStateException 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.HandRowType import net.pokeranalytics.android.ui.modules.handhistory.views.StreetCardView import net.pokeranalytics.android.ui.view.RowRepresentable import net.pokeranalytics.android.ui.view.rowrepresentable.CustomizableRowRepresentable import timber.log.Timber +import kotlin.math.max enum class HHKeyboard { ACTION, @@ -19,7 +21,7 @@ enum class HHKeyboard { class HHSelection(var index: Int, var keyboard: HHKeyboard) -class HHBuilder { +class HHBuilder : BoardChangedListener { /*** * The hand history @@ -34,7 +36,13 @@ class HHBuilder { /*** * All actions sorted by index */ - private var sortedActions: List = mutableListOf() + private var sortedActions: MutableList = mutableListOf() + + /*** + * The board cards sorted by position + */ + private lateinit var boardManager: BoardManager +// private var sortedBoardCards: MutableList = mutableListOf() var positions: LinkedHashSet = linkedSetOf() @@ -82,6 +90,8 @@ class HHBuilder { } this.sortedActions = computedActions +// this.sortedBoardCards = this.handHistory.board.sortedBy { it.index }.toMutableList() + this.boardManager = BoardManager(this.handHistory.board, this) } /*** @@ -174,7 +184,7 @@ class HHBuilder { val dropedIndex = dropNextActionsIfNecessary(index) - this.updateFollowupActions() + this.updateFollowupActions(index) // Automatically sets action for the previous empty actions val modifiedActions = mutableListOf() @@ -196,10 +206,98 @@ class HHBuilder { * Adds, if necessary, new ComputedAction for players that needs to act * Also adds, if necessary, the Street separators and board selectors */ - private fun updateFollowupActions() { - // TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + private fun updateFollowupActions(index: Int) { + + val computedAction = this.actionForIndex(index) + val type = computedAction.action.type + + when (type?.isSignificant) { + true -> { // opens the action and requires action from other + addsFollowupActionsIfNecessary(index) + } + false -> { // closes the action, pass to next street if necessary + createNextStreetIfNecessary(index) + } + else -> { } + } + } + private fun addsFollowupActionsIfNecessary(index: Int) { + val computedAction = this.actionForIndex(index) + val indexPosition = computedAction.position + + val activePositions = unfoldedPositions(index) + activePositions.remove(indexPosition) + + // We want to remove positions that already have an action after [index] + for (i in index + 1 until this.sortedActions.size) { + val ca = this.actionForIndex(i) + activePositions.remove(ca.position) + } + + // Circularly adds an action for missing positions + val firstPositionAfterCurrent = max(0, activePositions.indexOfFirst { it.ordinal > indexPosition.ordinal }) + for (i in 0 until activePositions.size) { + val position = activePositions[(firstPositionAfterCurrent + i) % activePositions.size] + this.addNewEmptyAction(position, computedAction.totalPotSize, lastRemainingStack(position, index)) + } + + } + + + private fun lastRemainingStack(position: Position, index: Int): Double? { + return this.sortedActions.take(index).lastOrNull { it.position == position }?.playerRemainingStack + } + + private fun addNewEmptyAction(position: Position, currentPotSize: Double, remainingStack: Double?) { + val action = Action() + action.index = this.sortedActions.size + action.position = position.ordinal + val computedAction = ComputedAction(action, currentPotSize, remainingStack, position) + this.sortedActions.add(computedAction) + } + + private fun unfoldedPositions(index: Int) : MutableList { + val folds = this.sortedActions.take(index).filter { it.action.type == Action.Type.FOLD } + .map { it.position } + val allPositions = this.positions + allPositions.removeAll(folds) + return allPositions.toMutableList() + } + + private fun createNextStreetIfNecessary(index: Int) { + val computedAction = this.actionForIndex(index) + val currentStreet = this.actionForIndex(index).action.street // TODO is it useful? + + getLastSignificantAction(index)?.action?.index?.let { significantIndex -> + + val indexPosition = computedAction.position + + val activePositions = unfoldedPositions(index) + activePositions.remove(indexPosition) + for (i in significantIndex + 1 until this.sortedActions.size) { + val ca = this.sortedActions[i] + val type = ca.action.type + if (type != null && !type.isSignificant) { // Calls and folds + activePositions.remove(ca.position) + } + } + + if (activePositions.isEmpty()) { + createNextStreet(index) + } + + } + } + + private fun createNextStreet(index: Int) { + // TODO + } + + /*** + * Returns the list of empty actions before the action at the given [index] + */ private fun getPreviousEmptyActions(index: Int) : List { val street = this.actionForIndex(index).action.street return this.sortedActions.take(index).filter { it.action.street == street && it.action.type == null } @@ -216,6 +314,9 @@ class HHBuilder { return null } + /*** + * Returns the number of active players at the beginning of the street + */ private fun remainingActivePlayerCountAtStreetStart(index: Int) : Int { return 0 } @@ -301,6 +402,9 @@ class HHBuilder { return null } + /*** + * Returns all "CALL" ComputedAction between the [index] and the next significant action + */ private fun getNextCalls(index: Int) : List { val nextSignificantIndex = getNextSignificantAction(index)?.action?.index ?: lastIndexOfStreet(index) return this.sortedActions.filter { @@ -357,6 +461,10 @@ class HHBuilder { return streetActions.drop(index + 1).map { it.position } } + /*** + * Sets the number of players playing the hand + * Defines the appropriate positions for this player count + */ fun setNumberOfPlayers(playerCount: Int) { this.handHistory.numberOfPlayers = playerCount this.positions = Position.positionsPerPlayers(playerCount) @@ -405,6 +513,9 @@ class HHBuilder { return rows } + /*** + * Returns the [index] of a ComputedAction given its [rowRepresentableIndex] + */ fun indexOfComputedAction(rowRepresentableIndex: Int) : Int { val computedAction = this.currentRowRepresentables[rowRepresentableIndex] as ComputedAction return computedAction.action.index @@ -432,6 +543,10 @@ class HHBuilder { return null } + /*** + * 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 @@ -445,5 +560,84 @@ class HHBuilder { } } + /*** + * Adds a card with the selected [value] + */ + fun cardValueSelected(value: Card.Value, currentSelection: HHSelection) { + when (this.currentRowRepresentables[currentSelection.index]) { + is StreetCardView -> { + val card = Card.newInstance(value.value) + this.boardManager.add(card) + } + } + } + + /*** + * 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) { + + when (val row = this.currentRowRepresentables[currentSelection.index]) { + is StreetCardView -> { + + val addNewCard = this.boardManager.lastCard(row.street)?.let { + if (it.suit != null) { + true + } else { + it.suit = suit + false + } + } ?: true + + if (addNewCard) { + val card = Card.newInstance(suit = suit) + this.boardManager.add(card) + } + + } + } + } + + /*** + * Deletes all the card of the selected street + */ + fun clearCards(currentSelection: HHSelection) { + val row = this.currentRowRepresentables[currentSelection.index] + when (row) { + is StreetCardView -> { + this.boardManager.clearStreet(row.street) + } + } + + } + + /*** + * Delete the last property of the last Card of the selected street + * 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.currentRowRepresentables[currentSelection.index] + when (row) { + is StreetCardView -> { + this.boardManager.lastCard(row.street)?.let { card -> + if (card.value != null && card.suit != null) { + card.suit = null + } else { + this.boardManager.remove(card) + } + } + } + } + } + + override fun boardChanged() { + this.currentRowRepresentables.filterIsInstance().forEach { + it.cards = this.boardManager.allCards + } + } + } diff --git a/app/src/main/java/net/pokeranalytics/android/model/realm/handhistory/Action.kt b/app/src/main/java/net/pokeranalytics/android/model/realm/handhistory/Action.kt index 00407157..137c22cd 100644 --- a/app/src/main/java/net/pokeranalytics/android/model/realm/handhistory/Action.kt +++ b/app/src/main/java/net/pokeranalytics/android/model/realm/handhistory/Action.kt @@ -34,6 +34,14 @@ open class Action : RealmObject() { } } + val requiresOpponentDecision: Boolean + get() { + return when(this) { + CALL, CALL_ALLIN, FOLD -> false + else -> true + } + } + override val viewType: Int = RowViewType.TITLE_GRID.ordinal companion object { diff --git a/app/src/main/java/net/pokeranalytics/android/model/realm/handhistory/Card.kt b/app/src/main/java/net/pokeranalytics/android/model/realm/handhistory/Card.kt index f9db2a52..52d5d91b 100644 --- a/app/src/main/java/net/pokeranalytics/android/model/realm/handhistory/Card.kt +++ b/app/src/main/java/net/pokeranalytics/android/model/realm/handhistory/Card.kt @@ -7,7 +7,9 @@ import android.text.style.ForegroundColorSpan import io.realm.RealmObject import net.pokeranalytics.android.R import net.pokeranalytics.android.exceptions.PAIllegalStateException -import timber.log.Timber +import net.pokeranalytics.android.model.handhistory.Street +import net.pokeranalytics.android.ui.view.RowRepresentable +import net.pokeranalytics.android.ui.view.RowViewType interface CardProperty @@ -28,79 +30,109 @@ fun List.formatted(context: Context) : CharSequence? { open class Card : RealmObject() { companion object { - fun valueOf(value: Int, suit: Suit) : Card { + fun newInstance(value: Int? = null, suit: Suit? = null, index: Int = 0) : Card { val card = Card() - card.value = value - card.suit = suit - Timber.d("suit = ${card.suitIdentifier}") + value?.let { card.value = it } + suit?.let { card.suit = it} + card.index = index return card } } - class Value(var value: Int) : CardProperty { + class Value(var value: Int?) : CardProperty, RowRepresentable { companion object { - fun format(value: Int) : String { + val values: List by lazy { + val v = mutableListOf(Value(null)) // null for x + (2..14).forEach { v.add(Value(it)) } + v + } + + fun format(value: Int?) : String { return when(value) { - 0 -> "x" in 2..9 -> "$value" 10 -> "T" 11 -> "J" 12 -> "Q" 13 -> "K" 14 -> "A" - else -> throw PAIllegalStateException("card value '$value' not handled") + else -> "X" } - } } + override fun getDisplayName(context: Context): String { + return this.formatted + } + val formatted: String get() { return format(this.value) } + override val viewType: Int = RowViewType.TITLE_GRID.ordinal + } - enum class Suit(val value: String) : CardProperty { - UNDEFINED("x"), + enum class Suit(val value: String) : CardProperty, RowRepresentable { SPADES("♠︎"), HEART("♥︎"), DIAMOND("♦︎"), CLOVER("♣︎"); + companion object { + fun format(suit: Suit?) : String { + return suit?.value ?: "x" + } + fun color(suit: Suit?) : Int { + return suit?.color ?: R.color.white + } + } + val color: Int get() { return when (this) { - UNDEFINED -> R.color.white SPADES -> R.color.white_dark HEART -> R.color.red DIAMOND -> R.color.diamond CLOVER -> R.color.clover } } + + override fun getDisplayName(context: Context): String { + return this.value + } + + override val viewType: Int = RowViewType.TITLE_GRID.ordinal + } /*** * The card value: 2..A * 0: undefined */ - var value: Int = 0 + var value: Int? = null + /*** + * Returns the formatted value of the card + */ val formattedValue: String get() { return Value.format(this.value) } /*** - * The card suit: heart, spades... + * The card suit identifier: heart, spades... */ - var suitIdentifier: Int = 0 + var suitIdentifier: Int? = null - var suit: Suit + /*** + * Returns the suit of the card + */ + var suit: Suit? get() { - return Suit.values()[this.suitIdentifier] + return this.suitIdentifier?.let { Suit.values()[it] } } set(value) { - this.suitIdentifier = value.ordinal + this.suitIdentifier = value?.ordinal } /*** @@ -108,11 +140,24 @@ open class Card : RealmObject() { */ var index: Int = 0 + val street: Street + get() { + return when (index) { + in 0..2 -> Street.FLOP + 3 -> Street.TURN + 4 -> Street.RIVER + else -> throw PAIllegalStateException("Card doesn't belong to any street") + } + } + + /*** + * Formats the Card into a Spannable String with the appropriate color + */ fun formatted(context: Context) : SpannableString { - val spannable = SpannableString(this.formattedValue + this.suit.value) + val spannable = SpannableString(this.formattedValue + Suit.format(this.suit)) spannable.setSpan( - ForegroundColorSpan(context.getColor(this.suit.color)), + ForegroundColorSpan(context.getColor(Suit.color(this.suit))), 0, spannable.length, SpannableString.SPAN_EXCLUSIVE_EXCLUSIVE diff --git a/app/src/main/java/net/pokeranalytics/android/model/realm/handhistory/HandHistory.kt b/app/src/main/java/net/pokeranalytics/android/model/realm/handhistory/HandHistory.kt index b662177f..dc578a96 100644 --- a/app/src/main/java/net/pokeranalytics/android/model/realm/handhistory/HandHistory.kt +++ b/app/src/main/java/net/pokeranalytics/android/model/realm/handhistory/HandHistory.kt @@ -124,8 +124,8 @@ open class HandHistory : RealmObject(), RowRepresentable, Identifiable, Filterab } - fun cardsForStreet(street: Street): List { - return this.board.sortedBy { it.index }.drop(street.totalBoardCards) + fun cardsForStreet(street: Street): MutableList { + return this.board.sortedBy { it.index }.take(street.totalBoardCards).toMutableList() } } \ No newline at end of file diff --git a/app/src/main/java/net/pokeranalytics/android/ui/modules/handhistory/HandHistoryAdapter.kt b/app/src/main/java/net/pokeranalytics/android/ui/modules/handhistory/HandHistoryAdapter.kt index 0ee772da..5fc3b9ef 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/modules/handhistory/HandHistoryAdapter.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/modules/handhistory/HandHistoryAdapter.kt @@ -282,6 +282,8 @@ class HandHistoryAdapter( override fun onBind(position: Int, row: RowRepresentable, adapter: RecyclerAdapter) { + this.currentPosition = position + val streetCardView = row as StreetCardView val street = streetCardView.street @@ -290,7 +292,8 @@ class HandHistoryAdapter( flopEditText.isFocusable = (street == Street.FLOP) flopEditText.isVisible = true - val text = streetCardView.cards.take(3).formatted(itemView.context) + val flop = streetCardView.cards.take(3) + val text = flop.formatted(itemView.context) flopEditText.setText(text) } diff --git a/app/src/main/java/net/pokeranalytics/android/ui/modules/handhistory/HandHistoryFragment.kt b/app/src/main/java/net/pokeranalytics/android/ui/modules/handhistory/HandHistoryFragment.kt index 7d11d523..7d07fdf9 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/modules/handhistory/HandHistoryFragment.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/modules/handhistory/HandHistoryFragment.kt @@ -66,7 +66,7 @@ class HandHistoryFragment : RealmFragment(), RowRepresentableDataSource, RowRepr initUI() this.edit() - this.model.currentSelection.value?.index?.let { + this.model.selectionLiveData.value?.index?.let { Timber.d(">>>> attempt to retrieveEditTextInputConnection") this.retrieveEditTextInputConnection(it) } @@ -84,7 +84,7 @@ class HandHistoryFragment : RealmFragment(), RowRepresentableDataSource, RowRepr } this.model.setBuilder(builder) - this.rows = this.model.builder.value?.rowRepresentables() ?: listOf() + this.rows = this.model.builderLiveData.value?.rowRepresentables() ?: listOf() } @@ -108,7 +108,7 @@ class HandHistoryFragment : RealmFragment(), RowRepresentableDataSource, RowRepr adapter = handHistoryAdapter } - this.model.currentSelection.observeForever { selection -> + this.model.selectionLiveData.observeForever { selection -> selection?.let { Timber.d("Current selection is ${selection.index} / ${selection.keyboard}") retrieveEditTextInputConnection(selection.index) @@ -129,7 +129,7 @@ class HandHistoryFragment : RealmFragment(), RowRepresentableDataSource, RowRepr // At first, the selection is defined before the holder is bound, // so we retrieve the editText inputConnection once the recycler view has been rendered this.recyclerView.viewTreeObserver.addOnGlobalLayoutListener { - this.model.currentSelection.value?.index?.let { + this.model.selectionLiveData.value?.index?.let { retrieveEditTextInputConnection(it) } } @@ -162,7 +162,7 @@ class HandHistoryFragment : RealmFragment(), RowRepresentableDataSource, RowRepr } private fun findNextActionToEdit() { - val selection = this.model.currentSelection.value + val selection = this.model.selectionLiveData.value val index = selection?.index ?: throw PAIllegalStateException("Request next with no selection") this.findNextActionToEdit(index, selection.keyboard) } @@ -201,16 +201,14 @@ class HandHistoryFragment : RealmFragment(), RowRepresentableDataSource, RowRepr return } - this.model.currentSelection.value?.index?.let { oldIndex -> + this.model.selectionLiveData.value?.index?.let { oldIndex -> refreshCells(oldIndex) } - this.model.currentSelection.value = HHSelection(position, HHKeyboard.values()[tag]) - // scrolls to selected position this.recyclerView.smoothScrollToPosition(position) - val keyboard = when (row) { + val keyboard: HHKeyboard = when (row) { is ComputedAction -> { when (tag) { HHKeyboard.ACTION.ordinal -> HHKeyboard.ACTION @@ -225,15 +223,18 @@ class HandHistoryFragment : RealmFragment(), RowRepresentableDataSource, RowRepr is StreetCardView -> { HHKeyboard.CARD } - else -> null + else -> throw PAIllegalStateException("unmanaged row type: $row") } + + this.model.selectionLiveData.value = HHSelection(position, keyboard) + Timber.d("row $position selected, show keyboard = $keyboard") - keyboard?.let { this.keyboard.show(keyboard) } + this.keyboard.show(keyboard) } override fun onRowDeselected(position: Int, row: RowRepresentable) { - this.model.currentSelection.value = null + this.model.selectionLiveData.value = null this.model.currentAmount = null } @@ -242,7 +243,7 @@ class HandHistoryFragment : RealmFragment(), RowRepresentableDataSource, RowRepr } override fun isSelected(position: Int, row: RowRepresentable, tag: Int): Boolean { - val currentSelection = this.model.currentSelection + val currentSelection = this.model.selectionLiveData val isSelectedIndex = (position == currentSelection.value?.index) val isSelectedAction = (tag == currentSelection.value?.keyboard?.ordinal) // Timber.d("position = $position, tag = $tag, current index = ${currentSelection?.index}, kb = ${currentSelection?.keyboard}") @@ -264,9 +265,9 @@ class HandHistoryFragment : RealmFragment(), RowRepresentableDataSource, RowRepr this.findNextActionToEdit() } - override fun cardValueSelected(value: Int) { + override fun cardValueSelected(value: Card.Value) { this.model.cardValueSelected(value) - this.handHistoryAdapter.notifyDataSetChanged() + this.handHistoryAdapter.notifyItemChanged(this.model.currentSelection.index) // TODO add test about number of cards before selecting next action? // this.findNextActionToEdit() @@ -274,12 +275,26 @@ class HandHistoryFragment : RealmFragment(), RowRepresentableDataSource, RowRepr override fun cardSuitSelected(suit: Card.Suit) { this.model.cardSuitSelected(suit) - this.handHistoryAdapter.notifyDataSetChanged() + this.handHistoryAdapter.notifyItemChanged(this.model.currentSelection.index) // TODO add test about number of cards? // this.findNextActionToEdit() } + override fun clearCards() { + this.model.clearCards() + this.handHistoryAdapter.notifyItemChanged(this.model.currentSelection.index) + } + + override fun cardSelectionEnded() { +// TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + } + + override fun cardBackSpaceSelected() { + this.model.deleteLastCardProperty() + this.handHistoryAdapter.notifyItemChanged(this.model.currentSelection.index) + } + override fun amountValidated() { Timber.d(">>> amount validated") this.model.amountValidated() @@ -293,9 +308,9 @@ class HandHistoryFragment : RealmFragment(), RowRepresentableDataSource, RowRepr } override fun closeKeyboard() { - this.model.currentSelection.value?.index?.let { + this.model.selectionLiveData.value?.index?.let { this.handHistoryAdapter.notifyItemChanged(it) - this.model.currentSelection.value = null + this.model.selectionLiveData.value = null } this.keyboard?.hide() } @@ -320,7 +335,7 @@ class HandHistoryFragment : RealmFragment(), RowRepresentableDataSource, RowRepr } private fun refreshCurrentRow() { - this.model.currentSelection.value?.index?.let { + this.model.selectionLiveData.value?.index?.let { Timber.d("refreshes row at index = $it") this.handHistoryAdapter.notifyItemChanged(it) } diff --git a/app/src/main/java/net/pokeranalytics/android/ui/modules/handhistory/HandHistoryViewModel.kt b/app/src/main/java/net/pokeranalytics/android/ui/modules/handhistory/HandHistoryViewModel.kt index bc7c7387..c9bd097f 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/modules/handhistory/HandHistoryViewModel.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/modules/handhistory/HandHistoryViewModel.kt @@ -14,51 +14,45 @@ import timber.log.Timber class HandHistoryViewModel : ViewModel() { + var builderLiveData = MutableLiveData() + + val builder: HHBuilder + get() { + return this.builderLiveData.value ?: throw PAIllegalStateException("Builder not found") + } + var isEdited = true - var currentSelection: MutableLiveData = MutableLiveData() + var selectionLiveData: MutableLiveData = MutableLiveData() -// var currentSelection: HHSelection? = null -// set(value) { -// field = value -// value?.let { -// Timber.d("Current selection is ${it.index} / ${it.keyboard}") -// } ?: run { -// Timber.d("No selection") -// } -// } + val currentSelection: HHSelection + get() { return selectionLiveData.value ?: throw PAIllegalStateException("No selection") } var currentAmount: String? = null var lastCardPropertySelection: CardProperty? = null - var builder = MutableLiveData() - fun setBuilder(builder: HHBuilder) { - this.builder.value = builder - } - - fun test() { -// this.builder. + this.builderLiveData.value = builder } private val actionIndexForSelection: Int get() { - this.currentSelection.value?.let { selection -> - return builder.value?.indexOfComputedAction(selection.index) ?: throw PAIllegalStateException("No builder") - } ?: throw PAIllegalStateException("No selection") + return this.builder.indexOfComputedAction(currentSelection.index) } - fun actionSelected(action: Action.Type) : List? { - builder.value?.let { - return it.selectAction(this.actionIndexForSelection, action) - } ?: throw PAIllegalStateException("Builder not found") + // Action + + fun actionSelected(action: Action.Type): List? { + return this.builder.selectAction(this.actionIndexForSelection, action) } + // Amount + fun amountValidated() { try { this.currentAmount?.toDouble()?.let { amount -> - builder.value?.setAmount(this.actionIndexForSelection, amount) + builderLiveData.value?.setAmount(this.actionIndexForSelection, amount) this.currentAmount = null } } catch (e: NumberFormatException) { @@ -67,29 +61,31 @@ class HandHistoryViewModel : ViewModel() { } fun clearAmount() { - builder.value?.clearAmount(this.actionIndexForSelection) + builderLiveData.value?.clearAmount(this.actionIndexForSelection) this.currentAmount = null } - fun cardValueSelected(value: Int) { + // Cards - this.currentSelection.value?.let { selection -> - selection.index - // get the appropriate card list, board or player's hand and give the information - } + fun cardValueSelected(value: Card.Value) { + this.builder.cardValueSelected(value, this.currentSelection) + } + + fun cardSuitSelected(suit: Card.Suit) { + this.builder.cardSuitSelected(suit, this.currentSelection) + } - TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + fun clearCards() { + this.builder.clearCards(this.currentSelection) } - fun cardSuitSelected(suit: Card.Suit) { - TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + fun deleteLastCardProperty() { + this.builder.deleteLastCardProperty(this.currentSelection) } - fun findIndexForEdition(startIndex: Int, keyboard: HHKeyboard? = null) : HHKeyboard? { - builder.value?.let { builder -> - this.currentSelection.value = builder.findIndexForEdition(startIndex, keyboard) - return currentSelection.value?.keyboard - } ?: throw PAIllegalStateException("Builder not defined") + fun findIndexForEdition(startIndex: Int, keyboard: HHKeyboard? = null): HHKeyboard? { + this.selectionLiveData.value = this.builder.findIndexForEdition(startIndex, keyboard) + return selectionLiveData.value?.keyboard } fun amountChanged(amount: String?) { @@ -97,15 +93,11 @@ class HandHistoryViewModel : ViewModel() { } fun positionsForSelection(): List { - this.builder.value?.let { - return it.positionsAtIndex(this.actionIndexForSelection) - } ?: throw PAIllegalStateException("Builder not defined") + return this.builder.positionsAtIndex(this.actionIndexForSelection) } fun nextActionIndexForPosition(position: Position): Int { - this.builder.value?.let { - return it.nextActionIndex(this.actionIndexForSelection, position) - } ?: throw PAIllegalStateException("Builder not defined") + return this.builder.nextActionIndex(this.actionIndexForSelection, position) } } \ No newline at end of file diff --git a/app/src/main/java/net/pokeranalytics/android/ui/modules/handhistory/views/CardSuitAdapter.kt b/app/src/main/java/net/pokeranalytics/android/ui/modules/handhistory/views/CardSuitAdapter.kt new file mode 100644 index 00000000..d69f754b --- /dev/null +++ b/app/src/main/java/net/pokeranalytics/android/ui/modules/handhistory/views/CardSuitAdapter.kt @@ -0,0 +1,62 @@ +package net.pokeranalytics.android.ui.modules.handhistory.views + +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import net.pokeranalytics.android.R +import net.pokeranalytics.android.model.realm.handhistory.Card +import net.pokeranalytics.android.ui.adapter.BindableHolder +import net.pokeranalytics.android.ui.adapter.RecyclerAdapter +import net.pokeranalytics.android.ui.adapter.RowRepresentableDataSource +import net.pokeranalytics.android.ui.adapter.RowRepresentableDelegate +import net.pokeranalytics.android.ui.view.RowRepresentable +import net.pokeranalytics.android.ui.view.RowViewType +import net.pokeranalytics.android.ui.view.holder.RowViewHolder +import timber.log.Timber + +class CardSuitAdapter(var keyboardListener: KeyboardListener) : + RecyclerView.Adapter(), + RowRepresentableDataSource, RowRepresentableDelegate, RecyclerAdapter { + + override var dataSource: RowRepresentableDataSource = this + override var delegate: RowRepresentableDelegate? = this + + private val suits = Card.Suit.values().toList() + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { + val layout = LayoutInflater.from(parent.context).inflate(R.layout.row_cell, parent, false) + return RowViewHolder(layout) + } + + override fun getItemCount(): Int { + return this.suits.size + } + + override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { + this.rowRepresentableForPosition(position)?.let { + (holder as BindableHolder).onBind(position, it, this) + } + } + + override fun adapterRows(): List? { + return this.suits + } + + override fun rowRepresentableForPosition(position: Int): RowRepresentable? { + return this.suits[position] + } + + override fun numberOfRows(): Int { + return this.suits.size + } + + override fun viewTypeForPosition(position: Int): Int { + return RowViewType.TITLE_GRID.ordinal + } + + override fun onRowSelected(position: Int, row: RowRepresentable, tag: Int) { + Timber.d("/////onRowSelected") + keyboardListener.cardSuitSelected(this.suits[position]) + } + +} \ No newline at end of file diff --git a/app/src/main/java/net/pokeranalytics/android/ui/modules/handhistory/views/CardValueAdapter.kt b/app/src/main/java/net/pokeranalytics/android/ui/modules/handhistory/views/CardValueAdapter.kt new file mode 100644 index 00000000..620c5328 --- /dev/null +++ b/app/src/main/java/net/pokeranalytics/android/ui/modules/handhistory/views/CardValueAdapter.kt @@ -0,0 +1,60 @@ +package net.pokeranalytics.android.ui.modules.handhistory.views + +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import net.pokeranalytics.android.R +import net.pokeranalytics.android.model.realm.handhistory.Card +import net.pokeranalytics.android.ui.adapter.BindableHolder +import net.pokeranalytics.android.ui.adapter.RecyclerAdapter +import net.pokeranalytics.android.ui.adapter.RowRepresentableDataSource +import net.pokeranalytics.android.ui.adapter.RowRepresentableDelegate +import net.pokeranalytics.android.ui.view.RowRepresentable +import net.pokeranalytics.android.ui.view.RowViewType +import net.pokeranalytics.android.ui.view.holder.RowViewHolder +import timber.log.Timber + +class CardValueAdapter(var keyboardListener: KeyboardListener) : + RecyclerView.Adapter(), + RowRepresentableDataSource, RowRepresentableDelegate, RecyclerAdapter { + + override var dataSource: RowRepresentableDataSource = this + override var delegate: RowRepresentableDelegate? = this + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { + val layout = LayoutInflater.from(parent.context).inflate(R.layout.row_cell, parent, false) + return RowViewHolder(layout) + } + + override fun getItemCount(): Int { + return Card.Value.values.size + } + + override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { + this.rowRepresentableForPosition(position)?.let { + (holder as BindableHolder).onBind(position, it, this) + } + } + + override fun adapterRows(): List? { + return Card.Value.values + } + + override fun rowRepresentableForPosition(position: Int): RowRepresentable? { + return Card.Value.values[position] + } + + override fun numberOfRows(): Int { + return Card.Value.values.size + } + + override fun viewTypeForPosition(position: Int): Int { + return RowViewType.TITLE_GRID.ordinal + } + + override fun onRowSelected(position: Int, row: RowRepresentable, tag: Int) { + Timber.d("/////onRowSelected") + keyboardListener.cardValueSelected(Card.Value.values[position]) + } + +} \ No newline at end of file diff --git a/app/src/main/java/net/pokeranalytics/android/ui/modules/handhistory/views/KeyboardCardView.kt b/app/src/main/java/net/pokeranalytics/android/ui/modules/handhistory/views/KeyboardCardView.kt index 25eebdbb..e32db42f 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/modules/handhistory/views/KeyboardCardView.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/modules/handhistory/views/KeyboardCardView.kt @@ -1,7 +1,67 @@ package net.pokeranalytics.android.ui.modules.handhistory.views import android.content.Context +import android.view.LayoutInflater +import androidx.recyclerview.widget.GridLayoutManager +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView +import kotlinx.android.synthetic.main.view_hand_keyboard_action.view.closeButton +import kotlinx.android.synthetic.main.view_hand_keyboard_card.view.* +import net.pokeranalytics.android.R +import net.pokeranalytics.android.exceptions.PAIllegalStateException class KeyboardCardView(context: Context) : AbstractKeyboardView(context) { + private lateinit var cardValueAdapter: CardValueAdapter + private lateinit var cardSuitAdapter: CardSuitAdapter + + init { + + LayoutInflater.from(context) + .inflate(R.layout.view_hand_keyboard_card, this, true) + + this.nextButton.setOnClickListener { + this.keyboardListener?.cardSelectionEnded() + } + + this.clearButton.setOnClickListener { + this.keyboardListener?.clearCards() + } + + this.closeButton.setOnClickListener { + this.keyboardListener?.closeKeyboard() + } + + this.backSpaceButton.setOnClickListener { + this.keyboardListener?.cardBackSpaceSelected() + } + + } + + override fun onListenerSet(listener: KeyboardListener) { + + // Position Recycler + this.keyboardListener?.let { + this.cardValueAdapter = CardValueAdapter(it) + this.cardSuitAdapter = CardSuitAdapter(it) + } ?: throw PAIllegalStateException("keyboard listener not set") + + val cardValueViewManager = GridLayoutManager(this.context, 7) + this.valueRecyclerView.apply { + setHasFixedSize(true) + layoutManager = cardValueViewManager + adapter = cardValueAdapter +// addItemDecoration(GridSpacingItemDecoration(spanCount, spacing, includeEdge)) + } + + val cardSuitViewManager = LinearLayoutManager(context, RecyclerView.HORIZONTAL, false) + this.suitRecyclerView.apply { + setHasFixedSize(true) + layoutManager = cardSuitViewManager + adapter = cardSuitAdapter +// addItemDecoration(GridSpacingItemDecoration(spanCount, spacing, includeEdge)) + } + + } + } \ No newline at end of file diff --git a/app/src/main/java/net/pokeranalytics/android/ui/modules/handhistory/views/KeyboardContainer.kt b/app/src/main/java/net/pokeranalytics/android/ui/modules/handhistory/views/KeyboardContainer.kt index c98c5ac6..b627857a 100644 --- a/app/src/main/java/net/pokeranalytics/android/ui/modules/handhistory/views/KeyboardContainer.kt +++ b/app/src/main/java/net/pokeranalytics/android/ui/modules/handhistory/views/KeyboardContainer.kt @@ -17,10 +17,13 @@ import net.pokeranalytics.android.model.realm.handhistory.Card interface KeyboardListener { fun actionSelected(action: Action.Type) fun amountChanged(amount: String?) - fun cardValueSelected(value: Int) - fun cardSuitSelected(suit: Card.Suit) fun amountValidated() fun clearAmount() + fun cardValueSelected(value: Card.Value) + fun cardSuitSelected(suit: Card.Suit) + fun clearCards() + fun cardBackSpaceSelected() + fun cardSelectionEnded() fun closeKeyboard() fun positionSelected(position: Position) } @@ -66,7 +69,7 @@ class KeyboardContainer(context: Context, attrs: AttributeSet?) : FrameLayout(co val height = this.height.toFloat() this.translationY = height this.visibility = View.VISIBLE - this.animate().translationY(0.0f).setDuration(250).start(); + this.animate().translationY(0.0f).setDuration(250).start() } } @@ -80,19 +83,6 @@ class KeyboardContainer(context: Context, attrs: AttributeSet?) : FrameLayout(co show() -// var view = this.keyboards[type] -// -// if (view == null) { -// view = when(type) { -// HHKeyboard.ACTION -> { KeyboardActionView(context) } -// HHKeyboard.AMOUNT -> { KeyboardAmountView(context) } -// HHKeyboard.CARD -> { KeyboardCardView(context) } -// } -// view.keyboardListener = this.keyboardListener -// this.keyboards[type] = view -// addView(view) -// } - this.keyboards[type]?.let { show(it) } ?: run { diff --git a/app/src/main/res/layout/view_hand_keyboard_card.xml b/app/src/main/res/layout/view_hand_keyboard_card.xml index 0a33efbe..42b09d4c 100644 --- a/app/src/main/res/layout/view_hand_keyboard_card.xml +++ b/app/src/main/res/layout/view_hand_keyboard_card.xml @@ -41,7 +41,7 @@ android:layout_weight="2"/> + + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index b3ba08b4..60572385 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -787,5 +787,6 @@ bet raise allin +