Commit Graph

4912 Commits

Author SHA1 Message Date
Doug 9ce3bd97d8 Move the status emoji placement on the home screen. (#6260)
* Minor tweaks to User Status.

- Change the layout of the status emoji on the Setting button.
- Remove the status emoji from the Settings screen (it's shown directly below in the status row).
2026-10-05 10:18:23 +01:00
ElementRobot 57f5498da0 Translations update (#6268)
Co-authored-by: Element CI <ci@element.io>
2026-10-05 10:01:50 +01:00
Stefan Ceriu 9f141585a2 Focus events on the live timeline when it has already loaded them
Opening a room on an event always built a detached timeline, even when the
live timeline already contained that event, e.g. when tapping the notification
for the newest message in a room.

The timeline controller now stays on the live timeline in that case, scrolling
to and highlighting the event, and only builds a detached timeline when the
event isn't loaded.
2026-10-02 16:52:19 +03:00
Stefan Ceriu 52b411e954 Revert "Open the room live when tapping the notification for its newest message"
This reverts commit 4c71cae0f.

Comparing against other delivered notifications doesn't reflect the timeline:
in rooms set to mentions and keywords, after swiping away newer notifications
or with messages sent from another device, newer messages can exist without a
notification, so the room opened live with the tapped event out of view.
2026-10-02 16:52:19 +03:00
Stefan Ceriu a50c80c179 Avoid flashing the room list skeletons on launch
On a cold launch the home screen appeared just before the cached rooms
published, briefly showing skeletons that were immediately replaced.

The home screen now starts in a new awaitingCachedRooms mode, keeping
the list blank while a cached room list is about to publish and falling
back to the skeletons after 500ms. Without a cache the skeletons show
straight away as before.
2026-10-02 16:37:22 +03:00
Mauro 4b6953e80f Point agents to Apple's Xcode agent skills in AGENTS.md (#6256) 2026-10-02 15:00:16 +02:00
Copilot c41a38159b Only offer joined rooms in the forward and share pickers (#6255)
* Initial plan

* Offer only joined rooms in destination pickers

Co-authored-by: Velin92 <34335419+Velin92@users.noreply.github.com>

* Clean whitespace in share picker test

Co-authored-by: Velin92 <34335419+Velin92@users.noreply.github.com>

* Restrict the shared picker room list to joined rooms

The alternate room summary provider, which backs the forward, share and
Add rooms pickers and global search, now always includes the SDK's
joined filter in its base filter. This replaces the per-call joinedOnly
flags, so Add rooms no longer offers invited rooms or spaces and no
screen can forget the flag.

A filter set before the provider has its room list is now applied once
the list is set, instead of being reset to the default. The share picker
hit this on a cold launch from the share extension.

The forward and share pickers also hide upgraded rooms, matching the
Suggestions section. The SDK has no filter for these.

Also registers the share picker's test file in the project, fixes the
blank-line indentation SwiftFormat flagged, and re-records the picker
snapshots without the upgraded room.

* Check room membership for forwarding suggestions and search breadcrumbs

RoomSummary now has isJoined, built from the room's membership. The
forwarding suggestions and the search breadcrumbs used a missing
joinRequestType to mean joined, which is also the case for rooms that
have been left or banned from. It only worked because the room list's
base filter already drops those.

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Velin92 <34335419+Velin92@users.noreply.github.com>
Co-authored-by: Mauro Romito <mauro.romito@element.io>
2026-10-02 12:44:33 +00:00
Stefan Ceriu 4fe58c2d0a Don't hold the room list on skeletons for an empty filtered result
The room list keeps showing skeletons while the provider reports loaded
but no summaries have published yet, to avoid flashing an empty list
before the first batch lands. That guard also fired when a filter
(chips, space or search) legitimately matched nothing, leaving the home
screen on placeholders forever instead of showing the empty filter
state.
2026-10-02 15:11:22 +03:00
Mauro d3604e8115 Announce toasts with VoiceOver (#6250)
* Announce toasts with VoiceOver

Toasts are posted from a separate overlay window and never take
VoiceOver focus, so their text was never spoken. UserIndicatorController
now posts a high priority announcement with the title whenever a toast
with readable text is submitted, including re-submissions of an already
visible toast with the same ID. Modal indicators are not announced.

* Remove empty-title toast announcement check

Co-authored-by: Velin92 <34335419+Velin92@users.noreply.github.com>

* Hide toasts from VoiceOver

The toast title is now announced by UserIndicatorController when the
toast is submitted, so letting VoiceOver also focus the toast itself
would only read the same text twice.

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
2026-10-02 12:29:18 +02:00
Mauro f91b7441e7 Suggest recently visited rooms when forwarding messages (#6251)
* Suggest recently visited rooms when forwarding messages

The Forward to screen now shows up to 5 recently visited rooms in a
Suggestions section, above a Chats section that lists every room. The
suggestions are never searched: while searching, only the Chats section
is shown and filtered. The source room, invites, spaces and upgraded
rooms are never suggested, and the section is hidden when there is
nothing to suggest.

The suggestions are resolved from the room summaries rather than room
proxies, so they show up without holding back the list, and they are
re-resolved as the room list loads after a cold start. ClientProxy now
exposes the recently visited room IDs for this.

The recently visited rooms filter is now async, so callers choose its
isolation instead of asserting it at runtime.

* Apply review suggestions to the forwarding suggestions

Rooms:
- Each room is listed once. Suggested rooms are left out of Chats unless
  searching, where Chats lists every result. This also removes the
  duplicated row whose selection changed without the tapped row's
  animation.
- The Chats header is hidden when the section has no rooms.

Suggestions:
- Resolve them once when the screen opens instead of on every room list
  update.
2026-10-02 12:04:07 +02:00
Mauro Romito e67a4c388f Read the number of selected messages to VoiceOver
The count was only on the forward button at the bottom, so VoiceOver
users had to go and find it after every tap. While selecting, each
selectable message now starts its label with "N messages selected".
The label changes on every toggle, so VoiceOver reads the new count
followed by the message, as in other messaging apps.
2026-10-01 21:39:47 +02:00
Mauro Romito 8ddd161625 Keep message selection active when every message is unselected
Unselecting the last message used to end the selection, closing it
without the user asking. Selection mode is now its own state: Forward
starts it and it only ends with the close button, once the messages are
forwarded, when the timeline changes or the feature is turned off. With
nothing selected the forward button stays visible but disabled.
2026-10-01 17:43:42 +02:00
Stefan Ceriu cdb5d4ee31 Group dependencies shared by Compound and the app in one Renovate PR
swift-snapshot-testing is pinned in both compound-ios/Package.swift and
project.yml. Renovate updated them from different groups, so one side got
bumped without the other and the Xcode build broke on the mismatched
Package.resolved. A dedicated "Shared Dependencies" group updates both
together, and since that PR touches project.yml the XcodeGen workflow
regenerates the project as well.
2026-10-01 16:37:26 +03:00
Stefan Ceriu 18b0975c99 Run all Renovate dependency groups on the same schedule
Tool and Compound dependencies had no schedule while project dependencies
were only updated every 2 weeks, so their PRs landed at unrelated times.
Put them all on the same biweekly Wednesday slot and rename the Compound
group to "Compound Dependencies" for consistency with the others.
2026-10-01 16:37:26 +03:00
Stefan Ceriu f084274acb Use current Renovate option names for the Compound rule
`managers` and `matchPaths` are deprecated in favour of `matchManagers`
and `matchFileNames`. Renovate was migrating them on the fly, this makes
the config match what it actually runs.
2026-10-01 16:37:26 +03:00
Stefan Ceriu a4ff68ed84 Bump swift-snapshot-testing in the main project too 2026-10-01 16:37:26 +03:00
renovate[bot] 9a62206a4f Update dependency pointfreeco/swift-snapshot-testing to v1.19.6 2026-10-01 16:37:26 +03:00
Stefan Ceriu 11dc19f7ed Await the session restore instead of polling for it
Replace the 100ms polling loop in the background app refresh with a
subject that the state machine's transition handler sets as soon as the
app is no longer restoring a session, whatever the outcome. The refresh
now awaits it once, with the same 5 second timeout, instead of waking
up repeatedly.

Move the wait back into the class body and silence type_body_length for
AppCoordinator rather than keeping a single-function extension around
to stay under the limit.
2026-10-01 15:59:42 +03:00
Stefan Ceriu a56a5c2819 Wait for the session restore in background app refresh
When iOS relaunches a terminated app for the task, the session is still
being restored asynchronously when the refresh starts. Wait up to 5
seconds for the restore to finish, bailing out early if the app isn't
restoring a session (e.g. signed out or the restore failed).

# Conflicts:
#	ElementX/Sources/Application/AppCoordinator.swift
2026-10-01 15:59:42 +03:00
Stefan Ceriu 38312b7473 Fix the search tab's layout now that its built against os27 2026-10-01 15:59:16 +03:00
Mauro Romito b65e8f6a7c Fix formatting-only edits not rendering in the timeline
Components of a formatted body were identified by their plain characters, so an edit
that only added formatting (e.g. wrapping a word in inline code) kept the same ID.
SwiftUI then reused the existing MessageText, whose @State string ignores new input,
and the old unformatted text kept rendering.

Identify components by the hash of their attributed string so formatting changes
produce a new ID.
2026-10-01 14:56:53 +02:00
Mauro Romito 7911df9537 Fix the media viewer getting stuck on "Loading more…" when swiping forward
QuickLook requests every page up front when the viewer opens. At that point the
media timeline is still empty, so every page after the tapped media is cached as
a forward pagination placeholder. Once the timeline loads it reports forward as
end reached, so no pagination happens and nothing ever replaces those cached
placeholders, leaving the viewer stuck when swiping forward.

When landing on a placeholder, or when the timeline updates, the controller now
checks whether the data source holds a different item at that index and if so
refreshes the current page. The refresh waits for any swipe to settle, as
refreshing mid-swipe breaks QLPreviewController.
2026-10-01 14:31:29 +02:00
Mauro Romito 61384f9986 Use the window scene initialiser for UIWindow in tests
UIWindow.init() is deprecated in iOS 26. AuthenticationStartScreenViewModelTests
now creates its fake window from the test host's connected scene, matching
ServerSelectionScreenViewModelTests.
2026-10-01 10:56:08 +02:00
Mauro Romito 26c417ae68 Move AlertInfo's button types out of the generic type
With Swift 6.4, the default value for AlertInfo.primaryButton warned that
T's Hashable conformance may be isolated and can't be used in a main
actor-isolated context. The nested AlertButton/AlertTextField types
don't depend on T, so move them to top level as AlertInfoButton and
AlertInfoTextField, and keep typealiases so existing call sites compile.

Constraining T to SendableMetatype isn't possible as the synthesized
Hashable conformances of our main actor-isolated alert enums are isolated.
2026-10-01 10:55:40 +02:00
Mauro 831234865b Fix Swift 6.4 warnings (#6240) 2026-10-01 10:55:19 +02:00
Mauro Romito 99c0fa5729 Title the forwarding screen "Forward to"
The forwarding screen now picks destinations for one or several
messages, so "Forward message" no longer fits. Use the common_forward_to
string from Localazy, as in the designs, and re-record its snapshots.
2026-09-30 17:40:55 +02:00
Stefan Ceriu b21d27dbbc Jump straight to notification tap and external deep link targets
Whether to animate a route was decided after resuming the client
services, by which time a notification tap or an external deep link
had already made the app active, so the user watched a navigation
animation from the room list. Read the app state as soon as the route
arrives instead, so these land directly on their target while routes
handled in the foreground keep animating.
2026-09-30 17:06:57 +03:00
Stefan Ceriu a87d65b05a Surface failed reactions as a send failure on their message
A reaction that fails to send can now block the room's send queue, but the
timeline only surfaced failures for the item itself, its edit or its
redaction. EventTimelineItemProxy.pendingSend now also falls back to our
first failed reaction, targeting it with SendTarget.reaction(key:), so the
message shows the red exclamation mark and the sending failed alert can
retry or remove it.

In-flight reactions are deliberately ignored so reacting doesn't flash a
sending indicator on the message.
2026-09-30 15:16:13 +03:00
Stefan Ceriu 4c71cae0f5 Open the room live when tapping the notification for its newest message
Tapping a message notification always opened the room on a timeline
focussed on that event, even when it was the newest message and the
live timeline already ends with it.

On tap, the notification manager now checks whether any other delivered
notification for the same room is more recent. If none is, the room is
opened live instead of focussed. Older notifications in a room keep
focussing on their event.
2026-09-30 14:50:04 +03:00
Stefan Ceriu 7973da8251 Throw from session directories and only fatal error when making sense. 2026-09-30 12:24:12 +03:00
Stefan Ceriu a8bc26dc93 Fix various UI test snapshot issues. 2026-09-30 12:23:54 +03:00
Stefan Ceriu 5a3c4ad2f5 Make the background app refresh task live in its own extension as well 2026-09-30 12:20:54 +03:00
Stefan Ceriu 49481f9af7 Add a search backfill app background processing task
To run when the device is idle, charging and connected to the network.
2026-09-30 12:20:54 +03:00
Stefan Ceriu d08b0e0090 Start a foreground search backfill request when entering the message search tab 2026-09-30 12:20:54 +03:00
Stefan Ceriu 790bf0a44e Adopt the new search backfill client interfaces. 2026-09-30 12:20:54 +03:00
Valere 8aae06d3ae Bump element-call-ios version to 0.1.0-rc.9 2026-09-30 08:20:36 +03:00
Stefan Ceriu ec4d1a3c04 Update some icons to use the primary accent color instead of tertiary for accessibility reasons. 2026-09-29 22:11:16 +03:00
Stefan Ceriu 0de6231399 Give search breadcrumbs a consistent row height
Query and room breadcrumbs reserved slightly different heights, and
rooms without a description collapsed further. Both now reserve the
space of a title and subtitle so every row lines up.
2026-09-29 21:53:04 +03:00
Stefan Ceriu a78e4f0c2a Add a clear all button to recent searches
Lets users wipe their whole search history at once from the recent
searches section header, as per the designs.
2026-09-29 21:53:04 +03:00
Stefan Ceriu 50b38555b6 Allow removing individual search breadcrumbs
Each recent search now has a trailing close button to remove it from
the history. The view action is logged without its payload so removed
queries don't end up in the logs.
2026-09-29 21:53:04 +03:00
Stefan Ceriu 313365ad83 Only record query breadcrumbs when the search is submitted
Queries were previously stored whenever a result was selected, which
meant half-typed queries ended up in the history. Now a query is only
recorded when the user submits the search field, while selecting a
result only records the room.
2026-09-29 21:53:04 +03:00
Stefan Ceriu bc018251c7 Update translations to bring in action.clear_all 2026-09-29 21:53:04 +03:00
Stefan Ceriu 1464a98ef0 Split the description of the new "Show all activity" notification setting 2026-09-29 21:36:44 +03:00
Mauro Romito e6bd8b0eb9 Fix the build after the translations update
The translations update removed screen_room_confirm_removal_message, as the redaction confirmation now asks the question in its title ("Remove message?"), matching Element X Android. Drop the message from RedactConfirmationView and re-record the previews whose copy changed.
2026-09-29 20:05:14 +03:00
Element CI dcaa2dffdb Translations update 2026-09-29 20:05:14 +03:00
Mauro b1ed870474 Support for Xcode 27 on CI (#6217)
* Run the tests on iOS 27.0

Bump the required simulator OS in the preview, UI and Compound tests, and the CI tool's default OS, from 26.5 to 27.0. Test devices stay the same.

iOS 27 writes transcoded videos 146 bytes larger, so update the expected sizes in MediaUploadingPreprocessorTests.

* Build and test on CI with Xcode 27

Select Xcode 27 in ci_common.sh and move every macOS workflow to the xcode-27 runner image, as macos-26 doesn't include Xcode 27. The Compound workflow now also creates its simulator on the iOS 27.0 runtime.

The xcode-27 runners are slower, so give the unit, Enterprise, Compound and snapshot recording jobs longer timeouts.

* Fix the preview snapshot layout on iOS 27

On iOS 27 the hosting controller applies the window's safe area when rendering, but the snapshot size comes from sizeThatFits, which ignores it. Component previews were shifted down and clipped at the bottom. Disable the hosting controller's safe area regions for these snapshots so the measured and rendered layouts match.

swift-snapshot-testing also renders into a window without a scene, and on iOS 27 a navigation stack in such a window reserves space for a large title it never shows, leaving a gap below the navigation bar. Attach the render window to the app's scene until swift-snapshot-testing handles it.

The invite users and add rooms screens sized their selected items row from a measured width stored in state, which is zero on the first layout pass, so snapshots could draw the row empty. Use containerRelativeFrame instead. The add rooms search previews now also wait for their results, and the search previews that show a clear button get a small precision tolerance, as it renders inconsistently in snapshots.

* Re-record the preview snapshots on iOS 27.0

Recorded on an iPhone SE (3rd generation) simulator running iOS 27.0 with Xcode 27.0 (27A266a). The changes come from iOS 27 rendering: text anti-aliasing, hyphenation and line breaking, navigation bars and toggles that now render in snapshots, lazy stacks that were blank on iOS 26, and pseudo-language locale formatting.

* Fix the UI tests on iOS 27

iOS 27 no longer exposes accessibility identifiers on SwiftUI menu items, so the space exploration test now finds them by label within the menu. On iPad, the start chat search field keeps focus after submitting and can swallow the next tap, so retry the tap if the create room screen doesn't appear.

* Re-record the UI test snapshots on iOS 27.0

Recorded on iPhone 17 and iPad (A16) simulators running iOS 27.0 with Xcode 27.0. The changes come from iOS 27 styling, like the keyboard height and glass borders. This also removes the iPad app lock setup snapshots, which have been orphaned since those tests stopped running on iPad.

* Fix the accessibility tests crashing on iOS 27

The accessibility tests' previews wrapper kept its ImageRenderer alive across the awaits that follow the render. On iOS 27, releasing it at that point tears down its view graph outside of a SwiftUI update, which hits an assertion and crashes the app. Release the renderer as soon as the image has been rendered.

* Keep the accessibility tests' image renderers alive on iOS 27

Releasing the ImageRenderer straight away wasn't enough: on iOS 27, releasing one that rendered a preview crashes SwiftUI whichever context it happens in. Keep the renderers alive instead. Each test launches a fresh app, so they only live for the one test.

* Share the UI tests' app settings with their mock user session

Since the user session flow reads its settings from UserSettings, the UI tests' mock user session was wrapping a fresh volatile AppSettings instead of the one the tests configure. The flags that skip onboarding weren't picked up, so every user session UI test got stuck on the notifications permission screen.

* Re-record the Compound snapshots on iOS 27.0

Apply the same safe area fix as the app's preview tests, so size-that-fits snapshots aren't clipped on iOS 27, and re-record the snapshots on an iPhone SE (3rd generation) simulator running iOS 27.0 in English (US).

* Fix a race reading the keyboard in the accessibility tests

On iOS 27 the QR code login screen's keyboard can be dismissing between checking that it exists and reading its frame, which fails the test. Snapshot it in a single query instead.
2026-09-29 17:02:48 +02:00
Element CI 90425460f9 Bump the calendar version ready for the next release 2026-09-29 16:30:46 +02:00
Danny d74d53e4ee Extend the room details screen hook (#6173)
* Allow Enterprise sections in room details

Signed-off-by: Daniel Anderson <daniel.anderson@toptal.com>

* Update the Enterprise submodule and strings

Signed-off-by: Daniel Anderson <daniel.anderson@toptal.com>

---------

Signed-off-by: Daniel Anderson <daniel.anderson@toptal.com>
2026-09-28 12:11:23 -06:00
Stefan Ceriu e51d869fdc Adopt the new send queue interfaces 2026-09-28 15:36:52 +03:00
Copilot 690f2be5f4 Resume app lock continuation after forced logout (#6199)
* Initial plan

* Resume app lock continuation on forced logout

Co-authored-by: pixlwave <6060466+pixlwave@users.noreply.github.com>

* Add regression coverage for forced logout verification

Co-authored-by: Velin92 <34335419+Velin92@users.noreply.github.com>

* Revert "Add regression coverage for forced logout verification"

This reverts commit 64cda7c665ab5ca736110d606250c26e22234619.

Co-authored-by: Velin92 <34335419+Velin92@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: pixlwave <6060466+pixlwave@users.noreply.github.com>
Co-authored-by: Velin92 <34335419+Velin92@users.noreply.github.com>
2026-09-28 12:28:01 +02:00