Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,18 @@
import { toTimelineAsset } from '$lib/utils/timeline-util';
import type { AssetResponseDto } from '@immich/sdk';
import { modalManager } from '@immich/ui';
import { mdiImageAlbum, mdiShareVariantOutline } from '@mdi/js';
import { mdiImageAlbum } from '@mdi/js';
import { t } from 'svelte-i18n';

interface Props {
asset: AssetResponseDto;
onAction: OnAction;
shared?: boolean;
}

let { asset, onAction, shared = false }: Props = $props();
let { asset, onAction }: Props = $props();

const onClick = async () => {
const albums = await modalManager.show(AlbumPickerModal, { shared });
const albums = await modalManager.show(AlbumPickerModal, {});

if (!albums || albums.length === 0) {
return;
Expand All @@ -40,10 +39,6 @@
};
</script>

<svelte:document use:shortcut={{ shortcut: { key: 'l', shift: shared }, onShortcut: onClick }} />
<svelte:document use:shortcut={{ shortcut: { key: 'l' }, onShortcut: onClick }} />

<MenuOption
icon={shared ? mdiShareVariantOutline : mdiImageAlbum}
text={shared ? $t('add_to_shared_album') : $t('add_to_album')}
{onClick}
/>
<MenuOption icon={mdiImageAlbum} text={$t('add_to_album')} {onClick} />
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,6 @@
<RestoreAction {asset} {onAction} />
{:else}
<AddToAlbumAction {asset} {onAction} />
<AddToAlbumAction {asset} {onAction} shared />
{/if}
{/if}

Expand Down
6 changes: 1 addition & 5 deletions web/src/lib/components/memory-page/memory-viewer.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@
mdiImageSearch,
mdiPause,
mdiPlay,
mdiPlus,
mdiSelectAll,
mdiVolumeHigh,
mdiVolumeOff,
Expand Down Expand Up @@ -339,10 +338,7 @@
onclick={handleSelectAll}
/>

<ButtonContextMenu icon={mdiPlus} title={$t('add_to')}>
<AddToAlbum />
<AddToAlbum shared />
</ButtonContextMenu>
<AddToAlbum />

<FavoriteAction removeFavorite={assetInteraction.isAllFavorite} />

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,15 @@ const createAlbumRow = (album: AlbumResponseDto, selected: boolean) => ({
});

describe('Album Modal', () => {
it('non-shared with no albums configured yet shows message and new', () => {
const converter = new AlbumModalRowConverter(false, AlbumSortBy.MostRecentPhoto, SortOrder.Desc);
it('no albums configured yet shows message and new', () => {
const converter = new AlbumModalRowConverter(AlbumSortBy.MostRecentPhoto, SortOrder.Desc);
const modalRows = converter.toModalRows('', [], [], -1, []);

expect(modalRows).toStrictEqual([createNewAlbumRow(false), createMessageRow('no_albums_yet')]);
});

it('non-shared with no matching albums shows message and new', () => {
const converter = new AlbumModalRowConverter(false, AlbumSortBy.MostRecentPhoto, SortOrder.Desc);
it('no matching albums shows message and new', () => {
const converter = new AlbumModalRowConverter(AlbumSortBy.MostRecentPhoto, SortOrder.Desc);
const modalRows = converter.toModalRows(
'matches_nothing',
[],
Expand All @@ -48,8 +48,8 @@ describe('Album Modal', () => {
expect(modalRows).toStrictEqual([createNewAlbumRow(false), createMessageRow('no_albums_with_name_yet')]);
});

it('non-shared displays single albums', () => {
const converter = new AlbumModalRowConverter(false, AlbumSortBy.MostRecentPhoto, SortOrder.Desc);
it('displays single albums', () => {
const converter = new AlbumModalRowConverter(AlbumSortBy.MostRecentPhoto, SortOrder.Desc);
const holidayAlbum = albumFactory.build({ albumName: 'Holidays' });
const modalRows = converter.toModalRows('', [], [holidayAlbum], -1, []);

Expand All @@ -60,8 +60,8 @@ describe('Album Modal', () => {
]);
});

it('non-shared displays multiple albums and recents', () => {
const converter = new AlbumModalRowConverter(false, AlbumSortBy.MostRecentPhoto, SortOrder.Desc);
it('displays multiple albums and recents', () => {
const converter = new AlbumModalRowConverter(AlbumSortBy.MostRecentPhoto, SortOrder.Desc);
const holidayAlbum = albumFactory.build({ albumName: 'Holidays' });
const constructionAlbum = albumFactory.build({ albumName: 'Construction' });
const birthdayAlbum = albumFactory.build({ albumName: 'Birthday' });
Expand All @@ -87,31 +87,8 @@ describe('Album Modal', () => {
]);
});

it('shared only displays albums and no recents', () => {
const converter = new AlbumModalRowConverter(true, AlbumSortBy.MostRecentPhoto, SortOrder.Desc);
const holidayAlbum = albumFactory.build({ albumName: 'Holidays' });
const constructionAlbum = albumFactory.build({ albumName: 'Construction' });
const birthdayAlbum = albumFactory.build({ albumName: 'Birthday' });
const christmasAlbum = albumFactory.build({ albumName: 'Christmas' });
const modalRows = converter.toModalRows(
'',
[holidayAlbum, constructionAlbum],
[holidayAlbum, constructionAlbum, birthdayAlbum, christmasAlbum],
-1,
[],
);

expect(modalRows).toStrictEqual([
createNewAlbumRow(false),
createAlbumRow(holidayAlbum, false),
createAlbumRow(constructionAlbum, false),
createAlbumRow(birthdayAlbum, false),
createAlbumRow(christmasAlbum, false),
]);
});

it('search changes messaging and removes recent and non-matching albums', () => {
const converter = new AlbumModalRowConverter(false, AlbumSortBy.MostRecentPhoto, SortOrder.Desc);
const converter = new AlbumModalRowConverter(AlbumSortBy.MostRecentPhoto, SortOrder.Desc);
const holidayAlbum = albumFactory.build({ albumName: 'Holidays' });
const constructionAlbum = albumFactory.build({ albumName: 'Construction' });
const birthdayAlbum = albumFactory.build({ albumName: 'Birthday' });
Expand All @@ -132,7 +109,7 @@ describe('Album Modal', () => {
});

it('selection can select new album row', () => {
const converter = new AlbumModalRowConverter(false, AlbumSortBy.MostRecentPhoto, SortOrder.Desc);
const converter = new AlbumModalRowConverter(AlbumSortBy.MostRecentPhoto, SortOrder.Desc);
const holidayAlbum = albumFactory.build({ albumName: 'Holidays' });
const constructionAlbum = albumFactory.build({ albumName: 'Construction' });
const modalRows = converter.toModalRows('', [holidayAlbum], [holidayAlbum, constructionAlbum], 0, []);
Expand All @@ -148,7 +125,7 @@ describe('Album Modal', () => {
});

it('selection can select recent row', () => {
const converter = new AlbumModalRowConverter(false, AlbumSortBy.MostRecentPhoto, SortOrder.Desc);
const converter = new AlbumModalRowConverter(AlbumSortBy.MostRecentPhoto, SortOrder.Desc);
const holidayAlbum = albumFactory.build({ albumName: 'Holidays' });
const constructionAlbum = albumFactory.build({ albumName: 'Construction' });
const modalRows = converter.toModalRows('', [holidayAlbum], [holidayAlbum, constructionAlbum], 1, []);
Expand All @@ -164,7 +141,7 @@ describe('Album Modal', () => {
});

it('selection can select last row', () => {
const converter = new AlbumModalRowConverter(false, AlbumSortBy.MostRecentPhoto, SortOrder.Desc);
const converter = new AlbumModalRowConverter(AlbumSortBy.MostRecentPhoto, SortOrder.Desc);
const holidayAlbum = albumFactory.build({ albumName: 'Holidays' });
const constructionAlbum = albumFactory.build({ albumName: 'Construction' });
const modalRows = converter.toModalRows('', [holidayAlbum], [holidayAlbum, constructionAlbum], 3, []);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,10 @@ export const isSelectableRowType = (type: AlbumModalRowType) =>
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;
constructor(sortBy: string, orderBy: string) {
this.sortBy = sortBy;
this.orderBy = orderBy;
}
Expand All @@ -44,8 +42,8 @@ export class AlbumModalRowConverter {
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 : [];
// only show recent albums if no search was entered
const recentAlbumsToShow = search.length === 0 ? recentAlbums : [];
const rows: AlbumModalRow[] = [{ type: AlbumModalRowType.NEW_ALBUM, selected: selectedRowIndex === 0 }];

const filteredAlbums = sortAlbums(
Expand All @@ -71,12 +69,10 @@ export class AlbumModalRowConverter {
}
}

if (!this.shared) {
rows.push({
type: AlbumModalRowType.SECTION,
text: (search.length === 0 ? $t('all_albums') : $t('albums')).toUpperCase(),
});
}
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()) {
Expand Down
30 changes: 19 additions & 11 deletions web/src/lib/components/timeline/actions/AddToAlbumAction.svelte
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

matching logic with web/src/lib/components/timeline/actions/FavoriteAction.svelte

Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,21 @@
import type { OnAddToAlbum } from '$lib/utils/actions';
import { addAssetsToAlbum, addAssetsToAlbums } from '$lib/utils/asset-utils';
import { getAssetControlContext } from '$lib/utils/context';
import { modalManager } from '@immich/ui';
import { mdiImageAlbum, mdiShareVariantOutline } from '@mdi/js';
import { IconButton, modalManager } from '@immich/ui';
import { mdiImageAlbum, mdiPlus } from '@mdi/js';
import { t } from 'svelte-i18n';

interface Props {
shared?: boolean;
onAddToAlbum?: OnAddToAlbum;
menuItem?: boolean;
}

let { shared = false, onAddToAlbum = () => {} }: Props = $props();
let { onAddToAlbum = () => {}, menuItem = false }: Props = $props();

const { getAssets } = getAssetControlContext();

const onClick = async () => {
const albums = await modalManager.show(AlbumPickerModal, { shared });
const albums = await modalManager.show(AlbumPickerModal, {});
if (!albums || albums.length === 0) {
return;
}
Expand All @@ -38,9 +38,17 @@
};
</script>

<MenuOption
{onClick}
text={shared ? $t('add_to_shared_album') : $t('add_to_album')}
icon={shared ? mdiShareVariantOutline : mdiImageAlbum}
shortcut={{ key: 'l', shift: shared }}
/>
{#if menuItem}
<MenuOption {onClick} text={$t('add_to_album')} icon={mdiImageAlbum} shortcut={{ key: 'l' }} />
{/if}

{#if !menuItem}
<IconButton
shape="round"
color="secondary"
variant="ghost"
icon={mdiPlus}
aria-label={$t('add_to_album')}
onclick={onClick}
/>
{/if}
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@

const handlePicker = async () => {
if (isAlbum) {
const albums = await modalManager.show(AlbumPickerModal, { shared: false });
const albums = await modalManager.show(AlbumPickerModal);
if (albums && albums.length > 0) {
const newValue = multiple ? albums.map((album) => album.id) : albums[0].id;
onchange(newValue);
Expand Down
9 changes: 4 additions & 5 deletions web/src/lib/modals/AlbumPickerModal.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -21,22 +21,21 @@
let selectedRowIndex: number = $state(-1);

interface Props {
shared: boolean;
onClose: (albums?: AlbumResponseDto[]) => void;
}

let { shared, onClose }: Props = $props();
let { onClose }: Props = $props();

onMount(async () => {
albums = await getAllAlbums({ shared: shared || undefined });
albums = await getAllAlbums({});
recentAlbums = albums.sort((a, b) => (new Date(a.updatedAt) > new Date(b.updatedAt) ? -1 : 1)).slice(0, 3);
loading = false;
});

const multiSelectedAlbumIds: string[] = $state([]);
const multiSelectActive = $derived(multiSelectedAlbumIds.length > 0);

const rowConverter = new AlbumModalRowConverter(shared, $albumViewSettings.sortBy, $albumViewSettings.sortOrder);
const rowConverter = new AlbumModalRowConverter($albumViewSettings.sortBy, $albumViewSettings.sortOrder);
const albumModalRows = $derived(
rowConverter.toModalRows(search, recentAlbums, albums, selectedRowIndex, multiSelectedAlbumIds),
);
Expand Down Expand Up @@ -146,7 +145,7 @@
};
</script>

<Modal title={shared ? $t('add_to_shared_album') : $t('add_to_album')} {onClose} size="small">
<Modal title={$t('add_to_album')} {onClose} size="small">
<ModalBody>
<div class="mb-2 flex max-h-100 flex-col">
{#if loading}
Expand Down
1 change: 0 additions & 1 deletion web/src/lib/modals/ShortcutsModal.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@
{ key: ['s'], action: $t('stack_selected_photos') },
{ key: ['l'], action: $t('add_to_album') },
{ key: ['t'], action: $t('tag_assets') },
{ key: ['⇧', 'l'], action: $t('add_to_shared_album') },
{ key: ['⇧', 'a'], action: $t('archive_or_unarchive_photo') },
{ key: ['⇧', 'd'], action: $t('download') },
{ key: ['Space'], action: $t('play_or_pause_video') },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -440,10 +440,7 @@
>
<CreateSharedLink />
<SelectAllAssets {timelineManager} {assetInteraction} />
<ButtonContextMenu icon={mdiPlus} title={$t('add_to')}>
<AddToAlbum />
<AddToAlbum shared />
</ButtonContextMenu>
<AddToAlbum />
{#if assetInteraction.isAllUserOwned}
<FavoriteAction
removeFavorite={assetInteraction.isAllFavorite}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
import { TimelineManager } from '$lib/managers/timeline-manager/timeline-manager.svelte';
import { AssetInteraction } from '$lib/stores/asset-interaction.svelte';
import { AssetVisibility } from '@immich/sdk';
import { mdiDotsVertical, mdiPlus } from '@mdi/js';
import { mdiDotsVertical } from '@mdi/js';
import { t } from 'svelte-i18n';
import type { PageData } from './$types';

Expand Down Expand Up @@ -70,10 +70,7 @@
/>
<CreateSharedLink />
<SelectAllAssets {timelineManager} {assetInteraction} />
<ButtonContextMenu icon={mdiPlus} title={$t('add_to')}>
<AddToAlbum />
<AddToAlbum shared />
</ButtonContextMenu>
<AddToAlbum />
<FavoriteAction
removeFavorite={assetInteraction.isAllFavorite}
onFavorite={(ids, isFavorite) => timelineManager.update(ids, (asset) => (asset.isFavorite = isFavorite))}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
import { TimelineManager } from '$lib/managers/timeline-manager/timeline-manager.svelte';
import { AssetInteraction } from '$lib/stores/asset-interaction.svelte';
import { preferences } from '$lib/stores/user.store';
import { mdiDotsVertical, mdiPlus } from '@mdi/js';
import { mdiDotsVertical } from '@mdi/js';
import { t } from 'svelte-i18n';
import type { PageData } from './$types';

Expand Down Expand Up @@ -71,10 +71,7 @@
<FavoriteAction removeFavorite onFavorite={(assetIds) => timelineManager.removeAssets(assetIds)} />
<CreateSharedLink />
<SelectAllAssets {timelineManager} {assetInteraction} />
<ButtonContextMenu icon={mdiPlus} title={$t('add_to')}>
<AddToAlbum />
<AddToAlbum shared />
</ButtonContextMenu>
<AddToAlbum />
<ButtonContextMenu icon={mdiDotsVertical} title={$t('menu')}>
<DownloadAction menuItem />
<ChangeDate menuItem />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
import { toTimelineAsset } from '$lib/utils/timeline-util';
import { joinPaths } from '$lib/utils/tree-utils';
import { IconButton, Text } from '@immich/ui';
import { mdiDotsVertical, mdiFolder, mdiFolderHome, mdiFolderOutline, mdiPlus, mdiSelectAll } from '@mdi/js';
import { mdiDotsVertical, mdiFolder, mdiFolderHome, mdiFolderOutline, mdiSelectAll } from '@mdi/js';
import { t } from 'svelte-i18n';
import type { PageData } from './$types';

Expand Down Expand Up @@ -130,10 +130,7 @@
icon={mdiSelectAll}
onclick={handleSelectAllAssets}
/>
<ButtonContextMenu icon={mdiPlus} title={$t('add_to')}>
<AddToAlbum onAddToAlbum={() => cancelMultiselect(assetInteraction)} />
<AddToAlbum onAddToAlbum={() => cancelMultiselect(assetInteraction)} shared />
</ButtonContextMenu>
<AddToAlbum onAddToAlbum={() => cancelMultiselect(assetInteraction)} />
<FavoriteAction
removeFavorite={assetInteraction.isAllFavorite}
onFavorite={function handleFavoriteUpdate(ids, isFavorite) {
Expand Down
Loading
Loading