Commit Graph

2170 Commits

Author SHA1 Message Date
Sedat-Qaja 3b7ed0a48b fix: remove rlement endpoints and links from the HealthChat
* fix(healthchat): switch off analytics, crash and bug reporting endpoints

Upstream ships *.localhost placeholders in Secrets.swift and marks the file assume-unchanged; with analytics on, the Element Call widget was handed Element's own PostHog and Sentry. nil hides the analytics prompt, the Analytics and Report a problem entries until HealthChat runs its own services.

* feat(healthchat): hide the Labs entry in settings

* fix(healthchat): point Copyright and the analytics terms at healthchat.ch

* docs(healthchat): add the 26.11.1 release notes

* feat(healthchat): drop the Element help links

* feat(healthchat): switch off location sharing

* test(healthchat): skip the analytics suite without PostHog
2026-10-19 14:40:20 +02:00
Sedat Qaja 979d20572d refactor(healthchat): move the session hooks onto UserHooks 2026-10-19 09:18:07 +02:00
Sedat Qaja 1b34a71857 chore(healthchat): resolve the rebase onto upstream 26.10.3 2026-10-19 09:18:06 +02:00
Sedat Qaja 1edfb8057f fix(healthchat): refresh the account status whenever settings appears
The banner kept telling the user to complete a profile they had just
completed, and nothing was fetched until the screen was actually shown.
2026-10-19 09:17:37 +02:00
Sedat Qaja d9524130fa feat(healthchat): advertise the account status in settings
Pending approval and an incomplete profile were only visible in the
members tab, which a new user has no reason to open.
2026-10-19 09:17:36 +02:00
Sedat Qaja 181c518dc7 feat(healthchat): show default contacts while approval is pending
An unapproved account only gets the server's default contacts, which are
its way to reach support — list them instead of discarding them, and hide
the search field that cannot return anything.
2026-10-19 09:17:35 +02:00
joel.poyet 7adc963cf9 Adapt the HealthChat hooks to the upstream 26.09.1 screen APIs
The rebase onto release/26.09.1 moved three things the fork depends on.

