diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml index 517c09d..2a8cdaf 100644 --- a/.github/FUNDING.yml +++ b/.github/FUNDING.yml @@ -1,2 +1,3 @@ +custom: https://www.paypal.com/ncp/payment/CMLKCFEJEMX5L patreon: agrawald github: agrawal-d diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 0050210..2c0f62a 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -23,5 +23,4 @@ jobs: - name: Publish Extension run: ./.github/publish.sh env: - VSCE_PAT: ${{ secrets.VSCE_PAT }} - + VSCE_PAT: ${{ secrets.VSCE_PAT }} diff --git a/src/types.ts b/src/types.ts index 10f3bf4..f7c3ff2 100644 --- a/src/types.ts +++ b/src/types.ts @@ -141,6 +141,11 @@ export type CreateLocalProblem = { command: 'create-local-problem'; }; +export type OpenUrl = { + command: 'url'; + url: string; +}; + export type WebviewToVSEvent = | RunAllCommand | GetInitialProblem @@ -151,7 +156,8 @@ export type WebviewToVSEvent = | DeleteTcsCommand | SubmitCf | OnlineJudgeEnv - | SubmitKattis; + | SubmitKattis + | OpenUrl; export type RunningCommand = { command: 'running'; @@ -216,7 +222,7 @@ export type CphSubmitResponse = { }; export type WebViewpersistenceState = { - ignoreSpaceWarning: boolean; + dialogCloseDate: number; }; declare global { diff --git a/src/webview/JudgeView.ts b/src/webview/JudgeView.ts index 7f56e5f..38ed362 100644 --- a/src/webview/JudgeView.ts +++ b/src/webview/JudgeView.ts @@ -97,6 +97,11 @@ class JudgeViewProvider implements vscode.WebviewViewProvider { break; } + case 'url': { + vscode.env.openExternal(vscode.Uri.parse(message.url)); + break; + } + default: { console.error('Unknown event received from webview'); } diff --git a/src/webview/frontend/App.tsx b/src/webview/frontend/App.tsx index 389d50a..6ee7d9b 100644 --- a/src/webview/frontend/App.tsx +++ b/src/webview/frontend/App.tsx @@ -17,6 +17,8 @@ declare const vscodeApi: { setState: (state: WebViewpersistenceState) => void; }; +const payPalUrl = 'https://www.paypal.com/ncp/payment/CMLKCFEJEMX5L'; + function Judge(props: { problem: Problem; updateProblem: (problem: Problem) => void; @@ -35,6 +37,17 @@ function Judge(props: { const [waitingForSubmit, setWaitingForSubmit] = useState(false); const [onlineJudgeEnv, setOnlineJudgeEnv] = useState(false); const [remoteMessage, setRemoteMessage] = useState(''); + const [webviewState, setWebviewState] = useState( + () => { + const vscodeState = vscodeApi.getState(); + console.log('Restored state:', vscodeState); + return { + dialogCloseDate: vscodeState?.dialogCloseDate || Date.now(), + }; + }, + ); + + console.log(webviewState); // Update problem if cases change. The only place where `updateProblem` is // allowed to ensure sync. @@ -46,6 +59,19 @@ function Judge(props: { }); }, [cases]); + const closeDonateBox = () => { + const newState = { + ...webviewState, + dialogCloseDate: Date.now(), + }; + setWebviewState(newState); + vscodeApi.setState(newState); + }; + + const sendMessageToVSCode = (message: WebviewToVSEvent) => { + vscodeApi.postMessage(message); + }; + useEffect(() => { console.log('Fetching remote text message'); const url = @@ -110,7 +136,7 @@ function Judge(props: { }; const refreshOnlineJudge = () => { - vscodeApi.postMessage({ + sendMessageToVSCode({ command: 'online-judge-env', value: onlineJudgeEnv, }); @@ -128,7 +154,7 @@ function Judge(props: { problem.tests[idx].input = input; problem.tests[idx].output = output; - vscodeApi.postMessage({ + sendMessageToVSCode({ command: 'run-single-and-save', problem, id, @@ -162,7 +188,7 @@ function Judge(props: { // Stop running executions. const stop = () => { - vscodeApi.postMessage({ + sendMessageToVSCode({ command: 'kill-running', problem, }); @@ -170,7 +196,7 @@ function Judge(props: { // Deletes the .prob file and closes webview const deleteTcs = () => { - vscodeApi.postMessage({ + sendMessageToVSCode({ command: 'delete-tcs', problem, }); @@ -178,14 +204,14 @@ function Judge(props: { const runAll = () => { refreshOnlineJudge(); - vscodeApi.postMessage({ + sendMessageToVSCode({ command: 'run-all-and-save', problem, }); }; const submitKattis = () => { - vscodeApi.postMessage({ + sendMessageToVSCode({ command: 'submitKattis', problem, }); @@ -194,7 +220,7 @@ function Judge(props: { }; const submitCf = () => { - vscodeApi.postMessage({ + sendMessageToVSCode({ command: 'submitCf', problem, }); @@ -225,7 +251,7 @@ function Judge(props: { const toggleOnlineJudgeEnv = () => { const newEnv = !onlineJudgeEnv; setOnlineJudgeEnv(newEnv); - vscodeApi.postMessage({ + sendMessageToVSCode({ command: 'online-judge-env', value: newEnv, }); @@ -291,11 +317,15 @@ function Judge(props: { }); const renderSubmitButton = () => { + if (!problem.url.startsWith('http')) { + return null; + } + let url: URL; try { url = new URL(problem.url); } catch (err) { - console.error(err); + console.error(err, problem); return null; } if ( @@ -358,9 +388,45 @@ function Judge(props: { } }; + const renderDonateButton = () => { + const diff = new Date().getTime() - webviewState.dialogCloseDate; + const diffInDays = diff / (1000 * 60 * 60 * 24); + console.log('Diff in days:', diffInDays); + if (diffInDays < 14) { + return null; + } + + return ( +
+ closeDonateBox()} + > + + +

🌸

+

If you find CPH useful, please consider supporting.

+

+ Your contribution helps support continued development of + CPH. CPH is free and open source, thanks to your support. +

+ + Donate + +
+ ); + }; + return (
{notification &&
{notification}
} + {renderDonateButton()} -
@@ -447,16 +522,21 @@ function Judge(props: { {' '} Stop - + sendMessageToVSCode({ + command: 'url', + url: 'https://github.com/agrawal-d/cph/blob/main/docs/user-guide.md', + }) + } > {' '} Help - +