Skip to content

feat(spaces): remove photos from a space from the Photos timeline - #1250

Open
defts wants to merge 2 commits into
open-noodle:mainfrom
defts:feat/space-remove-from-timeline
Open

defts wants to merge 2 commits into
open-noodle:mainfrom
defts:feat/space-remove-from-timeline

Conversation

@defts

@defts defts commented Oct 28, 2026 •

Copy link
Copy Markdown

Summary

With the space badge (#1249), the Photos timeline shows which photos are in a space, but taking one out still means opening the space and finding the photo again. This adds removing from a space to the selection on the main Photos timeline, on web and mobile.

  • Selected photos in one space where you are an Owner or Editor: the action reads "Remove from Trips" and acts on that space.
  • In several such spaces: "Remove from a space…" lists them, each with its colour and how many of the selected photos it holds, and you pick one.
  • In none, or only in spaces where you are a Viewer: no action.

The removal is the one a space already has: the same server call and rules, the same confirmation on web and none on mobile, as inside a space. Photos that are in the space through a linked album or library can't be removed this way; the message names the album to edit, or says the photo comes from a linked library.

Afterwards the badges update at once. Another member's photo that you only saw through that space leaves your timeline, in place on web rather than through a reload that would scroll back to the top; your own photos stay, without the badge.

Builds on #1249: it reuses its POST /assets/spaces route and its local queries, so it can only merge after it. Until then this PR also lists #1249's commit; its own changes are here: defts/gallery@feat/space-badge...feat/space-remove-from-timeline

Design doc: specs/2026-10-27-remove-from-space-timeline-design.md.

Screenshots

Web, photos in one space Web, photos in several spaces
web-remove-one web-remove-picker
Web, the existing confirmation Mobile, one space Mobile, several spaces
web-remove-confirm mobile-remove-one mobile-remove-picker

How

  • Web: web/src/lib/gallery/space-remove/. RemoveFromSpaceButton.svelte is a button of the Photos page's selection bar, shown whoever owns the selected photos, since an Editor may remove another member's photo. Once the selection settles (250 ms) it asks POST /assets/spaces about it, in batches of 1000 and cancelled if the selection changes, and keeps the spaces where the user is Owner or Editor. space-removal.ts holds the removal, which the in-space RemoveFromSpaceAction now shares: confirmation, removeAssets, the SpaceRemoveAssets event and the messages; after a partial removal it unselects what left and keeps the rest. SpacePickerModal takes an optional list of spaces with counts and a title, and then shows each space's colour.
  • Mobile: mobile/lib/gallery/. space_remove.provider.dart finds the removable spaces of the selection with one Drift query over the badge's three paths (json_each for large selections), joined to the user's Owner and Editor memberships. remove_from_spaces.action.dart is the action of the main timeline's selection sheet, with space_remove_picker.widget.dart when there are several spaces. space_removal.dart holds the removal and its messages, shared with the in-space action: SharedSpaceApiRepository.removeAssets now returns the IDs the server removed, and the photos left are explained through the linked-albums lookup, as on web. This moves the fork's removeFromSpace out of the upstream ActionNotifier and ActionService into the fork namespace.
  • The in-space action on mobile: its message was in English, untranslated, and counted the photos asked for. It now uses translated strings and the server's count, and explains the photos left. It still asks for no confirmation.
  • Strings: remove_from_named_space, remove_from_a_space and remove_from_space_library_blocked, in en and the nine overlay locales.
  • Docs: "From the Photos timeline" and "Photos that stay" in docs/docs/features/shared-spaces.md.

No server change, no migration.

Known limits

  • Only the main Photos timeline has the action. The other grids that offer "Add to album or space" (favorites, archive, search, map, people, folders, albums, memories, the viewer) could follow.
  • A space that holds the selected photos only through a linked album or library is still offered, since the route doesn't say by which path a photo is in a space; the removal then explains what to edit.
  • On web, another member's photo that you also see through partner sharing leaves the grid too, and comes back on the next load.
  • On mobile, the removable spaces are read once per selection: a role change synced while a selection is held shows from the next selection.

Verification

  • Web: space-removal.spec.ts (who may remove, grouping and order, batches and cancelling, a declined confirmation, a full and a partial removal, the linked-album, linked-library and fallback messages, a refusal), RemoveFromSpaceButton.spec.ts (hidden, one space, several, a dismissed picker, a late answer for an older selection, the timeline losing only another member's photo that was in that space alone), SpacePickerModal.spec.ts (the given spaces with counts and title).
  • Mobile: the query (space_remove_provider_test: each path, a photo reaching a space twice, roles, order, a selection larger than SQLite's variable limit), the action (remove_from_spaces_action_test: where it shows, one space, several, a dismissed picker, only photos still selected, a refusal keeping the selection), the removal and its messages (space_removal_test), the in-space action and the repository.
  • Full suites, on the branch merged with today's main: server unit (6942) and the utils medium suites (250), web (6763), mobile (3848); lint, tsc, svelte-check, dart analyze --fatal-infos and the i18n check clean.
  • By hand: web in Chromium and the app on the iOS simulator against a local stack (screenshots above), and the app on an iPhone.

Upstream files

Against the Immich v3.3.5 tag, on #1249 and with this PR:

File On #1249 With this PR
web/src/routes/(user)/photos/[[assetId=id]]/+page.svelte +44/−32 +46/−32: the import and <RemoveFromSpaceButton>
mobile/lib/presentation/widgets/bottom_sheet/general_bottom_sheet.widget.dart +2/−29 +4/−29: the import and the action
mobile/lib/providers/infrastructure/action.provider.dart +126 +113: removeFromSpace moved to the fork's SpaceRemovalService
mobile/lib/services/action.service.dart +40/−3 +28/−3: the same, with its space repository
mobile/test/services/action.service_test.dart +17/−2 +5/−1
mobile/test/unit/mocks.dart +19 +11

Everything else is in the fork namespaces and fork-owned files (SpacePickerModal, SchemaSpacePicker, RemoveFromSpaceAction on both platforms, the filtered timeline controller, the space repository), tests, docs and the strings.

@github-actions github-actions Bot added documentation Improvements or additions to documentation 🗄️server 🖥️web 📱mobile labels Oct 28, 2026
@Deeds67 Deeds67 added the changelog:feat Feature change for changelog label Oct 28, 2026
@defts
defts force-pushed the feat/space-remove-from-timeline branch from 836d908 to c97b545 Compare October 28, 2026 07:35
defts added 2 commits October 31, 2026 21:11
A thumbnail whose photo is in one of your spaces gets a badge in its
top-left corner: the Spaces icon in the space's colour, or white with a
count when the photo is in several spaces. It counts every path into a
space and stays off a space's own pages, the trash and the locked folder.

Web asks a new POST /assets/spaces in batches and drops its spaces list
when a space is edited, so a new colour shows without a reload. Mobile
reads its local database and syncs once the server has taken an add, a
removal or an edit, so the badge follows a change made in the app.

Design: specs/2026-10-26-space-badge-design.md
Selected photos on the Photos timeline can now be removed from a space
you own or edit, on web and mobile: "Remove from <space>" when they are
in one such space, a picker with each space's colour and count when they
are in several. The removal is the one a space already has, shared with
the in-space action on both platforms; photos kept by a linked album or
library are explained by name.

The badges update at once, and another member's photo seen only through
that space leaves the timeline, in place on web. On mobile, the in-space
action's message is now translated and uses the server's count.

Design: specs/2026-10-27-remove-from-space-timeline-design.md
@defts
defts force-pushed the feat/space-remove-from-timeline branch from c97b545 to 2232855 Compare October 31, 2026 21:31

This branch has not been deployed

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

Labels

changelog:feat Feature change for changelog documentation Improvements or additions to documentation 📱mobile 🗄️server 🖥️web

2 participants