summaryrefslogtreecommitdiffstats
path: root/src/client/view.rs
diff options
context:
space:
mode:
authorsalmonik <salmonik@tuta.io>2026-11-01 17:58:03 +0100
committersalmonik <salmonik@tuta.io>2026-11-01 17:58:03 +0100
commit46202ee2e398ffd49febe6684f5c6a8648da600d (patch)
tree00631532b6b4805ddc8a728246787651dd7185f2 /src/client/view.rs
parentdocs: document DOWNLOAD_URL and the XDG reset path (diff)
downloadzagan-bet-46202ee2e398ffd49febe6684f5c6a8648da600d.tar.gz
zagan-bet-46202ee2e398ffd49febe6684f5c6a8648da600d.zip
v4.0.1: introduce Command/View and port roulette to the shared boundary
Diffstat (limited to '')
-rw-r--r--src/client/view.rs103
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
6use crate::client::games::roulette::{Cursor, Direction};
7use crate::client::games::traits::GameState;
8use crate::roulette::{BetTarget, Bets};
9
10#[derive(Debug, Clone, Copy, PartialEq, Eq)]
11pub enum RoulettePhase {
12 Placing,
13 Spinning,
14 Result,
15}
16
17#[derive(Debug, Clone, PartialEq, Eq)]
18pub 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
31impl 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)]
87pub 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)]
94pub enum Command {
95 MoveCursor(Direction),
96 PlaceBet,
97 PlaceBetAt(BetTarget),
98 ClearBets,
99 SetChip(u64),
100 AdjustChip(i64),
101 Spin,
102 Leave,
103}