refactor: web stores => managers (1)

This commit is contained in:
Daniel Dietzler 2025-04-28 13:20:00 +02:00
parent 205260d31c
commit d1e62c3736
No known key found for this signature in database
GPG Key ID: A1C0B97CD8E18DFF
37 changed files with 196 additions and 143 deletions

View File

@ -1,7 +1,6 @@
<script lang="ts">
import SelectAllAssets from '$lib/components/photos-page/actions/select-all-assets.svelte';
import { assetViewingStore } from '$lib/stores/asset-viewing.store';
import { dragAndDropFilesStore } from '$lib/stores/drag-and-drop-files.store';
import { fileUploadHandler, openFileUploadDialog } from '$lib/utils/file-uploader';
import type { AlbumResponseDto, SharedLinkResponseDto, UserResponseDto } from '@immich/sdk';
import { AssetStore } from '$lib/stores/assets-store.svelte';
@ -20,6 +19,7 @@
import { t } from 'svelte-i18n';
import { onDestroy } from 'svelte';
import { AssetInteraction } from '$lib/stores/asset-interaction.svelte';
import { dragAndDropManager } from '$lib/managers/drag-and-drop.manager.svelte';
interface Props {
sharedLink: SharedLinkResponseDto;
@ -38,10 +38,10 @@
const assetInteraction = new AssetInteraction();
dragAndDropFilesStore.subscribe((value) => {
if (value.isDragging && value.files.length > 0) {
handlePromiseError(fileUploadHandler(value.files, album.id));
dragAndDropFilesStore.set({ isDragging: false, files: [] });
$effect(() => {
if (dragAndDropManager.isDragging && dragAndDropManager.files.length > 0) {
handlePromiseError(fileUploadHandler(dragAndDropManager.files, album.id));
dragAndDropManager.reset();
}
});
</script>

View File

@ -5,7 +5,6 @@
import NextAssetAction from '$lib/components/asset-viewer/actions/next-asset-action.svelte';
import PreviousAssetAction from '$lib/components/asset-viewer/actions/previous-asset-action.svelte';
import { AssetAction, ProjectionType } from '$lib/constants';
import { updateNumberOfComments } from '$lib/stores/activity.store';
import { closeEditorCofirm } from '$lib/stores/asset-editor.store';
import { assetViewingStore } from '$lib/stores/asset-viewing.store';
import { isShowDetail } from '$lib/stores/preferences.store';
@ -47,6 +46,7 @@
import PhotoViewer from './photo-viewer.svelte';
import SlideshowBar from './slideshow-bar.svelte';
import VideoViewer from './video-wrapper-viewer.svelte';
import { activityManager } from '$lib/managers/activity.manager.svelte';
type HasAsset = boolean;
@ -137,12 +137,12 @@
const handleAddComment = () => {
numberOfComments++;
updateNumberOfComments(1);
activityManager.updateNumberOfComments(1);
};
const handleRemoveComment = () => {
numberOfComments--;
updateNumberOfComments(-1);
activityManager.updateNumberOfComments(-1);
};
const handleFavorite = async () => {

View File

@ -46,7 +46,7 @@
import AlbumListItemDetails from './album-list-item-details.svelte';
import Portal from '$lib/components/shared-components/portal/portal.svelte';
import { getMetadataSearchQuery } from '$lib/utils/metadata-search';
import { isFaceEditMode } from '$lib/stores/face-edit.svelte';
import { faceManager } from '$lib/managers/face.manager.svelte';
interface Props {
asset: AssetResponseDto;
@ -207,7 +207,7 @@
padding="1"
size="20"
buttonSize="32"
onclick={() => (isFaceEditMode.value = !isFaceEditMode.value)}
onclick={() => (faceManager.isEditMode = !faceManager.isEditMode)}
/>
{#if people.length > 0 || unassignedFaces.length > 0}

View File

@ -1,5 +1,5 @@
<script lang="ts">
import { type DownloadProgress, downloadManager, downloadStore } from '$lib/stores/download-store.svelte';
import { downloadManager, type DownloadProgress } from '$lib/managers/download.manager.svelte';
import { locale } from '$lib/stores/preferences.store';
import { fly, slide } from 'svelte/transition';
import { getByteUnitString } from '../../utils/byte-units';
@ -13,15 +13,15 @@
};
</script>
{#if downloadStore.isDownloading}
{#if downloadManager.isDownloading}
<div
transition:fly={{ x: -100, duration: 350 }}
class="fixed bottom-10 left-2 z-[10000] max-h-[270px] w-[315px] rounded-2xl border bg-immich-bg p-4 text-sm shadow-sm"
>
<p class="mb-2 text-xs text-gray-500">{$t('downloading').toUpperCase()}</p>
<div class="my-2 mb-2 flex max-h-[200px] flex-col overflow-y-auto text-sm">
{#each Object.keys(downloadStore.assets) as downloadKey (downloadKey)}
{@const download = downloadStore.assets[downloadKey]}
{#each Object.keys(downloadManager.assets) as downloadKey (downloadKey)}
{@const download = downloadManager.assets[downloadKey]}
<div class="mb-2 flex place-items-center" transition:slide>
<div class="w-full pr-10">
<div class="flex place-items-center justify-between gap-2 text-xs font-medium">

View File

@ -2,7 +2,6 @@
import ImageThumbnail from '$lib/components/assets/thumbnail/image-thumbnail.svelte';
import { dialogController } from '$lib/components/shared-components/dialog/dialog';
import { notificationController } from '$lib/components/shared-components/notification/notification';
import { isFaceEditMode } from '$lib/stores/face-edit.svelte';
import { getPeopleThumbnailUrl } from '$lib/utils';
import { getAllPeople, createFace, type PersonResponseDto } from '@immich/sdk';
import { Button, Input } from '@immich/ui';
@ -10,6 +9,7 @@
import { onMount } from 'svelte';
import { assetViewingStore } from '$lib/stores/asset-viewing.store';
import { handleError } from '$lib/utils/handle-error';
import { faceManager } from '$lib/managers/face.manager.svelte';
interface Props {
htmlElement: HTMLImageElement | HTMLVideoElement;
@ -140,7 +140,7 @@
};
const cancel = () => {
isFaceEditMode.value = false;
faceManager.isEditMode = false;
};
const getPeople = async () => {
@ -303,7 +303,7 @@
} catch (error) {
handleError(error, 'Error tagging face');
} finally {
isFaceEditMode.value = false;
faceManager.isEditMode = false;
}
};
</script>

View File

@ -20,7 +20,7 @@
import { handleError } from '$lib/utils/handle-error';
import FaceEditor from '$lib/components/asset-viewer/face-editor/face-editor.svelte';
import { photoViewerImgElement } from '$lib/stores/assets-store.svelte';
import { isFaceEditMode } from '$lib/stores/face-edit.svelte';
import { faceManager } from '$lib/managers/face.manager.svelte';
interface Props {
asset: AssetResponseDto;
@ -109,7 +109,7 @@
};
$effect(() => {
if (isFaceEditMode.value && $photoZoomState.currentZoom > 1) {
if (faceManager.isEditMode && $photoZoomState.currentZoom > 1) {
zoomToggle();
}
});
@ -235,7 +235,7 @@
{/each}
</div>
{#if isFaceEditMode.value}
{#if faceManager.isEditMode}
<FaceEditor htmlElement={$photoViewerImgElement} {containerWidth} {containerHeight} assetId={asset.id} />
{/if}
{/if}

View File

@ -9,8 +9,8 @@
import type { SwipeCustomEvent } from 'svelte-gestures';
import { fade } from 'svelte/transition';
import { t } from 'svelte-i18n';
import { isFaceEditMode } from '$lib/stores/face-edit.svelte';
import FaceEditor from '$lib/components/asset-viewer/face-editor/face-editor.svelte';
import { faceManager } from '$lib/managers/face.manager.svelte';
interface Props {
assetId: string;
@ -94,7 +94,7 @@
let containerHeight = $state(0);
$effect(() => {
if (isFaceEditMode.value) {
if (faceManager.isEditMode) {
videoPlayer?.pause();
}
});
@ -141,7 +141,7 @@
</div>
{/if}
{#if isFaceEditMode.value}
{#if faceManager.isEditMode}
<FaceEditor htmlElement={videoPlayer} {containerWidth} {containerHeight} {assetId} />
{/if}
</div>

View File

@ -2,7 +2,6 @@
import { goto } from '$app/navigation';
import type { Action } from '$lib/components/asset-viewer/actions/action';
import { AppRoute, AssetAction } from '$lib/constants';
import { dragAndDropFilesStore } from '$lib/stores/drag-and-drop-files.store';
import { getKey, handlePromiseError } from '$lib/utils';
import { downloadArchive } from '$lib/utils/asset-utils';
import { fileUploadHandler, openFileUploadDialog } from '$lib/utils/file-uploader';
@ -22,6 +21,7 @@
import type { Viewport } from '$lib/stores/assets-store.svelte';
import { t } from 'svelte-i18n';
import { AssetInteraction } from '$lib/stores/asset-interaction.svelte';
import { dragAndDropManager } from '$lib/managers/drag-and-drop.manager.svelte';
interface Props {
sharedLink: SharedLinkResponseDto;
@ -35,10 +35,10 @@
let assets = $derived(sharedLink.assets);
dragAndDropFilesStore.subscribe((value) => {
if (value.isDragging && value.files.length > 0) {
handlePromiseError(handleUploadAssets(value.files));
dragAndDropFilesStore.set({ isDragging: false, files: [] });
$effect(() => {
if (dragAndDropManager.isDragging && dragAndDropManager.files.length > 0) {
handlePromiseError(handleUploadAssets(dragAndDropManager.files));
dragAndDropManager.reset();
}
});

View File

@ -6,7 +6,7 @@
type Padding,
} from '$lib/components/elements/buttons/circle-icon-button.svelte';
import ContextMenu from '$lib/components/shared-components/context-menu/context-menu.svelte';
import { optionClickCallbackStore, selectedIdStore } from '$lib/stores/context-menu.store';
import { contextMenuManager } from '$lib/managers/context-menu.manager.svelte';
import {
getContextMenuPositionFromBoundingRect,
getContextMenuPositionFromEvent,
@ -97,7 +97,7 @@
}
focusButton();
isOpen = false;
$selectedIdStore = undefined;
contextMenuManager.selectedId = undefined;
};
const handleOptionClick = () => {
@ -124,7 +124,7 @@
$effect(() => {
if (isOpen) {
$optionClickCallbackStore = handleOptionClick;
contextMenuManager.optionClickCallback = handleOptionClick;
}
});
</script>
@ -139,8 +139,8 @@
isOpen,
onEscape,
openDropdown,
selectedId: $selectedIdStore,
selectionChanged: (id) => ($selectedIdStore = id),
selectedId: contextMenuManager.selectedId,
selectionChanged: (id) => (contextMenuManager.selectedId = id),
}}
onresize={onResize}
{...restProps}
@ -178,7 +178,7 @@
<ContextMenu
{...contextMenuPosition}
{direction}
ariaActiveDescendant={$selectedIdStore}
ariaActiveDescendant={contextMenuManager.selectedId}
ariaLabelledBy={buttonId}
bind:menuElement={menuContainer}
id={menuId}

View File

@ -1,9 +1,9 @@
<script lang="ts">
import Icon from '$lib/components/elements/icon.svelte';
import { generateId } from '$lib/utils/generate-id';
import { optionClickCallbackStore, selectedIdStore } from '$lib/stores/context-menu.store';
import type { Shortcut } from '$lib/actions/shortcut';
import { shortcutLabel as computeShortcutLabel, shortcut as bindShortcut } from '$lib/actions/shortcut';
import { contextMenuManager } from '$lib/managers/context-menu.manager.svelte';
interface Props {
text: string;
@ -29,10 +29,10 @@
let id: string = generateId();
let isActive = $derived($selectedIdStore === id);
let isActive = $derived(contextMenuManager.selectedId === id);
const handleClick = () => {
$optionClickCallbackStore?.();
contextMenuManager.optionClickCallback?.();
onClick();
};
@ -51,8 +51,8 @@
<li
{id}
onclick={handleClick}
onmouseover={() => ($selectedIdStore = id)}
onmouseleave={() => ($selectedIdStore = undefined)}
onmouseover={() => (contextMenuManager.selectedId = id)}
onmouseleave={() => (contextMenuManager.selectedId = undefined)}
class="w-full p-4 text-left text-sm font-medium {textColor} focus:outline-none focus:ring-2 focus:ring-inset cursor-pointer border-gray-200 flex gap-2 items-center {isActive
? activeColor
: 'bg-slate-100'}"

View File

@ -4,7 +4,7 @@
import { shortcuts } from '$lib/actions/shortcut';
import { generateId } from '$lib/utils/generate-id';
import { contextMenuNavigation } from '$lib/actions/context-menu-navigation';
import { optionClickCallbackStore, selectedIdStore } from '$lib/stores/context-menu.store';
import { contextMenuManager } from '$lib/managers/context-menu.manager.svelte';
interface Props {
title: string;
@ -60,7 +60,7 @@
if (isOpen && menuContainer) {
triggerElement = document.activeElement as HTMLElement;
menuContainer.focus();
$optionClickCallbackStore = closeContextMenu;
contextMenuManager.optionClickCallback = closeContextMenu;
}
});
@ -77,8 +77,8 @@
closeDropdown: closeContextMenu,
container: menuContainer,
isOpen,
selectedId: $selectedIdStore,
selectionChanged: (id) => ($selectedIdStore = id),
selectedId: contextMenuManager.selectedId,
selectionChanged: (id) => (contextMenuManager.selectedId = id),
}}
use:shortcuts={[
{
@ -96,7 +96,7 @@
{direction}
{x}
{y}
ariaActiveDescendant={$selectedIdStore}
ariaActiveDescendant={contextMenuManager.selectedId}
ariaLabel={title}
bind:menuElement={menuContainer}
id={menuId}

View File

@ -1,7 +1,7 @@
<script lang="ts">
import { page } from '$app/state';
import { shouldIgnoreEvent } from '$lib/actions/shortcut';
import { dragAndDropFilesStore } from '$lib/stores/drag-and-drop-files.store';
import { dragAndDropManager } from '$lib/managers/drag-and-drop.manager.svelte';
import { fileUploadHandler } from '$lib/utils/file-uploader';
import { isAlbumsRoute, isSharedLinkRoute } from '$lib/utils/navigation';
import { t } from 'svelte-i18n';
@ -124,7 +124,8 @@
const filesArray: File[] = Array.from<File>(files);
if (isShare) {
dragAndDropFilesStore.set({ isDragging: true, files: filesArray });
dragAndDropManager.isDragging = true;
dragAndDropManager.files = filesArray;
} else {
await fileUploadHandler(filesArray, albumId);
}

View File

@ -10,7 +10,7 @@
import ImmichLogo from '$lib/components/shared-components/immich-logo.svelte';
import SearchBar from '$lib/components/shared-components/search-bar/search-bar.svelte';
import { AppRoute } from '$lib/constants';
import { authManager } from '$lib/stores/auth-manager.svelte';
import { authManager } from '$lib/managers/auth-manager.svelte';
import { mobileDevice } from '$lib/stores/mobile-device.svelte';
import { featureFlags } from '$lib/stores/server-config.store';
import { sidebarStore } from '$lib/stores/sidebar.svelte';

View File

@ -0,0 +1,17 @@
class ActivityManager {
#numberOfComments = $state<number>(0);
get numberOfComments() {
return this.#numberOfComments;
}
set numberOfComments(number: number) {
this.#numberOfComments = number;
}
updateNumberOfComments(addOrRemove: 1 | -1) {
this.#numberOfComments += addOrRemove;
}
}
export const activityManager = new ActivityManager();

View File

@ -1,6 +1,6 @@
import { goto } from '$app/navigation';
import { AppRoute } from '$lib/constants';
import { eventManager } from '$lib/stores/event-manager.svelte';
import { eventManager } from '$lib/managers/event.manager.svelte';
import { logout } from '@immich/sdk';
class AuthManager {

View File

@ -0,0 +1,22 @@
class ContextMenuManager {
#selectedId = $state<string | undefined>(undefined);
#optionClickCallback = $state<(() => void) | undefined>(undefined);
get selectedId() {
return this.#selectedId;
}
set selectedId(id: string | undefined) {
this.#selectedId = id;
}
get optionClickCallback() {
return this.#optionClickCallback;
}
set optionClickCallback(callback: (() => void) | undefined) {
this.#optionClickCallback = callback;
}
}
export const contextMenuManager = new ContextMenuManager();

View File

@ -0,0 +1,47 @@
export interface DownloadProgress {
progress: number;
total: number;
percentage: number;
abort: AbortController | null;
}
class DownloadManager {
#assets = $state<Record<string, DownloadProgress>>({});
#isDownloading = $derived(Object.keys(this.#assets).length > 0);
#update(key: string, value: Partial<DownloadProgress>) {
if (!this.#assets[key]) {
this.#assets[key] = { progress: 0, total: 0, percentage: 0, abort: null };
}
const item = this.#assets[key];
Object.assign(item, value);
item.percentage = Math.min(Math.floor((item.progress / item.total) * 100), 100);
}
get assets() {
return this.#assets;
}
get isDownloading() {
return this.#isDownloading;
}
add(key: string, total: number, abort?: AbortController) {
this.#update(key, { total, abort });
}
clear(key: string) {
delete this.#assets[key];
}
update(key: string, progress: number, total?: number) {
const download: Partial<DownloadProgress> = { progress };
if (total !== undefined) {
download.total = total;
}
this.#update(key, download);
}
}
export const downloadManager = new DownloadManager();

View File

@ -0,0 +1,27 @@
class DragAndDropManager {
#isDragging = $state<boolean>(false);
#files = $state<File[]>([]);
get isDragging() {
return this.#isDragging;
}
get files() {
return this.#files;
}
set isDragging(isDragging: boolean) {
this.#isDragging = isDragging;
}
set files(files: File[]) {
this.#files = files;
}
reset() {
this.#isDragging = false;
this.#files = [];
}
}
export const dragAndDropManager = new DragAndDropManager();

View File

@ -0,0 +1,13 @@
class FaceManager {
#isEditMode = $state(false);
get isEditMode() {
return this.#isEditMode;
}
set isEditMode(isEditMode: boolean) {
this.#isEditMode = isEditMode;
}
}
export const faceManager = new FaceManager();

View File

@ -1,11 +0,0 @@
import { writable } from 'svelte/store';
export const numberOfComments = writable<number>(0);
export const setNumberOfComments = (number: number) => {
numberOfComments.set(number);
};
export const updateNumberOfComments = (addOrRemove: 1 | -1) => {
numberOfComments.update((n) => n + addOrRemove);
};

View File

@ -1,6 +0,0 @@
import { writable } from 'svelte/store';
const selectedIdStore = writable<string | undefined>(undefined);
const optionClickCallbackStore = writable<(() => void) | undefined>(undefined);
export { optionClickCallbackStore, selectedIdStore };

View File

@ -1,51 +0,0 @@
export interface DownloadProgress {
progress: number;
total: number;
percentage: number;
abort: AbortController | null;
}
class DownloadStore {
assets = $state<Record<string, DownloadProgress>>({});
isDownloading = $derived(Object.keys(this.assets).length > 0);
#update(key: string, value: Partial<DownloadProgress> | null) {
if (value === null) {
delete this.assets[key];
return;
}
if (!this.assets[key]) {
this.assets[key] = { progress: 0, total: 0, percentage: 0, abort: null };
}
const item = this.assets[key];
Object.assign(item, value);
item.percentage = Math.min(Math.floor((item.progress / item.total) * 100), 100);
}
add(key: string, total: number, abort?: AbortController) {
this.#update(key, { total, abort });
}
clear(key: string) {
this.#update(key, null);
}
update(key: string, progress: number, total?: number) {
const download: Partial<DownloadProgress> = { progress };
if (total !== undefined) {
download.total = total;
}
this.#update(key, download);
}
}
export const downloadStore = new DownloadStore();
export const downloadManager = {
add: (key: string, total: number, abort?: AbortController) => downloadStore.add(key, total, abort),
clear: (key: string) => downloadStore.clear(key),
update: (key: string, progress: number, total?: number) => downloadStore.update(key, progress, total),
};

View File

@ -1,7 +0,0 @@
//store to track the state of the drag and drop and the files
import { writable } from 'svelte/store';
export const dragAndDropFilesStore = writable({
isDragging: false as boolean,
files: [] as File[],
});

View File

@ -1 +0,0 @@
export const isFaceEditMode = $state({ value: false });

View File

@ -1,4 +1,4 @@
import { eventManager } from '$lib/stores/event-manager.svelte';
import { eventManager } from '$lib/managers/event.manager.svelte';
import {
getAssetsByOriginalPath,
getUniqueOriginalPaths,

View File

@ -1,4 +1,4 @@
import { eventManager } from '$lib/stores/event-manager.svelte';
import { eventManager } from '$lib/managers/event.manager.svelte';
import { asLocalTimeISO } from '$lib/utils/date-time';
import {
type AssetResponseDto,

View File

@ -1,4 +1,4 @@
import { eventManager } from '$lib/stores/event-manager.svelte';
import { eventManager } from '$lib/managers/event.manager.svelte';
class SearchStore {
savedSearchTerms = $state<string[]>([]);

View File

@ -1,4 +1,4 @@
import { eventManager } from '$lib/stores/event-manager.svelte';
import { eventManager } from '$lib/managers/event.manager.svelte';
import { purchaseStore } from '$lib/stores/purchase.store';
import { type UserAdminResponseDto, type UserPreferencesResponseDto } from '@immich/sdk';
import { writable } from 'svelte/store';

View File

@ -1,4 +1,4 @@
import { eventManager } from '$lib/stores/event-manager.svelte';
import { eventManager } from '$lib/managers/event.manager.svelte';
import type {
AlbumResponseDto,
ServerAboutResponseDto,

View File

@ -1,4 +1,4 @@
import { authManager } from '$lib/stores/auth-manager.svelte';
import { authManager } from '$lib/managers/auth-manager.svelte';
import { createEventEmitter } from '$lib/utils/eventemitter';
import type { AssetResponseDto, ServerVersionResponseDto } from '@immich/sdk';
import { io, type Socket } from 'socket.io-client';

View File

@ -3,9 +3,9 @@ import FormatBoldMessage from '$lib/components/i18n/format-bold-message.svelte';
import type { InterpolationValues } from '$lib/components/i18n/format-message';
import { NotificationType, notificationController } from '$lib/components/shared-components/notification/notification';
import { AppRoute } from '$lib/constants';
import { downloadManager } from '$lib/managers/download.manager.svelte';
import type { AssetInteraction } from '$lib/stores/asset-interaction.svelte';
import { assetsSnapshot, isSelectingAllAssets, type AssetStore } from '$lib/stores/assets-store.svelte';
import { downloadManager } from '$lib/stores/download-store.svelte';
import { preferences } from '$lib/stores/user.store';
import { downloadRequest, getKey, withError } from '$lib/utils';
import { createAlbum } from '$lib/utils/album-utils';

View File

@ -34,7 +34,6 @@
} from '$lib/components/shared-components/notification/notification';
import UserAvatar from '$lib/components/shared-components/user-avatar.svelte';
import { AppRoute, AlbumPageViewMode } from '$lib/constants';
import { numberOfComments, setNumberOfComments, updateNumberOfComments } from '$lib/stores/activity.store';
import { assetViewingStore } from '$lib/stores/asset-viewing.store';
import { AssetStore } from '$lib/stores/assets-store.svelte';
import { SlideshowNavigation, SlideshowState, slideshowStore } from '$lib/stores/slideshow.store';
@ -87,6 +86,7 @@
import { confirmAlbumDelete } from '$lib/utils/album-utils';
import TagAction from '$lib/components/photos-page/actions/tag-action.svelte';
import { AssetInteraction } from '$lib/stores/asset-interaction.svelte';
import { activityManager } from '$lib/managers/activity.manager.svelte';
interface Props {
data: PageData;
@ -191,7 +191,7 @@
const getNumberOfComments = async () => {
try {
const { comments } = await getActivityStatistics({ albumId: album.id });
setNumberOfComments(comments);
activityManager.numberOfComments = comments;
} catch (error) {
handleError(error, $t('errors.cant_get_number_of_comments'));
}
@ -398,7 +398,7 @@
let albumId = $derived(album.id);
$effect(() => {
if (!album.isActivityEnabled && $numberOfComments === 0) {
if (!album.isActivityEnabled && activityManager.numberOfComments === 0) {
isShowActivity = false;
}
});
@ -420,7 +420,9 @@
let isOwned = $derived($user.id == album.ownerId);
let showActivityStatus = $derived(
album.albumUsers.length > 0 && !$showAssetViewer && (album.isActivityEnabled || $numberOfComments > 0),
album.albumUsers.length > 0 &&
!$showAssetViewer &&
(album.isActivityEnabled || activityManager.numberOfComments > 0),
);
let isEditor = $derived(
album.albumUsers.find(({ user: { id } }) => id === $user.id)?.role === AlbumUserRole.Editor ||
@ -712,7 +714,7 @@
<ActivityStatus
disabled={!album.isActivityEnabled}
{isLiked}
numberOfComments={$numberOfComments}
numberOfComments={activityManager.numberOfComments}
onFavorite={handleFavorite}
onOpenActivityTab={handleOpenAndCloseActivityTab}
/>
@ -735,8 +737,8 @@
albumId={album.id}
{isLiked}
bind:reactions
onAddComment={() => updateNumberOfComments(1)}
onDeleteComment={() => updateNumberOfComments(-1)}
onAddComment={() => activityManager.updateNumberOfComments(1)}
onDeleteComment={() => activityManager.updateNumberOfComments(-1)}
onDeleteLike={() => (isLiked = null)}
onClose={handleOpenAndCloseActivityTab}
/>

View File

@ -20,10 +20,10 @@
import ButtonContextMenu from '$lib/components/shared-components/context-menu/button-context-menu.svelte';
import EmptyPlaceholder from '$lib/components/shared-components/empty-placeholder.svelte';
import { AssetAction } from '$lib/constants';
import { faceManager } from '$lib/managers/face.manager.svelte';
import { AssetInteraction } from '$lib/stores/asset-interaction.svelte';
import { assetViewingStore } from '$lib/stores/asset-viewing.store';
import { AssetStore } from '$lib/stores/assets-store.svelte';
import { isFaceEditMode } from '$lib/stores/face-edit.svelte';
import { preferences, user } from '$lib/stores/user.store';
import {
updateStackedAssetInTimeline,
@ -76,7 +76,7 @@
};
beforeNavigate(() => {
isFaceEditMode.value = false;
faceManager.isEditMode = false;
});
</script>

View File

@ -7,7 +7,6 @@
NotificationType,
notificationController,
} from '$lib/components/shared-components/notification/notification';
import { downloadManager } from '$lib/stores/download-store.svelte';
import { locale } from '$lib/stores/preferences.store';
import { copyToClipboard } from '$lib/utils';
import { downloadBlob } from '$lib/utils/asset-utils';
@ -17,6 +16,7 @@
import { mdiCheckAll, mdiContentCopy, mdiDownload, mdiRefresh, mdiWrench } from '@mdi/js';
import { t } from 'svelte-i18n';
import type { PageData } from './$types';
import { downloadManager } from '$lib/managers/download.manager.svelte';
interface Props {
data: PageData;

View File

@ -22,7 +22,6 @@
import SettingAccordionState from '$lib/components/shared-components/settings/setting-accordion-state.svelte';
import SettingAccordion from '$lib/components/shared-components/settings/setting-accordion.svelte';
import { QueryParameter } from '$lib/constants';
import { downloadManager } from '$lib/stores/download-store.svelte';
import { featureFlags } from '$lib/stores/server-config.store';
import { copyToClipboard } from '$lib/utils';
import { downloadBlob } from '$lib/utils/asset-utils';
@ -53,6 +52,7 @@
import type { Component } from 'svelte';
import type { SettingsComponentProps } from '$lib/components/admin-page/settings/admin-settings';
import SearchBar from '$lib/components/elements/search-bar.svelte';
import { downloadManager } from '$lib/managers/download.manager.svelte';
interface Props {
data: PageData;

View File

@ -1,6 +1,6 @@
<script lang="ts">
import AuthPageLayout from '$lib/components/layouts/AuthPageLayout.svelte';
import { authManager } from '$lib/stores/auth-manager.svelte';
import { authManager } from '$lib/managers/auth-manager.svelte';
import { user } from '$lib/stores/user.store';
import { updateMyUser } from '@immich/sdk';
import { Alert, Button, Field, HelperText, PasswordInput, Stack, Text } from '@immich/ui';