* Add a Mentions room list filter
Adds a new filter chip to the room list that shows only rooms with
unread mentions, using the new mentions room list filter from the
Rust SDK (matrix-org/matrix-rust-sdk branch matthew/mentions-filter).
The SDK version needs bumping to a release that includes the new
filter kind before this can build against the released components.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* Order the room list filters by expected usage
Move Favourites ahead of People and Rooms so the more commonly used
filters (Unreads, Mentions, Favourites) sit first in the chip row —
Rooms and Invites are used rarely enough that it's fine for them to
wrap off the side.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Uk8aPxHn3BHCe52L226jdG
* update the SDK and use the appropriate rust filter types
* preview tests + app settings flag for mentions
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: Mauro Romito <mauro.romito@element.io>
Growing the list only once the last row was already visible, on top of the half a
second visible range throttle, meant hitting and bouncing off the end of the list
while the next page loaded. Ask for the next page half a page early instead, so
the growth happens while the user is still scrolling towards the boundary.
The threshold is clamped so that it stays positive for accounts with fewer rooms
than half a page, where it would otherwise always match and leave the list unable
to shrink back to a single page.
The room summary provider subscription only delivers its current state through an
async main queue hop, which can end up queued behind the first render. On a warm
launch, where the cached rooms have already been published before the home screen
exists, that leaves the skeletons up for the whole duration.
Read the current state at the end of init instead, alongside the rooms which were
already being read there.
The room summary provider publishes its loading state and its rooms through two
independent streams, so the state can report loaded before the first summaries
have been applied. Flipping the room list mode to .rooms at that point renders
an empty list until the summaries arrive.
Combine the two publishers into a single subscription so that the mode and the
rooms are always updated from the same pair of values, and keep the skeletons up
until the rooms have published. Only the initial transition is held back, an
empty list later on is a filter or a search result and must not send the mode
back to the skeletons.
* Fix an issue with macro compilation when using Xcode previews.
* Update the Chats/Spaces toolbars to match the Figma.
Fixes a bug with the status emoji in the liquid glass button.
The accessibility audit flagged the avatar node in AvatarSettingsButtonLabel
as having no description, since it carried an accessibility identifier but
never a label.
The avatar is purely decorative, both screens that use it wrap it in a button
that is already labelled with the Settings title, so it is now hidden from
accessibility and the identifier has moved up onto the buttons themselves,
where the UI and integration tests query it.
* Add a common .inverseMask view modifier and use a blend mode for efficiency.
This also fixes the snapshot rendering 🎉
* Add support for the status emoji on the app's Setting button.
* Align the room header decoration icons with the status emoji.
* Add missing snapshots.
* Update the SDK and hook up the status from Room Heroes.
Also start requesting profiles via sss when the feature flag is enabled.
* Add support for subscribing to your own profile.
* Add a developer flag for the search tab
Introduces a globalSearchEnabled user preference (off by default) with a toggle in Developer Options, used to gate the new search experience.
* Support search role tabs in the tab coordinator
Migrates the NavigationTabCoordinator to SwiftUI's value-based Tab API and adds an isSearch option so a tab can adopt the iOS 26 .search role, which detaches it into the trailing search button in the tab bar.
* Moves room search to a new screen
Adds a new screen that filters the alternate room summary provider as you type, shows an empty state, and lists matching rooms with their matrix identifier. Supports hardware keyboard selection (arrow keys to move through results, return to open) by reaching into the system search field.
* Present search in a dedicated tab
Adds the search tab to the chats flow on iOS 26 when the flag is enabled, rendered as the detached .search role button. The Cmd+K shortcut now selects this tab, and the home screen's inline search is hidden while the tab is available.
* Remove the old global search screen
The dedicated search tab replaces the Cmd+K floating window, so the GlobalSearchScreen, its window plumbing in the WindowManager, and its presentation in the chats flow are all removed.
* 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>
* Use our standard XYZMock(.init()) pattern everywhere instead of XYZMock.default.
* Remove the configuration parameter label on mock convenience inits.
* Update the enterprise submodule.
* create DependenciesProtocol and replace ServiceLocator registration with it
replace mocking calls for ServiceLocator to Dependencies
replace ServiceLocator with instance level calls
replace ServiceLocator configs with TestDependencies config in Tests
replace servicelocator usage in analytics service
replace remaining ServiceLocator calls in unit tests
that depended on the UnitTestAppCoordinator configuration with per suite dependencies instances
fix swiftlint warning
remove remaining references to ServiceLocator
make dependencies properties consistent in tests
delete Dependencies and DependenciesProtocol
fix whitespace modifications
updates from PR feedback
a pass over converting AppSettings and AnalyticsService test instance properties to per test instantiation
fix a missed PR feedback
Sync up after rebase
create DependenciesProtocol and replace ServiceLocator registration with it
replace mocking calls for ServiceLocator to Dependencies
replace ServiceLocator with instance level calls
replace ServiceLocator configs with TestDependencies config in Tests
replace servicelocator usage in analytics service
replace remaining ServiceLocator calls in unit tests
that depended on the UnitTestAppCoordinator configuration with per suite dependencies instances
fix swiftlint warning
remove remaining references to ServiceLocator
make dependencies properties consistent in tests
delete Dependencies and DependenciesProtocol
* AppSettings is instance level mockable now
* replace mocked and preview usages of reset + AppSettings global init with
AppSettings(store: UserDefaultsMock())
* AppSettings.UserDefaultsKeys is now a RawRep struct, making it extensible
* update tests with new AppSettings so it builds
* update remaining AppSettings test/mock inits
* AppSettings.UserDefaultsKey conformed to ExpressibleByStringLiteral
* addressed issues found in first pass ai review
* update AppSettings instantiations after rebase
* fix accessibility tests coordinator after rebase
* Rename to VolatileUserDefaults
* AppSettings init uses mandatory parameter
* Revert UserDefaultsKey to enum
* Add TrackedUserDefaults to be able to reset the defaults object
* Added volatile static func to AppSettings
* Use .volatile() static func instead of full init
* review fixups
* Resolve build issues after rebase
* updated enterprise module
* remove the static reset settings call from the preview tests
---------
Co-authored-by: Mauro Romito <mauro.romito@element.io>
* Create AnalyticsServiceProtocol and conform AnalyticsService
* Replace AnalyticsService properties and arguments with AnalyticsServiceProtocol
* Inline AnalyticsServiceMock replacing old mock
* handle more complex AnalyticsServiceMock callsites
* move documentation from AnalyticsService to AnalyticsServiceProtocol
Removes the ServiceLocator singleton and instead directly injects the dependencies it was holding for more control over instantiation of the various component subtrees and better visibility over how they're being used.
1. I removed the grey dots for when there is activity in rooms set to mentions or mute.
2. For all unread rooms, I made the message preview text bold for better legibility
3. For rooms with no unreads, I made the font weight regular, again for legibility
We have also mergeg the new room list activity rendering with the existing feature hide unread badge feature flag and provide 3 variations: current production behavior, no badge but bolding, and no bolding and no badge
Once the app starts the WindowManager is configured with SwiftUI's environment OpenWindowAction. It can then be used to register coordinators (that provide the toPresentable view) and an optional flow coordinator (as most of the screens are part of a flow, especially rooms).
Once a coordinator is registed, the WindowManager invokes the OpenWindowAction which in turn makes the Application call its newly introduced WindowManagerWindowType WindowGroup's block to instantiate a new visual window rooting that view.
The WindowManager is also responsible for wrapping the presentable in a disappearance block and clean up the coordinator stack.
# Conflicts:
# ElementX/Sources/Application/AppCoordinator.swift
* 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
* replace NavigationStack with ElementNavigationStack to allow the content to be rendered without a NavigationStack in a11y tests
* fix a11y tests
* update xcodeproject
* swiftformat fix
* use iOS 26.1 for CI
* use a wrapper to solve the issue for a11y tests
* ElementNavigationStack only uses the trick in DEBUG mode, and added a swiftlint rule to prevent the usage of NavigationStack