97 lines
2.5 KiB
TypeScript
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;
|