immich/web/src/lib/managers/event-manager.svelte.ts

115 lines
3.0 KiB
TypeScript

import type { ThemeSetting } from '$lib/managers/theme-manager.svelte';
import type { ReleaseEvent } from '$lib/types';
import type {
AlbumResponseDto,
LibraryResponseDto,
LoginResponseDto,
QueueResponseDto,
SharedLinkResponseDto,
SystemConfigDto,
UserAdminResponseDto,
} from '@immich/sdk';
export type Events = {
AppInit: [];
UserLogin: [];
AuthLogin: [LoginResponseDto];
AuthLogout: [];
LanguageChange: [{ name: string; code: string; rtl?: boolean }];
ThemeChange: [ThemeSetting];
AssetReplace: [{ oldAssetId: string; newAssetId: string }];
AlbumDelete: [AlbumResponseDto];
QueueUpdate: [QueueResponseDto];
SharedLinkCreate: [SharedLinkResponseDto];
SharedLinkUpdate: [SharedLinkResponseDto];
SharedLinkDelete: [SharedLinkResponseDto];
UserAdminCreate: [UserAdminResponseDto];
UserAdminUpdate: [UserAdminResponseDto];
UserAdminRestore: [UserAdminResponseDto];
// soft deleted
UserAdminDelete: [UserAdminResponseDto];
// confirmed permanently deleted from server
UserAdminDeleted: [{ id: string }];
SystemConfigUpdate: [SystemConfigDto];
LibraryCreate: [LibraryResponseDto];
LibraryUpdate: [LibraryResponseDto];
LibraryDelete: [{ id: string }];
ReleaseEvent: [ReleaseEvent];
TransitionToTimeline: [{ id: string }];
TimelineLoaded: [{ id: string | null }];
TransitionToAssetViewer: [];
AssetViewerLoaded: [];
RenderLoaded: [];
BeforeStartViewTransition: [];
Finished: [];
Ready: [];
UpdateCallbackDone: [];
StartViewTransition: [];
AssetViewerFree: [];
};
type Listener<EventMap extends Record<string, unknown[]>, K extends keyof EventMap> = (...params: EventMap[K]) => void;
class EventManager<EventMap extends Record<string, unknown[]>> {
private listeners: {
[K in keyof EventMap]?: {
listener: Listener<EventMap, K>;
once?: boolean;
}[];
} = {};
on<T extends keyof EventMap>(key: T, listener: (...params: EventMap[T]) => unknown) {
return this.addListener(key, listener, false);
}
once<T extends keyof EventMap>(key: T, listener: (...params: EventMap[T]) => unknown) {
return this.addListener(key, listener, true);
}
off<K extends keyof EventMap>(key: K, listener: Listener<EventMap, K>) {
if (this.listeners[key]) {
this.listeners[key] = this.listeners[key].filter((item) => item.listener !== listener);
}
return this;
}
emit<T extends keyof EventMap>(key: T, ...params: EventMap[T]) {
if (!this.listeners[key]) {
return;
}
for (const { listener } of this.listeners[key]) {
listener(...params);
}
// remove one time listeners
this.listeners[key] = this.listeners[key].filter((item) => !item.once);
}
private addListener<T extends keyof EventMap>(key: T, listener: (...params: EventMap[T]) => void, once: boolean) {
if (!this.listeners[key]) {
this.listeners[key] = [];
}
this.listeners[key].push({ listener, once });
return this;
}
}
export const eventManager = new EventManager<Events>();