|
@@ -1,6 +1,9 @@
|
|
|
import { api, AssetApiGetTimeBucketsRequest, AssetResponseDto } from '@api';
|
|
|
-import { writable } from 'svelte/store';
|
|
|
+import { throttle } from 'lodash-es';
|
|
|
+import { DateTime } from 'luxon';
|
|
|
+import { Unsubscriber, writable } from 'svelte/store';
|
|
|
import { handleError } from '../utils/handle-error';
|
|
|
+import { websocketStore } from './websocket';
|
|
|
|
|
|
export enum BucketPosition {
|
|
|
Above = 'above',
|
|
@@ -34,11 +37,33 @@ export class AssetBucket {
|
|
|
position!: BucketPosition;
|
|
|
}
|
|
|
|
|
|
+const isMismatched = (option: boolean | undefined, value: boolean): boolean =>
|
|
|
+ option === undefined ? false : option !== value;
|
|
|
+
|
|
|
const THUMBNAIL_HEIGHT = 235;
|
|
|
|
|
|
+interface AddAsset {
|
|
|
+ type: 'add';
|
|
|
+ value: AssetResponseDto;
|
|
|
+}
|
|
|
+
|
|
|
+interface DeleteAsset {
|
|
|
+ type: 'delete';
|
|
|
+ value: string;
|
|
|
+}
|
|
|
+
|
|
|
+interface TrashAsset {
|
|
|
+ type: 'trash';
|
|
|
+ value: string;
|
|
|
+}
|
|
|
+
|
|
|
+type PendingChange = AddAsset | DeleteAsset | TrashAsset;
|
|
|
+
|
|
|
export class AssetStore {
|
|
|
private store$ = writable(this);
|
|
|
private assetToBucket: Record<string, AssetLookup> = {};
|
|
|
+ private pendingChanges: PendingChange[] = [];
|
|
|
+ private unsubscribers: Unsubscriber[] = [];
|
|
|
|
|
|
initialized = false;
|
|
|
timelineHeight = 0;
|
|
@@ -52,6 +77,63 @@ export class AssetStore {
|
|
|
|
|
|
subscribe = this.store$.subscribe;
|
|
|
|
|
|
+ connect() {
|
|
|
+ this.unsubscribers.push(
|
|
|
+ websocketStore.onUploadSuccess.subscribe((value) => {
|
|
|
+ if (value) {
|
|
|
+ this.pendingChanges.push({ type: 'add', value });
|
|
|
+ this.processPendingChanges();
|
|
|
+ }
|
|
|
+ }),
|
|
|
+
|
|
|
+ websocketStore.onAssetTrash.subscribe((ids) => {
|
|
|
+ console.log('onAssetTrash', ids);
|
|
|
+ if (ids) {
|
|
|
+ for (const id of ids) {
|
|
|
+ this.pendingChanges.push({ type: 'trash', value: id });
|
|
|
+ }
|
|
|
+ this.processPendingChanges();
|
|
|
+ }
|
|
|
+ }),
|
|
|
+
|
|
|
+ websocketStore.onAssetDelete.subscribe((value) => {
|
|
|
+ if (value) {
|
|
|
+ this.pendingChanges.push({ type: 'delete', value });
|
|
|
+ this.processPendingChanges();
|
|
|
+ }
|
|
|
+ }),
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+ disconnect() {
|
|
|
+ for (const unsubscribe of this.unsubscribers) {
|
|
|
+ unsubscribe();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ processPendingChanges = throttle(() => {
|
|
|
+ for (const { type, value } of this.pendingChanges) {
|
|
|
+ switch (type) {
|
|
|
+ case 'add':
|
|
|
+ this.addAsset(value);
|
|
|
+ break;
|
|
|
+
|
|
|
+ case 'trash':
|
|
|
+ if (!this.options.isTrashed) {
|
|
|
+ this.removeAsset(value);
|
|
|
+ }
|
|
|
+ break;
|
|
|
+
|
|
|
+ case 'delete':
|
|
|
+ this.removeAsset(value);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ this.pendingChanges = [];
|
|
|
+ this.emit(true);
|
|
|
+ }, 10_000);
|
|
|
+
|
|
|
async init(viewport: Viewport) {
|
|
|
this.initialized = false;
|
|
|
this.timelineHeight = 0;
|
|
@@ -168,6 +250,46 @@ export class AssetStore {
|
|
|
return scrollTimeline ? delta : 0;
|
|
|
}
|
|
|
|
|
|
+ private addAsset(asset: AssetResponseDto): void {
|
|
|
+ if (
|
|
|
+ this.assetToBucket[asset.id] ||
|
|
|
+ this.options.userId ||
|
|
|
+ this.options.personId ||
|
|
|
+ this.options.albumId ||
|
|
|
+ isMismatched(this.options.isArchived, asset.isArchived) ||
|
|
|
+ isMismatched(this.options.isFavorite, asset.isFavorite)
|
|
|
+ ) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ const timeBucket = DateTime.fromISO(asset.fileCreatedAt).toUTC().startOf('month').toString();
|
|
|
+ let bucket = this.getBucketByDate(timeBucket);
|
|
|
+
|
|
|
+ if (!bucket) {
|
|
|
+ bucket = {
|
|
|
+ bucketDate: timeBucket,
|
|
|
+ bucketHeight: THUMBNAIL_HEIGHT,
|
|
|
+ assets: [],
|
|
|
+ cancelToken: null,
|
|
|
+ position: BucketPosition.Unknown,
|
|
|
+ };
|
|
|
+
|
|
|
+ this.buckets.push(bucket);
|
|
|
+ this.buckets = this.buckets.sort((a, b) => {
|
|
|
+ const aDate = DateTime.fromISO(a.bucketDate).toUTC();
|
|
|
+ const bDate = DateTime.fromISO(b.bucketDate).toUTC();
|
|
|
+ return bDate.diff(aDate).milliseconds;
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ bucket.assets.push(asset);
|
|
|
+ bucket.assets.sort((a, b) => {
|
|
|
+ const aDate = DateTime.fromISO(a.fileCreatedAt).toUTC();
|
|
|
+ const bDate = DateTime.fromISO(b.fileCreatedAt).toUTC();
|
|
|
+ return bDate.diff(aDate).milliseconds;
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
getBucketByDate(bucketDate: string): AssetBucket | null {
|
|
|
return this.buckets.find((bucket) => bucket.bucketDate === bucketDate) || null;
|
|
|
}
|