refactor state refresh.
This commit is contained in:
		| @@ -1,9 +1,9 @@ | ||||
| import { invoke } from '@tauri-apps/api/core'; | ||||
| import { Event, listen, UnlistenFn } from '@tauri-apps/api/event'; | ||||
| import { 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'; | ||||
| import { atomFamily, atomWithRefresh } from 'jotai/utils'; | ||||
| import { FC, ReactNode, useEffect, useRef } from 'react'; | ||||
|  | ||||
| export type Channels = 'a' | 'b'; | ||||
| type ChannelState = { | ||||
| @@ -15,7 +15,19 @@ type ChannelState = { | ||||
|   boostLevel: number; | ||||
|   maxBoostLevel: number; | ||||
| }; | ||||
| type PeripheralItem = { | ||||
|   id: string; | ||||
|   address: string; | ||||
|   represent: string; | ||||
|   isConnected: boolean; | ||||
|   rssi: number | null; | ||||
|   battery: number | null; | ||||
| }; | ||||
| type DeviceState = { | ||||
|   id: string | null; | ||||
|   address: string | null; | ||||
|   represent: string | null; | ||||
|   isConnected: boolean | null; | ||||
|   rssi: number | null; | ||||
|   battery: number | null; | ||||
| }; | ||||
| @@ -25,57 +37,136 @@ type BluetoothState = { | ||||
|   connected: string | null; | ||||
| }; | ||||
|  | ||||
| export const BleState = atom<BluetoothState>({ | ||||
|   ready: null, | ||||
|   searching: null, | ||||
|   connected: null, | ||||
| export const BleState = atomWithRefresh<BluetoothState>(async (get) => { | ||||
|   try { | ||||
|     const state = await invoke('central_device_state'); | ||||
|     return { | ||||
|       ready: state.isReady, | ||||
|       searching: state.isScanning, | ||||
|       connected: state.connected, | ||||
|     }; | ||||
|   } catch (e) { | ||||
|     console.error('[refresh central]', e); | ||||
|   } | ||||
|   return { | ||||
|     ready: null, | ||||
|     searching: null, | ||||
|     connected: null, | ||||
|   }; | ||||
| }); | ||||
| export const DeviceState = atom<DeviceState>({ | ||||
|   rssi: null, | ||||
|   battery: null, | ||||
| export const DeviceState = atomWithRefresh<DeviceState>(async (get) => { | ||||
|   try { | ||||
|     const state = await invoke('connected_peripheral_state'); | ||||
|     return { | ||||
|       id: state?.id, | ||||
|       address: state?.address, | ||||
|       represent: state?.represent, | ||||
|       isConnected: state?.isConnected, | ||||
|       rssi: state?.rssi, | ||||
|       battery: state?.battery, | ||||
|     }; | ||||
|   } catch (e) { | ||||
|     console.error('[refresh connected]', e); | ||||
|   } | ||||
|   return { | ||||
|     id: null, | ||||
|     address: null, | ||||
|     represent: null, | ||||
|     isConnected: null, | ||||
|     rssi: null, | ||||
|     battery: null, | ||||
|   }; | ||||
| }); | ||||
| export const FoundPeripherals = atomWithRefresh<PeripheralItem[]>(async (get) => { | ||||
|   try { | ||||
|     const peripherals = await invoke('found_peripherals'); | ||||
|     return peripherals.map((peripheral: PeripheralItem) => ({ | ||||
|       id: peripheral.id, | ||||
|       address: peripheral.address, | ||||
|       represent: peripheral.represent, | ||||
|       isConnected: peripheral.isConnected, | ||||
|       rssi: peripheral.rssi, | ||||
|       battery: peripheral.battery, | ||||
|     })); | ||||
|   } catch (e) { | ||||
|     console.error('[refresh found]', e); | ||||
|   } | ||||
|   return []; | ||||
| }); | ||||
| const Channels: Record<Channels, PrimitiveAtom<ChannelState>> = { | ||||
|   a: atom<ChannelState>({ | ||||
|     playing: false, | ||||
|     playMode: 'repeat-one', | ||||
|     strength: 0, | ||||
|     maxStrength: 100, | ||||
|     boosting: false, | ||||
|     boostLevel: 0, | ||||
|     maxBoostLevel: 100, | ||||
|   a: atomWithRefresh<ChannelState>(async (get) => { | ||||
|     try { | ||||
|       const state = await invoke('channel_a_state'); | ||||
|       return { | ||||
|         playing: state.isPlaying, | ||||
|         playMode: state.playMode, | ||||
|         strength: state.strength, | ||||
|         maxStrength: state.maxStrength, | ||||
|         boosting: state.isBoosting, | ||||
|         boostLevel: state.boostLevel, | ||||
|         maxBoostLevel: state.maxBoostLevel, | ||||
|       }; | ||||
|     } catch (e) { | ||||
|       console.error('[refresh channel a]', e); | ||||
|     } | ||||
|     return { | ||||
|       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, | ||||
|   b: atom<ChannelState>(async (get) => { | ||||
|     try { | ||||
|       const state = await invoke('channel_b_state'); | ||||
|       return { | ||||
|         playing: state.isPlaying, | ||||
|         playMode: state.playMode, | ||||
|         strength: state.strength, | ||||
|         maxStrength: state.maxStrength, | ||||
|         boosting: state.isBoosting, | ||||
|         boostLevel: state.boostLevel, | ||||
|         maxBoostLevel: state.maxBoostLevel, | ||||
|       }; | ||||
|     } catch (e) { | ||||
|       console.error('[refresh channel b]', e); | ||||
|     } | ||||
|     return { | ||||
|       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); | ||||
|     } | ||||
|   }, []); | ||||
|   const unlistenBle = useRef<UnlistenFn | null>(null); | ||||
|   const unlistenDevice = useRef<UnlistenFn | null>(null); | ||||
|   const unlistenPreipherals = useRef<UnlistenFn | null>(null); | ||||
|   const unlistenChannelA = useRef<UnlistenFn | null>(null); | ||||
|   const unlistenChannelB = useRef<UnlistenFn | null>(null); | ||||
|   const refreshBle = useSetAtom(BleState); | ||||
|   const refreshDevice = useSetAtom(DeviceState); | ||||
|   const refreshPeripherals = useSetAtom(FoundPeripherals); | ||||
|   const refreshChannelA = useSetAtom(ChannelState('a')); | ||||
|   const refreshChannelB = useSetAtom(ChannelState('b')); | ||||
|  | ||||
|   useEffect(() => { | ||||
|     (async function () { | ||||
|       try { | ||||
|         unlisten.current = await listen('app_state_updated', handleAppStateRefresh); | ||||
|         unlistenBle.current = await listen('central_state_updated', () => refreshBle()); | ||||
|         unlistenDevice.current = await listen('peripheral_connected', () => refreshDevice()); | ||||
|         unlistenPreipherals.current = await listen('peripherals_found', () => refreshPeripherals()); | ||||
|         unlistenChannelA.current = await listen('channel_a_updated', () => refreshChannelA()); | ||||
|         unlistenChannelB.current = await listen('channel_b_updated', () => refreshChannelB()); | ||||
|         await invoke('activate_central_adapter'); | ||||
|       } catch (e) { | ||||
|         console.error('[Activate Adapter]', e); | ||||
| @@ -87,7 +178,11 @@ const EstimWatchProvider: FC<{ children?: ReactNode }> = ({ children }) => { | ||||
|     })(); | ||||
|  | ||||
|     return () => { | ||||
|       unlisten.current?.(); | ||||
|       unlistenBle.current?.(); | ||||
|       unlistenDevice.current?.(); | ||||
|       unlistenPreipherals.current?.(); | ||||
|       unlistenChannelA.current?.(); | ||||
|       unlistenChannelB.current?.(); | ||||
|     }; | ||||
|   }, []); | ||||
|   return <>{children}</>; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user