Skip to content

Commit

Permalink
Merge branch 'h2-keystrokes' into development
Browse files Browse the repository at this point in the history
  • Loading branch information
Timtam committed Nov 6, 2024
2 parents 2bb422c + 520d598 commit 21c7e0f
Show file tree
Hide file tree
Showing 7 changed files with 643 additions and 740 deletions.
1,249 changes: 529 additions & 720 deletions client/package-lock.json

Large diffs are not rendered by default.

20 changes: 10 additions & 10 deletions client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,21 +21,21 @@
"detect-browser": "^5.3.0",
"howler": "^2.2.4",
"i18next": "^23.10.1",
"i18next-browser-languagedetector": "^7.2.1",
"i18next-browser-languagedetector": "^8.0.0",
"ml-array-sum": "^1.1.6",
"react": "^18.3.1",
"react-bootstrap": "^2.10.1",
"react-bootstrap-toasts": "^0.2.0",
"react-cookie": "^7.1.0",
"react-dom": "^18.2.0",
"react-helmet-async": "^2.0.4",
"react-i18next": "^14.1.0",
"react-i18next": "^15.1.0",
"react-router": "^6.22.3",
"react-router-bootstrap": "^0.26.2",
"react-router-dom": "^6.22.3",
"slugify": "^1.6.6",
"title-case": "^4.3.1",
"use-immer": "^0.9.0",
"use-immer": "^0.10.0",
"zod": "^3.22.4"
},
"devDependencies": {
Expand All @@ -45,19 +45,19 @@
"@types/react-bootstrap": "^0.32.36",
"@types/react-dom": "^18.2.19",
"@types/react-router-bootstrap": "^0.26.6",
"@typescript-eslint/eslint-plugin": "^7.0.2",
"@typescript-eslint/parser": "^7.0.2",
"@typescript-eslint/eslint-plugin": "^8.12.2",
"@typescript-eslint/parser": "^8.12.2",
"@vitejs/plugin-react-swc": "^3.5.0",
"eslint": "^8.56.0",
"eslint-plugin-react-hooks": "^4.6.0",
"eslint": "^9.13.0",
"eslint-plugin-react-hooks": "^5.0.0",
"eslint-plugin-react-refresh": "^0.4.5",
"prettier": "^3.2.5",
"prettier-plugin-organize-imports": "^3.2.4",
"prettier-plugin-organize-imports": "^4.1.0",
"toml": "^3.0.0",
"typescript": "^5.2.2",
"vite": "^5.1.4",
"vite-plugin-checker": "^0.6.4",
"vite-plugin-checker": "^0.8.0",
"vite-plugin-filter-replace": "^0.1.13",
"vite-tsconfig-paths": "^4.3.1"
"vite-tsconfig-paths": "^5.0.1"
}
}
4 changes: 4 additions & 0 deletions client/src/locale/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
"noHitAvailable": "Kein Hit verfügbar",
"stopHit": "Hit stoppen",
"playHit": "Hit abspielen",
"playOrStopHit": "Hit abspielen oder stoppen",
"playOrStopHitShortcut": "Alt+Umschalt+H",
"and": "und",
"gameNotStarted": "Das Spiel hat noch nicht begonnen.",
"waitingForPlayerHeading_one": "Du wartest noch auf <0>{{player}}</0>",
Expand Down Expand Up @@ -84,6 +86,7 @@
"youClaimedHit": "Du hast dir einen Hit genommen. Das war <0>{{title}}</0> von <1>{{artist}}</1> aus dem Jahr <2>{{year}}</2>. Der Hit stammt aus dem <3>{{pack}}</3> Pack.",
"youClaimedHitBelonging": "Du hast dir einen Hit genommen. Das war <0>{{title}}</0> von <1>{{artist}}</1> aus dem Jahr <2>{{year}}</2>. Der Hit ist bekannt aus <3>{{belongs_to}}</3> und stammt aus dem <4>{{pack}}</4> Pack.",
"skipHit": "Überspringe diesen Hit, indem du einen Chip bezahlst",
"skipHitShortcut": "Alt+Umschalt+I",
"skipHitNotGuessing": "Nur der Zugspieler kann einen Hit überspringen",
"skipHitNoToken": "Du musst einen Chip bezahlen können, um einen Hit zu überspringen",
"cannotSkipHit": "Du kannst derzeit keinen Hit überspringen",
Expand All @@ -101,6 +104,7 @@
"finalScore": "Hier sind die finalen Ergebnisse:",
"cancel": "Abbrechen",
"gameSettings": "Spieleinstellungen",
"gameSettingsShortcut": "Alt+Umschalt+E",
"gameSettingsHitGoal": "Wie viele Hits muss ein Spieler erraten, um das Spiel zu gewinnen?",
"goal": "Ziel",
"gameSettingsStartTokens": "Wie viele Chips bekommt jeder Spieler zu Beginn des Spiels?",
Expand Down
4 changes: 4 additions & 0 deletions client/src/locale/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
"noHitAvailable": "No hit available",
"stopHit": "Stop hit",
"playHit": "Play hit",
"playOrStopHit": "Play or stop hit",
"playOrStopHitShortcut": "Alt+Shift+H",
"and": "and",
"gameNotStarted": "The game hasn't started yet.",
"waitingForPlayerHeading_one": "You are waiting for <0>{{player}}</0> to make their move",
Expand Down Expand Up @@ -84,6 +86,7 @@
"youClaimedHit": "You claimed a hit. This was <0>{{title}}</0> by <1>{{artist}}</1> from <2>{{year}}</2>. This song belongs to the <3>{{pack}}</3> pack.",
"youClaimedHitBelonging": "You claimed a hit. This was <0>{{title}}</0> by <1>{{artist}}</1> from <2>{{year}}</2>. You might know this song from <3>{{belongs_to}}</3> and it belongs to the <3>{{pack}}</3> pack.",
"skipHit": "Skip this hit by paying one token",
"skipHitShortcut": "Alt+Shift+I",
"skipHitNotGuessing": "Only the guessing player can skip a hit",
"skipHitNoToken": "You need to pay a token to skip a hit",
"cannotSkipHit": "You cannot skip a hit right now",
Expand All @@ -101,6 +104,7 @@
"finalScore": "And here are the final results:",
"cancel": "Cancel",
"gameSettings": "Game settings",
"gameSettingsShortcut": "Alt+Shift+E",
"gameSettingsHitGoal": "How many hits do the players need to guess correctly in order to win?",
"goal": "Goal",
"gameSettingsStartTokens": "How many tokens should every player get when starting a game?",
Expand Down
60 changes: 53 additions & 7 deletions client/src/pages/game.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,14 @@ export function Game() {
return p && p.tokens >= 3
}

