| 1 | 1 | | import { useEffect, useState } from 'react'; |
| 2 | 2 | | import { pendingOptions } from '../game/ctl'; |
| 3 | + | import type { Prefs } from '../game/prefs'; |
| 3 | 4 | | import { labelOf, WIND_EN, WIND_NAMES, type Tile } from '../game/tiles'; |
| 4 | 5 | | import type { SeatId } from '../game/types'; |
| 5 | 6 | | import type { NetSession } from '../net/session'; |
| 6 | 7 | | import { seatFromUrl } from '../net/protocol'; |
| 7 | 8 | | import { Bi, CLAIM_LABEL } from './Bi'; |
| 9 | + | import { FullscreenToggle } from './FullscreenToggle'; |
| 8 | 10 | | import { Hand, type Throw } from './Hand'; |
| 9 | 11 | | import { TileView } from './TileView'; |
| 10 | 12 | | |
| 11 | 13 | | const SEATS: SeatId[] = [0, 1, 2, 3]; |
| 12 | 14 | | |
| 15 | + | interface CtlProps { |
| 16 | + | session: NetSession; |
| 17 | + | /** For the fullscreen button — a phone's address bar is a sixth of the |
| 18 | + | * height this screen has to hold a hand in. */ |
| 19 | + | prefs: Prefs; |
| 20 | + | onPrefs: (p: Prefs) => void; |
| 21 | + | } |
| 22 | + | |
| 13 | 23 | | /** |
| 14 | 24 | | * The phone at the party table: just your own tiles, held in landscape, with |
| 15 | 25 | | * the common screen doing all the talking. What it keeps of the full table is |
| ⋯ 2 unchanged lines |
| 18 | 28 | | * here, crosses the wire, and comes flying in from your edge of the shared |
| 19 | 29 | | * screen. |
| 20 | 30 | | */ |
| 21 | | - | export function Controller({ session }: { session: NetSession }) { |
| 31 | + | export function Controller({ session, prefs, onPrefs }: CtlProps) { |
| 22 | 32 | | const seat = session.mySeat; |
| 23 | 33 | | |
| 24 | 34 | | // The QR carries which seat it was stuck to; a phone that arrived some other |
| ⋯ 8 unchanged lines |
| 33 | 43 | | } |
| 34 | 44 | | }, [session, seat, asked]); |
| 35 | 45 | | |
| 36 | | - | if (seat === null) return <SeatPick session={session} joining={asked} />; |
| 37 | | - | return <SeatStrip session={session} seat={seat} />; |
| 46 | + | if (seat === null) { |
| 47 | + | return <SeatPick session={session} joining={asked} prefs={prefs} onPrefs={onPrefs} />; |
| 48 | + | } |
| 49 | + | return <SeatStrip session={session} seat={seat} prefs={prefs} onPrefs={onPrefs} />; |
| 38 | 50 | | } |
| 39 | 51 | | |
| 40 | | - | function SeatPick({ session, joining }: { session: NetSession; joining?: boolean }) { |
| 52 | + | function SeatPick({ session, joining, prefs, onPrefs }: CtlProps & { joining?: boolean }) { |
| 41 | 53 | | const seats = session.seats; |
| 42 | 54 | | const s = session.table.state; |
| 43 | 55 | | return ( |
| ⋯ 18 unchanged lines |
| 62 | 74 | | ); |
| 63 | 75 | | })} |
| 64 | 76 | | </div> |
| 77 | + | <FullscreenToggle prefs={prefs} onPrefs={onPrefs} /> |
| 65 | 78 | | </div> |
| 66 | 79 | | ); |
| 67 | 80 | | } |
| ⋯ 8 unchanged lines |
| 76 | 89 | | flung: boolean; |
| 77 | 90 | | } |
| 78 | 91 | | |
| 79 | | - | function SeatStrip({ session, seat }: { session: NetSession; seat: SeatId }) { |
| 92 | + | function SeatStrip({ session, seat, prefs, onPrefs }: CtlProps & { seat: SeatId }) { |
| 80 | 93 | | const table = session.table; |
| 81 | 94 | | const s = table.state; |
| 82 | 95 | | const p = s.players[seat]; |
| ⋯ 74 unchanged lines |
| 157 | 170 | | <button className="btn ghost sort" onClick={() => table.sortHand(seat)}> |
| 158 | 171 | | 理牌 |
| 159 | 172 | | </button> |
| 173 | + | <FullscreenToggle prefs={prefs} onPrefs={onPrefs} compact /> |
| 160 | 174 | | </div> |
| 161 | 175 | | |
| 162 | 176 | | <div className="ctl-actions"> |
| ⋯ 112 unchanged lines |