diff options
Diffstat (limited to 'src/client/view.rs')
| -rw-r--r-- | src/client/view.rs | 103 |
1 files changed, 103 insertions, 0 deletions
diff --git a/src/client/view.rs b/src/client/view.rs new file mode 100644 index 0000000..3683ac2 --- /dev/null +++ b/src/client/view.rs | |||
| @@ -0,0 +1,103 @@ | |||
| 1 | //! What a frontend draws and what it can ask the core to do. | ||
| 2 | //! | ||
| 3 | //! The core owns state and navigation; adapters map input to `Command` and | ||
| 4 | //! render `View`. Terminal text lives in [`crate::client::tui`], not here. | ||
| 5 | |||
| 6 | use crate::client::games::roulette::{Cursor, Direction}; | ||
| 7 | use crate::client::games::traits::GameState; | ||
| 8 | use crate::roulette::{BetTarget, Bets}; | ||
| 9 | |||
| 10 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] | ||
| 11 | pub enum RoulettePhase { | ||
| 12 | Placing, | ||
| 13 | Spinning, | ||
| 14 | Result, | ||
| 15 | } | ||
| 16 | |||
| 17 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
| 18 | pub struct RouletteView { | ||
| 19 | pub bet_amount: u64, | ||
| 20 | pub balance: Option<i64>, | ||
| 21 | pub chip: u64, | ||
| 22 | pub bets: Bets, | ||
| 23 | pub cursor: Cursor, | ||
| 24 | pub phase: RoulettePhase, | ||
| 25 | pub number: Option<u8>, | ||
| 26 | pub color: Option<String>, | ||
| 27 | pub winnings: Option<u64>, | ||
| 28 | pub error: Option<String>, | ||
| 29 | } | ||
| 30 | |||
| 31 | impl RouletteView { | ||
| 32 | pub fn from_state(state: &GameState) -> Self { | ||
| 33 | let bets = state | ||
| 34 | .data | ||
| 35 | .get("bets") | ||
| 36 | .and_then(|raw| Bets::from_json(raw).ok()) | ||
| 37 | .unwrap_or_default(); | ||
| 38 | let chip = state | ||
| 39 | .data | ||
| 40 | .get("chip") | ||
| 41 | .and_then(|value| value.parse().ok()) | ||
| 42 | .unwrap_or(10); | ||
| 43 | let cursor = state | ||
| 44 | .data | ||
| 45 | .get("cursor") | ||
| 46 | .map(|raw| Cursor::parse(raw)) | ||
| 47 | .unwrap_or_default(); | ||
| 48 | let phase = match state.data.get("status").map(String::as_str) { | ||
| 49 | Some("spinning") => RoulettePhase::Spinning, | ||
| 50 | Some("result") => RoulettePhase::Result, | ||
| 51 | _ => RoulettePhase::Placing, | ||
| 52 | }; | ||
| 53 | let number = state.data.get("number").and_then(|value| value.parse().ok()); | ||
| 54 | let color = state.data.get("color").cloned(); | ||
| 55 | let winnings = state | ||
| 56 | .data | ||
| 57 | .get("winnings") | ||
| 58 | .and_then(|value| value.parse().ok()); | ||
| 59 | let balance = state | ||
| 60 | .data | ||
| 61 | .get("balance") | ||
| 62 | .and_then(|value| value.parse().ok()); | ||
| 63 | let error = state | ||
| 64 | .data | ||
| 65 | .get("error") | ||
| 66 | .cloned() | ||
| 67 | .filter(|message| !message.is_empty()); | ||
| 68 | |||
| 69 | Self { | ||
| 70 | bet_amount: state.bet_amount, | ||
| 71 | balance, | ||
| 72 | chip, | ||
| 73 | bets, | ||
| 74 | cursor, | ||
| 75 | phase, | ||
| 76 | number, | ||
| 77 | color, | ||
| 78 | winnings, | ||
| 79 | error, | ||
| 80 | } | ||
| 81 | } | ||
| 82 | } | ||
| 83 | |||
| 84 | /// Everything a frontend can draw. `Text` is the bridge for games that have | ||
| 85 | /// not been ported to a structured view yet. | ||
| 86 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
| 87 | pub enum View { | ||
| 88 | Roulette(RouletteView), | ||
| 89 | Text(Vec<String>), | ||
| 90 | } | ||
| 91 | |||
| 92 | /// Semantic input. Frontends turn keys and clicks into these. | ||
| 93 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
| 94 | pub enum Command { | ||
| 95 | MoveCursor(Direction), | ||
| 96 | PlaceBet, | ||
| 97 | PlaceBetAt(BetTarget), | ||
| 98 | ClearBets, | ||
| 99 | SetChip(u64), | ||
| 100 | AdjustChip(i64), | ||
| 101 | Spin, | ||
| 102 | Leave, | ||
| 103 | } | ||