const skipHit = async () =>
await gameService.skip(
game.id,
game.mode === GameMode.Local
? game.players.find((p) => p.turn_player)?.id
: undefined,
)

useEffect(() => {
let eventSource = new EventSource(`/api/games/${game.id}/events`)

Expand Down Expand Up @@ -297,20 +305,41 @@ export function Game() {
startOrStopGame()
},
}
let handleShowSettings = {
onPressed: () => {
setShowSettings(true)
},
}
let handleSkipHit = {
onPressed: () => {
skipHit()
},
}

if (!modalShown) {
bindKeyCombo("alt + shift + j", handleJoinGame)
bindKeyCombo("alt + shift + q", handleLeaveGame)
if (
game.state === GameState.Open &&
(game.players.find((p) => p.id === user?.id)?.creator ??
false) === true
)
bindKeyCombo("alt + shift + e", handleShowSettings)

if (canStartOrStopGame()) {
bindKeyCombo("alt + shift + s", handleStartOrStopGame)
}
if (canSkip()) {
bindKeyCombo("alt + shift + i", handleSkipHit)
}
}

return () => {
unbindKeyCombo("alt + shift + j", handleJoinGame)
unbindKeyCombo("alt + shift + q", handleLeaveGame)
unbindKeyCombo("alt + shift + e", handleShowSettings)
unbindKeyCombo("alt + shift + s", handleStartOrStopGame)
unbindKeyCombo("alt + shift + i", handleSkipHit)
}
}, [game, user, modalShown])

