desktop/src/configurator/configurator.tsx

147 lines
5.0 KiB
TypeScript

import { invoke } from '@tauri-apps/api';
import { FC, useCallback, useEffect, useMemo, useState } from 'react';
import tw, { styled } from 'twin.macro';
import { useAsync, useAsyncCallback } from 'react-async-hook';
import { DisplayWithLedStrips } from './components/display-with-led-strips';
import { PickerConfiguration } from './models/picker-configuration';
import { DisplayConfig } from './models/display-config';
import { ScreenshotDto } from './models/screenshot.dto';
import { Alert, Fab, Snackbar } from '@mui/material';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faRotateBack, faSpinner } from '@fortawesome/free-solid-svg-icons';
import { update } from 'ramda';
import { CompletedLedStrip } from './components/completed-led-strip';
import { LedCountProvider } from './contents/led-count';
import debug from 'debug';
import { useSnackbar } from 'notistack';
import { fillParentCss } from '../styles/fill-parent';
const logger = debug('app:configurator');
const getPickerConfig = () => invoke<PickerConfiguration>('get_picker_config');
const getScreenshotOfDisplays = () =>
invoke<ScreenshotDto[]>('take_snapshot').then((items) => {
return items;
});
const getScreenshotByConfig = async (config: DisplayConfig) => {
return await invoke<ScreenshotDto>('get_screenshot_by_config', {
config,
});
};
const writePickerConfig = async (config: PickerConfiguration) => {
return await invoke<void>('write_picker_config', {
config,
});
};
const StyledConfiguratorContainer = styled.section(
tw`flex flex-col items-stretch relative overflow-hidden`,
fillParentCss,
);
const StyledDisplayContainer = styled.section(tw`overflow-auto`);
const ConfiguratorInner: FC = () => {
const { enqueueSnackbar } = useSnackbar();
const { loading: pendingPickerConfig, result: savedPickerConfig } = useAsync(
getPickerConfig,
[],
);
const { loading: pendingScreenshotOfDisplays, result: defaultScreenshotOfDisplays } =
useAsync(getScreenshotOfDisplays, []);
const [screenshotOfDisplays, setScreenshotOfDisplays] = useState<ScreenshotDto[]>([]);
const { loading: pendingGetLedColorsByConfig, execute: onDisplayConfigChange } =
useAsyncCallback(async (value: DisplayConfig) => {
const screenshot = await getScreenshotByConfig(value);
setScreenshotOfDisplays((old) => {
const index = old.findIndex((it) => it.config.id === screenshot.config.id);
const newValue = update(index, screenshot, old);
savedPickerConfig &&
writePickerConfig({
...savedPickerConfig,
display_configs: newValue.map((it) => it.config),
});
return newValue;
});
});
const [displayConfigs, setDisplayConfigs] = useState<DisplayConfig[]>([]);
useEffect(() => {
const displayConfigs = savedPickerConfig?.display_configs;
if (displayConfigs && defaultScreenshotOfDisplays) {
setDisplayConfigs(displayConfigs);
setScreenshotOfDisplays(defaultScreenshotOfDisplays);
(async () => {
for (const config of displayConfigs) {
await onDisplayConfigChange(config);
}
})().then();
}
}, [savedPickerConfig, onDisplayConfigChange, defaultScreenshotOfDisplays]);
const resetBackToDefaultConfig = useCallback(() => {
if (defaultScreenshotOfDisplays) {
setScreenshotOfDisplays(defaultScreenshotOfDisplays);
} else {
enqueueSnackbar('Default Config was not found. please try again later.', {
variant: 'error',
});
}
}, [setScreenshotOfDisplays, defaultScreenshotOfDisplays]);
const displays = useMemo(() => {
if (screenshotOfDisplays) {
return screenshotOfDisplays.map((screenshot, index) => (
<DisplayWithLedStrips
key={index}
config={screenshot.config}
screenshot={screenshot}
onChange={(value) => onDisplayConfigChange(value)}
/>
));
}
}, [displayConfigs, screenshotOfDisplays]);
if (pendingPickerConfig || pendingScreenshotOfDisplays) {
return (
<section>
{JSON.stringify({ pendingPickerConfig, pendingScreenshotOfDisplays })}
</section>
);
}
return (
<StyledConfiguratorContainer>
<CompletedLedStrip
screenshots={screenshotOfDisplays}
onDisplayConfigChange={onDisplayConfigChange}
/>
<StyledDisplayContainer tw="overflow-y-auto">{displays}</StyledDisplayContainer>
<Fab
aria-label="reset"
size="small"
tw="top-2 right-2 absolute"
onClick={resetBackToDefaultConfig}
>
<FontAwesomeIcon icon={faRotateBack} />
</Fab>
<Snackbar open={pendingGetLedColorsByConfig} autoHideDuration={3000}>
<Alert icon={<FontAwesomeIcon icon={faSpinner} />} sx={{ width: '100%' }}>
This is a success message!
</Alert>
</Snackbar>
</StyledConfiguratorContainer>
);
};
export const Configurator = () => {
return (
<LedCountProvider>
<ConfiguratorInner />
</LedCountProvider>
);
};