estim_control/src/context/EstimContext.tsx
2025-02-26 05:39:36 +08:00

97 lines
2.5 KiB
TypeScript

import { invoke } from '@tauri-apps/api/core';
import { Event, listen, UnlistenFn } from '@tauri-apps/api/event';
import { message } from '@tauri-apps/plugin-dialog';
import { atom, PrimitiveAtom, useSetAtom } from 'jotai';
import { atomFamily } from 'jotai/utils';
import { FC, ReactNode, useCallback, useEffect, useRef } from 'react';
export type Channels = 'a' | 'b';
type ChannelState = {
playing: boolean;
playMode: 'shuffle' | 'repeat' | 'repeat-one';
strength: number;
maxStrength: number;
boosting: boolean;
boostLevel: number;
maxBoostLevel: number;
};
type DeviceState = {
rssi: number | null;
battery: number | null;
};
type BluetoothState = {
ready: boolean | null;
searching: boolean | null;
connected: string | null;
};
export const BleState = atom<BluetoothState>({
ready: null,
searching: null,
connected: null,
});
export const DeviceState = atom<DeviceState>({
rssi: null,
battery: null,
});
const Channels: Record<Channels, PrimitiveAtom<ChannelState>> = {
a: atom<ChannelState>({
playing: false,
playMode: 'repeat-one',
strength: 0,
maxStrength: 100,
boosting: false,
boostLevel: 0,
maxBoostLevel: 100,
}),
b: atom<ChannelState>({
playing: false,
playMode: 'repeat-one',
strength: 0,
maxStrength: 100,
boosting: false,
boostLevel: 0,
maxBoostLevel: 100,
}),
};
export const ChannelState = atomFamily((channel: Channels) => Channels[channel]);
const EstimWatchProvider: FC<{ children?: ReactNode }> = ({ children }) => {
const unlisten = useRef<UnlistenFn | null>(null);
const setBleState = useSetAtom(BleState);
const handleAppStateRefresh = useCallback(async (event: Event<unknown>) => {
try {
const newState = await invoke('refresh_application_state');
setBleState({
ready: newState.central.is_ready,
searching: newState.central.is_scanning,
connected: newState.central.connected,
});
} catch (e) {
console.error('[Answer refresh state]', e);
}
}, []);
useEffect(() => {
(async function () {
try {
unlisten.current = await listen('app_state_updated', handleAppStateRefresh);
await invoke('activate_central_adapter');
} catch (e) {
console.error('[Activate Adapter]', e);
await message('Fail to activate Bluetooth adapter.', {
title: 'Bluetooth Error',
kind: 'error',
});
}
})();
return () => {
unlisten.current?.();
};
}, []);
return <>{children}</>;
};
export default EstimWatchProvider;