Skip to content

feat: search, trip memories, map, slideshow, long-press selection#3485

Open
karlitschek wants to merge 1 commit into
frank/feat/photos-ui-improvementsfrom
frank/feat/photos-search-memories-map
Open

feat: search, trip memories, map, slideshow, long-press selection#3485
karlitschek wants to merge 1 commit into
frank/feat/photos-ui-improvementsfrom
frank/feat/photos-search-memories-map

Conversation

@karlitschek
Copy link
Copy Markdown
Member

Five user-visible additions on top of the Vue 3 migration. Each is intentionally minimum-viable so they ship together; each has clear "deferred to a follow-up" boundaries called out below.

  1. Free-text search by filename

    • New PhotosFilter nameFilter that emits a DAV <d:like> query against <d:displayname/>. Special characters in the user's query are escaped (XML + SQL LIKE wildcards) before being embedded in the request body.
    • NcTextField in PhotosApp's #search slot, debounced 300ms. Typing pushes a single value into selectedFilters.name; the existing filtersQuery / extraFilters pipeline does the rest, so search composes cleanly with the existing date-range and place filters.
    • Deferred: content search ("beach", "sunset") — that requires Recognize-app integration and is out of scope here. The filename + EXIF-anchored search should already feel transformative.
  2. Trip memories (/memories)

    • New services/memories.ts clusters loaded photos by capture- date gaps (>2 days starts a new trip; clusters of <8 photos are dropped to keep noise out). Cover photo is picked from near the trip's midpoint to avoid arrival/departure shots.
    • New MemoriesView with tile cards (cover + date range + count). Click opens the NC Viewer with the trip's photos as the gallery list.
    • Routed at /memories with a navigation entry next to "On this day". On first visit the view triggers a 500-photo fetch so the page isn't empty before the timeline has been scrolled.
    • Deferred: server-side trip detection (would scale to libraries of millions of photos), and place-anchored / "year ago today" memory cards.
  3. Photos map (/map)

    • New MapView using @vue-leaflet's LMap + LMarker, plotting every loaded photo that has GPS metadata. Click a marker → opens NC Viewer with all geotagged photos as the gallery list.
    • nc:metadata-photos-gps is now registered in main.ts so the timeline endpoint returns the field; previously it was only registered in sidebar.ts.
    • Centred on the centroid of the first 200 photos so users land somewhere relevant rather than on null island.
    • Replaces the previous /maps route that redirected out to the external Maps app. The inline view works for everyone whether or not Maps is installed.
    • Deferred: leaflet.markercluster integration (real libraries above ~5000 geotagged photos will need it).
  4. Photo slideshow

    • New Slideshow component, full-page Teleport, plays through a supplied list of photos with play/pause + prev/next + close and ESC/arrow/space keyboard shortcuts. Auto-advance is 4s.
    • Triggered from a "Slideshow" button in the TimelineView header (visible when no selection is active and at least one photo has been fetched). Plays through the timeline's currently loaded photos in capture order.
    • Deliberately self-contained — the NC Viewer app is in a separate codebase, so adding a slideshow mode there is out-of-scope. This stays a Photos-internal feature.
  5. Long-press multi-select

    • FileComponent now starts a 500ms long-press timer on pointerdown; if the press is held that long, the selection toggles and the subsequent click is swallowed. Mouse and touch both go through pointer events, so the same code paths handle desktop right-click-equivalent and mobile tap-and-hold.
    • The existing checkbox-on-hover affordance still works on desktop; long-press is the addition for mobile users for whom the checkbox was a finicky tap target.

Build / lint / tests all green after these changes.

Five user-visible additions on top of the Vue 3 migration. Each is
intentionally minimum-viable so they ship together; each has clear
"deferred to a follow-up" boundaries called out below.

1. Free-text search by filename
   - New PhotosFilter `nameFilter` that emits a DAV `<d:like>` query
     against `<d:displayname/>`. Special characters in the user's
     query are escaped (XML + SQL LIKE wildcards) before being
     embedded in the request body.
   - NcTextField in PhotosApp's `#search` slot, debounced 300ms.
     Typing pushes a single value into `selectedFilters.name`; the
     existing filtersQuery / extraFilters pipeline does the rest, so
     search composes cleanly with the existing date-range and place
     filters.
   - Deferred: content search ("beach", "sunset") — that requires
     Recognize-app integration and is out of scope here. The
     filename + EXIF-anchored search should already feel
     transformative.

2. Trip memories (/memories)
   - New `services/memories.ts` clusters loaded photos by capture-
     date gaps (>2 days starts a new trip; clusters of <8 photos
     are dropped to keep noise out). Cover photo is picked from
     near the trip's midpoint to avoid arrival/departure shots.
   - New MemoriesView with tile cards (cover + date range + count).
     Click opens the NC Viewer with the trip's photos as the
     gallery list.
   - Routed at /memories with a navigation entry next to "On this
     day". On first visit the view triggers a 500-photo fetch so
     the page isn't empty before the timeline has been scrolled.
   - Deferred: server-side trip detection (would scale to libraries
     of millions of photos), and place-anchored / "year ago today"
     memory cards.

3. Photos map (/map)
   - New MapView using @vue-leaflet's LMap + LMarker, plotting every
     loaded photo that has GPS metadata. Click a marker → opens NC
     Viewer with all geotagged photos as the gallery list.
   - `nc:metadata-photos-gps` is now registered in main.ts so the
     timeline endpoint returns the field; previously it was only
     registered in sidebar.ts.
   - Centred on the centroid of the first 200 photos so users land
     somewhere relevant rather than on null island.
   - Replaces the previous /maps route that redirected out to the
     external Maps app. The inline view works for everyone whether
     or not Maps is installed.
   - Deferred: leaflet.markercluster integration (real libraries
     above ~5000 geotagged photos will need it).

4. Photo slideshow
   - New Slideshow component, full-page Teleport, plays through a
     supplied list of photos with play/pause + prev/next + close
     and ESC/arrow/space keyboard shortcuts. Auto-advance is 4s.
   - Triggered from a "Slideshow" button in the TimelineView header
     (visible when no selection is active and at least one photo
     has been fetched). Plays through the timeline's currently
     loaded photos in capture order.
   - Deliberately self-contained — the NC Viewer app is in a
     separate codebase, so adding a slideshow mode there is
     out-of-scope. This stays a Photos-internal feature.

5. Long-press multi-select
   - FileComponent now starts a 500ms long-press timer on
     pointerdown; if the press is held that long, the selection
     toggles and the subsequent click is swallowed. Mouse and
     touch both go through pointer events, so the same code paths
     handle desktop right-click-equivalent and mobile tap-and-hold.
   - The existing checkbox-on-hover affordance still works on
     desktop; long-press is the addition for mobile users for whom
     the checkbox was a finicky tap target.

Build / lint / tests all green after these changes.

Signed-off-by: Frank Karlitschek <frank@nextcloud.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@karlitschek
Copy link
Copy Markdown
Member Author

@jancborchardt @skjnldsv

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant