Signal-Desktop/ts/context/createNativeThemeListener.ts

83 lines
2.0 KiB
TypeScript

// Copyright 2021 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
/* eslint-disable no-restricted-syntax */
import type { NativeThemeState } from '../types/NativeThemeNotifier.d';
export type Callback = (change: NativeThemeState) => void;
export interface MinimalIPC {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
send(channel: string, ...args: ReadonlyArray<any>): void;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
sendSync(channel: string): any;
on(
channel: string,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
listener: (event: unknown, ...args: ReadonlyArray<any>) => void
): this;
}
type SystemThemeType = 'dark' | 'light';
export type SystemThemeHolder = { systemTheme: SystemThemeType };
export type NativeThemeType = {
getSystemTheme: () => SystemThemeType;
subscribe: (fn: Callback) => void;
unsubscribe: (fn: Callback) => void;
update: () => SystemThemeType;
};
export function createNativeThemeListener(
ipc: MinimalIPC,
holder: SystemThemeHolder
): NativeThemeType {
const subscribers = new Array<Callback>();
let theme = ipc.sendSync('native-theme:init');
let systemTheme: SystemThemeType;
function update(): SystemThemeType {
const nextSystemTheme = theme.shouldUseDarkColors ? 'dark' : 'light';
// eslint-disable-next-line no-param-reassign
holder.systemTheme = nextSystemTheme;
return nextSystemTheme;
}
function subscribe(fn: Callback): void {
subscribers.push(fn);
}
function unsubscribe(fn: Callback): void {
const index = subscribers.indexOf(fn);
if (index !== -1) {
subscribers.splice(index, 1);
}
}
ipc.on(
'native-theme:changed',
(_event: unknown, change: NativeThemeState) => {
theme = change;
systemTheme = update();
for (const fn of subscribers) {
fn(change);
}
}
);
systemTheme = update();
return {
getSystemTheme: () => systemTheme,
subscribe,
unsubscribe,
update,
};
}