- Scroll the list to the top using a LaunchedEffect instead of recreating the LazyListState on each search query change.
- Use isBlank to check the search query, to match the logic of RoomSelectSearchDataSource.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Use try/finally instead of the awaitClose block, so that the entries stream, the controller and the
dynamic adapters are destroyed even if the suspending onControllerCreated callback is cancelled or
throws before awaitClose is reached.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The enterprise repository is private, so only mention the number of new
commits in the generated PR description.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* Expose edit/redaction send states and retry/abort send from the Rust SDK
Pending edits and redactions have their own send queue entries, separate
from the original event. Surface them so the UI can reflect and act on them:
- Add `SendTarget` (Event, Edit, Redaction, Reaction) to the matrix API,
with a mapper to the Rust SDK type.
- Add `editSendState` and `redactionSendState` to `EventTimelineItem` and
map them from the SDK item.
- Add `Timeline.retrySend` / `Timeline.abortSend`, which take a `SendTarget`
so the right queued request is retried or removed. Implement them in
`RustTimeline` and in `FakeTimeline`.
* Track edit and redaction send states on timeline events
`TimelineItem.Event` now carries `editSendState` and `redactionSendState`
next to `localSendState`.
- `failedToSend` is true when any of the three states is failed, so a
failed edit or redaction is shown like a failed message.
- `pendingSend()` returns the first pending state together with its
`SendTarget`; the read receipt row, the send failure dialog and the
timeline presenter use it instead of reading `localSendState` directly.
- `TimelineItemReadReceiptView` is restructured so the row is only
rendered when there is something to show, and the send state takes
precedence over read receipts.
- Update the previews provider and test fixtures for the new fields, and
make `aMessageEvent`'s send state nullable.
* Retry and remove failed sends through the timeline
Retrying or removing a failed message used the event's `SendHandle`, which
only knows about the original send. Route both through the timeline with
the `SendTarget` of the pending request instead:
- `TimelineController` gains `retrySend` (which also re-enables the send
queue) and `abortSend`, acting on the current timeline.
- `MessagesPresenter` retries via `retrySend`, and does nothing when the
event has no pending send state.
- Redacting something that was never sent (no event ID) or a pending
edit/redaction now aborts the queued request rather than sending a
redaction, and no confirmation is asked for.
- Update the presenter tests accordingly.
* Log send queue errors
Log when the SDK reports a send queue error for a room, and when the
send queue is disabled, to help diagnose messages stuck in the queue.
* Make sure we display send queue errors before verification states
* Fix logic for displaying read receipts and add more screenshot tests
* Only use states with read receipts in `ReadReceiptBottomSheetStatePreviewParam`
* Handle `LocalEventSendState = null` state just like `LocalEventSendState.Sent`
* Add `TimelineItemAction.AbortSend` and use it for both:
1. Aborting sending a message/edit/redaction from the 'sending failed' dialog.
2. Abort sending a local message when selected from the timeline -> redact action.
* Update screenshots
---------
Co-authored-by: ElementBot <android@element.io>
When a PR is merged on develop with the enterprise submodule targeting a commit
which is not on the enterprise main branch, open a PR to update it to the latest
commit of main. The workflow also runs daily and manually to keep the submodule
up to date.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Previously, only the small remove button could get the keyboard focus, and the
focus ring was barely visible. Now the whole item is focusable, the focus ring is
drawn around it, and pressing an activation key (Enter, Space, D-pad center)
removes the item. Touch behavior is unchanged: only the remove button is clickable.
Also add a shared `activationKeys` set in the designsystem module.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The dynamic entries controller of a room list is created asynchronously, once
the entries are observed. Filters set before that were silently dropped, so for
instance the search query was not applied to the rooms of a newly selected
account in the room select screen.
RustDynamicRoomList now owns the controller, remembers the last requested filter,
and applies it when the controller is created if it differs from the initial one.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The room select screen was using a SearchBar, with an active mode displaying the search results instead of the room
list. Use a SearchField instead, displayed above the room list, which filters the rooms directly. The account switch
section and the selected rooms are now also displayed while searching.
- Remove isSearchActive from the state, and the ToggleSearchActive event.
- The "No results" message is displayed when the query is not blank and no room matches it.
- The back button now always closes the screen.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* Fix timestamp color to match the designs.
* Don't limit the call and unread row height to 16dp: the font size is not fixed and it might display components in a broken state
* Ensure the alignment works
* Remove `SemanticColors.unreadIndicator` and use `.iconAccentPrimary` and `.textActionAccent` instead
* Simplify and document `UnreadIndicatorAtom`
* Use `fontBodySmMedium` for the font size in the unread indicator
* Update screenshots
---------
Co-authored-by: ElementBot <android@element.io>
Move the "Rooms" section header inside the LazyColumn of the search results, so that it scrolls with the list
instead of staying fixed above it, as it is done for the room list when the search is not active.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The nested scroll connection of the account switch section was always attached. When the section is not displayed
(single account, Forward mode, or search active), its height offset limit is never set and stays at -Float.MAX_VALUE,
so the connection consumed all the scroll events and the room list could not be scrolled.
Only attach the connection when the account switch section is displayed.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The config is the same for all the files and all the rooms, so there is no need to read it for each file.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
All the accounts are proposed in the account switch, even the ones with an
invalid token, so that the user can still see them. If the selected account
has an invalid token, or is invalidated while the screen is displayed (for
instance signed out from another device), the error is displayed instead of
the room list, the selected rooms are cleared, and the client of this account
is not used anymore.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
If the client of the selected account cannot be restored, the room list was
never loaded and there was no feedback to the user.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The share feature does not need it anymore, so there is no reason to expose it
in the matrix api module.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Instead of creating a SharePresenter from the graph of another session, the
SharePresenter now gets the client of the selected session from the
MatrixClientProvider and uses an AppScope ShareDataSender to send the data.
To be able to send media from AppScope, MediaSenderRoomFactory is now bound in
AppScope and takes the MatrixClient as a parameter, and a new
MediaOptimizationConfigProviderFactory provides the media optimization config
of any session.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
When several accounts are signed in, sharing into the app no longer goes through the account selection screen. The room select screen (Share mode) now displays the selected account and an account switch on top of the room list, with a design similar to the multi account section of the settings.
Selecting another account displays the rooms of this account in place, scrolled to the top, without recreating the screen. The content is then shared from the room select screen using the selected account, with the same progress and error dialogs as when sharing with the current account. The current account is switched only once the share has succeeded, then the room is opened if the content has been shared to a single room.
Implementation:
- RoomSelectNode is now in the AppScope and uses MatrixClientProvider to get the room list of the selected session.
- ShareNode gets the SharePresenter of the selected session from its session graph, using the new ShareBindings.
- SessionGraphFactory is moved to the matrix api module so that it can be used by features.
The account selection screen is still used for permalinks.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>