From 1307cdde768c06effadb68d2e3e882a5ce5456e2 Mon Sep 17 00:00:00 2001 From: thsparks Date: Thu, 27 Oct 2022 10:54:55 -0700 Subject: [PATCH 01/13] Make JoinCodeLabel have just the join code and copy button. --- multiplayer/src/components/GamePage.tsx | 5 ++++- multiplayer/src/components/JoinCodeLabel.tsx | 4 ++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/multiplayer/src/components/GamePage.tsx b/multiplayer/src/components/GamePage.tsx index 6503c978af3..31d430fb7e9 100644 --- a/multiplayer/src/components/GamePage.tsx +++ b/multiplayer/src/components/GamePage.tsx @@ -36,7 +36,10 @@ export default function Render(props: GamePageProps) {
- +
+
{lf("Join Code: ")}
+ +
{lf("Keyboard Controls")}
diff --git a/multiplayer/src/components/JoinCodeLabel.tsx b/multiplayer/src/components/JoinCodeLabel.tsx index e824c9970f2..79e24666008 100644 --- a/multiplayer/src/components/JoinCodeLabel.tsx +++ b/multiplayer/src/components/JoinCodeLabel.tsx @@ -32,9 +32,9 @@ export default function Render() {
{state.gameState?.joinCode && (
- {lf("Join Code: {0}", state.gameState?.joinCode)} + {state.gameState?.joinCode} + const joinCode = state.gameState?.joinCode; + const displayJoinCode = joinCode?.slice(0, 3) + " " + joinCode?.slice(3); + return joinCode ? ( +
+ {displayJoinCode} +
- ); + ) : null; } diff --git a/multiplayer/src/util/index.ts b/multiplayer/src/util/index.ts index b800f55fffd..d36f5335685 100644 --- a/multiplayer/src/util/index.ts +++ b/multiplayer/src/util/index.ts @@ -46,7 +46,7 @@ export function cleanupJoinCode( joinCode: string | undefined ): string | undefined { if (!joinCode) return undefined; - joinCode = joinCode.trim(); + joinCode = joinCode.replaceAll(' ', ''); if (joinCode.length !== 6) return undefined; joinCode = joinCode.toUpperCase().replace(/[^A-Z0-9]/g, ""); if (joinCode.length !== 6) return undefined; From df2b29d8920ddf2b6984a7fc06cf9f8fb9f46a7f Mon Sep 17 00:00:00 2001 From: thsparks Date: Thu, 27 Oct 2022 13:38:13 -0700 Subject: [PATCH 03/13] Pull out copy button. I want to be able to adjust this separately from the join code's appearance. --- multiplayer/src/components/CopyButton.tsx | 53 +++++++++++++++++++ multiplayer/src/components/GamePage.tsx | 5 +- multiplayer/src/components/HostLobby.tsx | 37 ++++++-------- multiplayer/src/components/JoinCodeLabel.tsx | 54 +++++--------------- multiplayer/src/util/index.ts | 2 +- 5 files changed, 86 insertions(+), 65 deletions(-) create mode 100644 multiplayer/src/components/CopyButton.tsx diff --git a/multiplayer/src/components/CopyButton.tsx b/multiplayer/src/components/CopyButton.tsx new file mode 100644 index 00000000000..c28ad289012 --- /dev/null +++ b/multiplayer/src/components/CopyButton.tsx @@ -0,0 +1,53 @@ +import { faCopy } from "@fortawesome/free-regular-svg-icons"; +import { faCheck } from "@fortawesome/free-solid-svg-icons"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { useContext, useEffect, useState } from "react"; +import { AppStateContext } from "../state/AppStateContext"; + +export default function Render(props: { + copyValue: string; + title: string; + eventName?: string; +}) { + const { state } = useContext(AppStateContext); + const [copySuccessful, setCopySuccessful] = useState(false); + const copyTimeoutMs = 2500; + + const copyValue = async () => { + if (props.eventName) pxt.tickEvent(props.eventName); + if (state.gameState?.joinCode) { + navigator.clipboard.writeText(props.copyValue); + setCopySuccessful(true); + } + }; + + useEffect(() => { + if (copySuccessful) { + let resetCopyTimer = setTimeout(() => { + setCopySuccessful(false); + }, copyTimeoutMs); + return () => { + clearTimeout(resetCopyTimer); + }; + } + }, [copySuccessful]); + + return ( + + ); +} diff --git a/multiplayer/src/components/GamePage.tsx b/multiplayer/src/components/GamePage.tsx index d60348a7628..6503c978af3 100644 --- a/multiplayer/src/components/GamePage.tsx +++ b/multiplayer/src/components/GamePage.tsx @@ -36,10 +36,7 @@ export default function Render(props: GamePageProps) {
-
-
{lf("Code: ")}
- -
+
{lf("Keyboard Controls")}
diff --git a/multiplayer/src/components/HostLobby.tsx b/multiplayer/src/components/HostLobby.tsx index 58e7914df65..fddc2b8125f 100644 --- a/multiplayer/src/components/HostLobby.tsx +++ b/multiplayer/src/components/HostLobby.tsx @@ -4,7 +4,8 @@ import { Input } from "react-common/components/controls/Input"; import { startGameAsync } from "../epics"; import { clearModal } from "../state/actions"; import { AppStateContext } from "../state/AppStateContext"; -import JoinCodeLabel from "./JoinCodeLabel"; +import CopyButton from "./CopyButton"; +import Loading from "./Loading"; import PresenceBar from "./PresenceBar"; export default function Render() { @@ -18,35 +19,31 @@ export default function Render() { await startGameAsync(); }; - const handleCopyClick = () => { - pxt.tickEvent("mp.hostlobby.copyjoinlink"); - if (pxt.BrowserUtils.isIpcRenderer()) { - if (inputRef.current) { - setCopySuccessful( - pxt.BrowserUtils.legacyCopyText(inputRef.current) - ); - } - } else { - navigator.clipboard.writeText(joinLink); - setCopySuccessful(true); - } - }; + const joinCode = state.gameState?.joinCode; + if (!joinCode) { + return ; + } - const handleCopyBlur = () => { - setCopySuccessful(false); - }; + const displayJoinCode = joinCode?.slice(0, 3) + " " + joinCode?.slice(3); const joinLinkBaseUrl = "aka.ms/a9"; const inviteString = lf("Go to {0} and enter code", joinLinkBaseUrl); + const fullJoinLink = `${joinLinkBaseUrl}?join=${joinCode}`; // TODO multiplayer : create full link - const joinLink = `${state.gameState?.joinCode}`; // TODO multiplayer : create full link return (
{inviteString}
-
- +
+ {displayJoinCode} +
+ +
+ )}
- ) : null; + ); } diff --git a/multiplayer/src/util/index.ts b/multiplayer/src/util/index.ts index d36f5335685..edc54031361 100644 --- a/multiplayer/src/util/index.ts +++ b/multiplayer/src/util/index.ts @@ -46,7 +46,7 @@ export function cleanupJoinCode( joinCode: string | undefined ): string | undefined { if (!joinCode) return undefined; - joinCode = joinCode.replaceAll(' ', ''); + joinCode = joinCode.replaceAll(" ", ""); if (joinCode.length !== 6) return undefined; joinCode = joinCode.toUpperCase().replace(/[^A-Z0-9]/g, ""); if (joinCode.length !== 6) return undefined; From 468c6f4b0ec73e4d367da87d895606e7e554caab Mon Sep 17 00:00:00 2001 From: thsparks Date: Thu, 27 Oct 2022 14:01:05 -0700 Subject: [PATCH 04/13] Use deep link when copying the code --- multiplayer/src/components/HostLobby.tsx | 12 ++++-------- multiplayer/src/components/JoinCodeLabel.tsx | 10 +++++----- 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/multiplayer/src/components/HostLobby.tsx b/multiplayer/src/components/HostLobby.tsx index fddc2b8125f..a4f17820e29 100644 --- a/multiplayer/src/components/HostLobby.tsx +++ b/multiplayer/src/components/HostLobby.tsx @@ -1,17 +1,15 @@ import { useContext, useRef, useState } from "react"; import { Button } from "react-common/components/controls/Button"; -import { Input } from "react-common/components/controls/Input"; import { startGameAsync } from "../epics"; import { clearModal } from "../state/actions"; import { AppStateContext } from "../state/AppStateContext"; +import { makeJoinLink, SHORT_LINK } from "../util"; import CopyButton from "./CopyButton"; import Loading from "./Loading"; import PresenceBar from "./PresenceBar"; export default function Render() { const { state, dispatch } = useContext(AppStateContext); - const [copySuccessful, setCopySuccessful] = useState(false); - const inputRef = useRef(null); const onStartGameClick = async () => { pxt.tickEvent("mp.hostlobby.startgame"); @@ -25,10 +23,8 @@ export default function Render() { } const displayJoinCode = joinCode?.slice(0, 3) + " " + joinCode?.slice(3); - - const joinLinkBaseUrl = "aka.ms/a9"; - const inviteString = lf("Go to {0} and enter code", joinLinkBaseUrl); - const fullJoinLink = `${joinLinkBaseUrl}?join=${joinCode}`; // TODO multiplayer : create full link + const inviteString = lf("Go to {0} and enter code", SHORT_LINK()); + const joinDeepLink = makeJoinLink(joinCode); return (
@@ -39,7 +35,7 @@ export default function Render() { {displayJoinCode}
diff --git a/multiplayer/src/components/JoinCodeLabel.tsx b/multiplayer/src/components/JoinCodeLabel.tsx index a1e0c27a7d4..a196de1f8b2 100644 --- a/multiplayer/src/components/JoinCodeLabel.tsx +++ b/multiplayer/src/components/JoinCodeLabel.tsx @@ -1,13 +1,13 @@ import { useContext, useEffect, useState } from "react"; import { AppStateContext } from "../state/AppStateContext"; +import { makeJoinLink } from "../util"; import CopyButton from "./CopyButton"; export default function Render() { const { state } = useContext(AppStateContext); - const [copySuccessful, setCopySuccessful] = useState(false); - const copyTimeoutMs = 2500; const joinCode = state.gameState?.joinCode; + const joinDeepLink = joinCode ? makeJoinLink(joinCode) : ""; return (
{joinCode && ( @@ -16,9 +16,9 @@ export default function Render() {
{joinCode}
From 3299030d17452666c74669f3683670533d6e793d Mon Sep 17 00:00:00 2001 From: thsparks Date: Thu, 27 Oct 2022 14:15:59 -0700 Subject: [PATCH 05/13] Have arcade sim take full screen on smaller screens --- multiplayer/src/components/ArcadeSimulator.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/multiplayer/src/components/ArcadeSimulator.tsx b/multiplayer/src/components/ArcadeSimulator.tsx index 58cabb48781..b41be18e17a 100644 --- a/multiplayer/src/components/ArcadeSimulator.tsx +++ b/multiplayer/src/components/ArcadeSimulator.tsx @@ -156,7 +156,7 @@ export default function Render() {
); } From 1fd548a857216981c540d70ec1d667187a8300f9 Mon Sep 17 00:00:00 2001 From: thsparks Date: Thu, 27 Oct 2022 14:16:19 -0700 Subject: [PATCH 06/13] Prettier --- multiplayer/src/components/ArcadeSimulator.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/multiplayer/src/components/ArcadeSimulator.tsx b/multiplayer/src/components/ArcadeSimulator.tsx index b41be18e17a..5e9a92e6d4d 100644 --- a/multiplayer/src/components/ArcadeSimulator.tsx +++ b/multiplayer/src/components/ArcadeSimulator.tsx @@ -156,7 +156,9 @@ export default function Render() {
); } From ee46d4ebe437bf68c130268e683fd7e19aea5fe2 Mon Sep 17 00:00:00 2001 From: thsparks Date: Thu, 27 Oct 2022 14:26:49 -0700 Subject: [PATCH 07/13] Include a link in the invite string --- multiplayer/src/components/HostLobby.tsx | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/multiplayer/src/components/HostLobby.tsx b/multiplayer/src/components/HostLobby.tsx index a4f17820e29..e7efcb34d4c 100644 --- a/multiplayer/src/components/HostLobby.tsx +++ b/multiplayer/src/components/HostLobby.tsx @@ -22,14 +22,19 @@ export default function Render() { return ; } + + // To get a link in the middle of the invite string, we actually preserve the {0} and insert the link manually as an html element later. + const inviteString = lf("Go to {0} and enter code", "{0}"); + const inviteStringSegments = inviteString.split("{0}"); + const shortLink = SHORT_LINK(); + const displayJoinCode = joinCode?.slice(0, 3) + " " + joinCode?.slice(3); - const inviteString = lf("Go to {0} and enter code", SHORT_LINK()); const joinDeepLink = makeJoinLink(joinCode); return (
- {inviteString} + {inviteStringSegments[0]}{{shortLink}}{inviteStringSegments[1]}
{displayJoinCode} From cc899a7e7ca8a42f56bdd1e4d4676dbb717479e0 Mon Sep 17 00:00:00 2001 From: thsparks Date: Thu, 27 Oct 2022 14:31:28 -0700 Subject: [PATCH 08/13] Sans font for start game button --- multiplayer/src/components/HostLobby.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/multiplayer/src/components/HostLobby.tsx b/multiplayer/src/components/HostLobby.tsx index e7efcb34d4c..3aeee42cdcb 100644 --- a/multiplayer/src/components/HostLobby.tsx +++ b/multiplayer/src/components/HostLobby.tsx @@ -47,7 +47,7 @@ export default function Render() {