|
|
|
@ -5,7 +5,7 @@
|
|
|
|
import { handleError } from '$lib/utils/handle-error';
|
|
|
|
import { handleError } from '$lib/utils/handle-error';
|
|
|
|
import { getAllPeople, getPerson, mergePerson, type PersonResponseDto } from '@immich/sdk';
|
|
|
|
import { getAllPeople, getPerson, mergePerson, type PersonResponseDto } from '@immich/sdk';
|
|
|
|
import { Button, Icon, IconButton, modalManager, toastManager } from '@immich/ui';
|
|
|
|
import { Button, Icon, IconButton, modalManager, toastManager } from '@immich/ui';
|
|
|
|
import { mdiCallMerge, mdiMerge, mdiSwapHorizontal } from '@mdi/js';
|
|
|
|
import { mdiCallMerge, mdiMerge, mdiPlus, mdiSwapHorizontal } from '@mdi/js';
|
|
|
|
import { onMount } from 'svelte';
|
|
|
|
import { onMount } from 'svelte';
|
|
|
|
import { t } from 'svelte-i18n';
|
|
|
|
import { t } from 'svelte-i18n';
|
|
|
|
import { flip } from 'svelte/animate';
|
|
|
|
import { flip } from 'svelte/animate';
|
|
|
|
@ -14,6 +14,7 @@
|
|
|
|
import ControlAppBar from '../shared-components/control-app-bar.svelte';
|
|
|
|
import ControlAppBar from '../shared-components/control-app-bar.svelte';
|
|
|
|
import FaceThumbnail from './face-thumbnail.svelte';
|
|
|
|
import FaceThumbnail from './face-thumbnail.svelte';
|
|
|
|
import PeopleList from './people-list.svelte';
|
|
|
|
import PeopleList from './people-list.svelte';
|
|
|
|
|
|
|
|
import PeopleViewModal from "$lib/modals/PeopleViewModal.svelte";
|
|
|
|
|
|
|
|
|
|
|
|
interface Props {
|
|
|
|
interface Props {
|
|
|
|
person: PersonResponseDto;
|
|
|
|
person: PersonResponseDto;
|
|
|
|
@ -49,11 +50,6 @@
|
|
|
|
return;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (selectedPeople.length >= 5) {
|
|
|
|
|
|
|
|
toastManager.warning($t('merge_people_limit'));
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
selectedPeople = [selected, ...selectedPeople];
|
|
|
|
selectedPeople = [selected, ...selectedPeople];
|
|
|
|
|
|
|
|
|
|
|
|
if (selectedPeople.length === 1 && !person.name && selected.name) {
|
|
|
|
if (selectedPeople.length === 1 && !person.name && selected.name) {
|
|
|
|
@ -80,6 +76,15 @@
|
|
|
|
handleError(error, $t('cannot_merge_people'));
|
|
|
|
handleError(error, $t('cannot_merge_people'));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const showPeopleViewModal = async () => {
|
|
|
|
|
|
|
|
// Sets the selected people that remained after closing the modal.
|
|
|
|
|
|
|
|
selectedPeople = await modalManager.show(PeopleViewModal, {
|
|
|
|
|
|
|
|
people: selectedPeople,
|
|
|
|
|
|
|
|
peopleToNotShow: [person],
|
|
|
|
|
|
|
|
screenHeight
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
};
|
|
|
|
</script>
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
|
|
<svelte:window bind:innerHeight={screenHeight} />
|
|
|
|
<svelte:window bind:innerHeight={screenHeight} />
|
|
|
|
@ -109,7 +114,7 @@
|
|
|
|
<p class="mb-4 text-center uppercase dark:text-white">{$t('choose_matching_people_to_merge')}</p>
|
|
|
|
<p class="mb-4 text-center uppercase dark:text-white">{$t('choose_matching_people_to_merge')}</p>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="grid grid-flow-col-dense place-content-center place-items-center gap-4">
|
|
|
|
<div class="grid grid-flow-col-dense place-content-center place-items-center gap-4">
|
|
|
|
{#each selectedPeople as person (person.id)}
|
|
|
|
{#each selectedPeople.slice(0, 5) as person, _ (person.id)}
|
|
|
|
<div animate:flip={{ duration: 250, easing: quintOut }}>
|
|
|
|
<div animate:flip={{ duration: 250, easing: quintOut }}>
|
|
|
|
<FaceThumbnail border circle {person} selectable thumbnailSize={120} onClick={() => onSelect(person)} />
|
|
|
|
<FaceThumbnail border circle {person} selectable thumbnailSize={120} onClick={() => onSelect(person)} />
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
@ -119,6 +124,18 @@
|
|
|
|
<div class="relative h-full">
|
|
|
|
<div class="relative h-full">
|
|
|
|
<div class="flex flex-col h-full justify-between">
|
|
|
|
<div class="flex flex-col h-full justify-between">
|
|
|
|
<div class="flex h-full items-center justify-center">
|
|
|
|
<div class="flex h-full items-center justify-center">
|
|
|
|
|
|
|
|
{#if selectedPeople.length > 5}
|
|
|
|
|
|
|
|
<div class="absolute top-2">
|
|
|
|
|
|
|
|
<IconButton
|
|
|
|
|
|
|
|
shape="round"
|
|
|
|
|
|
|
|
color="secondary"
|
|
|
|
|
|
|
|
aria-label={$t('show_all_selected_people')}
|
|
|
|
|
|
|
|
icon={mdiPlus}
|
|
|
|
|
|
|
|
size="medium"
|
|
|
|
|
|
|
|
onclick={showPeopleViewModal}
|
|
|
|
|
|
|
|
/>
|
|
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
{/if}
|
|
|
|
<Icon icon={mdiCallMerge} size="48" class="rotate-90 dark:text-white" />
|
|
|
|
<Icon icon={mdiCallMerge} size="48" class="rotate-90 dark:text-white" />
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
{#if selectedPeople.length === 1}
|
|
|
|
{#if selectedPeople.length === 1}
|
|
|
|
|