@@ -1,10 +1,10 @@
|
||||
import { writable } from 'svelte/store';
|
||||
|
||||
function createAlbumAssetSelectionStore() {
|
||||
const isAlbumAssetSelectionOpen = writable<boolean>(false);
|
||||
return {
|
||||
isAlbumAssetSelectionOpen
|
||||
};
|
||||
const isAlbumAssetSelectionOpen = writable<boolean>(false);
|
||||
return {
|
||||
isAlbumAssetSelectionOpen,
|
||||
};
|
||||
}
|
||||
|
||||
export const albumAssetSelectionStore = createAlbumAssetSelectionStore();
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { AssetGridState, BucketPosition } from '$lib/models/asset-grid-state';
|
||||
import { api, AssetResponseDto } from '@api';
|
||||
import { sortBy } from 'lodash-es';
|
||||
import { derived, writable } from 'svelte/store';
|
||||
import { assetGridState, assetStore } from './assets.store';
|
||||
import { sortBy } from 'lodash-es';
|
||||
|
||||
// Asset Viewer
|
||||
export const viewingAssetStoreState = writable<AssetResponseDto>();
|
||||
@@ -12,147 +12,144 @@ export const isViewingAssetStoreState = writable<boolean>(false);
|
||||
export const assetsInAlbumStoreState = writable<AssetResponseDto[]>([]);
|
||||
export const selectedAssets = writable<Set<AssetResponseDto>>(new Set());
|
||||
export const selectedGroup = writable<Set<string>>(new Set());
|
||||
export const isMultiSelectStoreState = derived(
|
||||
selectedAssets,
|
||||
($selectedAssets) => $selectedAssets.size > 0
|
||||
);
|
||||
export const isMultiSelectStoreState = derived(selectedAssets, ($selectedAssets) => $selectedAssets.size > 0);
|
||||
|
||||
function createAssetInteractionStore() {
|
||||
let _assetGridState = new AssetGridState();
|
||||
let _viewingAssetStoreState: AssetResponseDto;
|
||||
let _selectedAssets: Set<AssetResponseDto>;
|
||||
let _selectedGroup: Set<string>;
|
||||
let _assetsInAlbums: AssetResponseDto[];
|
||||
let savedAssetLength = 0;
|
||||
let assetSortedByDate: AssetResponseDto[] = [];
|
||||
let _assetGridState = new AssetGridState();
|
||||
let _viewingAssetStoreState: AssetResponseDto;
|
||||
let _selectedAssets: Set<AssetResponseDto>;
|
||||
let _selectedGroup: Set<string>;
|
||||
let _assetsInAlbums: AssetResponseDto[];
|
||||
let savedAssetLength = 0;
|
||||
let assetSortedByDate: AssetResponseDto[] = [];
|
||||
|
||||
// Subscriber
|
||||
assetGridState.subscribe((state) => {
|
||||
_assetGridState = state;
|
||||
});
|
||||
// Subscriber
|
||||
assetGridState.subscribe((state) => {
|
||||
_assetGridState = state;
|
||||
});
|
||||
|
||||
viewingAssetStoreState.subscribe((asset) => {
|
||||
_viewingAssetStoreState = asset;
|
||||
});
|
||||
viewingAssetStoreState.subscribe((asset) => {
|
||||
_viewingAssetStoreState = asset;
|
||||
});
|
||||
|
||||
selectedAssets.subscribe((assets) => {
|
||||
_selectedAssets = assets;
|
||||
});
|
||||
selectedAssets.subscribe((assets) => {
|
||||
_selectedAssets = assets;
|
||||
});
|
||||
|
||||
selectedGroup.subscribe((group) => {
|
||||
_selectedGroup = group;
|
||||
});
|
||||
selectedGroup.subscribe((group) => {
|
||||
_selectedGroup = group;
|
||||
});
|
||||
|
||||
assetsInAlbumStoreState.subscribe((assets) => {
|
||||
_assetsInAlbums = assets;
|
||||
});
|
||||
assetsInAlbumStoreState.subscribe((assets) => {
|
||||
_assetsInAlbums = assets;
|
||||
});
|
||||
|
||||
// Methods
|
||||
// Methods
|
||||
|
||||
/**
|
||||
* Asset Viewer
|
||||
*/
|
||||
const setViewingAsset = async (asset: AssetResponseDto) => {
|
||||
setViewingAssetId(asset.id);
|
||||
};
|
||||
/**
|
||||
* Asset Viewer
|
||||
*/
|
||||
const setViewingAsset = async (asset: AssetResponseDto) => {
|
||||
setViewingAssetId(asset.id);
|
||||
};
|
||||
|
||||
const setViewingAssetId = async (id: string) => {
|
||||
const { data } = await api.assetApi.getAssetById({ id });
|
||||
viewingAssetStoreState.set(data);
|
||||
isViewingAssetStoreState.set(true);
|
||||
};
|
||||
const setViewingAssetId = async (id: string) => {
|
||||
const { data } = await api.assetApi.getAssetById({ id });
|
||||
viewingAssetStoreState.set(data);
|
||||
isViewingAssetStoreState.set(true);
|
||||
};
|
||||
|
||||
const setIsViewingAsset = (isViewing: boolean) => {
|
||||
isViewingAssetStoreState.set(isViewing);
|
||||
};
|
||||
const setIsViewingAsset = (isViewing: boolean) => {
|
||||
isViewingAssetStoreState.set(isViewing);
|
||||
};
|
||||
|
||||
const navigateAsset = async (direction: 'next' | 'previous') => {
|
||||
// Flatten and sort the asset by date if there are new assets
|
||||
if (assetSortedByDate.length === 0 || savedAssetLength !== _assetGridState.assets.length) {
|
||||
assetSortedByDate = sortBy(_assetGridState.assets, (a) => a.fileCreatedAt);
|
||||
savedAssetLength = _assetGridState.assets.length;
|
||||
}
|
||||
const navigateAsset = async (direction: 'next' | 'previous') => {
|
||||
// Flatten and sort the asset by date if there are new assets
|
||||
if (assetSortedByDate.length === 0 || savedAssetLength !== _assetGridState.assets.length) {
|
||||
assetSortedByDate = sortBy(_assetGridState.assets, (a) => a.fileCreatedAt);
|
||||
savedAssetLength = _assetGridState.assets.length;
|
||||
}
|
||||
|
||||
// Find the index of the current asset
|
||||
const currentIndex = assetSortedByDate.findIndex((a) => a.id === _viewingAssetStoreState.id);
|
||||
// Find the index of the current asset
|
||||
const currentIndex = assetSortedByDate.findIndex((a) => a.id === _viewingAssetStoreState.id);
|
||||
|
||||
// Get the next or previous asset
|
||||
const nextIndex = direction === 'previous' ? currentIndex + 1 : currentIndex - 1;
|
||||
// Get the next or previous asset
|
||||
const nextIndex = direction === 'previous' ? currentIndex + 1 : currentIndex - 1;
|
||||
|
||||
// Run out of asset, this might be because there is no asset in the next bucket.
|
||||
if (nextIndex == -1) {
|
||||
let nextBucket = '';
|
||||
// Find next bucket that doesn't have all assets loaded
|
||||
// Run out of asset, this might be because there is no asset in the next bucket.
|
||||
if (nextIndex == -1) {
|
||||
let nextBucket = '';
|
||||
// Find next bucket that doesn't have all assets loaded
|
||||
|
||||
for (const bucket of _assetGridState.buckets) {
|
||||
if (bucket.assets.length === 0) {
|
||||
nextBucket = bucket.bucketDate;
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (const bucket of _assetGridState.buckets) {
|
||||
if (bucket.assets.length === 0) {
|
||||
nextBucket = bucket.bucketDate;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (nextBucket !== '') {
|
||||
await assetStore.getAssetsByBucket(nextBucket, BucketPosition.Below);
|
||||
navigateAsset(direction);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (nextBucket !== '') {
|
||||
await assetStore.getAssetsByBucket(nextBucket, BucketPosition.Below);
|
||||
navigateAsset(direction);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const nextAsset = assetSortedByDate[nextIndex];
|
||||
if (nextAsset) {
|
||||
setViewingAsset(nextAsset);
|
||||
}
|
||||
};
|
||||
const nextAsset = assetSortedByDate[nextIndex];
|
||||
if (nextAsset) {
|
||||
setViewingAsset(nextAsset);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Multiselect
|
||||
*/
|
||||
const addAssetToMultiselectGroup = (asset: AssetResponseDto) => {
|
||||
// Not select if in album already
|
||||
if (_assetsInAlbums.find((a) => a.id === asset.id)) {
|
||||
return;
|
||||
}
|
||||
/**
|
||||
* Multiselect
|
||||
*/
|
||||
const addAssetToMultiselectGroup = (asset: AssetResponseDto) => {
|
||||
// Not select if in album already
|
||||
if (_assetsInAlbums.find((a) => a.id === asset.id)) {
|
||||
return;
|
||||
}
|
||||
|
||||
_selectedAssets.add(asset);
|
||||
selectedAssets.set(_selectedAssets);
|
||||
};
|
||||
_selectedAssets.add(asset);
|
||||
selectedAssets.set(_selectedAssets);
|
||||
};
|
||||
|
||||
const removeAssetFromMultiselectGroup = (asset: AssetResponseDto) => {
|
||||
_selectedAssets.delete(asset);
|
||||
selectedAssets.set(_selectedAssets);
|
||||
};
|
||||
const removeAssetFromMultiselectGroup = (asset: AssetResponseDto) => {
|
||||
_selectedAssets.delete(asset);
|
||||
selectedAssets.set(_selectedAssets);
|
||||
};
|
||||
|
||||
const addGroupToMultiselectGroup = (group: string) => {
|
||||
_selectedGroup.add(group);
|
||||
selectedGroup.set(_selectedGroup);
|
||||
};
|
||||
const addGroupToMultiselectGroup = (group: string) => {
|
||||
_selectedGroup.add(group);
|
||||
selectedGroup.set(_selectedGroup);
|
||||
};
|
||||
|
||||
const removeGroupFromMultiselectGroup = (group: string) => {
|
||||
_selectedGroup.delete(group);
|
||||
selectedGroup.set(_selectedGroup);
|
||||
};
|
||||
const removeGroupFromMultiselectGroup = (group: string) => {
|
||||
_selectedGroup.delete(group);
|
||||
selectedGroup.set(_selectedGroup);
|
||||
};
|
||||
|
||||
const clearMultiselect = () => {
|
||||
_selectedAssets.clear();
|
||||
_selectedGroup.clear();
|
||||
_assetsInAlbums = [];
|
||||
const clearMultiselect = () => {
|
||||
_selectedAssets.clear();
|
||||
_selectedGroup.clear();
|
||||
_assetsInAlbums = [];
|
||||
|
||||
selectedAssets.set(_selectedAssets);
|
||||
selectedGroup.set(_selectedGroup);
|
||||
assetsInAlbumStoreState.set(_assetsInAlbums);
|
||||
};
|
||||
selectedAssets.set(_selectedAssets);
|
||||
selectedGroup.set(_selectedGroup);
|
||||
assetsInAlbumStoreState.set(_assetsInAlbums);
|
||||
};
|
||||
|
||||
return {
|
||||
setViewingAsset,
|
||||
setViewingAssetId,
|
||||
setIsViewingAsset,
|
||||
navigateAsset,
|
||||
addAssetToMultiselectGroup,
|
||||
removeAssetFromMultiselectGroup,
|
||||
addGroupToMultiselectGroup,
|
||||
removeGroupFromMultiselectGroup,
|
||||
clearMultiselect
|
||||
};
|
||||
return {
|
||||
setViewingAsset,
|
||||
setViewingAssetId,
|
||||
setIsViewingAsset,
|
||||
navigateAsset,
|
||||
addAssetToMultiselectGroup,
|
||||
removeAssetFromMultiselectGroup,
|
||||
addGroupToMultiselectGroup,
|
||||
removeGroupFromMultiselectGroup,
|
||||
clearMultiselect,
|
||||
};
|
||||
}
|
||||
|
||||
export const assetInteractionStore = createAssetInteractionStore();
|
||||
|
||||
+163
-163
@@ -1,6 +1,6 @@
|
||||
import { AssetGridState, BucketPosition } from '$lib/models/asset-grid-state';
|
||||
import { AssetCountByTimeBucketResponseDto, api } from '@api';
|
||||
import { sumBy, flatMap } from 'lodash-es';
|
||||
import { api, AssetCountByTimeBucketResponseDto } from '@api';
|
||||
import { flatMap, sumBy } from 'lodash-es';
|
||||
import { writable } from 'svelte/store';
|
||||
|
||||
/**
|
||||
@@ -10,189 +10,189 @@ export const assetGridState = writable<AssetGridState>(new AssetGridState());
|
||||
export const loadingBucketState = writable<{ [key: string]: boolean }>({});
|
||||
|
||||
function createAssetStore() {
|
||||
let _assetGridState = new AssetGridState();
|
||||
assetGridState.subscribe((state) => {
|
||||
_assetGridState = state;
|
||||
});
|
||||
let _assetGridState = new AssetGridState();
|
||||
assetGridState.subscribe((state) => {
|
||||
_assetGridState = state;
|
||||
});
|
||||
|
||||
let _loadingBucketState: { [key: string]: boolean } = {};
|
||||
loadingBucketState.subscribe((state) => {
|
||||
_loadingBucketState = state;
|
||||
});
|
||||
let _loadingBucketState: { [key: string]: boolean } = {};
|
||||
loadingBucketState.subscribe((state) => {
|
||||
_loadingBucketState = state;
|
||||
});
|
||||
|
||||
const estimateViewportHeight = (assetCount: number, viewportWidth: number): number => {
|
||||
// Ideally we would use the average aspect ratio for the photoset, however assume
|
||||
// a normal landscape aspect ratio of 3:2, then discount for the likelihood we
|
||||
// will be scaling down and coalescing.
|
||||
const thumbnailHeight = 235;
|
||||
const unwrappedWidth = (3 / 2) * assetCount * thumbnailHeight * (7 / 10);
|
||||
const rows = Math.ceil(unwrappedWidth / viewportWidth);
|
||||
const height = rows * thumbnailHeight;
|
||||
return height;
|
||||
};
|
||||
const estimateViewportHeight = (assetCount: number, viewportWidth: number): number => {
|
||||
// Ideally we would use the average aspect ratio for the photoset, however assume
|
||||
// a normal landscape aspect ratio of 3:2, then discount for the likelihood we
|
||||
// will be scaling down and coalescing.
|
||||
const thumbnailHeight = 235;
|
||||
const unwrappedWidth = (3 / 2) * assetCount * thumbnailHeight * (7 / 10);
|
||||
const rows = Math.ceil(unwrappedWidth / viewportWidth);
|
||||
const height = rows * thumbnailHeight;
|
||||
return height;
|
||||
};
|
||||
|
||||
/**
|
||||
* Set initial state
|
||||
* @param viewportHeight
|
||||
* @param viewportWidth
|
||||
* @param data
|
||||
*/
|
||||
const setInitialState = (
|
||||
viewportHeight: number,
|
||||
viewportWidth: number,
|
||||
data: AssetCountByTimeBucketResponseDto,
|
||||
userId: string | undefined
|
||||
) => {
|
||||
assetGridState.set({
|
||||
viewportHeight,
|
||||
viewportWidth,
|
||||
timelineHeight: 0,
|
||||
buckets: data.buckets.map((bucket) => ({
|
||||
bucketDate: bucket.timeBucket,
|
||||
bucketHeight: estimateViewportHeight(bucket.count, viewportWidth),
|
||||
assets: [],
|
||||
cancelToken: new AbortController(),
|
||||
position: BucketPosition.Unknown
|
||||
})),
|
||||
assets: [],
|
||||
userId
|
||||
});
|
||||
/**
|
||||
* Set initial state
|
||||
* @param viewportHeight
|
||||
* @param viewportWidth
|
||||
* @param data
|
||||
*/
|
||||
const setInitialState = (
|
||||
viewportHeight: number,
|
||||
viewportWidth: number,
|
||||
data: AssetCountByTimeBucketResponseDto,
|
||||
userId: string | undefined,
|
||||
) => {
|
||||
assetGridState.set({
|
||||
viewportHeight,
|
||||
viewportWidth,
|
||||
timelineHeight: 0,
|
||||
buckets: data.buckets.map((bucket) => ({
|
||||
bucketDate: bucket.timeBucket,
|
||||
bucketHeight: estimateViewportHeight(bucket.count, viewportWidth),
|
||||
assets: [],
|
||||
cancelToken: new AbortController(),
|
||||
position: BucketPosition.Unknown,
|
||||
})),
|
||||
assets: [],
|
||||
userId,
|
||||
});
|
||||
|
||||
// Update timeline height based on calculated bucket height
|
||||
assetGridState.update((state) => {
|
||||
state.timelineHeight = sumBy(state.buckets, (d) => d.bucketHeight);
|
||||
return state;
|
||||
});
|
||||
};
|
||||
// Update timeline height based on calculated bucket height
|
||||
assetGridState.update((state) => {
|
||||
state.timelineHeight = sumBy(state.buckets, (d) => d.bucketHeight);
|
||||
return state;
|
||||
});
|
||||
};
|
||||
|
||||
const getAssetsByBucket = async (bucket: string, position: BucketPosition) => {
|
||||
try {
|
||||
const currentBucketData = _assetGridState.buckets.find((b) => b.bucketDate === bucket);
|
||||
if (currentBucketData?.assets && currentBucketData.assets.length > 0) {
|
||||
assetGridState.update((state) => {
|
||||
const bucketIndex = state.buckets.findIndex((b) => b.bucketDate === bucket);
|
||||
state.buckets[bucketIndex].position = position;
|
||||
return state;
|
||||
});
|
||||
return;
|
||||
}
|
||||
const getAssetsByBucket = async (bucket: string, position: BucketPosition) => {
|
||||
try {
|
||||
const currentBucketData = _assetGridState.buckets.find((b) => b.bucketDate === bucket);
|
||||
if (currentBucketData?.assets && currentBucketData.assets.length > 0) {
|
||||
assetGridState.update((state) => {
|
||||
const bucketIndex = state.buckets.findIndex((b) => b.bucketDate === bucket);
|
||||
state.buckets[bucketIndex].position = position;
|
||||
return state;
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
loadingBucketState.set({
|
||||
..._loadingBucketState,
|
||||
[bucket]: true
|
||||
});
|
||||
const { data: assets } = await api.assetApi.getAssetByTimeBucket(
|
||||
{
|
||||
getAssetByTimeBucketDto: {
|
||||
timeBucket: [bucket],
|
||||
userId: _assetGridState.userId,
|
||||
withoutThumbs: true
|
||||
}
|
||||
},
|
||||
{ signal: currentBucketData?.cancelToken.signal }
|
||||
);
|
||||
loadingBucketState.set({
|
||||
..._loadingBucketState,
|
||||
[bucket]: false
|
||||
});
|
||||
loadingBucketState.set({
|
||||
..._loadingBucketState,
|
||||
[bucket]: true,
|
||||
});
|
||||
const { data: assets } = await api.assetApi.getAssetByTimeBucket(
|
||||
{
|
||||
getAssetByTimeBucketDto: {
|
||||
timeBucket: [bucket],
|
||||
userId: _assetGridState.userId,
|
||||
withoutThumbs: true,
|
||||
},
|
||||
},
|
||||
{ signal: currentBucketData?.cancelToken.signal },
|
||||
);
|
||||
loadingBucketState.set({
|
||||
..._loadingBucketState,
|
||||
[bucket]: false,
|
||||
});
|
||||
|
||||
// Update assetGridState with assets by time bucket
|
||||
assetGridState.update((state) => {
|
||||
const bucketIndex = state.buckets.findIndex((b) => b.bucketDate === bucket);
|
||||
state.buckets[bucketIndex].assets = assets;
|
||||
state.buckets[bucketIndex].position = position;
|
||||
state.assets = flatMap(state.buckets, (b) => b.assets);
|
||||
return state;
|
||||
});
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
} catch (e: any) {
|
||||
if (e.name === 'CanceledError') {
|
||||
return;
|
||||
}
|
||||
console.error('Failed to get asset for bucket ', bucket);
|
||||
console.error(e);
|
||||
}
|
||||
};
|
||||
// Update assetGridState with assets by time bucket
|
||||
assetGridState.update((state) => {
|
||||
const bucketIndex = state.buckets.findIndex((b) => b.bucketDate === bucket);
|
||||
state.buckets[bucketIndex].assets = assets;
|
||||
state.buckets[bucketIndex].position = position;
|
||||
state.assets = flatMap(state.buckets, (b) => b.assets);
|
||||
return state;
|
||||
});
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
} catch (e: any) {
|
||||
if (e.name === 'CanceledError') {
|
||||
return;
|
||||
}
|
||||
console.error('Failed to get asset for bucket ', bucket);
|
||||
console.error(e);
|
||||
}
|
||||
};
|
||||
|
||||
const removeAsset = (assetId: string) => {
|
||||
assetGridState.update((state) => {
|
||||
const bucketIndex = state.buckets.findIndex((b) => b.assets.some((a) => a.id === assetId));
|
||||
const assetIndex = state.buckets[bucketIndex].assets.findIndex((a) => a.id === assetId);
|
||||
state.buckets[bucketIndex].assets.splice(assetIndex, 1);
|
||||
const removeAsset = (assetId: string) => {
|
||||
assetGridState.update((state) => {
|
||||
const bucketIndex = state.buckets.findIndex((b) => b.assets.some((a) => a.id === assetId));
|
||||
const assetIndex = state.buckets[bucketIndex].assets.findIndex((a) => a.id === assetId);
|
||||
state.buckets[bucketIndex].assets.splice(assetIndex, 1);
|
||||
|
||||
if (state.buckets[bucketIndex].assets.length === 0) {
|
||||
_removeBucket(state.buckets[bucketIndex].bucketDate);
|
||||
}
|
||||
state.assets = flatMap(state.buckets, (b) => b.assets);
|
||||
return state;
|
||||
});
|
||||
};
|
||||
if (state.buckets[bucketIndex].assets.length === 0) {
|
||||
_removeBucket(state.buckets[bucketIndex].bucketDate);
|
||||
}
|
||||
state.assets = flatMap(state.buckets, (b) => b.assets);
|
||||
return state;
|
||||
});
|
||||
};
|
||||
|
||||
const _removeBucket = (bucketDate: string) => {
|
||||
assetGridState.update((state) => {
|
||||
const bucketIndex = state.buckets.findIndex((b) => b.bucketDate === bucketDate);
|
||||
state.buckets.splice(bucketIndex, 1);
|
||||
state.assets = flatMap(state.buckets, (b) => b.assets);
|
||||
return state;
|
||||
});
|
||||
};
|
||||
const _removeBucket = (bucketDate: string) => {
|
||||
assetGridState.update((state) => {
|
||||
const bucketIndex = state.buckets.findIndex((b) => b.bucketDate === bucketDate);
|
||||
state.buckets.splice(bucketIndex, 1);
|
||||
state.assets = flatMap(state.buckets, (b) => b.assets);
|
||||
return state;
|
||||
});
|
||||
};
|
||||
|
||||
const updateBucketHeight = (bucket: string, actualBucketHeight: number): number => {
|
||||
let scrollTimeline = false;
|
||||
let heightDelta = 0;
|
||||
const updateBucketHeight = (bucket: string, actualBucketHeight: number): number => {
|
||||
let scrollTimeline = false;
|
||||
let heightDelta = 0;
|
||||
|
||||
assetGridState.update((state) => {
|
||||
const bucketIndex = state.buckets.findIndex((b) => b.bucketDate === bucket);
|
||||
// Update timeline height based on the new bucket height
|
||||
const estimateBucketHeight = state.buckets[bucketIndex].bucketHeight;
|
||||
assetGridState.update((state) => {
|
||||
const bucketIndex = state.buckets.findIndex((b) => b.bucketDate === bucket);
|
||||
// Update timeline height based on the new bucket height
|
||||
const estimateBucketHeight = state.buckets[bucketIndex].bucketHeight;
|
||||
|
||||
heightDelta = actualBucketHeight - estimateBucketHeight;
|
||||
state.timelineHeight += heightDelta;
|
||||
heightDelta = actualBucketHeight - estimateBucketHeight;
|
||||
state.timelineHeight += heightDelta;
|
||||
|
||||
scrollTimeline = state.buckets[bucketIndex].position == BucketPosition.Above;
|
||||
scrollTimeline = state.buckets[bucketIndex].position == BucketPosition.Above;
|
||||
|
||||
state.buckets[bucketIndex].bucketHeight = actualBucketHeight;
|
||||
state.buckets[bucketIndex].position = BucketPosition.Unknown;
|
||||
state.buckets[bucketIndex].bucketHeight = actualBucketHeight;
|
||||
state.buckets[bucketIndex].position = BucketPosition.Unknown;
|
||||
|
||||
return state;
|
||||
});
|
||||
return state;
|
||||
});
|
||||
|
||||
if (scrollTimeline) {
|
||||
return heightDelta;
|
||||
}
|
||||
if (scrollTimeline) {
|
||||
return heightDelta;
|
||||
}
|
||||
|
||||
return 0;
|
||||
};
|
||||
return 0;
|
||||
};
|
||||
|
||||
const cancelBucketRequest = async (token: AbortController, bucketDate: string) => {
|
||||
token.abort();
|
||||
// set new abort controller for bucket
|
||||
assetGridState.update((state) => {
|
||||
const bucketIndex = state.buckets.findIndex((b) => b.bucketDate === bucketDate);
|
||||
state.buckets[bucketIndex].cancelToken = new AbortController();
|
||||
return state;
|
||||
});
|
||||
};
|
||||
const cancelBucketRequest = async (token: AbortController, bucketDate: string) => {
|
||||
token.abort();
|
||||
// set new abort controller for bucket
|
||||
assetGridState.update((state) => {
|
||||
const bucketIndex = state.buckets.findIndex((b) => b.bucketDate === bucketDate);
|
||||
state.buckets[bucketIndex].cancelToken = new AbortController();
|
||||
return state;
|
||||
});
|
||||
};
|
||||
|
||||
const updateAsset = (assetId: string, isFavorite: boolean) => {
|
||||
assetGridState.update((state) => {
|
||||
const bucketIndex = state.buckets.findIndex((b) => b.assets.some((a) => a.id === assetId));
|
||||
const assetIndex = state.buckets[bucketIndex].assets.findIndex((a) => a.id === assetId);
|
||||
state.buckets[bucketIndex].assets[assetIndex].isFavorite = isFavorite;
|
||||
const updateAsset = (assetId: string, isFavorite: boolean) => {
|
||||
assetGridState.update((state) => {
|
||||
const bucketIndex = state.buckets.findIndex((b) => b.assets.some((a) => a.id === assetId));
|
||||
const assetIndex = state.buckets[bucketIndex].assets.findIndex((a) => a.id === assetId);
|
||||
state.buckets[bucketIndex].assets[assetIndex].isFavorite = isFavorite;
|
||||
|
||||
state.assets = flatMap(state.buckets, (b) => b.assets);
|
||||
return state;
|
||||
});
|
||||
};
|
||||
state.assets = flatMap(state.buckets, (b) => b.assets);
|
||||
return state;
|
||||
});
|
||||
};
|
||||
|
||||
return {
|
||||
setInitialState,
|
||||
getAssetsByBucket,
|
||||
removeAsset,
|
||||
updateBucketHeight,
|
||||
cancelBucketRequest,
|
||||
updateAsset
|
||||
};
|
||||
return {
|
||||
setInitialState,
|
||||
getAssetsByBucket,
|
||||
removeAsset,
|
||||
updateBucketHeight,
|
||||
cancelBucketRequest,
|
||||
updateAsset,
|
||||
};
|
||||
}
|
||||
|
||||
export const assetStore = createAssetStore();
|
||||
|
||||
@@ -1,25 +1,25 @@
|
||||
import { writable, derived } from 'svelte/store';
|
||||
import { derived, writable } from 'svelte/store';
|
||||
|
||||
export const downloadAssets = writable<Record<string, number>>({});
|
||||
|
||||
export const isDownloading = derived(downloadAssets, ($downloadAssets) => {
|
||||
if (Object.keys($downloadAssets).length == 0) {
|
||||
return false;
|
||||
}
|
||||
if (Object.keys($downloadAssets).length == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
return true;
|
||||
});
|
||||
|
||||
const update = (key: string, value: number | null) => {
|
||||
downloadAssets.update((state) => {
|
||||
const newState = { ...state };
|
||||
if (value === null) {
|
||||
delete newState[key];
|
||||
} else {
|
||||
newState[key] = value;
|
||||
}
|
||||
return newState;
|
||||
});
|
||||
downloadAssets.update((state) => {
|
||||
const newState = { ...state };
|
||||
if (value === null) {
|
||||
delete newState[key];
|
||||
} else {
|
||||
newState[key] = value;
|
||||
}
|
||||
return newState;
|
||||
});
|
||||
};
|
||||
|
||||
export const clearDownload = (key: string) => update(key, null);
|
||||
|
||||
@@ -2,6 +2,6 @@
|
||||
import { writable } from 'svelte/store';
|
||||
|
||||
export const dragAndDropFilesStore = writable({
|
||||
isDragging: false as boolean,
|
||||
files: [] as File[]
|
||||
isDragging: false as boolean,
|
||||
files: [] as File[],
|
||||
});
|
||||
|
||||
@@ -1,39 +1,38 @@
|
||||
import { browser } from '$app/environment';
|
||||
import { persisted } from 'svelte-local-storage-store';
|
||||
|
||||
const initialTheme =
|
||||
browser && !window.matchMedia('(prefers-color-scheme: dark)').matches ? 'light' : 'dark';
|
||||
const initialTheme = browser && !window.matchMedia('(prefers-color-scheme: dark)').matches ? 'light' : 'dark';
|
||||
|
||||
// The 'color-theme' key is also used by app.html to prevent FOUC on page load.
|
||||
export const colorTheme = persisted<'dark' | 'light'>('color-theme', initialTheme, {
|
||||
serializer: {
|
||||
parse: (text) => (text === 'light' ? text : 'dark'),
|
||||
stringify: (obj) => obj
|
||||
}
|
||||
serializer: {
|
||||
parse: (text) => (text === 'light' ? text : 'dark'),
|
||||
stringify: (obj) => obj,
|
||||
},
|
||||
});
|
||||
|
||||
// Locale to use for formatting dates, numbers, etc.
|
||||
export const locale = persisted<string | undefined>('locale', undefined, {
|
||||
serializer: {
|
||||
parse: (text) => text,
|
||||
stringify: (obj) => obj ?? ''
|
||||
}
|
||||
serializer: {
|
||||
parse: (text) => text,
|
||||
stringify: (obj) => obj ?? '',
|
||||
},
|
||||
});
|
||||
|
||||
export interface MapSettings {
|
||||
allowDarkMode: boolean;
|
||||
onlyFavorites: boolean;
|
||||
relativeDate: string;
|
||||
dateAfter: string;
|
||||
dateBefore: string;
|
||||
allowDarkMode: boolean;
|
||||
onlyFavorites: boolean;
|
||||
relativeDate: string;
|
||||
dateAfter: string;
|
||||
dateBefore: string;
|
||||
}
|
||||
|
||||
export const mapSettings = persisted<MapSettings>('map-settings', {
|
||||
allowDarkMode: true,
|
||||
onlyFavorites: false,
|
||||
relativeDate: '',
|
||||
dateAfter: '',
|
||||
dateBefore: ''
|
||||
allowDarkMode: true,
|
||||
onlyFavorites: false,
|
||||
relativeDate: '',
|
||||
dateAfter: '',
|
||||
dateBefore: '',
|
||||
});
|
||||
|
||||
export const videoViewerVolume = persisted<number>('video-viewer-volume', 1, {});
|
||||
@@ -41,9 +40,9 @@ export const videoViewerVolume = persisted<number>('video-viewer-volume', 1, {})
|
||||
export const isShowDetail = persisted<boolean>('info-opened', false, {});
|
||||
|
||||
export interface AlbumViewSettings {
|
||||
sortBy: string;
|
||||
sortBy: string;
|
||||
}
|
||||
|
||||
export const albumViewSettings = persisted<AlbumViewSettings>('album-view-settings', {
|
||||
sortBy: 'Most recent photo'
|
||||
sortBy: 'Most recent photo',
|
||||
});
|
||||
|
||||
@@ -1,45 +1,45 @@
|
||||
import { writable, derived } from 'svelte/store';
|
||||
import { derived, writable } from 'svelte/store';
|
||||
import type { UploadAsset } from '../models/upload-asset';
|
||||
|
||||
function createUploadStore() {
|
||||
const uploadAssets = writable<Array<UploadAsset>>([]);
|
||||
const uploadAssets = writable<Array<UploadAsset>>([]);
|
||||
|
||||
const { subscribe } = uploadAssets;
|
||||
const { subscribe } = uploadAssets;
|
||||
|
||||
const isUploading = derived(uploadAssets, ($uploadAssets) => {
|
||||
return $uploadAssets.length > 0 ? true : false;
|
||||
});
|
||||
const isUploading = derived(uploadAssets, ($uploadAssets) => {
|
||||
return $uploadAssets.length > 0 ? true : false;
|
||||
});
|
||||
|
||||
const addNewUploadAsset = (newAsset: UploadAsset) => {
|
||||
uploadAssets.update((currentSet) => [...currentSet, newAsset]);
|
||||
};
|
||||
const addNewUploadAsset = (newAsset: UploadAsset) => {
|
||||
uploadAssets.update((currentSet) => [...currentSet, newAsset]);
|
||||
};
|
||||
|
||||
const updateProgress = (id: string, progress: number) => {
|
||||
uploadAssets.update((uploadingAssets) => {
|
||||
return uploadingAssets.map((asset) => {
|
||||
if (asset.id == id) {
|
||||
return {
|
||||
...asset,
|
||||
progress: progress
|
||||
};
|
||||
}
|
||||
const updateProgress = (id: string, progress: number) => {
|
||||
uploadAssets.update((uploadingAssets) => {
|
||||
return uploadingAssets.map((asset) => {
|
||||
if (asset.id == id) {
|
||||
return {
|
||||
...asset,
|
||||
progress: progress,
|
||||
};
|
||||
}
|
||||
|
||||
return asset;
|
||||
});
|
||||
});
|
||||
};
|
||||
return asset;
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const removeUploadAsset = (id: string) => {
|
||||
uploadAssets.update((uploadingAsset) => uploadingAsset.filter((a) => a.id != id));
|
||||
};
|
||||
const removeUploadAsset = (id: string) => {
|
||||
uploadAssets.update((uploadingAsset) => uploadingAsset.filter((a) => a.id != id));
|
||||
};
|
||||
|
||||
return {
|
||||
subscribe,
|
||||
isUploading,
|
||||
addNewUploadAsset,
|
||||
updateProgress,
|
||||
removeUploadAsset
|
||||
};
|
||||
return {
|
||||
subscribe,
|
||||
isUploading,
|
||||
addNewUploadAsset,
|
||||
updateProgress,
|
||||
removeUploadAsset,
|
||||
};
|
||||
}
|
||||
|
||||
export const uploadAssetsStore = createUploadStore();
|
||||
|
||||
@@ -1,32 +1,32 @@
|
||||
import { Socket, io } from 'socket.io-client';
|
||||
import { io, Socket } from 'socket.io-client';
|
||||
|
||||
let websocket: Socket;
|
||||
|
||||
export const openWebsocketConnection = () => {
|
||||
try {
|
||||
websocket = io('', {
|
||||
path: '/api/socket.io',
|
||||
transports: ['polling'],
|
||||
reconnection: true,
|
||||
forceNew: true,
|
||||
autoConnect: true
|
||||
});
|
||||
try {
|
||||
websocket = io('', {
|
||||
path: '/api/socket.io',
|
||||
transports: ['polling'],
|
||||
reconnection: true,
|
||||
forceNew: true,
|
||||
autoConnect: true,
|
||||
});
|
||||
|
||||
listenToEvent(websocket);
|
||||
} catch (e) {
|
||||
console.log('Cannot connect to websocket ', e);
|
||||
}
|
||||
listenToEvent(websocket);
|
||||
} catch (e) {
|
||||
console.log('Cannot connect to websocket ', e);
|
||||
}
|
||||
};
|
||||
|
||||
const listenToEvent = (socket: Socket) => {
|
||||
//TODO: if we are not using this, we should probably remove it?
|
||||
socket.on('on_upload_success', () => undefined);
|
||||
//TODO: if we are not using this, we should probably remove it?
|
||||
socket.on('on_upload_success', () => undefined);
|
||||
|
||||
socket.on('error', (e) => {
|
||||
console.log('Websocket Error', e);
|
||||
});
|
||||
socket.on('error', (e) => {
|
||||
console.log('Websocket Error', e);
|
||||
});
|
||||
};
|
||||
|
||||
export const closeWebsocketConnection = () => {
|
||||
websocket?.close();
|
||||
websocket?.close();
|
||||
};
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { writable } from 'svelte/store';
|
||||
import type { ZoomImageWheelState } from '@zoom-image/core';
|
||||
import { writable } from 'svelte/store';
|
||||
|
||||
export const photoZoomState = writable<ZoomImageWheelState>();
|
||||
|
||||
Reference in New Issue
Block a user