Files
cinny/src/app/features/settings/about/About.tsx

344 lines
13 KiB
TypeScript

import React, { useCallback, useEffect, useState } from 'react';
import { getVersion } from '@tauri-apps/api/app';
import { Box, Text, IconButton, Icon, Icons, Scroll, Button, config, toRem } from 'folds';
import { Page, PageContent, PageHeader } from '../../../components/page';
import { SequenceCard } from '../../../components/sequence-card';
import { SequenceCardStyle } from '../styles.css';
import { SettingTile } from '../../../components/setting-tile';
import PaarrotSVG from '../../../../../public/res/svg/paarrot.svg';
import { clearCacheAndReload } from '../../../../client/initMatrix';
import { useMatrixClient } from '../../../hooks/useMatrixClient';
type AboutProps = {
requestClose: () => void;
};
export function About({ requestClose }: AboutProps) {
const mx = useMatrixClient();
const [version, setVersion] = useState<string>('');
const [protocolStatus, setProtocolStatus] = useState<string>('Checking desktop protocol integration...');
const [protocolBusy, setProtocolBusy] = useState<boolean>(false);
const formatProtocolStatus = useCallback((data: {
scheme: string;
platform: string;
isDefault: boolean;
registerCall: boolean;
error: string | null;
windows: null | {
userChoiceProgId: string | null;
userChoiceCommand: string | null;
hkcuCommand: string | null;
hklmCommand: string | null;
};
}): string => {
const state = data.isDefault ? 'registered' : 'not registered';
const startupState = data.registerCall ? 'ok' : 'no-change';
const owner =
data.platform === 'win32' && data.windows?.userChoiceProgId
? ` Current default ProgId=${data.windows.userChoiceProgId}.`
: '';
const missingHint =
data.platform === 'win32' && !data.windows?.hkcuCommand && !data.windows?.hklmCommand
? ` ${data.scheme} link type is missing from Windows registry. Use Repair to create it.`
: '';
const errorPart = data.error ? ` Error: ${data.error}` : '';
return `${data.scheme} is ${state} (startup=${startupState}) on ${data.platform}.${owner}${missingHint}${errorPart}`;
}, []);
const refreshProtocolStatus = useCallback(() => {
if (!window.electron?.protocol?.getStatus) {
setProtocolStatus('Desktop protocol diagnostics are unavailable in this environment.');
return;
}
window.electron.protocol
.getStatus()
.then((result) => {
if (!result?.success || !result.data) {
setProtocolStatus(result?.error ?? 'Unable to query protocol state.');
return;
}
setProtocolStatus(formatProtocolStatus(result.data));
})
.catch((error) => {
setProtocolStatus(`Protocol diagnostics failed: ${error instanceof Error ? error.message : String(error)}`);
});
}, [formatProtocolStatus]);
const repairProtocolHandler = () => {
if (!window.electron?.protocol?.repair) {
setProtocolStatus('Protocol repair is unavailable in this environment.');
return;
}
setProtocolBusy(true);
window.electron.protocol
.repair()
.then((result) => {
if (!result?.success || !result.data) {
setProtocolStatus(result?.error ?? 'Protocol repair failed.');
return;
}
setProtocolStatus(formatProtocolStatus(result.data));
setProtocolBusy(false);
})
.catch((error) => {
setProtocolStatus(`Protocol repair failed: ${error instanceof Error ? error.message : String(error)}`);
setProtocolBusy(false);
});
};
useEffect(() => {
getVersion().then(setVersion).catch(() => setVersion('unknown'));
refreshProtocolStatus();
}, [refreshProtocolStatus]);
return (
<Page>
<PageHeader outlined={false}>
<Box grow="Yes" gap="200">
<Box grow="Yes" alignItems="Center" gap="200">
<Text size="H3" truncate>
About
</Text>
</Box>
<Box shrink="No">
<IconButton onClick={requestClose} variant="Surface">
<Icon src={Icons.Cross} />
</IconButton>
</Box>
</Box>
</PageHeader>
<Box grow="Yes">
<Scroll hideTrack visibility="Hover">
<PageContent>
<Box direction="Column" gap="700">
<Box gap="400">
<Box shrink="No">
<img
style={{ width: toRem(60), height: toRem(60) }}
src={PaarrotSVG}
alt="Paarrot logo"
/>
</Box>
<Box direction="Column" gap="300">
<Box direction="Column" gap="100">
<Box gap="100" alignItems="End">
<Text size="H3">Paarrot</Text>
<Text size="T200">v{version}</Text>
</Box>
<Text>Squawk to yer mateys!</Text>
</Box>
<Box gap="200" wrap="Wrap">
<Button
as="a"
href="https://github.com/Paarrot/Paarrot-Desktop"
rel="noreferrer noopener"
target="_blank"
variant="Secondary"
fill="Soft"
size="300"
radii="300"
before={<Icon src={Icons.Code} size="100" filled />}
>
<Text size="B300">Source Code</Text>
</Button>
</Box>
</Box>
</Box>
<Box direction="Column" gap="100">
<Text size="L400">Options</Text>
<SequenceCard
className={SequenceCardStyle}
variant="SurfaceVariant"
direction="Column"
gap="400"
>
<SettingTile
title="Clear Cache & Reload"
description="Clear all your locally stored data and reload from server."
after={
<Button
onClick={() => clearCacheAndReload(mx)}
variant="Secondary"
fill="Soft"
size="300"
radii="300"
outlined
>
<Text size="B300">Clear Cache</Text>
</Button>
}
/>
<SettingTile
title="Protocol Handler (paarrot://)"
description={protocolStatus}
after={
<Box gap="100">
<Button
onClick={repairProtocolHandler}
variant="Secondary"
fill="Soft"
size="300"
radii="300"
outlined
disabled={protocolBusy}
>
<Text size="B300">Repair</Text>
</Button>
<Button
onClick={refreshProtocolStatus}
variant="Secondary"
fill="Soft"
size="300"
radii="300"
outlined
disabled={protocolBusy}
>
<Text size="B300">Refresh</Text>
</Button>
</Box>
}
/>
</SequenceCard>
</Box>
<Box direction="Column" gap="100">
<Text size="L400">Credits</Text>
<SequenceCard
className={SequenceCardStyle}
variant="SurfaceVariant"
direction="Column"
gap="400"
>
<Box
as="ul"
direction="Column"
gap="200"
style={{
margin: 0,
paddingLeft: config.space.S400,
}}
>
<li>
<Text size="T300">
The{' '}
<a
href="https://github.com/matrix-org/matrix-js-sdk"
rel="noreferrer noopener"
target="_blank"
>
matrix-js-sdk
</a>{' '}
is ©{' '}
<a
href="https://matrix.org/foundation"
rel="noreferrer noopener"
target="_blank"
>
The Matrix.org Foundation C.I.C
</a>{' '}
used under the terms of{' '}
<a
href="http://www.apache.org/licenses/LICENSE-2.0"
rel="noreferrer noopener"
target="_blank"
>
Apache 2.0
</a>
.
</Text>
</li>
<li>
<Text size="T300">
The{' '}
<a
href="https://github.com/mozilla/twemoji-colr"
target="_blank"
rel="noreferrer noopener"
>
twemoji-colr
</a>{' '}
font is ©{' '}
<a href="https://mozilla.org/" target="_blank" rel="noreferrer noopener">
Mozilla Foundation
</a>{' '}
used under the terms of{' '}
<a
href="http://www.apache.org/licenses/LICENSE-2.0"
target="_blank"
rel="noreferrer noopener"
>
Apache 2.0
</a>
.
</Text>
</li>
<li>
<Text size="T300">
The{' '}
<a
href="https://twemoji.twitter.com"
target="_blank"
rel="noreferrer noopener"
>
Twemoji
</a>{' '}
emoji art is ©{' '}
<a
href="https://twemoji.twitter.com"
target="_blank"
rel="noreferrer noopener"
>
Twitter, Inc and other contributors
</a>{' '}
used under the terms of{' '}
<a
href="https://creativecommons.org/licenses/by/4.0/"
target="_blank"
rel="noreferrer noopener"
>
CC-BY 4.0
</a>
.
</Text>
</li>
<li>
<Text size="T300">
The{' '}
<a
href="https://material.io/design/sound/sound-resources.html"
target="_blank"
rel="noreferrer noopener"
>
Material sound resources
</a>{' '}
are ©{' '}
<a href="https://google.com" target="_blank" rel="noreferrer noopener">
Google
</a>{' '}
used under the terms of{' '}
<a
href="https://creativecommons.org/licenses/by/4.0/"
target="_blank"
rel="noreferrer noopener"
>
CC-BY 4.0
</a>
.
</Text>
</li>
</Box>
</SequenceCard>
</Box>
</Box>
</PageContent>
</Scroll>
</Box>
</Page>
);
}