1
0
forked from Cutlery/immich

Compare commits

...

15 Commits

Author SHA1 Message Date
martabal
8fd54e3994
Merge branch 'main' into fix/edit-faces-notification 2024-04-08 19:58:32 +02:00
martabal
ad9aafd484
Merge branch 'main' into fix/edit-faces-notification 2024-04-06 18:52:53 +02:00
martabal
8eca25007e
Merge branch 'main' into fix/edit-faces-notification 2024-04-02 19:30:27 +02:00
martabal
86b200e870
Merge branch 'main' into fix/edit-faces-notification 2024-03-19 18:37:43 +01:00
martabal
5dcc4ddfc6
Merge branch 'main' into fix/edit-faces-notification 2024-03-18 20:35:59 +01:00
martabal
6b10994bd2
Merge branch 'main' into fix/edit-faces-notification 2024-03-13 23:32:40 +01:00
martabal
12ede06411
Merge branch 'main' into fix/edit-faces-notification 2024-03-11 23:02:02 +01:00
martabal
121e9f1f1c
merge main 2024-03-08 22:50:34 +01:00
martabal
c263607515
Merge branch 'main' into fix/edit-faces-notification 2024-03-03 15:04:50 +01:00
martabal
4cb2e16549
merge main 2024-02-27 21:03:12 +01:00
martabal
0f8fb8d38b
Merge branch 'main' into fix/edit-faces-notification 2024-02-27 08:02:51 +01:00
martabal
107157b856
rename 2024-02-27 08:02:47 +01:00
martabal
87cbcc02c3
fix: use id instead of index 2024-02-23 00:46:41 +01:00
martabal
62531a75eb
fix: lint 2024-02-22 18:48:51 +01:00
martabal
29c7663caa
fix: notification number of people when editing faces 2024-02-22 18:41:17 +01:00
2 changed files with 88 additions and 67 deletions

View File

@ -21,7 +21,7 @@
export let peopleWithFaces: AssetFaceResponseDto[]; export let peopleWithFaces: AssetFaceResponseDto[];
export let allPeople: PersonResponseDto[]; export let allPeople: PersonResponseDto[];
export let editedPersonIndex: number; export let editedPerson: PersonResponseDto;
export let assetType: AssetTypeEnum; export let assetType: AssetTypeEnum;
export let assetId: string; export let assetId: string;
@ -106,7 +106,7 @@
const handleCreatePerson = async () => { const handleCreatePerson = async () => {
const timeout = setTimeout(() => (isShowLoadingNewPerson = true), timeBeforeShowLoadingSpinner); const timeout = setTimeout(() => (isShowLoadingNewPerson = true), timeBeforeShowLoadingSpinner);
const personToUpdate = peopleWithFaces.find((person) => person.id === peopleWithFaces[editedPersonIndex].id); const personToUpdate = peopleWithFaces.find((face) => face.person?.id === editedPerson.id);
const newFeaturePhoto = personToUpdate ? await zoomImageToBase64(personToUpdate) : null; const newFeaturePhoto = personToUpdate ? await zoomImageToBase64(personToUpdate) : null;
@ -229,7 +229,7 @@
<div class="immich-scrollbar mt-4 flex flex-wrap gap-2 overflow-y-auto"> <div class="immich-scrollbar mt-4 flex flex-wrap gap-2 overflow-y-auto">
{#if searchName == ''} {#if searchName == ''}
{#each allPeople as person (person.id)} {#each allPeople as person (person.id)}
{#if person.id !== peopleWithFaces[editedPersonIndex].person?.id} {#if person.id !== editedPerson.id}
<div class="w-fit"> <div class="w-fit">
<button class="w-[90px]" on:click={() => dispatch('reassign', person)}> <button class="w-[90px]" on:click={() => dispatch('reassign', person)}>
<div class="relative"> <div class="relative">
@ -255,7 +255,7 @@
{/each} {/each}
{:else} {:else}
{#each searchedPeople as person (person.id)} {#each searchedPeople as person (person.id)}
{#if person.id !== peopleWithFaces[editedPersonIndex].person?.id} {#if person.id !== editedPerson.id}
<div class="w-fit"> <div class="w-fit">
<button class="w-[90px]" on:click={() => dispatch('reassign', person)}> <button class="w-[90px]" on:click={() => dispatch('reassign', person)}>
<div class="relative"> <div class="relative">

View File

@ -28,14 +28,14 @@
export let assetType: AssetTypeEnum; export let assetType: AssetTypeEnum;
// keep track of the changes // keep track of the changes
let numberOfPersonToCreate: string[] = []; let peopleToCreate: string[] = [];
let numberOfAssetFaceGenerated: string[] = []; let assetFaceGenerated: string[] = [];
// faces // faces
let peopleWithFaces: AssetFaceResponseDto[] = []; let peopleWithFaces: AssetFaceResponseDto[] = [];
let selectedPersonToReassign: (PersonResponseDto | null)[]; let selectedPersonToReassign: Record<string, PersonResponseDto> = {};
let selectedPersonToCreate: (string | null)[]; let selectedPersonToCreate: Record<string, string> = {};
let editedPersonIndex: number; let editedPerson: PersonResponseDto;
// loading spinners // loading spinners
let isShowLoadingDone = false; let isShowLoadingDone = false;
@ -49,6 +49,8 @@
let loaderLoadingDoneTimeout: ReturnType<typeof setTimeout>; let loaderLoadingDoneTimeout: ReturnType<typeof setTimeout>;
let automaticRefreshTimeout: ReturnType<typeof setTimeout>; let automaticRefreshTimeout: ReturnType<typeof setTimeout>;
const thumbnailWidth = '90px';
const dispatch = createEventDispatcher<{ const dispatch = createEventDispatcher<{
close: void; close: void;
refresh: void; refresh: void;
@ -60,8 +62,6 @@
const { people } = await getAllPeople({ withHidden: true }); const { people } = await getAllPeople({ withHidden: true });
allPeople = people; allPeople = people;
peopleWithFaces = await getFaces({ id: assetId }); peopleWithFaces = await getFaces({ id: assetId });
selectedPersonToCreate = Array.from({ length: peopleWithFaces.length });
selectedPersonToReassign = Array.from({ length: peopleWithFaces.length });
} catch (error) { } catch (error) {
handleError(error, "Can't get faces"); handleError(error, "Can't get faces");
} finally { } finally {
@ -71,12 +71,12 @@
} }
const onPersonThumbnail = (personId: string) => { const onPersonThumbnail = (personId: string) => {
numberOfAssetFaceGenerated.push(personId); assetFaceGenerated.push(personId);
if ( if (
isEqual(numberOfAssetFaceGenerated, numberOfPersonToCreate) && isEqual(assetFaceGenerated, peopleToCreate) &&
loaderLoadingDoneTimeout && loaderLoadingDoneTimeout &&
automaticRefreshTimeout && automaticRefreshTimeout &&
selectedPersonToCreate.filter((person) => person !== null).length === numberOfPersonToCreate.length Object.keys(selectedPersonToCreate).length === peopleToCreate.length
) { ) {
clearTimeout(loaderLoadingDoneTimeout); clearTimeout(loaderLoadingDoneTimeout);
clearTimeout(automaticRefreshTimeout); clearTimeout(automaticRefreshTimeout);
@ -97,36 +97,41 @@
dispatch('close'); dispatch('close');
}; };
const handleReset = (index: number) => { const handleReset = (id: string) => {
if (selectedPersonToReassign[index]) { if (selectedPersonToReassign[id]) {
selectedPersonToReassign[index] = null; delete selectedPersonToReassign[id];
// trigger reactivity
selectedPersonToReassign = selectedPersonToReassign;
} }
if (selectedPersonToCreate[index]) { if (selectedPersonToCreate[id]) {
selectedPersonToCreate[index] = null; delete selectedPersonToCreate[id];
// trigger reactivity
selectedPersonToCreate = selectedPersonToCreate;
} }
}; };
const handleEditFaces = async () => { const handleEditFaces = async () => {
loaderLoadingDoneTimeout = setTimeout(() => (isShowLoadingDone = true), timeBeforeShowLoadingSpinner); loaderLoadingDoneTimeout = setTimeout(() => (isShowLoadingDone = true), timeBeforeShowLoadingSpinner);
const numberOfChanges = const numberOfChanges = Object.keys(selectedPersonToCreate).length + Object.keys(selectedPersonToReassign).length;
selectedPersonToCreate.filter((person) => person !== null).length +
selectedPersonToReassign.filter((person) => person !== null).length;
if (numberOfChanges > 0) { if (numberOfChanges > 0) {
try { try {
for (const [index, peopleWithFace] of peopleWithFaces.entries()) { for (const personWithFace of peopleWithFaces) {
const personId = selectedPersonToReassign[index]?.id; const personId = selectedPersonToReassign[personWithFace.id]?.id;
if (personId) { if (personId) {
await reassignFacesById({ await reassignFacesById({
id: personId, id: personId,
faceDto: { id: peopleWithFace.id }, faceDto: { id: personWithFace.id },
}); });
} else if (selectedPersonToCreate[index]) { } else if (selectedPersonToCreate[personWithFace.id]) {
const data = await createPerson({ personCreateDto: {} }); const data = await createPerson({ personCreateDto: {} });
numberOfPersonToCreate.push(data.id); peopleToCreate.push(data.id);
await reassignFacesById({ await reassignFacesById({
id: data.id, id: data.id,
faceDto: { id: peopleWithFace.id }, faceDto: { id: personWithFace.id },
}); });
} }
} }
@ -141,7 +146,7 @@
} }
isShowLoadingDone = false; isShowLoadingDone = false;
if (numberOfPersonToCreate.length === 0) { if (peopleToCreate.length === 0) {
clearTimeout(loaderLoadingDoneTimeout); clearTimeout(loaderLoadingDoneTimeout);
dispatch('refresh'); dispatch('refresh');
} else { } else {
@ -150,23 +155,26 @@
}; };
const handleCreatePerson = (newFeaturePhoto: string | null) => { const handleCreatePerson = (newFeaturePhoto: string | null) => {
const personToUpdate = peopleWithFaces.find((person) => person.id === peopleWithFaces[editedPersonIndex].id); const personToUpdate = peopleWithFaces.find((face) => face.person?.id === editedPerson.id);
if (newFeaturePhoto && personToUpdate) { if (newFeaturePhoto && personToUpdate) {
selectedPersonToCreate[peopleWithFaces.indexOf(personToUpdate)] = newFeaturePhoto; selectedPersonToCreate[personToUpdate.id] = newFeaturePhoto;
} }
showSeletecFaces = false; showSeletecFaces = false;
}; };
const handleReassignFace = (person: PersonResponseDto | null) => { const handleReassignFace = (person: PersonResponseDto | null) => {
if (person) { const personToUpdate = peopleWithFaces.find((face) => face.person?.id === editedPerson.id);
selectedPersonToReassign[editedPersonIndex] = person; if (person && personToUpdate) {
selectedPersonToReassign[personToUpdate.id] = person;
showSeletecFaces = false; showSeletecFaces = false;
} }
}; };
const handlePersonPicker = (index: number) => { const handlePersonPicker = (person: PersonResponseDto | null) => {
editedPersonIndex = index; if (person) {
showSeletecFaces = true; editedPerson = person;
showSeletecFaces = true;
}
}; };
</script> </script>
@ -217,35 +225,48 @@
on:mouseleave={() => ($boundingBoxesArray = [])} on:mouseleave={() => ($boundingBoxesArray = [])}
> >
<div class="relative"> <div class="relative">
<ImageThumbnail {#if selectedPersonToCreate[face.id]}
curve <ImageThumbnail
shadow curve
url={selectedPersonToCreate[index] || shadow
getPeopleThumbnailUrl(selectedPersonToReassign[index]?.id || face.person.id)} url={selectedPersonToCreate[face.id]}
altText={selectedPersonToReassign[index] altText={selectedPersonToCreate[face.id]}
? selectedPersonToReassign[index]?.name title={'New person'}
: selectedPersonToCreate[index] widthStyle={thumbnailWidth}
? 'New person' heightStyle={thumbnailWidth}
: getPersonNameWithHiddenValue(face.person?.name, face.person?.isHidden)} />
title={selectedPersonToReassign[index] {:else if selectedPersonToReassign[face.id]}
? selectedPersonToReassign[index]?.name <ImageThumbnail
: selectedPersonToCreate[index] curve
? 'New person' shadow
: getPersonNameWithHiddenValue(face.person?.name, face.person?.isHidden)} url={getPeopleThumbnailUrl(selectedPersonToReassign[face.id].id)}
widthStyle="90px" altText={selectedPersonToReassign[face.id]?.name || selectedPersonToReassign[face.id].id}
heightStyle="90px" title={getPersonNameWithHiddenValue(
thumbhash={null} selectedPersonToReassign[face.id].name,
hidden={selectedPersonToReassign[index] face.person?.isHidden,
? selectedPersonToReassign[index]?.isHidden )}
: selectedPersonToCreate[index] widthStyle={thumbnailWidth}
? false heightStyle={thumbnailWidth}
: face.person?.isHidden} hidden={selectedPersonToReassign[face.id].isHidden}
/> />
{:else}
<ImageThumbnail
curve
shadow
url={getPeopleThumbnailUrl(face.person.id)}
altText={face.person.name || face.person.id}
title={getPersonNameWithHiddenValue(face.person.name, face.person.isHidden)}
widthStyle={thumbnailWidth}
heightStyle={thumbnailWidth}
hidden={face.person.isHidden}
/>
{/if}
</div> </div>
{#if !selectedPersonToCreate[index]}
{#if !selectedPersonToCreate[face.id]}
<p class="relative mt-1 truncate font-medium" title={face.person?.name}> <p class="relative mt-1 truncate font-medium" title={face.person?.name}>
{#if selectedPersonToReassign[index]?.id} {#if selectedPersonToReassign[face.id]?.id}
{selectedPersonToReassign[index]?.name} {selectedPersonToReassign[face.id]?.name}
{:else} {:else}
{face.person?.name} {face.person?.name}
{/if} {/if}
@ -253,8 +274,8 @@
{/if} {/if}
<div class="absolute -right-[5px] -top-[5px] h-[20px] w-[20px] rounded-full bg-blue-700"> <div class="absolute -right-[5px] -top-[5px] h-[20px] w-[20px] rounded-full bg-blue-700">
{#if selectedPersonToCreate[index] || selectedPersonToReassign[index]} {#if selectedPersonToCreate[face.id] || selectedPersonToReassign[face.id]}
<button on:click={() => handleReset(index)} class="flex h-full w-full"> <button on:click={() => handleReset(face.id)} class="flex h-full w-full">
<div class="absolute left-1/2 top-1/2 translate-x-[-50%] translate-y-[-50%] transform"> <div class="absolute left-1/2 top-1/2 translate-x-[-50%] translate-y-[-50%] transform">
<div> <div>
<Icon path={mdiRestart} size={18} /> <Icon path={mdiRestart} size={18} />
@ -262,7 +283,7 @@
</div> </div>
</button> </button>
{:else} {:else}
<button on:click={() => handlePersonPicker(index)} class="flex h-full w-full"> <button on:click={() => handlePersonPicker(face.person)} class="flex h-full w-full">
<div <div
class="absolute left-1/2 top-1/2 h-[2px] w-[14px] translate-x-[-50%] translate-y-[-50%] transform bg-white" class="absolute left-1/2 top-1/2 h-[2px] w-[14px] translate-x-[-50%] translate-y-[-50%] transform bg-white"
/> />
@ -282,7 +303,7 @@
<AssignFaceSidePanel <AssignFaceSidePanel
{peopleWithFaces} {peopleWithFaces}
{allPeople} {allPeople}
{editedPersonIndex} {editedPerson}
{assetType} {assetType}
{assetId} {assetId}
on:close={() => (showSeletecFaces = false)} on:close={() => (showSeletecFaces = false)}