1
0

Improved sizing of game UI for phones.

Signed-off-by: James Ketrenos <james_eikona@ketrenos.com>
This commit is contained in:
James Ketrenos 2022-02-04 15:45:59 -08:00
parent b8195b6b8b
commit 38c6f4069d
4 changed files with 113 additions and 127 deletions

View File

@ -4,6 +4,7 @@
position: relative; position: relative;
flex: 1; flex: 1;
align-items: stretch; align-items: stretch;
margin-right: 40vw;
} }
/* Offset 'BorderBox' such that 0,0 is the center /* Offset 'BorderBox' such that 0,0 is the center

View File

@ -119,15 +119,16 @@
} }
.Game { .Game {
display: inline-flex; display: flex;
position: absolute;
flex-direction: column; flex-direction: column;
box-sizing: border-box; box-sizing: border-box;
width: 40vw;
max-height: 100vh; max-height: 100vh;
overflow: hidden; overflow: hidden;
max-width: 40vw; max-width: 40vw;
z-index: 100; z-index: 100;
padding: 0.5em; padding: 0.5em;
right: 0px;
} }
.Game > * { .Game > * {
@ -139,48 +140,61 @@
margin-bottom: 0.5em; margin-bottom: 0.5em;
} }
.Game .lobby { .Game.lobby {
max-width: 100vw;
width: 100vw; width: 100vw;
position: absolute;
} }
/*
* Game
* Message
* Players
* Chat
* Action
*/
.Chat { .Chat {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
flex: 1; flex-grow: 1;
padding: 0.5em; padding: 0.5em;
} }
.Chat > * { .ChatList {
/* for Firefox */ /* for Firefox */
min-height: 0; min-height: 0;
} flex-grow: 1;
flex-shrink: 1;
#ChatList {
flex: 1;
overflow: auto; overflow: auto;
scroll-behavior: smooth; scroll-behavior: smooth;
align-items: flex-start; align-items: flex-start;
} }
#ChatList .MuiListItem-gutters { .ChatInput {
flex-grow: 0;
flex-shrink: 0;
}
.ChatList .MuiListItem-gutters {
padding: 2px 0 2px 0; padding: 2px 0 2px 0;
} }
#ChatList .MuiTypography-body1 { .ChatList .MuiTypography-body1 {
font-size: 0.8rem; font-size: 0.8rem;
} }
#ChatList .MuiTypography-body2 { .ChatList .MuiTypography-body2 {
font-size: 0.7rem; font-size: 0.7rem;
} }
#ChatList .MuiListItemText-multiline { .ChatList .MuiListItemText-multiline {
margin-top: 0; margin-top: 0;
margin-bottom: 0; margin-bottom: 0;
padding: 4px 0px 4px 4px; padding: 4px 0px 4px 4px;
} }
#ChatList .PlayerColor { .ChatList .PlayerColor {
width: 1em; width: 1em;
height: 1em; height: 1em;
padding: 0; padding: 0;
@ -188,6 +202,8 @@
} }
.Players { .Players {
flex: 1 0;
overflow: hidden;
padding: 0.5em; padding: 0.5em;
user-select: none; user-select: none;
} }
@ -311,6 +327,7 @@
.Action { .Action {
display: flex; display: flex;
flex: 1 0;
align-items: center; align-items: center;
justify-content: space-evenly; justify-content: space-evenly;
background-color: rgba(16, 16, 16, 0.25); background-color: rgba(16, 16, 16, 0.25);
@ -340,9 +357,9 @@ button {
} }
.Message { .Message {
display: inline; display: inline-block;
flex: 1 0;
justify-content: left; justify-content: left;
background-color: rgba(224, 224, 224);
text-align: left; text-align: left;
font-size: 12pt; font-size: 12pt;
padding: 0.5em; padding: 0.5em;

View File

@ -156,7 +156,7 @@ class Resource extends React.Component {
} }
}; };
const Chat = ({ table, promoteGameState }) => { const Chat = ({ table }) => {
const [lastTop, setLastTop] = useState(0), const [lastTop, setLastTop] = useState(0),
[autoScroll, setAutoscroll] = useState(true), [autoScroll, setAutoscroll] = useState(true),
[scrollTime, setScrollTime] = useState(0); [scrollTime, setScrollTime] = useState(0);
@ -170,12 +170,8 @@ const Chat = ({ table, promoteGameState }) => {
setAutoscroll(true); setAutoscroll(true);
} }
promoteGameState({ table.sendChat(event.target.value);
chat: {
player: table.game.color ? table.game.color : undefined,
message: event.target.value
}
});
event.target.value = ""; event.target.value = "";
} }
}; };
@ -230,11 +226,11 @@ const Chat = ({ table, promoteGameState }) => {
const messages = table.game && table.game.chat.map((item, index) => { const messages = table.game && table.game.chat.map((item, index) => {
/* If the date is in the future, set it to now */ /* If the date is in the future, set it to now */
const name = getPlayerName(table.game.sessions, item.from), const name = item.from ? item.from : item.color,
from = name ? `${name}, ` : ''; from = name ? `${name}, ` : '';
return ( return (
<ListItem key={`msg-${item.date}`}> <ListItem key={`msg-${item.date}`}>
<PlayerColor color={item.from}/> <PlayerColor color={item.color}/>
<ListItemText primary={item.message} <ListItemText primary={item.message}
secondary={(<>{from} secondary={(<>{from}
<Moment fromNow date={item.date > Date.now() ? <Moment fromNow date={item.date > Date.now() ?
@ -247,10 +243,10 @@ const Chat = ({ table, promoteGameState }) => {
return ( return (
<Paper className="Chat"> <Paper className="Chat">
<List id="ChatList" onScroll={chatScroll}> <List className="ChatList" id="ChatList" onScroll={chatScroll}>
{ messages } { messages }
</List> </List>
<TextField className="chatInput" <TextField className="ChatInput"
disabled={!name} disabled={!name}
onChange={chatInput} onChange={chatInput}
onKeyPress={chatKeyPress} onKeyPress={chatKeyPress}
@ -375,7 +371,6 @@ const PlayerName = ({table}) => {
} }
const sendName = () => { const sendName = () => {
console.log(`Send: ${name}`);
if (name !== table.game.name) { if (name !== table.game.name) {
table.setPlayerName(name); table.setPlayerName(name);
} else { } else {
@ -417,7 +412,6 @@ const getPlayerName = (sessions, color) => {
* player's active item in the game */ * player's active item in the game */
const Players = ({ table }) => { const Players = ({ table }) => {
const toggleSelected = (key) => { const toggleSelected = (key) => {
console.log('toggle');
table.setSelected(table.game.color === key ? "" : key); table.setSelected(table.game.color === key ? "" : key);
} }
@ -480,7 +474,6 @@ class Table extends React.Component {
this.componentDidMount = this.componentDidMount.bind(this); this.componentDidMount = this.componentDidMount.bind(this);
this.updateDimensions = this.updateDimensions.bind(this); this.updateDimensions = this.updateDimensions.bind(this);
this.throwDice = this.throwDice.bind(this); this.throwDice = this.throwDice.bind(this);
this.promoteGameState = this.promoteGameState.bind(this);
this.resetGameLoad = this.resetGameLoad.bind(this); this.resetGameLoad = this.resetGameLoad.bind(this);
this.loadGame = this.loadGame.bind(this); this.loadGame = this.loadGame.bind(this);
this.rollDice = this.rollDice.bind(this); this.rollDice = this.rollDice.bind(this);
@ -544,6 +537,39 @@ class Table extends React.Component {
}); });
} }
sendChat(message) {
if (this.loadTimer) {
window.clearTimeout(this.loadTimer);
this.loadTimer = null;
}
return window.fetch(`${base}/api/v1/games/${this.state.game.id}/chat`, {
method: "PUT",
cache: 'no-cache',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ message: message })
}).then((res) => {
if (res.status >= 400) {
throw new Error(`Unable to send chat message!`);
}
return res.json();
}).then((game) => {
const error = (game.status !== 'success') ? game.status : undefined;
this.updateGame(game);
this.updateMessage();
this.setState({ error: error });
}).catch((error) => {
console.error(error);
this.setState({error: error.message});
}).then(() => {
this.resetGameLoad();
});
}
setPlayerName(name) { setPlayerName(name) {
if (this.loadTimer) { if (this.loadTimer) {
window.clearTimeout(this.loadTimer); window.clearTimeout(this.loadTimer);
@ -696,39 +722,6 @@ class Table extends React.Component {
this.loadTimer = window.setTimeout(this.loadGame, 1000); this.loadTimer = window.setTimeout(this.loadGame, 1000);
} }
promoteGameState(change) {
console.log("Requesting state change: ", change);
if (this.loadTimer) {
window.clearTimeout(this.loadTimer);
this.loadTimer = null;
}
return window.fetch(`${base}/api/v1/games/${this.state.game.id}`, {
method: "PUT",
cache: 'no-cache',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(change)
}).then((res) => {
if (res.status >= 400) {
console.error(res);
throw new Error(`Unable to change state`);
}
return res.json();
}).then((game) => {
this.updateGame(game);
this.setState({ error: "" });
}).catch((error) => {
console.error(error);
this.setState({error: error.message});
}).then(() => {
this.resetGameLoad();
});
}
setGameState(state) { setGameState(state) {
if (this.loadTimer) { if (this.loadTimer) {
window.clearTimeout(this.loadTimer); window.clearTimeout(this.loadTimer);
@ -1007,16 +1000,19 @@ class Table extends React.Component {
return ( return (
<div className="Table"> <div className="Table">
<Board game={game}/> <Board game={game}/>
{ game && <div className={'Game ' + game.state}> { game && <div className={'Game ' + game.state}>
<Paper className="Message">{ this.state.message }</Paper> <Paper className="Message">{ this.state.message }</Paper>
{(this.state.pickName || !game.name) && <PlayerName table={this}/> } {(this.state.pickName || !game.name) && <PlayerName table={this}/> }
{(!this.state.pickName && game.name) && <> {(!this.state.pickName && game.name) && <>
<Players table={this}/> <Players table={this}/>
<Chat table={this} promoteGameState={this.promoteGameState}/> <Chat table={this}/>
<Action table={this}/> <Action table={this}/>
</> } </> }
</div> } </div> }
{ game && game.state === 'game-order' && { game && game.state === 'game-order' &&
<GameOrder table={this}/> <GameOrder table={this}/>
} }

View File

@ -181,7 +181,7 @@ const processGameOrder = (game, player, dice) => {
message = `Player order set to ${players.map((player, index) => { message = `Player order set to ${players.map((player, index) => {
return `${index+1}. ${getPlayerName(game, player)}`; return `${index+1}. ${getPlayerName(game, player)}`;
}).join(', ')}.`; }).join(', ')}.`;
game.chat.push({ date: Date.now(), message: message }); addChatMessage(game, null, message);
game.state = 'active' game.state = 'active'
message = `Game has started!`; message = `Game has started!`;
} else { } else {
@ -190,7 +190,7 @@ const processGameOrder = (game, player, dice) => {
} }
if (message) { if (message) {
game.chat.push({ date: Date.now(), message: message }); addChatMessage(game, null, message);
} }
} }
@ -230,7 +230,7 @@ const roll = (game, session) => {
} }
if (!error && message) { if (!error && message) {
game.chat.push({ from: session.color, date: Date.now(), message: message }); addChatMessage(game, session, message);
} }
return error; return error;
}; };
@ -387,10 +387,7 @@ const adminActions = (game, action, value) => {
} }
console.log(`Kicking ${value} from ${game.id}.`); console.log(`Kicking ${value} from ${game.id}.`);
const preamble = session.name ? `${session.name}, playing as ${color},` : color; const preamble = session.name ? `${session.name}, playing as ${color},` : color;
game.chat.push({ addChatMessage(game, null, `${preamble} was kicked from game by the Admin.`);
date: Date.now(),
message: `${preamble} was kicked from game by the Admin.`
});
if (player) { if (player) {
session.player = undefined; session.player = undefined;
clearPlayer(player); clearPlayer(player);
@ -433,10 +430,8 @@ const setPlayerName = (game, session, name) => {
return `You can not set your name to nothing!`; return `You can not set your name to nothing!`;
} }
game.chat.push({ addChatMessage(game, null, message);
date: Date.now(),
message: message
});
} }
const setPlayerColor = (game, session, color) => { const setPlayerColor = (game, session, color) => {
@ -452,20 +447,17 @@ const setPlayerColor = (game, session, color) => {
} }
const priorActive = getActiveCount(game); const priorActive = getActiveCount(game);
let message;
if (player) { if (player) {
/* Deselect currently active player for this session */ /* Deselect currently active player for this session */
clearPlayer(player); clearPlayer(player);
let message;
if (game.state !== 'lobby') { if (game.state !== 'lobby') {
message = `${name} has exited to the lobby and is no longer playing as ${session.color}.` message = `${name} has exited to the lobby and is no longer playing as ${session.color}.`
addChatMessage(game, null, message);
} else { } else {
message = `${name} is no longer ${session.color}.`; message = `${name} is no longer ${session.color}.`;
} }
game.chat.push({
date: Date.now(),
message: message
});
session.player = undefined; session.player = undefined;
session.color = undefined; session.color = undefined;
} }
@ -477,6 +469,9 @@ const setPlayerColor = (game, session, color) => {
/* If the player is not selecting a color, then return */ /* If the player is not selecting a color, then return */
if (!color) { if (!color) {
if (message) {
addChatMessage(game, null, message);
}
return; return;
} }
@ -499,23 +494,26 @@ const setPlayerColor = (game, session, color) => {
session.player.status = `Active`; session.player.status = `Active`;
session.player.lastActive = Date.now(); session.player.lastActive = Date.now();
session.color = color; session.color = color;
game.chat.push({ addChatMessage(game, session, `${session.name} has chosen to play as ${color}.`);
from: color,
date: Date.now(),
message: `${session.name} has chosen to play as ${color}.`
});
const afterActive = getActiveCount(game); const afterActive = getActiveCount(game);
if (afterActive !== priorActive) { if (afterActive !== priorActive) {
if (priorActive < 2 && afterActive >= 2) { if (priorActive < 2 && afterActive >= 2) {
game.chat.push({ addChatMessage(game, null,
date: Date.now(), `There are now enough players to start the game when you are ready.`);
message: `There are now enough players to start the game when you are ready.`
});
} }
} }
}; };
const addChatMessage = (game, session, message) => {
game.chat.push({
from: session ? session.name : undefined,
color: session ? session.color : undefined,
date: Date.now(),
message: message
});
};
router.put("/:id/:action/:value?", async (req, res) => { router.put("/:id/:action/:value?", async (req, res) => {
const { action, id } = req.params, const { action, id } = req.params,
value = req.params.value ? req.params.value : ""; value = req.params.value ? req.params.value : "";
@ -547,6 +545,10 @@ router.put("/:id/:action/:value?", async (req, res) => {
case 'player-selected': case 'player-selected':
error = setPlayerColor(game, session, value); error = setPlayerColor(game, session, value);
return sendGame(req, res, game, error); return sendGame(req, res, game, error);
case 'chat':
const chat = req.body;
addChatMessage(game, session, chat.message);
return sendGame(req, res, game);
} }
if (!session.player) { if (!session.player) {
@ -571,7 +573,7 @@ router.put("/:id/:action/:value?", async (req, res) => {
if (!error) { if (!error) {
shuffleBoard(game); shuffleBoard(game);
const message = `${name} requested a new board.`; const message = `${name} requested a new board.`;
game.chat.push({ date: Date.now(), message: message }); addChatMessage(game, null, message);
console.log(message); console.log(message);
} }
break break
@ -600,7 +602,7 @@ router.put("/:id/:action/:value?", async (req, res) => {
} }
message = `${name} requested to start the game.`; message = `${name} requested to start the game.`;
game.chat.push({ date: Date.now(), message: message }); addChatMessage(game, null, message);
game.state = state; game.state = state;
break; break;
} }
@ -624,38 +626,6 @@ router.get("/:id", async (req, res/*, next*/) => {
return sendGame(req, res, game); return sendGame(req, res, game);
}); });
router.put("/:id", (req, res/*, next*/) => {
const { id } = req.params;
console.log("PUT games/" + id);
if (!(id in games)) {
const error = `Game not found: ${req.params.id}`;
return res.status(404).send(error);
}
const game = games[id],
changes = req.body;
for (let change in changes) {
switch (change) {
case "chat":
console.log("Chat change.");
game.chat.push({
from: changes.chat.player,
date: Date.now(),
message: changes.chat.message
});
/*
if (game.chat.length > 10) {
game.chat.splice(0, game.chat.length - 10);
}
*/
break;
}
}
return sendGame(req, res, game);
});
const getActiveCount = (game) => { const getActiveCount = (game) => {
let active = 0; let active = 0;
for (let color in game.players) { for (let color in game.players) {
@ -672,7 +642,7 @@ const sendGame = async (req, res, game, error) => {
if (active < 2 && game.state != 'lobby' && game.state != 'invalid') { if (active < 2 && game.state != 'lobby' && game.state != 'invalid') {
let message = "Insufficient players in game. Setting back to lobby." let message = "Insufficient players in game. Setting back to lobby."
console.log(game); console.log(game);
game.chat.push({ date: Date.now(), message: message }); addChatMessage(game, null, message);
console.log(message); console.log(message);
game.state = 'lobby'; game.state = 'lobby';
} }
@ -770,10 +740,12 @@ const createGame = (id) => {
wheat: 19, wheat: 19,
longestRoad: null, longestRoad: null,
largestArmy: null, largestArmy: null,
chat: [ { date: Date.now(), message: `New game started for ${id}` } ], chat: [],
id: id id: id
}; };
addChatMessage(game, null, `New game started for ${id}`);
[ "pips", "borders", "tiles" ].forEach((field) => { [ "pips", "borders", "tiles" ].forEach((field) => {
game[field] = assetData[field] game[field] = assetData[field]
}); });