From e3662c69d5e9b77afc49162bbe906156674f97e4 Mon Sep 17 00:00:00 2001 From: Ashley Davis Date: Sun, 28 Jul 2024 18:29:29 +1000 Subject: [PATCH] Removed sortDate which obscures the fact that some photos aren't dated. Now using `photoDate` to sort and group photos by date. photoDate can be missing for undated photos so they are now being groupe so they can easily be identified. --- backend/src/server.ts | 3 +-- electron/frontend/src/app.tsx | 2 +- .../frontend/src/context/scan-context.tsx | 1 - electron/frontend/src/pages/computer.tsx | 1 + frontend/src/app.tsx | 2 +- mobile/frontend/src/app.tsx | 2 +- mobile/frontend/src/context/scan-context.tsx | 1 - packages/defs/src/lib/asset.ts | 5 ---- .../src/components/gallery-layout.tsx | 10 ++++++-- .../user-interface/src/components/gallery.tsx | 11 +++++++-- .../src/context/asset-database-source.tsx | 1 - .../src/context/gallery-context.tsx | 24 +++++++++++++++---- .../src/context/upload-context.tsx | 1 - .../user-interface/src/lib/create-layout.ts | 12 ++++++---- .../user-interface/src/lib/gallery-item.ts | 5 ---- .../pages/gallery/components/asset-info.tsx | 4 ++-- .../src/pages/gallery/gallery.tsx | 8 +++++++ .../src/test/lib/layout.test.ts | 10 ++++---- tools/upload/src/index.ts | 1 - 19 files changed, 63 insertions(+), 41 deletions(-) diff --git a/backend/src/server.ts b/backend/src/server.ts index dd2be94..80e1596 100644 --- a/backend/src/server.ts +++ b/backend/src/server.ts @@ -19,7 +19,6 @@ const dateFields = [ "fileDate", "photoDate", "uploadDate", - "sortDate", ]; // @@ -362,7 +361,7 @@ export async function createServer(now: () => Date, db: Db, storage: IStorage) { const collection = db.collection(collectionName); const records = await collection.find({ setId }) .sort({ - sortDate: -1, // Reverse chronological order. + photoDate: -1, // Reverse chronological order. }) .skip(skip) .limit(limit) diff --git a/electron/frontend/src/app.tsx b/electron/frontend/src/app.tsx index 5db9cf9..b7f0023 100644 --- a/electron/frontend/src/app.tsx +++ b/electron/frontend/src/app.tsx @@ -10,7 +10,7 @@ function GallerySetup() { return ( dayjs(asset.sortDate).toDate()} + sortFn={asset => asset.photoDate ? dayjs(asset.photoDate).toDate() : undefined} > diff --git a/electron/frontend/src/context/scan-context.tsx b/electron/frontend/src/context/scan-context.tsx index 903cfb8..661b98d 100644 --- a/electron/frontend/src/context/scan-context.tsx +++ b/electron/frontend/src/context/scan-context.tsx @@ -54,7 +54,6 @@ export function ScanContextProvider({ children }: IProps) { contentType: fileDetails.contentType, hash, fileDate: dayjs(fileDate).toISOString(), - sortDate: dayjs(fileDate).toISOString(), uploadDate: dayjs().toISOString(), setId: "this doesn't make sense here", userId: user!._id, diff --git a/electron/frontend/src/pages/computer.tsx b/electron/frontend/src/pages/computer.tsx index 3f6ecfc..f2e1b0c 100644 --- a/electron/frontend/src/pages/computer.tsx +++ b/electron/frontend/src/pages/computer.tsx @@ -24,6 +24,7 @@ export function ComputerPage() { > diff --git a/frontend/src/app.tsx b/frontend/src/app.tsx index 5dd41b8..eec1a8a 100644 --- a/frontend/src/app.tsx +++ b/frontend/src/app.tsx @@ -11,7 +11,7 @@ function GallerySetup() { return ( dayjs(galleryItem.sortDate).toDate()} + sortFn={asset => asset.photoDate ? dayjs(asset.photoDate).toDate() : undefined} >
diff --git a/mobile/frontend/src/app.tsx b/mobile/frontend/src/app.tsx index 2b65df5..414bd0b 100644 --- a/mobile/frontend/src/app.tsx +++ b/mobile/frontend/src/app.tsx @@ -13,7 +13,7 @@ function GallerySetup() { dayjs(asset.sortDate).toDate()} + sortFn={asset => asset.photoDate ? dayjs(asset.photoDate).toDate() : undefined} >
{ diff --git a/packages/defs/src/lib/asset.ts b/packages/defs/src/lib/asset.ts index 16a29da..8dfeb82 100644 --- a/packages/defs/src/lib/asset.ts +++ b/packages/defs/src/lib/asset.ts @@ -70,11 +70,6 @@ export interface IAsset { // photoDate?: string; - // - // Date by which to sort the asset. - // - sortDate: string; - // /// The date the asset was uploaded. // diff --git a/packages/user-interface/src/components/gallery-layout.tsx b/packages/user-interface/src/components/gallery-layout.tsx index 73b531d..2e92b02 100644 --- a/packages/user-interface/src/components/gallery-layout.tsx +++ b/packages/user-interface/src/components/gallery-layout.tsx @@ -1,7 +1,7 @@ import React, { useEffect, useRef, useState } from "react"; import { IGalleryItem, IGalleryRow } from "../lib/gallery-item"; import { useGallery } from "../context/gallery-context"; -import { IGalleryLayout, computePartialLayout } from "../lib/create-layout"; +import { GetHeadingsFn, IGalleryLayout, computePartialLayout } from "../lib/create-layout"; import { GalleryImage } from "./gallery-image"; import { throttle } from "lodash"; @@ -152,6 +152,11 @@ export interface IGalleryLayoutProps { // Event raised when an item in the gallery has been clicked. // onItemClick: ItemClickFn | undefined; + + // + // Gets headings from a gallery item. + // + getHeadings?: GetHeadingsFn; } // @@ -161,6 +166,7 @@ export function GalleryLayout({ galleryWidth = 600, targetRowHeight = 150, onItemClick = undefined, + getHeadings, }: IGalleryLayoutProps) { const { items } = useGallery(); @@ -177,7 +183,7 @@ export function GalleryLayout({ // Computes the gallery layout. // useEffect(() => { - setLayout(computePartialLayout(undefined, items, galleryWidth, targetRowHeight)); + setLayout(computePartialLayout(undefined, items, galleryWidth, targetRowHeight, getHeadings)); }, [items, galleryWidth, targetRowHeight]); // diff --git a/packages/user-interface/src/components/gallery.tsx b/packages/user-interface/src/components/gallery.tsx index 7c756ac..5494585 100644 --- a/packages/user-interface/src/components/gallery.tsx +++ b/packages/user-interface/src/components/gallery.tsx @@ -4,6 +4,7 @@ import useResizeObserver from "@react-hook/resize-observer"; import { useGallery } from "../context/gallery-context"; import { GalleryItemContextProvider } from "../context/gallery-item-context"; import { AssetView } from "./asset-view"; +import { GetHeadingsFn } from "../lib/create-layout"; // // Adds a small gutter on the right hand side of the gallery for some whitespace. @@ -15,12 +16,17 @@ export interface IGalleryProps { // The target height for rows in the gallery. // targetRowHeight: number; + + // + // Gets headings from a gallery item. + // + getHeadings?: GetHeadingsFn; } // // A photo gallery component. // -export function Gallery({ targetRowHeight }: IGalleryProps) { +export function Gallery({ targetRowHeight, getHeadings }: IGalleryProps) { // // The interface to the gallery. @@ -75,7 +81,8 @@ export function Gallery({ targetRowHeight }: IGalleryProps) { onItemClick={item => { setOpenAssetView(true) setSelectedItemId(item._id); - }} + }} + getHeadings={getHeadings} /> {selectedItemId && diff --git a/packages/user-interface/src/context/asset-database-source.tsx b/packages/user-interface/src/context/asset-database-source.tsx index e27a6fe..d10eff9 100644 --- a/packages/user-interface/src/context/asset-database-source.tsx +++ b/packages/user-interface/src/context/asset-database-source.tsx @@ -126,7 +126,6 @@ export function AssetDatabaseProvider({ children }: IAssetDatabaseProviderProps) location: asset.location, fileDate: asset.fileDate, photoDate: asset.photoDate, - sortDate: asset.sortDate, uploadDate: dayjs().toISOString(), properties: asset.properties, labels: asset.labels, diff --git a/packages/user-interface/src/context/gallery-context.tsx b/packages/user-interface/src/context/gallery-context.tsx index e033f35..0c99eec 100644 --- a/packages/user-interface/src/context/gallery-context.tsx +++ b/packages/user-interface/src/context/gallery-context.tsx @@ -518,14 +518,28 @@ export function GalleryContextProvider({ sortFn, children }: IGalleryContextProv const sorted = items.slice(); if (sortFn !== undefined) { sorted.sort((a, b) => { // Warning: this mutates the array we just cloned. - if (sortFn(a) < sortFn(b)) { - return 1; + const sortA = sortFn(a); + const sortB = sortFn(b); + if (sortA === undefined) { + if (sortB === undefined) { + return 0; // Equal. + } + else { + return -1; // a has no sort value, so it comes first. + } } - else if (a.sortDate > b.sortDate) { - return -1; + else if (sortB === undefined) { + return 1; // b has no sort value, so it comes first. + } + + if (sortA < sortB) { + return 1; // a comes after b. + } + else if (sortA > sortB) { + return -1; // a comes before b. } else { - return 0; + return 0; // a and b are equal. } }); } diff --git a/packages/user-interface/src/context/upload-context.tsx b/packages/user-interface/src/context/upload-context.tsx index cb0bd98..16a4291 100644 --- a/packages/user-interface/src/context/upload-context.tsx +++ b/packages/user-interface/src/context/upload-context.tsx @@ -443,7 +443,6 @@ export function UploadContextProvider({ children }: IProps) { location, fileDate: nextUpload.fileDate, photoDate, - sortDate: photoDate || nextUpload.fileDate, uploadDate: dayjs().toISOString(), properties, labels, diff --git a/packages/user-interface/src/lib/create-layout.ts b/packages/user-interface/src/lib/create-layout.ts index d654788..8c80d70 100644 --- a/packages/user-interface/src/lib/create-layout.ts +++ b/packages/user-interface/src/lib/create-layout.ts @@ -36,10 +36,15 @@ function headingsMatch(headingsA: string[], headingsB: string[]): boolean { return true; } +// +// Gets headings from an item. +// +export type GetHeadingsFn = (item: IGalleryItem) => string[]; + // // Creates or updates a row-based layout for items in the gallery. // -export function computePartialLayout(layout: IGalleryLayout | undefined, items: IGalleryItem[], galleryWidth: number, targetRowHeight: number): IGalleryLayout { +export function computePartialLayout(layout: IGalleryLayout | undefined, items: IGalleryItem[], galleryWidth: number, targetRowHeight: number, getHeadings: GetHeadingsFn | undefined): IGalleryLayout { if (!layout) { layout = { @@ -92,10 +97,7 @@ export function computePartialLayout(layout: IGalleryLayout | undefined, items: // Compute headings for the item. // TODO: This should be customizable. Heading could also be location (country, city, suburb, etc) or something else. // - const itemHeadings = [ - dayjs(item.sortDate).format("MMMM"), - dayjs(item.sortDate).format("YYYY"), - ]; + const itemHeadings = getHeadings ? getHeadings(item) : []; if (curRow.items.length > 0) { if (curRow.width + computedWidth > galleryWidth) { diff --git a/packages/user-interface/src/lib/gallery-item.ts b/packages/user-interface/src/lib/gallery-item.ts index afae3d0..065fdd9 100644 --- a/packages/user-interface/src/lib/gallery-item.ts +++ b/packages/user-interface/src/lib/gallery-item.ts @@ -58,11 +58,6 @@ export interface IGalleryItem { // photoDate?: string; - // - /// The date the asset is sorted by in the backend. - // - sortDate: string; - // /// The date the asset was uploaded. // diff --git a/packages/user-interface/src/pages/gallery/components/asset-info.tsx b/packages/user-interface/src/pages/gallery/components/asset-info.tsx index da0dd5d..1b185ed 100644 --- a/packages/user-interface/src/pages/gallery/components/asset-info.tsx +++ b/packages/user-interface/src/pages/gallery/components/asset-info.tsx @@ -200,10 +200,10 @@ export function AssetInfo({ open, onClose, onDeleted }: IAssetInfoProps) {
- {dayjs(asset.sortDate).format("MMM D, YYYY")} + {asset.photoDate ? dayjs(asset.photoDate).format("MMM D, YYYY") : "No date" }
- {dayjs(asset.sortDate).format("HH:mm")} + {asset.photoDate ? dayjs(asset.photoDate).format("HH:mm") : "No time" }
diff --git a/packages/user-interface/src/pages/gallery/gallery.tsx b/packages/user-interface/src/pages/gallery/gallery.tsx index 2a791fb..3f29400 100644 --- a/packages/user-interface/src/pages/gallery/gallery.tsx +++ b/packages/user-interface/src/pages/gallery/gallery.tsx @@ -4,6 +4,7 @@ import { useParams } from "react-router-dom"; import { useApp } from "../../context/app-context"; import { useGallery } from "../../context/gallery-context"; import { useAssetDatabase } from "../../context/asset-database-source"; +import dayjs from "dayjs"; export interface IGalleryPageProps { } @@ -30,6 +31,13 @@ export function GalleryPage({}: IGalleryPageProps) { item.photoDate + ? [ + dayjs(item.photoDate).format("MMMM"), + dayjs(item.photoDate).format("YYYY"), + ] + : [ "Undated" ] + } /> ); diff --git a/packages/user-interface/src/test/lib/layout.test.ts b/packages/user-interface/src/test/lib/layout.test.ts index 6e74ade..bbd63a5 100644 --- a/packages/user-interface/src/test/lib/layout.test.ts +++ b/packages/user-interface/src/test/lib/layout.test.ts @@ -6,7 +6,7 @@ describe("layout", () => { const galleryWidth = 600; const targetRowHeight = 200; - const rows = computePartialLayout(undefined, [], galleryWidth, targetRowHeight); + const rows = computePartialLayout(undefined, [], galleryWidth, targetRowHeight, undefined); expect(rows).toEqual({ galleryHeight: 0, rows: [] @@ -25,7 +25,7 @@ describe("layout", () => { const galleryWidth = 600; const targetRowHeight = 200; - const layout = computePartialLayout(undefined, gallery, galleryWidth, targetRowHeight); + const layout = computePartialLayout(undefined, gallery, galleryWidth, targetRowHeight, undefined); expect(layout.rows.length).toBe(2); @@ -56,7 +56,7 @@ describe("layout", () => { const galleryWidth = 600; const targetRowHeight = 200; - const layout = computePartialLayout(undefined, items, galleryWidth, targetRowHeight); + const layout = computePartialLayout(undefined, items, galleryWidth, targetRowHeight, undefined); expect(layout.rows.length).toBe(2); const row = layout.rows[1]; @@ -88,7 +88,7 @@ describe("layout", () => { const galleryWidth = 600; const targetRowHeight = 200; - const layout = computePartialLayout(undefined, items, galleryWidth, targetRowHeight); + const layout = computePartialLayout(undefined, items, galleryWidth, targetRowHeight, undefined); expect(layout.rows.length).toBe(3); const firstRow = layout.rows[1]; @@ -120,7 +120,7 @@ describe("layout", () => { const galleryWidth = 600; const targetRowHeight = 200; - const layout = computePartialLayout(undefined, items, galleryWidth, targetRowHeight); + const layout = computePartialLayout(undefined, items, galleryWidth, targetRowHeight, undefined); const firstRow = layout.rows[1]; expect(firstRow.items.length).toBe(2); expect(firstRow.height).toBeGreaterThan(targetRowHeight); diff --git a/tools/upload/src/index.ts b/tools/upload/src/index.ts index 7e65160..e88ad28 100644 --- a/tools/upload/src/index.ts +++ b/tools/upload/src/index.ts @@ -279,7 +279,6 @@ async function uploadAsset(filePath: string, actualFilePath: string | undefined, location, fileDate, photoDate: assetDetails.photoDate, - sortDate: assetDetails.photoDate || fileDate, uploadDate: dayjs().toISOString(), properties, labels,