From 38b80e0d5941a2321afeda77ca139fe1b1de6631 Mon Sep 17 00:00:00 2001 From: Akita Noek Date: Fri, 6 Dec 2024 12:15:02 -0700 Subject: [PATCH 1/5] Re-integrate custom games back onto unified play page, toggle display behind Explore custom games button --- src/lib/preferences.ts | 1 + src/views/Play/CustomGames.styl | 12 +++ src/views/Play/CustomGames.tsx | 129 +++++++++++++++++--------------- src/views/Play/Play.styl | 13 ++++ src/views/Play/Play.tsx | 29 ++++++- src/views/Play/QuickMatch.styl | 3 +- src/views/Play/QuickMatch.tsx | 6 +- 7 files changed, 125 insertions(+), 68 deletions(-) diff --git a/src/lib/preferences.ts b/src/lib/preferences.ts index 956fe6b3bb..a3b03893bc 100644 --- a/src/lib/preferences.ts +++ b/src/lib/preferences.ts @@ -41,6 +41,7 @@ export const defaults = { "automatch.bot": 0, "automatch.lower-rank-diff": 3, "automatch.upper-rank-diff": 3, + "automatch.show-custom-games": false, "board-labeling": "automatic", "chat.show-all-global-channels": true, "chat.show-all-group-channels": true, diff --git a/src/views/Play/CustomGames.styl b/src/views/Play/CustomGames.styl index 6450686b4f..84d75a4cf0 100644 --- a/src/views/Play/CustomGames.styl +++ b/src/views/Play/CustomGames.styl @@ -22,6 +22,7 @@ align-items: stretch; justify-content: center; box-sizing: border-box; + margin-bottom: 8rem; .header-container { width: 100%; @@ -58,6 +59,17 @@ } } + .create-custom-games-buttons { + display: flex; + gap: 1rem; + justify-content: space-between; + width: 100%; + + button { + height: 3rem; + font-size: 1.1rem; + } + } // This shenanigans is needed to ensure that the canvas of the seek graph // remains rendered, so we don't loose the reference we have to it. diff --git a/src/views/Play/CustomGames.tsx b/src/views/Play/CustomGames.tsx index a31a69525d..786fd94226 100644 --- a/src/views/Play/CustomGames.tsx +++ b/src/views/Play/CustomGames.tsx @@ -49,7 +49,7 @@ import { anyChallengesToShow, challenge_sort, time_per_move_challenge_sort } fro import { RengoManagementPane } from "@/components/RengoManagementPane"; import { RengoTeamManagementPane } from "@/components/RengoTeamManagementPane"; import { PlayContext } from "./PlayContext"; -import { ChallengeModalBody } from "@/components/ChallengeModal"; +import { challenge } from "@/components/ChallengeModal"; const CHALLENGE_LIST_FREEZE_PERIOD = 1000; // Freeze challenge list for this period while they move their mouse on it @@ -391,6 +391,12 @@ export function CustomGames(): JSX.Element { }); }, [live_list, cancelOpenChallenge]); + const disable_challenge_buttons = !!( + liveOwnChallengePending() || + live_rengo_challenge_to_show || + automatch_manager.active_live_automatcher + ); + return (
- - {liveOwnChallengePending() ? ( - <> -
{_("Waiting for opponent...")}
-
-
-
-
-
+ {liveOwnChallengePending() ? ( + +
{_("Waiting for opponent...")}
+
+
+
+
-
- -
- - ) : live_rengo_challenge_to_show ? ( - <> - +
+ +
+ + ) : live_rengo_challenge_to_show ? ( + + + - - setPaneLock(live_rengo_challenge_to_show.challenge_id, lock) - } - /> - - - ) : ( -
- void) => { - console.log("on", event, callback); - }, - off: (event: "open" | "close", callback: () => void) => { - console.log("off", event, callback); - }, - }} + lock={(lock: boolean) => + setPaneLock(live_rengo_challenge_to_show.challenge_id, lock) + } /> -
- )} -
+
+ + ) : null}

@@ -505,6 +493,27 @@ export function CustomGames(): JSX.Element { showIcons={true} toggleHandler={toggleFilterHandler} > + +
+ + +

diff --git a/src/views/Play/Play.styl b/src/views/Play/Play.styl index f4f81c5d2a..edf05c50d7 100644 --- a/src/views/Play/Play.styl +++ b/src/views/Play/Play.styl @@ -169,6 +169,18 @@ } } + + .custom-games-toggle-container { + margin-top: 2rem; + text-align: center; + margin-bottom: 8rem; + &.showing-custom-games { + margin-bottom: 1rem; + } + } + .custom-games-toggle { + font-size: 1.3rem; + } } @@ -307,4 +319,5 @@ .fa-times-circle-o { cursor: pointer; } + } diff --git a/src/views/Play/Play.tsx b/src/views/Play/Play.tsx index 8e153ca833..93b8011c94 100644 --- a/src/views/Play/Play.tsx +++ b/src/views/Play/Play.tsx @@ -18,12 +18,18 @@ import * as React from "react"; import * as preferences from "@/lib/preferences"; -import { _, pgettext } from "@/lib/translate"; +//import { _, pgettext } from "@/lib/translate"; +import { _ } from "@/lib/translate"; import { QuickMatch } from "./QuickMatch"; import { CustomGames } from "./CustomGames"; export function Play(): JSX.Element { - const [tab, setTab] = preferences.usePreference("play.tab"); + const [show_custom_games, setShowCustomGames] = preferences.usePreference( + "automatch.show-custom-games", + ); + const toggleCustomGames = React.useCallback(() => { + setShowCustomGames(!show_custom_games); + }, [show_custom_games]); React.useEffect(() => { window.document.title = _("Play"); @@ -31,6 +37,7 @@ export function Play(): JSX.Element { return (
+ {/*

{pgettext("Play page", "Matchmaking")} @@ -51,9 +58,27 @@ export function Play(): JSX.Element {

+ */} + {/* {tab === "automatch" && } {tab === "custom" && } + */} + + +
+
+ +
+ {show_custom_games && } +
); } diff --git a/src/views/Play/QuickMatch.styl b/src/views/Play/QuickMatch.styl index 631e767a7e..ffd045907d 100644 --- a/src/views/Play/QuickMatch.styl +++ b/src/views/Play/QuickMatch.styl @@ -538,6 +538,7 @@ padding-left: 0.5rem; } } + } @@ -547,7 +548,6 @@ flex-direction: column; margin-right: 0rem; margin-left: 0rem; - margin-bottom: 8rem; column-gap: 0rem; margin-top: 0rem; @@ -573,6 +573,7 @@ width: 100%; left: 0; right: 0; + z-index: z.dock; themed background-color bg .play-button { margin: 0; diff --git a/src/views/Play/QuickMatch.tsx b/src/views/Play/QuickMatch.tsx index ee667ab6bc..3258dc0701 100644 --- a/src/views/Play/QuickMatch.tsx +++ b/src/views/Play/QuickMatch.tsx @@ -50,7 +50,6 @@ import { sfx } from "@/lib/sfx"; import { Link } from "react-router-dom"; import Select from "react-select"; import { SPEED_OPTIONS } from "./SPEED_OPTIONS"; -import { AvailableQuickMatches } from "./AvailableQuickMatches"; moment.relativeTimeThreshold("m", 56); export interface SelectOption { @@ -674,6 +673,7 @@ export function QuickMatch(): JSX.Element { minMenuHeight={400} maxMenuHeight={400} menuPlacement="auto" + isDisabled={search_active} onChange={(opt) => { if (opt) { setHandicaps(opt.value as "enabled" | "standard" | "disabled"); @@ -768,10 +768,6 @@ export function QuickMatch(): JSX.Element {
- ); } From 0f74538c287ea08bd29bd3eb47ee58eafc5b2147 Mon Sep 17 00:00:00 2001 From: Akita Noek Date: Fri, 6 Dec 2024 14:42:55 -0700 Subject: [PATCH 2/5] Add support for selecting multiple acceptable size/time settings --- src/lib/automatch_manager.tsx | 6 +- src/lib/preferences.ts | 11 ++- src/lib/types.ts | 15 --- src/views/Play/CustomGames.tsx | 6 +- src/views/Play/QuickMatch.styl | 11 ++- src/views/Play/QuickMatch.tsx | 171 ++++++++++++++++++++++++++------- 6 files changed, 163 insertions(+), 57 deletions(-) diff --git a/src/lib/automatch_manager.tsx b/src/lib/automatch_manager.tsx index a375c1a1bc..e4273be25a 100644 --- a/src/lib/automatch_manager.tsx +++ b/src/lib/automatch_manager.tsx @@ -31,7 +31,11 @@ interface Events { export type AutomatchPreferences = AutomatchPreferencesBase & { uuid: string; - size_speed_options: Array<{ size: Size; speed: Speed }>; + size_speed_options: Array<{ + size: Size; + speed: Speed; + system: "byoyomi" | "fischer"; + }>; }; class AutomatchToast extends React.PureComponent<{}, any> { diff --git a/src/lib/preferences.ts b/src/lib/preferences.ts index a3b03893bc..be6d596541 100644 --- a/src/lib/preferences.ts +++ b/src/lib/preferences.ts @@ -34,7 +34,7 @@ export const defaults = { "play.tab": "automatch" as "automatch" | "custom", "automatch.size": "9x9" as Size, "automatch.speed": "rapid" as JGOFTimeControlSpeed, - "automatch.game-clock": "flexible" as "exact" | "flexible", + "automatch.game-clock": "flexible" as "exact" | "flexible" | "multiple", "automatch.handicaps": "standard" as "enabled" | "standard" | "disabled", "automatch.time-control": "fischer" as "fischer" | "byoyomi", "automatch.opponent": "human" as "human" | "bot", @@ -42,6 +42,15 @@ export const defaults = { "automatch.lower-rank-diff": 3, "automatch.upper-rank-diff": 3, "automatch.show-custom-games": false, + "automatch.multiple-sizes": { "9x9": false, "13x13": false, "19x19": false }, + "automatch.multiple-speeds": { + "blitz-fischer": false, + "blitz-byoyomi": false, + "rapid-fischer": false, + "rapid-byoyomi": false, + "live-fischer": false, + "live-byoyomi": false, + }, "board-labeling": "automatic", "chat.show-all-global-channels": true, "chat.show-all-group-channels": true, diff --git a/src/lib/types.ts b/src/lib/types.ts index b9647cf50e..252f1026ca 100644 --- a/src/lib/types.ts +++ b/src/lib/types.ts @@ -100,21 +100,6 @@ export interface AutomatchPreferencesBase { condition: AutomatchCondition; value: "japanese" | "chinese" | "aga" | "korean" | "nz" | "ing"; }; - time_control: { - condition: AutomatchCondition; - value: { - system: AutomatchTimeControlSystem; - initial_time?: number; - time_increment?: number; - max_time?: number; - main_time?: number; - period_time?: number; - periods?: number; - stones_per_period?: number; - per_move?: number; - pause_on_weekends?: boolean; - }; - }; handicap: { condition: AutomatchCondition; value: "enabled" | "disabled"; diff --git a/src/views/Play/CustomGames.tsx b/src/views/Play/CustomGames.tsx index 786fd94226..bb94641fc1 100644 --- a/src/views/Play/CustomGames.tsx +++ b/src/views/Play/CustomGames.tsx @@ -567,10 +567,8 @@ export function CustomGames(): JSX.Element { .join(",")} - - {m.time_control.condition === "no-preference" - ? pgettext("Automatch: no preference", "No preference") - : timeControlSystemText(m.time_control.value.system)} + + {timeControlSystemText(m.size_speed_options[0].system)} diff --git a/src/views/Play/QuickMatch.styl b/src/views/Play/QuickMatch.styl index ffd045907d..c66b427417 100644 --- a/src/views/Play/QuickMatch.styl +++ b/src/views/Play/QuickMatch.styl @@ -385,7 +385,7 @@ } .speed-options { - margin-bottom: 2rem; + //margin-bottom: 2rem; } .opponent-options { @@ -539,7 +539,14 @@ } } - + .multiple-options-description { + font-size: 0.9rem; + font-style: italic; + themed color shade1 + padding-right: 0.5rem; + padding-left: 0.5rem; + margin-bottom: 0.5rem; + } } @media (max-width: hamburger-cutoff) { diff --git a/src/views/Play/QuickMatch.tsx b/src/views/Play/QuickMatch.tsx index 3258dc0701..56ac1edb6b 100644 --- a/src/views/Play/QuickMatch.tsx +++ b/src/views/Play/QuickMatch.tsx @@ -78,6 +78,14 @@ const game_clock_options: OptionWithDescription[] = [ "Prefer one time setting, but accept the other similarly paced time setting", ), }, + { + value: "multiple", + label: _("Multiple"), + description: pgettext( + "Game Clock option description for being able to choose between multiple time settings", + "Pick multiple acceptable time settings", + ), + }, ]; const handicap_options: OptionWithDescription[] = [ @@ -159,6 +167,13 @@ export function QuickMatch(): JSX.Element { const cancel_bot_game = React.useRef<() => void>(() => {}); const [game_clock, setGameClock] = preferences.usePreference("automatch.game-clock"); + const [multiple_sizes, setMultipleSizes] = preferences.usePreference( + "automatch.multiple-sizes", + ); + const [multiple_speeds, setMultipleSpeeds] = preferences.usePreference( + "automatch.multiple-speeds", + ); + React.useEffect(() => { automatch_manager.on("entry", refresh); automatch_manager.on("start", refresh); @@ -192,9 +207,40 @@ export function QuickMatch(): JSX.Element { // Open challenge console.log("findMatch", board_size, game_speed); - const size_speed_options: Array<{ size: Size; speed: Speed }> = [ - { size: board_size, speed: game_speed }, - ]; + const size_speed_options: Array<{ + size: Size; + speed: Speed; + system: "fischer" | "byoyomi"; + }> = []; + + if (game_clock === "exact" || game_clock === "flexible") { + size_speed_options.push({ + size: board_size, + speed: game_speed, + system: time_control_system, + }); + if (game_clock === "flexible" && game_speed !== "correspondence") { + size_speed_options.push({ + size: board_size, + speed: game_speed, + system: time_control_system === "fischer" ? "byoyomi" : "fischer", + }); + } + } else { + for (const size in multiple_sizes) { + if (multiple_sizes[size as keyof typeof multiple_sizes]) { + for (const speed_system in multiple_speeds) { + if (multiple_speeds[speed_system as keyof typeof multiple_speeds]) { + const [speed, system] = speed_system.split("-"); + size_speed_options.push({ size, speed, system } as any); + } + } + } + } + + // shuffle the options so we aren't biasing towards the same settings all the time + size_speed_options.sort(() => Math.random() - 0.5); + } const preferences: AutomatchPreferences = { uuid: uuid(), @@ -205,12 +251,6 @@ export function QuickMatch(): JSX.Element { condition: "required", value: "japanese", }, - time_control: { - condition: game_clock === "flexible" ? "preferred" : "required", - value: { - system: time_control_system, - }, - }, handicap: { condition: handicaps === "standard" ? "preferred" : "required", value: handicaps === "disabled" ? "disabled" : "enabled", @@ -236,6 +276,8 @@ export function QuickMatch(): JSX.Element { refresh, automatch_manager, setCorrespondenceSpinner, + multiple_sizes, + multiple_speeds, ]); const playComputer = React.useCallback(() => { @@ -405,6 +447,70 @@ export function QuickMatch(): JSX.Element { const search_active = !!automatch_manager.active_live_automatcher || correspondence_spinner || bot_spinner; + function isSizeActive(size: Size) { + if (game_clock === "multiple") { + return multiple_sizes[size]; + } else { + return board_size === size; + } + } + + function isSpeedSystemActive(speed: JGOFTimeControlSpeed, system: "fischer" | "byoyomi") { + if (game_clock === "multiple") { + return multiple_speeds[`${speed as "blitz" | "rapid" | "live"}-${system}`]; + } else { + return game_speed === speed && time_control_system === system; + } + } + + function toggleSpeedSystem(speed: JGOFTimeControlSpeed, system: "fischer" | "byoyomi") { + if (game_clock === "multiple") { + const new_speeds = { + ...multiple_speeds, + [`${speed as "blitz" | "rapid" | "live"}-${system}`]: + !multiple_speeds[`${speed as "blitz" | "rapid" | "live"}-${system}`], + }; + delete (new_speeds as any)["correspondence-fischer"]; + delete (new_speeds as any)["correspondence-byoyomi"]; + + if (Object.values(new_speeds).filter((x) => x).length > 0) { + setMultipleSpeeds(new_speeds); + } + } else { + setGameSpeed(speed); + setTimeControlSystem(system); + } + } + + function toggleSize(size: Size) { + if (game_clock === "multiple") { + const new_sizes = { + ...multiple_sizes, + [size]: !multiple_sizes[size], + }; + + if (Object.values(new_sizes).filter((x) => x).length > 0) { + setMultipleSizes(new_sizes); + } + } else { + setBoardSize(size); + } + } + + // nothing selected? Select what we last had selected + if (game_clock === "multiple") { + if (Object.values(multiple_sizes).filter((x) => x).length === 0) { + toggleSize(board_size); + } + if (Object.values(multiple_speeds).filter((x) => x).length === 0) { + if (game_speed !== "correspondence") { + toggleSpeedSystem(game_speed, time_control_system); + } else { + toggleSpeedSystem("rapid", time_control_system); + } + } + } + // Construction of the pane we need to show... return ( <> @@ -418,11 +524,11 @@ export function QuickMatch(): JSX.Element {
{(["9x9", "13x13", "19x19"] as Size[]).map((s) => (
-
+ {game_clock === "multiple" && ( +
+ {_("Select all the settings you are comfortable playing with.")} +
+ )} {( ["blitz", "rapid", "live", "correspondence"] as JGOFTimeControlSpeed[] ).map((speed) => { @@ -480,16 +593,6 @@ export function QuickMatch(): JSX.Element { >
{opt.time_estimate} - {/* - - {opt.fischer.time_estimate || opt.time_estimate} - - {opt.byoyomi?.time_estimate && ( - - {opt.byoyomi.time_estimate} - - )} - */}
{ - setGameSpeed(speed); - setTimeControlSystem("fischer"); + toggleSpeedSystem(speed, "fischer"); }} > {shortDurationString(opt.fischer.initial_time)} @@ -533,14 +638,12 @@ export function QuickMatch(): JSX.Element {
+
{_("Rank range")}
Date: Sat, 7 Dec 2024 07:44:09 -0700 Subject: [PATCH 5/5] Added some perfectly clear descriptions of the clock ranges when dealing with multiple board size selections --- src/views/Play/QuickMatch.tsx | 59 ++++++++++++++++++++++++++++++++--- 1 file changed, 55 insertions(+), 4 deletions(-) diff --git a/src/views/Play/QuickMatch.tsx b/src/views/Play/QuickMatch.tsx index 7fd72c63bb..47a8ccee0a 100644 --- a/src/views/Play/QuickMatch.tsx +++ b/src/views/Play/QuickMatch.tsx @@ -511,6 +511,20 @@ export function QuickMatch(): JSX.Element { } } + const selected_size_count = + game_clock === "multiple" ? Object.values(multiple_sizes).filter((x) => x).length : 1; + + const min_selected_size = multiple_sizes["9x9"] + ? "9x9" + : multiple_sizes["13x13"] + ? "13x13" + : "19x19"; + const max_selected_size = multiple_sizes["19x19"] + ? "19x19" + : multiple_sizes["13x13"] + ? "13x13" + : "9x9"; + // Construction of the pane we need to show... return ( <> @@ -580,7 +594,14 @@ export function QuickMatch(): JSX.Element { {( ["blitz", "rapid", "live", "correspondence"] as JGOFTimeControlSpeed[] ).map((speed) => { - const opt = SPEED_OPTIONS[board_size as any][speed]; + const opt = + SPEED_OPTIONS[ + game_clock === "multiple" + ? min_selected_size + : (board_size as any) + ][speed]; + const min_opt = SPEED_OPTIONS[min_selected_size as any][speed]; + const max_opt = SPEED_OPTIONS[max_selected_size as any][speed]; return (
- {opt.time_estimate} + + {selected_size_count > 1 && speed !== "correspondence" + ? `${ + min_opt.time_estimate + } - ${max_opt.time_estimate.replace( + /\u223c/, + "", + )}` + : opt.time_estimate} +
- {shortDurationString(opt.fischer.initial_time)} + {selected_size_count > 1 && speed !== "correspondence" + ? `${shortDurationString( + min_opt.fischer.initial_time, + ).replace( + /[^0-9]+/g, + "", + )} - ${shortDurationString( + max_opt.fischer.initial_time, + )}` + : shortDurationString(opt.fischer.initial_time)} {" + "} {shortDurationString(opt.fischer.time_increment)} @@ -647,7 +686,19 @@ export function QuickMatch(): JSX.Element { }} disabled={search_active} > - {shortDurationString(opt.byoyomi.main_time)} + {selected_size_count > 1 && + speed !== "correspondence" + ? `${shortDurationString( + min_opt.byoyomi!.main_time, + ).replace( + /[^0-9]+/g, + "", + )} - ${shortDurationString( + max_opt.byoyomi!.main_time, + )}` + : shortDurationString( + opt.byoyomi.main_time, + )} {" + "} {opt.byoyomi.periods}x {shortDurationString(