Expand Down Expand Up @@ -387,6 +416,21 @@ export function Game() {
?.creator ?? false) === false
}
aria-expanded={false}
aria-keyshortcuts={
game.state === GameState.Open &&
(game.players.find((p) => p.id === user?.id)
?.creator ?? false) === true
? t("gameSettingsShortcut")
: ""
}
aria-label={
detect()?.name === "firefox" &&
game.state === GameState.Open &&
(game.players.find((p) => p.id === user?.id)
?.creator ?? false) === true
? `${t("gameSettingsShortcut")} ${t("gameSettings")}`
: ""
}
onClick={() => setShowSettings(true)}
>
{game.state !== GameState.Open
Expand Down Expand Up @@ -542,18 +586,20 @@ export function Game() {
duration={
game.state === GameState.Confirming ? 0 : game.hit_duration
}
shortcut={t("playOrStopHitShortcut")}
/>
<Button
className="me-2"
disabled={!canSkip()}
onClick={async () =>
await gameService.skip(
game.id,
game.mode === GameMode.Local
? game.players.find((p) => p.turn_player)?.id
: undefined,
)
aria-keyshortcuts={canSkip() ? t("skipHitShortcut") : ""}
aria-label={
detect()?.name === "firefox"
? canSkip()
? `${t("skipHitShortcut")} ${t("skipHit")}`
: ""
: ""
}
onClick={skipHit}
>
{canSkip()
? t("skipHit")
Expand Down
32 changes: 30 additions & 2 deletions client/src/pages/game/hit-player.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import EventManager from "@lomray/event-manager"
import { bindKeyCombo, unbindKeyCombo } from "@rwh/keystrokes"
import { useLocalStorage } from "@uidotdev/usehooks"
import { detect } from "detect-browser"
import { Howl } from "howler"
import {
forwardRef,
Expand All @@ -11,6 +13,7 @@ import {
import Button from "react-bootstrap/Button"
import { useTranslation } from "react-i18next"
import { Events, Sfx } from "../../events"
import { useModalShown } from "../../hooks"

interface HitPlayerTimers {
sfxTimer: ReturnType<typeof setTimeout> | null
Expand All @@ -22,6 +25,7 @@ export type HitPlayerProps = {
duration: number
onPlay?: () => void
autoplay?: boolean
shortcut?: string
}

export type HitPlayerRef = {
Expand All @@ -31,7 +35,7 @@ export type HitPlayerRef = {

export const HitPlayer = forwardRef<HitPlayerRef, HitPlayerProps>(
function HitPlayer(
{ src, duration, onPlay, autoplay }: HitPlayerProps,
{ src, duration, onPlay, autoplay, shortcut }: HitPlayerProps,
ref,
) {
let player = useRef<Howl | null>(null)
Expand All @@ -43,6 +47,7 @@ export const HitPlayer = forwardRef<HitPlayerRef, HitPlayerProps>(
let { t } = useTranslation()
let [volume] = useLocalStorage("musicVolume", "1.0")
let [sfxVolume] = useLocalStorage("sfxVolume", "1.0")
let modalShown = useModalShown()

const play = () => {
if (timers.current.stopTimer) {
Expand Down Expand Up @@ -122,7 +127,22 @@ export const HitPlayer = forwardRef<HitPlayerRef, HitPlayerProps>(
}
player.current = null
}
}, [src, playing])

let handlePlayOrStopHit = {
onPressed: () => {
if (playing) setPlaying(false)
else setPlaying(true)
},
}

if (shortcut !== undefined && src !== "" && !modalShown) {
bindKeyCombo("alt + shift + h", handlePlayOrStopHit)
}

return () => {
unbindKeyCombo("alt + shift + h", handlePlayOrStopHit)
}
}, [src, playing, shortcut, modalShown])

useEffect(() => {
player.current?.volume(parseFloat(volume))
Expand All @@ -148,6 +168,14 @@ export const HitPlayer = forwardRef<HitPlayerRef, HitPlayerProps>(
<Button
className="me-2"
disabled={src === ""}
aria-keyshortcuts={shortcut !== undefined ? shortcut : ""}
aria-label={
detect()?.name === "firefox" &&
shortcut !== undefined &&
src !== ""
? `${shortcut} ${playing ? t("stopHit") : t("playHit")}`
: ""
}
onClick={() => {
if (playing === true) {
setPlaying(false)
Expand Down
14 changes: 13 additions & 1 deletion client/src/shortcuts.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ export default function Shortcuts({
<td>{t("localGameShortcut")}</td>
</tr>
<tr>
<th rowSpan={21}>{t("game")}</th>
<th rowSpan={24}>{t("game")}</th>
</tr>
<tr>
<td>{t("joinGame")}</td>
Expand All @@ -65,6 +65,10 @@ export default function Shortcuts({
<td>{t("stopGame")}</td>
<td>{t("stopGameShortcut")}</td>
</tr>
<tr>
<td>{t("gameSettings")}</td>
<td>{t("gameSettingsShortcut")}</td>
</tr>
<tr>
<td>{t("confirmYes")}</td>
<td>{t("yesShortcut")}</td>
Expand All @@ -89,6 +93,14 @@ export default function Shortcuts({
<td>{t("submitGuess")}</td>
<td>{t("submitGuessShortcut")}</td>
</tr>
<tr>
<td>{t("skipHit")}</td>
<td>{t("skipHitShortcut")}</td>
</tr>
<tr>
<td>{t("playOrStopHit")}</td>
<td>{t("playOrStopHitShortcut")}</td>
</tr>
{Array.from({ length: 10 }, (_, i) => (
<tr>
<td>
Expand Down

0 comments on commit 21c7e0f

Please sign in to comment.