Upstream now owns a UserProfileScreenHook of its own (#5980), which rewrites a
screen's view state rather than injecting a view. The fork's section hook keeps
its behaviour under the fork-only name ExtendedProfileSectionHook, so both can
live side by side and upstream's file stays untouched. Upstream's new @AppHook
macro generates the same register<Name> methods, so registration is unchanged.

UserProfileScreenCoordinatorParameters lost appSettings and reordered its
arguments, and UserDetailsEditScreenCoordinator now publishes its own
UserDetailsEditScreenCoordinatorAction instead of borrowing the room one
(#5893). The members flow and the profile editor follow both.

AppSettings.override gained oAuthClientURIPath (#5934), whose default appends
apps/ios to the website URL. HealthChat passes nil to keep the registered
client_uri at https://healthchat.ch exactly as the shipped build has it —
changing what the app registers with MAS is not a side effect a rebase should
have.
2026-10-19 09:17:33 +02:00
joel.poyet 209a36cbea Let members edit their profile and invite others (#12)
* Add HealthChat API and extended profile services

Expose OpenID tokens and homeserver credentials from the client proxy, and
add fork-only services for the HealthChat member directory backend
(api.healthchat.ch) plus a service that reads MSC4133 extended profile
fields directly from the homeserver. Groundwork for the members tab and
the profile screens.

Claude-Session: https://claude.ai/code/session_013qdTbAWsZj2quQzEkagXaS

* Show extended profile details on the profile screens

Add a UserProfileScreenHook that lets the fork inject an extra Form
section below the header of the user profile and room member details
screens. The HealthChat implementation loads the MSC4133 extended
profile fields and renders them with tappable phone/email/website
links, hiding the section entirely for profiles without any fields.

Strings live in a new fork-only HealthChat.strings table (de/en/fr,
generated as HealthChatL10n via SwiftGen) since Untranslated.strings
pins the English bundle.

Claude-Session: https://claude.ai/code/session_013qdTbAWsZj2quQzEkagXaS

* Add a member directory tab

Add a HomeTabsHook that lets the fork append an extra tab to the home
tab bar, and a HealthChat members flow behind it: a directory of all
approved members from the HealthChat API with server-side search,
pending-approval and error states, chat shortcuts and pushed member
profiles. Chats and calls are handed back to the session flow via the
hook's actions publisher.

Claude-Session: https://claude.ai/code/session_013qdTbAWsZj2quQzEkagXaS

* Let members edit their profile and invite others

Add a native profile editor for the HealthChat extended profile fields
(13 fields plus avatar, saved as a partial diff through the HealthChat
API so displayname derivation and Zitadel sync stay server-side), an
invitation sheet (email plus personal note) and a profile-completeness
hint on the member directory.

A new UserDetailsEditScreenHook lets the fork substitute the profile
editor behind the settings user row — the stock display-name editor
would let users edit a value the next profile update derives away.

Claude-Session: https://claude.ai/code/session_013qdTbAWsZj2quQzEkagXaS
2026-10-19 09:17:32 +02:00
joel.poyet c0f167ccf7 Add a member directory tab (#11)
* Add HealthChat API and extended profile services

Expose OpenID tokens and homeserver credentials from the client proxy, and
add fork-only services for the HealthChat member directory backend
(api.healthchat.ch) plus a service that reads MSC4133 extended profile
fields directly from the homeserver. Groundwork for the members tab and
the profile screens.

Claude-Session: https://claude.ai/code/session_013qdTbAWsZj2quQzEkagXaS

* Show extended profile details on the profile screens

Add a UserProfileScreenHook that lets the fork inject an extra Form
section below the header of the user profile and room member details
screens. The HealthChat implementation loads the MSC4133 extended
profile fields and renders them with tappable phone/email/website
links, hiding the section entirely for profiles without any fields.

Strings live in a new fork-only HealthChat.strings table (de/en/fr,
generated as HealthChatL10n via SwiftGen) since Untranslated.strings
pins the English bundle.

Claude-Session: https://claude.ai/code/session_013qdTbAWsZj2quQzEkagXaS

* Add a member directory tab

Add a HomeTabsHook that lets the fork append an extra tab to the home
tab bar, and a HealthChat members flow behind it: a directory of all
approved members from the HealthChat API with server-side search,
pending-approval and error states, chat shortcuts and pushed member
profiles. Chats and calls are handed back to the session flow via the
hook's actions publisher.

Claude-Session: https://claude.ai/code/session_013qdTbAWsZj2quQzEkagXaS
2026-10-19 09:17:31 +02:00
joel.poyet dffeb4f9bb Show extended profile details on the profile screens (#10)
* Add HealthChat API and extended profile services

Expose OpenID tokens and homeserver credentials from the client proxy, and
add fork-only services for the HealthChat member directory backend
(api.healthchat.ch) plus a service that reads MSC4133 extended profile
fields directly from the homeserver. Groundwork for the members tab and
the profile screens.

Claude-Session: https://claude.ai/code/session_013qdTbAWsZj2quQzEkagXaS

* Show extended profile details on the profile screens

Add a UserProfileScreenHook that lets the fork inject an extra Form
section below the header of the user profile and room member details
screens. The HealthChat implementation loads the MSC4133 extended
profile fields and renders them with tappable phone/email/website
links, hiding the section entirely for profiles without any fields.

Strings live in a new fork-only HealthChat.strings table (de/en/fr,
generated as HealthChatL10n via SwiftGen) since Untranslated.strings
pins the English bundle.

Claude-Session: https://claude.ai/code/session_013qdTbAWsZj2quQzEkagXaS
2026-10-19 09:17:31 +02:00
joel.poyet 1da4c0302e Point the classic app identifiers at HealthChat rather than Element (#1)
ClassicAppManager migrates an existing user's session and encryption keys by
reading the legacy app's app-group container and keychain. Those identifiers
defaulted to Element's own, which this team cannot provision, so loadAccounts()
threw invalidAppGroupIdentifier — caught and logged, never surfaced. Since both
apps share a bundle id, the result would be every existing user silently logged
out and losing local history when they update.

The legacy identifiers belong to HealthChat and are provisionable under the same
team, so repoint them rather than dropping them.

Also stop sending accounts without key backup to a dead end. Upstream shows those
users a sheet asking them to open Element Classic and set up backup first, but this
update replaces that app and nothing registers its URL scheme, so the sheet's only
button does nothing. Sign in directly instead: the user re-verifies the device and
loses only history that by definition has no backup.
2026-10-19 09:17:29 +02:00
joel.poyet 3d1fa27a4b Rebrand as HealthChat and pin the account provider to healthchat.ch
Applies the HealthChat product identity through the fork seams upstream already
provides, so no upstream logic files are touched and merges stay clean.

- Variants/HealthChat/healthchat.yml holds the identity scalars (display name,
  bundle id ch.healthchat.element, app group, development team) and is included
  permanently from project.yml. APP_NAME stays ElementX so the module name and
  @testable import ElementX keep working.
- ElementX/Sources/AppHooks/HealthChat/ registers an AppSettings hook pinning
  accountProviders to healthchat.ch with other providers disabled, push through
  sygnal.healthchat.ch and a custom-scheme OIDC redirect; plus a Compound hook
  recolouring the accent token family to the HealthChat blue.
- Entitlements are edited directly in ElementX/SupportingFiles/target.yml rather
  than in the variant, because XcodeGen concatenates arrays on include-merge and
  a variant can override scalars but cannot remove array entries. Drops the
  Element Classic app group and keychain group, and narrows associated domains
  to app.healthchat.ch, keeping matrix.to for permalinks.
- Info.plist CFBundleName now follows APP_DISPLAY_NAME — it, not
  CFBundleDisplayName, is what the web authentication sign-in alert shows.
- App logo and app icon assets swapped in place; the onboarding welcome title
  moves to a new screen_onboarding_welcome_title_ios untranslated string.
2026-10-19 09:17:24 +02:00
Mauro 268d6c8ead Notify every signed-in account and turn notifications on and off per account (#6337)
* Store the notifications switch per account

Adds AccountSettings.enableNotifications and moves the app-wide value into the signed in accounts before they're restored: the first account takes it out of the app settings and the others get the same switch, so someone who turned notifications off keeps them off.

* Add a notification service to every user session

Each account's NotificationService sets its pusher when its notifications are on and deletes it when they're off (appending with multiple accounts), keeps the account's unread count and decides which of its delivered notifications to clear. It asks the NotificationManager, the only owner of the notification center, through actions: remove the notifications matching a rule, request authorization and the unread count. The UserSessionManager connects every live session's service to the manager, and flows and screens use the session's service instead of the manager, which leaves the flow parameters.

* Route notifications by account

Taps only open rooms of the active account for now, a tap made while restoring only opens once its account is the active one, replies are sent from the account they were made for, and signing out only clears that account's notifications unless it was the last one. The notification extension hides pushes for an account that signed out while other accounts are still signed in.

* Turn notifications on and off for each account

The notification settings switch is now saved per account, and each account's NotificationService sets or deletes its pusher when it changes, asking for permission when it's turned on.

* Apply review suggestions to multi-account notifications

Migration
- Move the notifications switch with a single per-account migration, like 26.10.1 and 26.10.2, and drop its dedicated test.

Notification manager and service
- Follow each account's badge count publisher directly, removing the badge count action and the stored counts.
- Only reset the badge and unregister from APNs when the last account signs out, as each account already clears its own notifications.
- Set up the service's subscriptions in a single setupSubscriptions().
- Rename switchChanged(to:) to enableNotificationsChanged(to:) and pusherConfiguration(identifiers:) to pusherConfiguration(for:).
- Build the service without hopping to the main actor, it already runs there.

Notification service extension
- Check the account's switch in NotificationHandler using the session's settings, and log an error when a push arrives for an account that's turned off.
- Always show pushes that match no signed-in account and log an error, so a broken setup stays visible.

Other
- Store a pending inline reply in a PendingInlineReplyDetails struct.
- Assign the chats tab badge with weakAssign.
- Make PusherConfiguration Equatable so the pusher test checks it in one expectation.
- Clarify the comment about notifications without a receiver.

* Print instead of logging before the app hooks run in the NSE

A push that matches no signed-in account goes back to printing, as MXLog shouldn't be used before the app hooks have run. The push is still shown so a broken setup stays visible.
2026-10-15 13:10:26 +02:00
Mauro Romito 09ecec4306 Ignore repeated confirms on the server selection screen
Tapping Continue and then the keyboard's Done key (or double tapping
Continue) started two server configurations. With a password-only server
both asked the flow to show the login screen, and the second request hit
the authentication state machine's unexpected transition fatalError.

Keep the running confirmation task and ignore further confirms until it
finishes, so the flow continues once. The guard clears afterwards so
confirming again after going back from the login screen still works.

Fixes ELEMENT-X-IOS-XED
2026-10-15 12:34:50 +02:00
Doug b6ccbbc6c3 Add a new UserHooks container and move some AppHooks. (#6332)
* Add a UserHooks system with just the CreateRoomScreenHook for now.

* Move more hooks into UserHooks.

* Pass the ClientProxy to makeUserHooks instead of calling AppHooks.configure(with:).

* Update the Enterprise submodule.
2026-10-15 10:49:27 +01:00
Stefan Ceriu 27e59a81e4 Fix integration tests following the search tab introduction
Tabbar tabs now can take accessibility identifiers and the integration test uses the newly expected flow.
2026-10-14 20:14:27 +03:00
Danny ae9e0cc176 Remove unused room details hook support (#6325)
* Remove unused room details hook support

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

* Update the Enterprise submodule.
2026-10-13 16:19:45 +00:00
Stefan Ceriu 900b24bc5e Remove unnecessary iOS 26+ search screen restriction. 2026-10-13 19:00:43 +03:00
Stefan Ceriu 95fc43f4fc Bump the RustSDK to v26.10.13 2026-10-13 19:00:43 +03:00
Mauro b31950789f Move synchronous image upload preparation off the main actor (#6323)
* Move synchronous image upload preparation off the main actor

Signed-off-by: Ivan Magda <imagda15@gmail.com>

* Make media preparation cooperative with cancellation

Replace the dispatch queue with concurrent copy, image and video-thumbnail
functions. Return sendable upload metadata directly, bound each batch to
two preparations and discard unfinished results when cancellation occurs.

Keep file metadata reads synchronous and prevent the preview from sending
a result after its preparation task has been cancelled. Replace unrelated
tests with cancellation and batch-order coverage requested during review.

* Update MediaUploadingPreprocessor.swift

* Run media preparation in a nonisolated preprocessor

Make MediaUploadingPreprocessor a nonisolated struct whose copy, image
processing and video thumbnail run in @concurrent instance methods,
instead of a main-actor type with static helpers and an extra setting
parameter.

Check cancellation with plain early returns between the slow steps,
name the batch limit, stop logging cancelled video exports as errors,
and restore develop's structure and doc comments where they were changed
without need.

Replace the tests that didn't reach the new code with tests for cleanup
on failure, on batch failure and on cancellation, and make the preview
test set up its blocking mock before the view model starts processing.

* Apply review suggestions to media preparation

Docs:
- Drop the doc comment on maximumConcurrentProcessingCount, the name says it.
- Move the cleanup note into the main description of both processMedia
  functions, so the Returns lines match develop again.

Tests:
- Rename the test helper to copyResourceToTemporaryDirectory(_:).

---------

Signed-off-by: Ivan Magda <imagda15@gmail.com>
Co-authored-by: Ivan Magda <imagda15@gmail.com>
2026-10-13 17:33:22 +02:00
Doug ac29354b08 Move any visible account settings into AccountSettings. (#6308)
* Remove the now unused setting to disable in-app notifications.

* Move visible account settings into AccountSettings.

Have ignored enableNotifications for now as that will require reworking the NotificationManager.

* Allow different sounds to be selected for each account.

* Move defaultNotificationTone into AccountSettings.
2026-10-13 15:21:13 +01:00
Stefan Ceriu 011087baf5 Adopt correct UIAA and session token passing usage as per spec. 2026-10-12 22:38:31 +03:00
Ivan Magda ad88f0da7c Update room suggestions and search when space membership changes (#6316)
* Avoid repeated space membership scans in room search

Signed-off-by: Ivan Magda <imagda15@gmail.com>

* Refresh room candidates when space membership changes

Keep known space room IDs in a set updated by the room publisher and by
successful additions. Filter both suggestions and search results through
that set, retaining exclusions while the space list resets and reloads.

Preserve the initial recent-room eligibility filter so existing children
do not consume the five suggestion slots. Cover live membership updates
and partial-save filtering in both candidate lists.

---------

Signed-off-by: Ivan Magda <imagda15@gmail.com>
2026-10-12 14:03:44 +00:00
Mauro 60db364436 Introduce a user session manager (#6295) 2026-10-09 14:07:39 +02:00
Doug 65bab49f39 Remove the CommonSettingsProtocol and use UserSession to carry multiple dependencies. (#6302)
* Remove the CommonSettingsProtocol.

* Replace multiple dependencies with the UserSession when it carries them.
2026-10-09 10:20:00 +01:00
Stefan Ceriu 61fe2a8158 Add a shared NotificationCountBadge view
Extract the unread notification count capsule from the room list cell into
its own view so it can be reused elsewhere. It caps the displayed value at
99+ and comes in a medium size (used by the room list) and a small size.
2026-10-09 11:44:39 +03:00
Doug fc75f90ef5 Remove the dynamic member lookup from UserSettings in favour of nested access. (#6294)
* Remove the dynamic member lookup from UserSettings in favour of nested access.

* Remove forwarding methods from UserSettings.

* Update the Enterprise submodule.
2026-10-08 15:19:44 +01:00
Doug c296659ad6 Only show media captions in QuickLook once. (#6287) 2026-10-08 11:10:28 +01:00
Doug 3b40aadc98 Re-organise SettingsScreen to have distinct Account/App settings. (#6288)
* Re-organise SettingsScreen to have distinct Account/App settings.

* Remove the AdvancedSettingsScreen.
2026-10-07 16:51:28 +01:00
Mauro f2eaa8e80d Show the multi-account announcement on the HomeScreen (#6265)
* Present the multi-account announcement when nothing else is showing

The user session flow owns onboarding, verification and settings, so it presents the announcement in the tab sheet slot with the lowest priority: once the verification state is known, and whenever onboarding, settings or a verification sheet is dismissed. Routes and sign-out dismiss settings without triggering it, and it is marked as seen when presented.

* Show the multi-account announcement on the home screen

Following review, the announcement is a best-effort sheet on the home
screen instead of a UserSessionFlowCoordinator state. It's presented when
the room list appears with the flag on, the announcement armed and the
session verified, and counts as seen once its content appears.

- Restore UserSessionFlowCoordinator to develop.
- HomeScreenViewModel presents the announcement through a binding and
  waits for a known verification state, so it never competes with the
  identity confirmation onboarding.
- Add account only closes the sheet until the add account flow exists.
- Rename MultiAccountAnnouncementScreen to MultiAccountAnnouncementView
  and drop its unused coordinator and view model protocol.
- Size the sheet from the measured navigation bar height and match the
  Figma spacing; the hard-coded 44pt pushed the content under the button.

* Present the multi-account announcement from the home screen view model

The announcement no longer needs its own view model: the view takes the
home screen's context and presents through a boolean binding, like the
home screen banners.

- Drop MultiAccountAnnouncementViewModel and its models. The view sends
  home screen actions to close or add an account and builds its own
  attributed subtitle.
- Check the verification state when the room list appears instead of
  waiting for it. Restored sessions already know it by then, unverified
  ones get the identity confirmation cover first and the room list
  appears again once it's dismissed. Nothing is left subscribed, so the
  sheet can no longer turn up later wherever the user is.
2026-10-07 12:29:51 +02:00
Doug cf25287308 Add a LocationSharingSettingsScreen. (#6281) 2026-10-07 09:10:15 +01:00
Doug ce3829f253 Add a MediaUploadQualitySettingsScreen. (#6279) 2026-10-07 09:10:14 +01:00
Doug 51dd2efe23 Add a ModerationAndSafetySettingsScreen. (#6278) 2026-10-07 09:10:14 +01:00
Doug 93825c01ad Initial implementation of AccountSettings. (#6275)
* Make the UserPreference macro also generate an accessor for the key name.

* Initial implementation of AccountSettings.

- Add an AccountUserDefaults storage with a userID prefix on the key.
- Migrate the 2 values reset by AppSettings.resetSessionSpecificSettings to AccountSettings.

* Rename UserSettings.volatile() to UserSettings.mock()

Given it now has a userID parameter with a default value..
2026-10-06 17:52:24 +01:00
Stefan Ceriu acd18f3aa9 Fix location sharing double sheet presentation on the Mac
Which would override each other and break the UI state
2026-10-06 17:40:19 +03:00
mxandreas 4640f9cec0 Add hooks for room creation and privacy & security settings screen. (#6270)
Add hooks for the create room and security and privacy screens.
2026-10-06 09:05:49 +00:00
Mauro 60c11c8172 Add the multi-account announcement screen (#6263)
* Add the multi-account announcement screen

A self-sizing bottom sheet telling users they can now add multiple accounts, matching the designs. Close and Add account both report back to the coordinator; nothing presents it yet.

* Use the Localazy strings for the multi-account announcement

The copy now lives in Localazy as screen.multi_account_announcement.*, named after the screen rather than the room list.

* Apply review suggestions to the multi-account announcement

- Use an ElementNavigationStack with a toolbar close button, like RedactConfirmationView, instead of an overlaid glass button.

* Remove the large text preview from the multi-account announcement

Other sheets built the same way don't snapshot Dynamic Type sizes, and the iOS 26 bar material it would show isn't rendered in snapshots.

* Use TitleAndIcon for the multi-account announcement

TitleAndIcon now takes an attributed subtitle (#6274), so the sheet no longer needs to rebuild its layout by hand. The snapshots are unchanged.
2026-10-05 18:03:19 +02:00
Mauro 8a6e297cba Media preview single stale refresh (#6272) 2026-10-05 14:35:16 +02:00
Mauro 49457f7ae8 Multi account feature flag (#6261)
* Add a multi-account feature flag

The flag lives in Developer options. Switching it on arms the upcoming one-time multi-account announcement, whose seen state defaults to true so fresh installs never see it.

* Add an Add account row to Settings behind the multi-account flag

The row sits in its own section under the user status, as in the designs. Tapping it is routed up to the settings flow, which ignores it until the add account flow exists.

* Remove the Developer options view model tests

The Developer options screen is excluded from coverage, so these tests don't add value.

* Apply review suggestions to the multi-account flag

- Order the multi-account requirements in DeveloperOptionsProtocol to match the screen's sections.
- Drop the redundant "Experimental" from the toggle's subtitle.
2026-10-05 13:04:16 +02:00
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
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
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 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
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 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 d08b0e0090 Start a foreground search backfill request when entering the message search tab 2026-09-30 12:20:54 +03:00