diff --git a/web/src/lib/components/asset-viewer/asset-viewer-nav-bar.svelte b/web/src/lib/components/asset-viewer/asset-viewer-nav-bar.svelte index d19b428750fda..12d56d6fdf8e6 100644 --- a/web/src/lib/components/asset-viewer/asset-viewer-nav-bar.svelte +++ b/web/src/lib/components/asset-viewer/asset-viewer-nav-bar.svelte @@ -43,6 +43,7 @@ } from '@mdi/js'; import { canCopyImageToClipboard } from '$lib/utils/asset-utils'; import { t } from 'svelte-i18n'; + import UserAvatar from '$lib/components/shared-components/user-avatar.svelte'; export let asset: AssetResponseDto; export let album: AlbumResponseDto | null = null; @@ -82,6 +83,11 @@ class="flex w-[calc(100%-3rem)] justify-end gap-2 overflow-hidden text-white" data-testid="asset-viewer-navbar-actions" > + {#if asset.owner && asset.owner.id != $user.id} +
+ +
+ {/if} {#if !asset.isTrashed && $user} {/if} @@ -124,7 +130,6 @@ title={$t('editor')} /> {/if} --> - {#if isOwner} diff --git a/web/src/lib/components/asset-viewer/detail-panel.svelte b/web/src/lib/components/asset-viewer/detail-panel.svelte index 88ea98778faca..d8ebac3d5f126 100644 --- a/web/src/lib/components/asset-viewer/detail-panel.svelte +++ b/web/src/lib/components/asset-viewer/detail-panel.svelte @@ -462,9 +462,13 @@ {/if} -{#if currentAlbum && currentAlbum.albumUsers.length > 0 && asset.owner} +{#if (currentAlbum && currentAlbum.albumUsers.length > 0 && asset.owner && asset.ownerId != $user.id) || (asset.ownerId != $user.id && asset.owner)}
-

{$t('shared_by').toUpperCase()}

+ {#if currentAlbum} +

{$t('shared_by').toUpperCase()}

+ {:else} +

{$t('partner_sharing').toUpperCase()}

+ {/if}
diff --git a/web/src/lib/components/assets/thumbnail/thumbnail.svelte b/web/src/lib/components/assets/thumbnail/thumbnail.svelte index af22887185a36..f4ee52038af13 100644 --- a/web/src/lib/components/assets/thumbnail/thumbnail.svelte +++ b/web/src/lib/components/assets/thumbnail/thumbnail.svelte @@ -2,11 +2,14 @@ import { intersectionObserver } from '$lib/actions/intersection-observer'; import Icon from '$lib/components/elements/icon.svelte'; import { ProjectionType } from '$lib/constants'; - import { getAssetThumbnailUrl, isSharedLink } from '$lib/utils'; + import { getAssetThumbnailUrl, isSharedLink, handlePromiseError } from '$lib/utils'; + import { handleError } from '$lib/utils/handle-error'; import { getAltText } from '$lib/utils/thumbnail-util'; import { timeToSeconds } from '$lib/utils/date-time'; - import { AssetMediaSize, AssetTypeEnum, type AssetResponseDto } from '@immich/sdk'; - import { locale, playVideoThumbnailOnHover } from '$lib/stores/preferences.store'; + import { user } from '$lib/stores/user.store'; + import { AssetMediaSize, AssetTypeEnum, type AssetResponseDto, type UserResponseDto } from '@immich/sdk'; + import { locale, playVideoThumbnailOnHover, showUserThumbnails } from '$lib/stores/preferences.store'; + import { getUserAndCacheResult } from '$lib/utils/users'; import { getAssetPlaybackUrl } from '$lib/utils'; import { mdiArchiveArrowDownOutline, @@ -19,6 +22,7 @@ } from '@mdi/js'; import { fade } from 'svelte/transition'; + import { t } from 'svelte-i18n'; import ImageThumbnail from './image-thumbnail.svelte'; import VideoThumbnail from './video-thumbnail.svelte'; import { currentUrlReplaceAssetId } from '$lib/utils/navigation'; @@ -30,6 +34,7 @@ import { onDestroy } from 'svelte'; import { TUNABLES } from '$lib/utils/tunables'; import { thumbhash } from '$lib/actions/thumbhash'; + import UserAvatar from '$lib/components/shared-components/user-avatar.svelte'; export let asset: AssetResponseDto; export let dateGroup: DateGroup | undefined = undefined; @@ -44,6 +49,7 @@ export let readonly = false; export let showArchiveIcon = false; export let showStackedIcon = true; + export let showUserThumbnailsinViewer = true; export let intersectionConfig: { root?: HTMLElement; bottom?: string; @@ -63,7 +69,6 @@ let className = ''; export { className as class }; - let { IMAGE_THUMBNAIL: { THUMBHASH_FADE_DURATION }, } = TUNABLES; @@ -74,6 +79,7 @@ let intersecting = false; let lastRetrievedElement: HTMLElement | undefined; let loaded = false; + let shareUser: UserResponseDto | undefined; $: if (!retrieveElement) { lastRetrievedElement = undefined; @@ -82,6 +88,9 @@ lastRetrievedElement = element; onRetrieveElement?.(element); } + $: if ($showUserThumbnails && showUserThumbnailsinViewer && (isSharedLink() || asset.ownerId != $user.id)) { + handlePromiseError(getShareUser()); + } $: width = thumbnailSize || thumbnailWidth || 235; $: height = thumbnailSize || thumbnailHeight || 235; @@ -159,6 +168,14 @@ } }; + const getShareUser = async () => { + try { + shareUser = await getUserAndCacheResult(asset.ownerId); + } catch (error) { + handleError(error, $t('errors.unable_to_load_liked_status')); + } + }; + onDestroy(() => { assetStore?.taskManager.removeAllTasksForComponent(componentId); }); @@ -268,6 +285,12 @@
{/if} + {#if shareUser && showUserThumbnailsinViewer} +
+ +
+ {/if} + {#if !isSharedLink() && showArchiveIcon && asset.isArchived}
diff --git a/web/src/lib/components/photos-page/asset-date-group.svelte b/web/src/lib/components/photos-page/asset-date-group.svelte index b2780cc1a06b0..9246d0f219369 100644 --- a/web/src/lib/components/photos-page/asset-date-group.svelte +++ b/web/src/lib/components/photos-page/asset-date-group.svelte @@ -20,6 +20,7 @@ export let singleSelect = false; export let withStacked = false; export let showArchiveIcon = false; + export let showUserThumbnailsinViewer = true; export let assetGridElement: HTMLElement | undefined = undefined; export let renderThumbsAtBottomMargin: string | undefined = undefined; export let renderThumbsAtTopMargin: string | undefined = undefined; @@ -207,6 +208,7 @@ onRetrieveElement={(element) => onRetrieveElement(dateGroup, asset, element)} showStackedIcon={withStacked} {showArchiveIcon} + {showUserThumbnailsinViewer} {asset} {groupIndex} onClick={(asset) => onClick(dateGroup.assets, dateGroup.groupTitle, asset)} diff --git a/web/src/lib/components/photos-page/asset-grid.svelte b/web/src/lib/components/photos-page/asset-grid.svelte index 6de36c803e775..487fdccaaee70 100644 --- a/web/src/lib/components/photos-page/asset-grid.svelte +++ b/web/src/lib/components/photos-page/asset-grid.svelte @@ -62,6 +62,7 @@ export let withStacked = false; export let showArchiveIcon = false; export let isShared = false; + export let showUserThumbnailsinViewer = true; export let album: AlbumResponseDto | null = null; export let isShowDeleteConfirmation = false; export let onSelect: (asset: AssetResponseDto) => void = () => {}; @@ -839,6 +840,7 @@ renderThumbsAtBottomMargin={THUMBNAIL_INTERSECTION_ROOT_BOTTOM} {withStacked} {showArchiveIcon} + {showUserThumbnailsinViewer} {assetStore} {assetInteractionStore} {isSelectionMode} @@ -864,6 +866,7 @@ - export type Size = 'full' | 'sm' | 'md' | 'lg' | 'xl' | 'xxl' | 'xxxl'; + export type Size = 'full' | 'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'xxl' | 'xxxl';