mirror of
https://github.com/bulwarkmail/native.git
synced 2026-11-01 00:07:01 +00:00
feat: refetch filters and vacation on push and fan state changes out to screens
This commit is contained in:
@@ -10,6 +10,9 @@ import { Mail, Calendar, BookUser, HardDrive, Settings } from 'lucide-react-nati
|
||||
import { startLiveUpdates, type LiveUpdatesHandle } from './src/api/push-stream';
|
||||
import { jmapClient } from './src/api/jmap-client';
|
||||
import type { StateChange } from './src/api/types';
|
||||
import { dispatchStateChange } from './src/lib/state-change-bus';
|
||||
import { useFilterStore } from './src/stores/filter-store';
|
||||
import { useVacationStore } from './src/stores/vacation-store';
|
||||
import {
|
||||
addMessageListener,
|
||||
addNotificationTapListener,
|
||||
@@ -406,10 +409,19 @@ export default function App() {
|
||||
let appActive = AppState.currentState !== 'background' && AppState.currentState !== 'inactive';
|
||||
|
||||
const onStateChange = async (change: StateChange) => {
|
||||
// Filters / vacation edited elsewhere (webmail, another device): refetch
|
||||
// so the settings panes don't save stale state over the newer script.
|
||||
const primary = (() => { try { return jmapClient.accountId; } catch { return null; } })();
|
||||
const own = primary ? change.changed?.[primary] : undefined;
|
||||
const extra: Promise<unknown>[] = [];
|
||||
if (own?.SieveScript) extra.push(useFilterStore.getState().fetchFilters().catch(() => undefined));
|
||||
if (own?.VacationResponse) extra.push(useVacationStore.getState().fetch().catch(() => undefined));
|
||||
dispatchStateChange(change);
|
||||
await Promise.all([
|
||||
useEmailStore.getState().handleStateChange(change),
|
||||
useContactsStore.getState().handleStateChange(change),
|
||||
useCalendarStore.getState().handleStateChange(change),
|
||||
...extra,
|
||||
]);
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
// Fan-out of JMAP StateChange events to screens that have no store of their
|
||||
// own (Scheduled list, Files). The mail/contacts/calendar stores subscribe
|
||||
// directly in App.tsx; anything else listens here for the type it cares about.
|
||||
|
||||
import type { StateChange } from '../api/types';
|
||||
|
||||
type Listener = (accountId: string, state: string, change: StateChange) => void;
|
||||
|
||||
const listeners = new Map<string, Set<Listener>>();
|
||||
|
||||
/** Subscribe to changes of one JMAP type (e.g. `EmailSubmission`, `FileNode`). */
|
||||
export function onStateChangeType(type: string, listener: Listener): () => void {
|
||||
let set = listeners.get(type);
|
||||
if (!set) {
|
||||
set = new Set();
|
||||
listeners.set(type, set);
|
||||
}
|
||||
set.add(listener);
|
||||
return () => {
|
||||
set?.delete(listener);
|
||||
};
|
||||
}
|
||||
|
||||
export function dispatchStateChange(change: StateChange): void {
|
||||
for (const [accountId, types] of Object.entries(change.changed ?? {})) {
|
||||
for (const [type, state] of Object.entries(types ?? {})) {
|
||||
const set = listeners.get(type);
|
||||
if (!set) continue;
|
||||
for (const l of set) {
|
||||
try {
|
||||
l(accountId, state, change);
|
||||
} catch {
|
||||
// a broken listener must not break the others
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user