mirror of
https://github.com/immich-app/immich.git
synced 2026-05-22 15:42:32 -04:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c139259af8 |
@@ -14,7 +14,6 @@ import 'package:immich_mobile/providers/backup/asset_upload_progress.provider.da
|
||||
import 'package:immich_mobile/providers/infrastructure/asset.provider.dart';
|
||||
import 'package:immich_mobile/providers/infrastructure/asset_viewer/asset.provider.dart' show assetExifProvider;
|
||||
import 'package:immich_mobile/providers/infrastructure/tag.provider.dart';
|
||||
import 'package:immich_mobile/providers/server_info.provider.dart';
|
||||
import 'package:immich_mobile/providers/timeline/multiselect.provider.dart';
|
||||
import 'package:immich_mobile/providers/user.provider.dart';
|
||||
import 'package:immich_mobile/providers/websocket.provider.dart';
|
||||
@@ -22,7 +21,6 @@ import 'package:immich_mobile/routing/router.dart';
|
||||
import 'package:immich_mobile/services/action.service.dart';
|
||||
import 'package:immich_mobile/services/download.service.dart';
|
||||
import 'package:immich_mobile/services/foreground_upload.service.dart';
|
||||
import 'package:immich_mobile/utils/semver.dart';
|
||||
import 'package:immich_mobile/widgets/asset_grid/delete_dialog.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
import 'package:openapi/api.dart';
|
||||
@@ -538,22 +536,14 @@ class ActionNotifier extends Notifier<void> {
|
||||
return ActionResult(count: ids.length, success: false, error: 'Expected single asset for applying edits');
|
||||
}
|
||||
|
||||
Future<void> editReady;
|
||||
if (ref.read(serverInfoProvider).serverVersion >= const SemVer(major: 3, minor: 0, patch: 0)) {
|
||||
editReady = ref.read(websocketProvider.notifier).waitForEvent("AssetEditReadyV2", (dynamic data) {
|
||||
final eventAsset = SyncAssetV2.fromJson(data["asset"]);
|
||||
return eventAsset?.id == ids.first;
|
||||
}, const Duration(seconds: 10));
|
||||
} else {
|
||||
editReady = ref.read(websocketProvider.notifier).waitForEvent("AssetEditReadyV1", (dynamic data) {
|
||||
final eventAsset = SyncAssetV1.fromJson(data["asset"]);
|
||||
return eventAsset?.id == ids.first;
|
||||
}, const Duration(seconds: 10));
|
||||
}
|
||||
final completer = ref.read(websocketProvider.notifier).waitForEvent("AssetEditReadyV1", (dynamic data) {
|
||||
final eventAsset = SyncAssetV1.fromJson(data["asset"]);
|
||||
return eventAsset?.id == ids.first;
|
||||
}, const Duration(seconds: 10));
|
||||
|
||||
try {
|
||||
await _service.applyEdits(ids.first, edits);
|
||||
await editReady;
|
||||
await completer;
|
||||
return const ActionResult(count: 1, success: true);
|
||||
} catch (error, stack) {
|
||||
_logger.severe('Failed to apply edits to assets', error, stack);
|
||||
|
||||
@@ -149,29 +149,35 @@
|
||||
return { width: 1, height: 1 };
|
||||
});
|
||||
|
||||
const { insetInlineStart, top, rasterWidth, rasterHeight, rasterScale } = $derived.by(() => {
|
||||
const scaleFn = objectFit === 'cover' ? scaleToCover : scaleToFit;
|
||||
const { width, height } = scaleFn(imageDimensions, container);
|
||||
if (maxRasterPixels === 0) {
|
||||
const { insetInlineStart, top, displayWidth, displayHeight, rasterWidth, rasterHeight, rasterScale } = $derived.by(
|
||||
() => {
|
||||
const scaleFn = objectFit === 'cover' ? scaleToCover : scaleToFit;
|
||||
const { width, height } = scaleFn(imageDimensions, container);
|
||||
if (maxRasterPixels === 0) {
|
||||
return {
|
||||
insetInlineStart: (container.width - width) / 2 + 'px',
|
||||
top: (container.height - height) / 2 + 'px',
|
||||
displayWidth: width + 'px',
|
||||
displayHeight: height + 'px',
|
||||
rasterWidth: width + 'px',
|
||||
rasterHeight: height + 'px',
|
||||
rasterScale: 1,
|
||||
};
|
||||
}
|
||||
const nativeRatio = imageDimensions.width / width;
|
||||
const budgetRatio = Math.sqrt(maxRasterPixels / Math.max(width * height, 1));
|
||||
const rasterRatio = Math.max(1, Math.min(nativeRatio, budgetRatio));
|
||||
return {
|
||||
insetInlineStart: (container.width - width) / 2 + 'px',
|
||||
top: (container.height - height) / 2 + 'px',
|
||||
rasterWidth: width + 'px',
|
||||
rasterHeight: height + 'px',
|
||||
rasterScale: 1,
|
||||
displayWidth: width + 'px',
|
||||
displayHeight: height + 'px',
|
||||
rasterWidth: width * rasterRatio + 'px',
|
||||
rasterHeight: height * rasterRatio + 'px',
|
||||
rasterScale: 1 / rasterRatio,
|
||||
};
|
||||
}
|
||||
const nativeRatio = imageDimensions.width / width;
|
||||
const budgetRatio = Math.sqrt(maxRasterPixels / Math.max(width * height, 1));
|
||||
const rasterRatio = Math.max(1, Math.min(nativeRatio, budgetRatio));
|
||||
return {
|
||||
insetInlineStart: (container.width - width) / 2 + 'px',
|
||||
top: (container.height - height) / 2 + 'px',
|
||||
rasterWidth: width * rasterRatio + 'px',
|
||||
rasterHeight: height * rasterRatio + 'px',
|
||||
rasterScale: 1 / rasterRatio,
|
||||
};
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
const { status } = $derived(adaptiveImageLoader);
|
||||
const alt = $derived(status.urls.preview ? $getAltText(toTimelineAsset(asset)) : '');
|
||||
@@ -261,7 +267,6 @@
|
||||
{alt}
|
||||
width={rasterWidth}
|
||||
height={rasterHeight}
|
||||
{overlays}
|
||||
quality="preview"
|
||||
src={status.urls.preview}
|
||||
bind:ref={previewElement}
|
||||
@@ -274,11 +279,22 @@
|
||||
{alt}
|
||||
width={rasterWidth}
|
||||
height={rasterHeight}
|
||||
{overlays}
|
||||
quality="original"
|
||||
src={status.urls.original}
|
||||
bind:ref={originalElement}
|
||||
/>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
{#if overlays}
|
||||
<div
|
||||
class="pointer-events-none absolute"
|
||||
style:inset-inline-start={insetInlineStart}
|
||||
style:top
|
||||
style:width={displayWidth}
|
||||
style:height={displayHeight}
|
||||
>
|
||||
{@render overlays()}
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
<script lang="ts">
|
||||
import Image from '$lib/components/Image.svelte';
|
||||
import type { AdaptiveImageLoader, ImageQuality } from '$lib/utils/adaptive-image-loader.svelte';
|
||||
import type { Snippet } from 'svelte';
|
||||
|
||||
type Props = {
|
||||
adaptiveImageLoader: AdaptiveImageLoader;
|
||||
@@ -12,7 +11,6 @@
|
||||
ref?: HTMLImageElement;
|
||||
width: string;
|
||||
height: string;
|
||||
overlays?: Snippet;
|
||||
};
|
||||
|
||||
let {
|
||||
@@ -24,7 +22,6 @@
|
||||
ref = $bindable(),
|
||||
width,
|
||||
height,
|
||||
overlays,
|
||||
}: Props = $props();
|
||||
</script>
|
||||
|
||||
@@ -42,6 +39,5 @@
|
||||
draggable={false}
|
||||
data-testid={quality}
|
||||
/>
|
||||
{@render overlays?.()}
|
||||
</div>
|
||||
{/key}
|
||||
|
||||
@@ -127,7 +127,7 @@ export class EditManager {
|
||||
|
||||
try {
|
||||
// Setup the websocket listener before sending the edit request
|
||||
const editCompleted = waitForWebsocketEvent('AssetEditReadyV2', (event) => event.asset.id === assetId, 10_000);
|
||||
const editCompleted = waitForWebsocketEvent('AssetEditReadyV1', (event) => event.asset.id === assetId, 10_000);
|
||||
|
||||
await (edits.length === 0
|
||||
? removeAssetEdits({ id: assetId })
|
||||
|
||||
@@ -5,7 +5,7 @@ import {
|
||||
type NotificationDto,
|
||||
type ServerVersionResponseDto,
|
||||
type SyncAssetEditV1,
|
||||
type SyncAssetV2,
|
||||
type SyncAssetV1,
|
||||
} from '@immich/sdk';
|
||||
import { io, type Socket } from 'socket.io-client';
|
||||
import { get, writable } from 'svelte/store';
|
||||
@@ -41,7 +41,7 @@ export interface Events {
|
||||
AppRestartV1: (event: AppRestartEvent) => void;
|
||||
|
||||
MaintenanceStatusV1: (event: MaintenanceStatusResponseDto) => void;
|
||||
AssetEditReadyV2: (data: { asset: SyncAssetV2; edit: SyncAssetEditV1[] }) => void;
|
||||
AssetEditReadyV1: (data: { asset: SyncAssetV1; edit: SyncAssetEditV1[] }) => void;
|
||||
}
|
||||
|
||||
const websocket: Socket<Events> = io({
|
||||
|
||||
Reference in New Issue
Block a user