mirror of
https://github.com/immich-app/immich.git
synced 2025-12-22 07:10:56 -08:00
* Multi add to album picker: - update modal for multi select - Update add-to-album and add-to-album-action to work with new array return from AlbumPickerModal - Add asset-utils.addAssetsToAlbums (incomplete) * initial addToAlbums endpoint * - fix endpoint - add test * - update return type - make open-api * - simplify return dto - handle notification * - fix returns - clean up * - update i18n - format & check * - checks * - correct successId count - fix assets_cannot_be_added language call * tests * foromat * refactor * - update successful add message to included total attempted * - fix web test - format i18n * - fix open-api * - fix imports to resolve checks * - PR suggestions * open-api * refactor addAssetsToAlbums * refactor it again * - fix error returns and tests * - swap icon for IconButton - don't nest the buttons * open-api * - Cleanup multi-select button to match Thumbnail * merge and openapi * - remove onclick from icon element * - fix double onClose call with keyboard shortcuts * - spelling and formatting - apply new api permission * - open-api * chore: styling * translation --------- Co-authored-by: Alex <alex.tran1502@gmail.com>
99 lines
3.2 KiB
TypeScript
99 lines
3.2 KiB
TypeScript
import { sortAlbums } from '$lib/utils/album-utils';
|
|
import { normalizeSearchString } from '$lib/utils/string-utils';
|
|
import type { AlbumResponseDto } from '@immich/sdk';
|
|
import { t } from 'svelte-i18n';
|
|
import { get } from 'svelte/store';
|
|
|
|
export const SCROLL_PROPERTIES: ScrollIntoViewOptions = { block: 'center', behavior: 'smooth' };
|
|
|
|
export enum AlbumModalRowType {
|
|
SECTION = 'section',
|
|
MESSAGE = 'message',
|
|
NEW_ALBUM = 'newAlbum',
|
|
ALBUM_ITEM = 'albumItem',
|
|
}
|
|
|
|
export type AlbumModalRow = {
|
|
type: AlbumModalRowType;
|
|
selected?: boolean;
|
|
multiSelected?: boolean;
|
|
text?: string;
|
|
album?: AlbumResponseDto;
|
|
};
|
|
|
|
export const isSelectableRowType = (type: AlbumModalRowType) =>
|
|
type === AlbumModalRowType.NEW_ALBUM || type === AlbumModalRowType.ALBUM_ITEM;
|
|
|
|
const $t = get(t);
|
|
|
|
export class AlbumModalRowConverter {
|
|
private readonly shared: boolean;
|
|
private readonly sortBy: string;
|
|
private readonly orderBy: string;
|
|
|
|
constructor(shared: boolean, sortBy: string, orderBy: string) {
|
|
this.shared = shared;
|
|
this.sortBy = sortBy;
|
|
this.orderBy = orderBy;
|
|
}
|
|
|
|
toModalRows(
|
|
search: string,
|
|
recentAlbums: AlbumResponseDto[],
|
|
albums: AlbumResponseDto[],
|
|
selectedRowIndex: number,
|
|
multiSelectedAlbumIds: string[],
|
|
): AlbumModalRow[] {
|
|
// only show recent albums if no search was entered, or we're in the normal albums (non-shared) modal.
|
|
const recentAlbumsToShow = !this.shared && search.length === 0 ? recentAlbums : [];
|
|
const rows: AlbumModalRow[] = [];
|
|
rows.push({ type: AlbumModalRowType.NEW_ALBUM, selected: selectedRowIndex === 0 });
|
|
|
|
const filteredAlbums = sortAlbums(
|
|
search.length > 0 && albums.length > 0
|
|
? albums.filter((album) => {
|
|
return normalizeSearchString(album.albumName).includes(normalizeSearchString(search));
|
|
})
|
|
: albums,
|
|
{ sortBy: this.sortBy, orderBy: this.orderBy },
|
|
);
|
|
|
|
if (filteredAlbums.length > 0) {
|
|
if (recentAlbumsToShow.length > 0) {
|
|
rows.push({ type: AlbumModalRowType.SECTION, text: $t('recent').toUpperCase() });
|
|
const selectedOffsetDueToNewAlbumRow = 1;
|
|
for (const [i, album] of recentAlbums.entries()) {
|
|
rows.push({
|
|
type: AlbumModalRowType.ALBUM_ITEM,
|
|
selected: selectedRowIndex === i + selectedOffsetDueToNewAlbumRow,
|
|
multiSelected: multiSelectedAlbumIds.includes(album.id),
|
|
album,
|
|
});
|
|
}
|
|
}
|
|
|
|
if (!this.shared) {
|
|
rows.push({
|
|
type: AlbumModalRowType.SECTION,
|
|
text: (search.length === 0 ? $t('all_albums') : $t('albums')).toUpperCase(),
|
|
});
|
|
}
|
|
|
|
const selectedOffsetDueToNewAndRecents = 1 + recentAlbumsToShow.length;
|
|
for (const [i, album] of filteredAlbums.entries()) {
|
|
rows.push({
|
|
type: AlbumModalRowType.ALBUM_ITEM,
|
|
selected: selectedRowIndex === i + selectedOffsetDueToNewAndRecents,
|
|
multiSelected: multiSelectedAlbumIds.includes(album.id),
|
|
album,
|
|
});
|
|
}
|
|
} else if (albums.length > 0) {
|
|
rows.push({ type: AlbumModalRowType.MESSAGE, text: $t('no_albums_with_name_yet') });
|
|
} else {
|
|
rows.push({ type: AlbumModalRowType.MESSAGE, text: $t('no_albums_yet') });
|
|
}
|
|
return rows;
|
|
}
|
|
}
|