Commit Graph

272 Commits

Author SHA1 Message Date
Mauro 426fdc70a1 Add a developer option and selection mode for timeline messages (#6102)
* Add a developer option and selection mode for timeline messages

First step of the multi-select messages feature (element-meta#3255, iOS
counterpart of element-x-android#6918). Everything is gated behind the new
`messageMultiSelectEnabled` developer option and nothing changes while it
is off.

- Adds a "Select" action to the timeline item menu for remote messages in
  the room, focused and thread timelines. Choosing it enters selection
  mode with that message selected.
- While selecting, every bubbled row shows a checkbox on its leading edge
  and tapping or long pressing a row toggles it. State events, redacted
  messages, live locations, unsupported events and local echoes cannot be
  selected and stay inert. Selected rows get the accent background.
- The navigation bar swaps to a Cancel button and an "N selected" title,
  the back button is hidden and the composer is removed until the
  selection ends (Cancel or deselecting the last item). This is the hook
  where the bulk action bar will land in the next PR.
- The selection is capped at 30 messages, showing a toast when the cap
  is hit, and is cleared if the developer option is switched off.
- The selection state lives in `TimelineViewModel` so room and thread
  timelines share the behaviour without extra plumbing.

Includes unit tests for the menu action gating and the selection state
transitions, plus RoomScreen and bubble styler previews for the new state.

* Harden the timeline selection mode after review

- Reconcile the selection with timeline updates: selected messages that
  become unselectable (e.g. redacted) are dropped, and the selection is
  cleared when the timeline is swapped for a focused or live one, so the
  count can never refer to items that aren't on screen.
- Keep the composer mounted but collapsed while selecting, instead of
  removing it from the hierarchy. This preserves the draft and composer
  mode and avoids the disappear side effects. The footer with the identity
  warnings stays visible.
- Give the long press modifier an `isEnabled` flag so the recogniser is
  disabled while selecting, rather than only skipping the action while
  still animating and buzzing.
- Gate the Mac context menu on the selection like the other gestures.
- VoiceOver: a selectable bubble becomes a button carrying the selected
  trait whose default action toggles it, non-selectable rows lose their
  message actions while selecting, and reactions, thread summaries and the
  checkbox are hidden from the accessibility tree in selection mode.

* Stop voice message recordings when entering selection mode

The composer is collapsed rather than removed while selecting, so an
in-progress recording would otherwise keep the microphone open out of
sight. Entering the selection now stops the recording, which moves the
composer to the preview state so the message is still there to play or
send once the selection ends. Playback of voice messages is unaffected.

* Use the translated strings for the message selection mode

The selection strings have been imported to Localazy, so the untranslated
placeholders are dropped in favour of `action_select`,
`screen_room_maximum_messages_selected` and the `screen_room_selection_count`
plural. Only these keys are taken from the download to keep the change
focused.

* Apply review suggestions to the message selection mode

Addresses the first review round on the selection mode:

- Undecryptable messages are no longer selectable, as none of the bulk
  actions can be taken on them from the single item menu either.
- Renames for clarity: the menu action is `selectMessages` (leaving room
  for a future `selectText`), the view action is `startSelection`, the
  state exposes `contains(_:)`, `limit` and `isAtLimit`, and the composer
  collapsing modifier is `collapsedInPlace(_:)`.
- `canSelectMessages` uses a switch expression, the selection state doc
  comment refers to a feature flag rather than Labs, the recording helper
  doc describes only what it does, and `toggleSelection()` moves below
  the subviews.

* Keep the accessibility labels of timeline items while selecting

The selection mode used to replace each item's accessibility body with a
plain combined element, dropping the sender name representation and the
gallery label. The per item labelling now always applies, and the selection
only changes the interaction on top of it: the message actions are offered
as before, or the item becomes a button carrying the selected trait whose
default action toggles it. Polls and galleries collapse into a single
element only while selecting, as their children are inert then.

* Keep the timeline types within the lint limits after rebasing

The redaction reason work on develop grew the menu action handler and the
timeline view model right up to SwiftLint's size limits, so the selection
additions tipped them over. The `selectMessages` case now shares the
`downloadMedia` break and the selection flag subscription lives in the
selection extension.

* Fix the snapshot regressions from the selection mode

- Drop `geometryGroup()` from the bubble row: it stopped the avatar
  placeholder initial from rendering, which showed up as a mismatch in
  every timeline item snapshot.
- Collapse the composer with opacity instead of clipping, as the clip also
  removed the composer background from the home indicator area while the
  composer was fully visible.
- Keep the timeline item menu preview on the default flag-off state so the
  existing menu snapshots stay valid.
- Record the new "Selecting" room screen and "Selection" bubble snapshots
  on the same iPhone SE simulator CI uses.
2026-09-09 13:36:57 +02:00
Mauro Romito 098edab1b4 use disambiguated display name for avatar change events 2026-09-08 12:39:07 +02:00
Ghazi Tozri b4a36ad465 hide the forward action on live location shares (#6091)
Live location shares have no message event content, so forwarding always failed silently. Exclude them from `isForwardable` matching polls logic
2026-09-01 16:23:20 +03:00
Stefan Ceriu 5cb4a2fe5a Add CustomStringConvertible conformances to timeline item contents 2026-08-13 16:25:18 +03:00
Mauro Romito e32c534b89 pr suggestions 2026-07-31 15:14:39 +02:00
Mauro Romito b044764310 unified the filtering of the gallery items 2026-07-31 15:14:39 +02:00
Mauro ae795df530 Allow previews in the timeline to include filtered galleries (#5943)
* remove the usage of the timeline kind override in favour of getting it properly from the timeline view model

* allow the previews to include gallery items filtered by the allowed types when started outside the gallery

sss

asa

* fix for actions not being forwarded to the timeline right

* pr suggestions
2026-07-30 13:49:22 +02:00
Mauro Romito 7ea9aeb174 Open a full-screen preview when tapping a gallery item
Tapping a gallery tile/row opens the existing media preview scoped to that gallery's attachments, paging between them. Introduces a typed MediaPreviewItemID (replacing the stringly-typed preview identifier) and a gallery-scoped TimelineMediaPreviewDataSource; the tap routes through TimelineInteractionHandler/TimelineViewModel. Non-previewable (.other) items are skipped without shifting the tapped index.

Co-authored-by: svetoslav.mitov <svetoslav.mitov@sportinno.com>

just use id instead of previewID

removed horrible multiline ternary

pr suggestions

remove redundant code

remove empty caption display + gallery uses the appropriate media timeline actions
2026-07-28 16:49:08 +02:00
Mauro 4d7d61dae7 Render galleries with non-visual attachments as a list (#5932)
* Render galleries with non-visual attachments as a list

Adds GalleryListView (with GalleryDivider) for galleries containing a file or audio item, extracting the shared FileTypeIconView from FileRoomTimelineView. GalleryRoomTimelineView picks the list vs the grid via usesListLayout. Tapping to open the preview lands in a follow-up.

Co-authored-by: svetoslav.mitov <svetoslav.mitov@sportinno.com>

* pr suggestions

---------

Co-authored-by: svetoslav.mitov <svetoslav.mitov@sportinno.com>
2026-07-27 18:46:15 +02:00
Mauro 274da99787 Render image and video in galleries as a grid (#5929) 2026-07-24 18:47:39 +02:00
Mauro Romito 4a9cd02fbc Add the gallery timeline item rendered as a placeholder
Introduces the GalleryRoomTimelineItem and its typed GalleryItem model (reusing the existing per-message content types), builds it in the RoomTimelineItemFactory and routes it through RoomTimelineItemView. For now it renders as a placeholder; the grid/list media views and the full-screen preview land in follow-up PRs.

Co-authored-by: svetoslav.mitov <svetoslav.mitov@sportinno.com>
2026-07-24 11:51:00 +02:00
Valere Fedronic 0f72fe3511 Add support for active call item rendering in timeline (#5775)
* feat(timeline): Add support for active call item rendering in timeline

* Update active call as per design (show raw count of members)

* fixup project files

* revert unexpected generated mocks change

* code review

* Record preview snapshots

* revert changes on project.yml

* post rebase fix
2026-07-22 15:13:46 +01:00
Mauro 9093631f8b Periphery cleanup (#5893) 2026-07-20 11:16:11 +02:00
Doug 85f28d017d Update the SDK and handle API breaks. (#5871)
* Update the SDK and handle API breaks.

* Rename sdkUserThing to rustUserThing for consistency.

* Add user status ClientProxy methods.

* Rename UserStatus.UserSet to UserStatus.Raw.
2026-07-14 16:35:37 +01:00
Mauro 0a77ba6c90 Swift format enforce isEmpty rule (#5843)
* swift format enforce isEmpty rule

* revert scheme

* use trailing closure
2026-07-06 15:39:16 +02:00
Stefan Ceriu dd6f8bc281 Group RoomTimelineItemFactory public methods under Public/Private marks
Move the protocol methods to the top under a Public mark and gather the
helpers beneath a Private mark.
2026-07-03 13:39:45 +03:00
Stefan Ceriu 5851100f07 Expose a global search service from the client
Wrap the SDK's SearchService in a SearchServiceProxy that publishes typed
message results and paginates on demand, expose it on the ClientProxy, and
enable the search index store on the session. Also opens up the timeline item
factory's message content builder so the proxy can reuse it.
2026-07-03 13:39:45 +03:00
svetoslav-sportinno 30e4e6339d Add max selections support for polls (#5726) 2026-06-22 13:39:12 +02:00
Mauro a520d94760 Swift 6 Migration (#5733)
* Enable Swift 6.2 with default main actor isolation for the app target

Turn on SWIFT_VERSION 6.2, SWIFT_APPROACHABLE_CONCURRENCY and SWIFT_DEFAULT_ACTOR_ISOLATION = MainActor for the ElementX target, matching the NSE and Share Extension (which already use 6.2 without the main actor default).

# Conflicts:
#	ElementX.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved

* Update the code generation templates for Swift 6

Emit nonisolated/@unchecked Sendable mocks and nonisolated string enums, and mark async mock methods @concurrent so they keep suspending like the real implementations (otherwise intermediate states are unobservable in tests). Includes the regenerated mocks and strings.

# Conflicts:
#	ElementX/Sources/Mocks/Generated/GeneratedMocks.swift

* Make the data layer and services nonisolated and Sendable

Annotate the value-type models, Rust SDK proxy wrappers, timeline item graph, settings, logging and NSE-shared types as nonisolated, and conform the service protocols to Sendable so their existentials can cross isolation boundaries. These types run off the main actor and no longer inherit the target's default main actor isolation.

* Adopt the new isolation across call sites, mocks and signatures

Update call sites, closure signatures and mock configuration helpers to match the nonisolated/Sendable data layer, including the main actor isolated mock inits and the @Sendable filter on recentlyVisitedRooms.

^ Conflicts:
^	ElementX/Sources/Services/SecureBackup/SecureBackupController.swift

* Remove redundant @MainActor annotations

With the app target defaulting to main actor isolation, the explicit @MainActor on view models, coordinators, views and their protocols is no longer required.

* Fix concurrency hotspots surfaced by the migration

Resolve the room summary main-thread deadlock by moving diff processing onto AsyncStreams, add the SDKListener.onMainActor FIFO bridge for SDK callbacks, hop KVO/timer/UIKit callbacks to the main actor via assumeIsolated, add isolated deinits, and apply the few justified nonisolated(unsafe) escapes for queue-confined Apple APIs.

* Fix the unit tests for Swift 6 concurrency

Hop the waitForConfirmation body onto the caller's actor (Swift Testing runs confirmation closures off-actor), and adjust the affected suites and async signatures.

* offload diffs on concurrent threads instead of main actor

* make room info protocols sendable

* use a task group for fetching data so that everything runs concurrently in the TextRoomTimelineView when getting the preview.

* use the generic onMainActor implementation, which already makes a stream and send the continuation on the main actor.

* small pr comments issues being addressed

* update enterprise

* Update StaticCode to 1.1.0 and specify the required Swift isolation.

* fix ElementCallServiceTests

* update enterprise

* re-generate mocks

* update enterprise

* enterprise new code conformed to swift 6

---------

Co-authored-by: Doug <douglase@element.io>
2026-06-18 17:55:31 +02:00
Doug fa67713726 Run SwiftFormat. 2026-05-27 17:11:42 +01:00
Mauro Romito b3e6373750 update sdk to 26.05.18 2026-05-18 17:40:17 +02:00
Mauro Romito 07fc022a65 prevent replies to LLS timeline items, and live location sharing in threads 2026-05-12 17:26:02 +02:00
Mauro Romito 686753721e new implementation based on the usage of NSTextAttachment to allocate space for the timestamp 2026-05-12 14:46:18 +02:00
Valere Fedronic ba23153ab4 feat: Render declined calls in DM timeline (#5512)
* feat: Render declined calls in DM timeline

* Record preview snapshots

* review: Use CallIntent constant

* review: clean-up

* Record preview snapshots

* review: Move private field to the bottom with MARK: - Private

* review: Male CallIntent a string enum to use rawValue

---------

Co-authored-by: Element CI <ci@element.io>
2026-05-11 14:51:30 +03:00
Stefan Ceriu 30593909de Simplify and fix implementation 2026-04-17 17:17:55 +03:00
Mauro 922fcafcd5 Live Location Sharing Banner (#5370)
* Live Location Sharing Banner

# Conflicts:
#	ElementX.xcodeproj/project.pbxproj

* updated the top banner modifier and the top banner views

# Conflicts:
#	ElementX/Resources/Localizations/en-US.lproj/Localizable.strings
#	ElementX/Resources/Localizations/en.lproj/Localizable.strings

* improved the stopping function from the timeline item

* stop live location sharing before starting a new one.

* added some tests for LiveLocationManager

* pr suggestions
2026-04-10 14:50:42 +02:00
Doug f26b4a1cd0 Update the SDK handling breaking changes. (#5364) 2026-04-08 21:11:57 +01:00
Stefan Ceriu 5984001720 Remove the shouldDisambiguateDisplayNames parameter from the RoomEvent and RoomStateEvent string builders. 2026-04-02 12:30:43 +03:00
Stefan Ceriu 212cd42161 Fix a couple of warnings 2026-04-01 14:09:23 +03:00
Mauro Romito e3a8c7f423 implemented the display logic for the formatted date 2026-03-30 14:05:31 +02:00
Mauro b8d337e4ce Render the live location timeline item (#5209)
* created the data for the timeline item

# Conflicts:
#	ElementX/Sources/Other/Logging/Tracing.swift
#	ElementX/Sources/Services/Authentication/AuthenticationService.swift
#	ElementX/Sources/Services/Authentication/LinkNewDeviceService.swift

* Implemented the LLS timeline item

* updated preview tests

* pr and design suggestions

* previewscrollview is debug only
2026-03-24 10:34:00 +01:00
Mauro dfee18e511 Rename Sign Out to Remove Device + Update SDK 26.03.18 (#5280)
* update the sdk

* updated preview tests

# Conflicts:
#	ElementX/Sources/Screens/Timeline/View/Style/TimelineItemSendInfoLabel.swift
#	ElementX/Sources/Screens/Timeline/View/TimelineItemViews/LiveLocationRoomTimelineView.swift

* update sdk to 26.03.18 + regenerated preview tests after sign out copy change

* updated UI tests

* pr suggestions
2026-03-18 17:34:45 +01:00
Mauro Romito 12d96ed9d2 update SDK to 26.03.10 2026-03-10 12:35:11 +01:00
Mauro Romito 9e68da4ff0 implementing static location sheet 2026-03-09 18:14:41 +01:00
Mauro bbbb2e9dee Refactor and redesign Location Sharing Screen (#5155)
* refactored the static location screen to the location sharing screen

# Conflicts:
#	UnitTests/Sources/LocationSharingScreenViewModelTests.swift

# Conflicts:
#	ElementX.xcodeproj/project.pbxproj

* implemented a custom pin with an overlayable view

* implemented the render of the user when the location is sender instead of the pin type

* removed description and body they are not used at all.

* reimplemented single button for sharing this or user location + implemented an experimental way to update annotations

* removed unnecessary @Suite description

* implemented a way to display the alert on top of the sheet and added a spinner to the center user location button

* fixed alerts strings

* fixed a failing test

* improved preview tests
2026-03-06 12:51:16 +01:00
Stefan Ceriu 61763d9893 Bump the RustSDK to v26.02.03 (#5051)
Bump the RustSDK to v26.02.03
Fix breaking changes and add support for the new background task error reporting delegate and the new room invite latest event.
2026-02-06 12:08:44 +02:00
Stefan Ceriu 23062901c0 Update files following swiftformat upgrade 2026-01-27 12:50:57 +02:00
Skye Elliot a30ae24d16 Display a badge for messages decrypted using shared keys. (#4937)
* feat: Show info badge for messages decrypted with shared keys

* tests: Add snapshots and tests for forwarder icon.

* fix: Update `EventBasedTimelineItemProtocol.hasStatusIcon`

* fix: Address review comments.

* fix: Use two translations for key forwarded dialog content.

* refactor: Rename `TimelineItemForwarder` to `TimelineItemKeyForwarder`.

Additionally adds a `[weak self]` guard to `encryptionForwarder` alert
handler.

* tests: Add `previewLayout` directive to `encryptionForwarder` previews

* refactor: Remove unused translations, use short-circuiting condition.
2026-01-19 14:27:49 +00:00
Doug f2607affd2 Adopt the new latest event API. (#4779) 2025-11-25 11:52:48 +00:00
Doug 2be321862f Fix another bug where the app could crash on launch if the access token had expired. (#4733)
Updates the SDK.
2025-11-11 15:29:23 +00:00
Mauro f7dd9cdcf8 Update copyright holding and dates (#4640)
* Update copyright holding and dates

* compound IDE Macros updated

* update copyright

* update copyrights done

* update templates and README
2025-10-21 14:34:56 +02:00
Doug 6377d9be67 A couple of small tweaks. (#4569)
* Stop ignoring the safe area with the suggestions view.

They weren't visible on iPad (hidden behind the sidebar) and I can't find any instance when they're shown where the safe area comes into play.

* Make sure the room list deselects the cell when dismissed a room.

* Use the backports pattern in more places.

* Fix the annoying header on macOS.

* Silence some warnings

* Fix compound CI branch name.
2025-10-03 12:09:17 +01:00
Doug c5fccdce5e Show space invites in the room list. (#4545) 2025-09-29 13:57:58 +01:00
Stefan Ceriu bfaca7cff9 Implement link previews for text messages using Apple's LinkPreview framework (#4520) 2025-09-19 12:48:09 +00:00
Doug d571e27637 Update the SDK. (#4517) 2025-09-17 15:43:38 +01:00
Mauro b816f0cf56 A11y: added a hint to inform the user that max selections have been reached (#4308)
* a11y added a hint to inform the user that max selections have been reached

* added string
2025-07-08 17:33:47 +02:00
Doug aebc224de1 Update the SDK. (#4286) 2025-07-03 16:49:13 +00:00
Stefan Ceriu 5315f962c6 Render the number of thread replies on the thread summary timeline view. 2025-06-12 16:54:53 +03:00
Stefan Ceriu de608b486e Fix breaking changes following SDK update. 2025-06-10 15:09:20 +03:00
Mauro Romito 26a7d5ac82 pr suggestions 2025-06-06 10:49:29 +02:00