From 4ea652aeb882d92c789ac8fe9df228c99246cc6f Mon Sep 17 00:00:00 2001 From: Christopher Makarem <23037854+x24git@users.noreply.github.com> Date: Wed, 28 Aug 2024 17:13:53 -0700 Subject: [PATCH 1/2] inital proof of concept icons --- .../lib/components/assets/thumbnail/thumbnail.svelte | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/web/src/lib/components/assets/thumbnail/thumbnail.svelte b/web/src/lib/components/assets/thumbnail/thumbnail.svelte index 2ac8402b5f4cc..7eff461cf9d26 100644 --- a/web/src/lib/components/assets/thumbnail/thumbnail.svelte +++ b/web/src/lib/components/assets/thumbnail/thumbnail.svelte @@ -2,9 +2,10 @@ 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, getUserInfo, isSharedLink } from '$lib/utils'; import { getAltText } from '$lib/utils/thumbnail-util'; import { timeToSeconds } from '$lib/utils/date-time'; + import { user } from '$lib/stores/user.store'; import { AssetMediaSize, AssetTypeEnum, type AssetResponseDto } from '@immich/sdk'; import { locale, playVideoThumbnailOnHover } from '$lib/stores/preferences.store'; import { getAssetPlaybackUrl } from '$lib/utils'; @@ -30,6 +31,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; @@ -63,7 +65,6 @@ let className = ''; export { className as class }; - let { IMAGE_THUMBNAIL: { THUMBHASH_FADE_DURATION }, } = TUNABLES; @@ -267,6 +268,12 @@ {/if} + {#if isSharedLink() || asset.ownerId != user.userId} +
+ +
+ {/if} + {#if !isSharedLink() && showArchiveIcon && asset.isArchived}
From 6f0a7d0638f8e90c6287d84c5aa1cb02b86854b4 Mon Sep 17 00:00:00 2001 From: Christopher Makarem <23037854+x24git@users.noreply.github.com> Date: Fri, 6 Sep 2024 15:25:18 -0700 Subject: [PATCH 2/2] Add user avatars to web timelines --- .../asset-viewer/asset-viewer-nav-bar.svelte | 7 +++- .../asset-viewer/detail-panel.svelte | 8 +++-- .../assets/thumbnail/thumbnail.svelte | 26 +++++++++++--- .../photos-page/asset-date-group.svelte | 2 ++ .../components/photos-page/asset-grid.svelte | 3 ++ .../shared-components/user-avatar.svelte | 6 ++-- .../user-settings-page/app-settings.svelte | 9 +++++ web/src/lib/i18n/en.json | 2 ++ web/src/lib/stores/preferences.store.ts | 2 ++ web/src/lib/stores/users.store.ts | 35 +++++++++++++++++++ web/src/lib/utils/users.ts | 16 +++++++++ .../[[assetId=id]]/+page.svelte | 2 +- 12 files changed, 107 insertions(+), 11 deletions(-) create mode 100644 web/src/lib/stores/users.store.ts create mode 100644 web/src/lib/utils/users.ts 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 db216641d5c2f..c45a7f1f8e1e9 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; @@ -83,6 +84,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} @@ -125,7 +131,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 04f4476e07635..e5f266323e196 100644 --- a/web/src/lib/components/asset-viewer/detail-panel.svelte +++ b/web/src/lib/components/asset-viewer/detail-panel.svelte @@ -455,9 +455,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 cfffceb45da4b..f4ee52038af13 100644 --- a/web/src/lib/components/assets/thumbnail/thumbnail.svelte +++ b/web/src/lib/components/assets/thumbnail/thumbnail.svelte @@ -2,12 +2,14 @@ import { intersectionObserver } from '$lib/actions/intersection-observer'; import Icon from '$lib/components/elements/icon.svelte'; import { ProjectionType } from '$lib/constants'; - import { getAssetThumbnailUrl, getUserInfo, 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 { user } from '$lib/stores/user.store'; - import { AssetMediaSize, AssetTypeEnum, type AssetResponseDto } from '@immich/sdk'; - import { locale, playVideoThumbnailOnHover } from '$lib/stores/preferences.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, @@ -20,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'; @@ -46,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; @@ -75,6 +79,7 @@ let intersecting = false; let lastRetrievedElement: HTMLElement | undefined; let loaded = false; + let shareUser: UserResponseDto | undefined; $: if (!retrieveElement) { lastRetrievedElement = undefined; @@ -83,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; @@ -160,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); }); @@ -269,9 +285,9 @@
{/if} - {#if isSharedLink() || asset.ownerId != user.userId} + {#if shareUser && showUserThumbnailsinViewer}
- +
{/if} 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 240b6c2ba2162..392d4878f43f8 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; @@ -209,6 +210,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 f59911dbaf6c4..e851a6655737e 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; @@ -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';