The previous warning could trigger with abnormal numbers, since there
could be related events applying to a pinned event, the `loaded_events`
list could be bigger than the list of `pinned_event_ids`, due to the
eager flattening. This patch makes it display the correct number, by
postponing the flattening after the warning.
For non-live timelines, the recurring pattern was the following:
- first, fill the timeline with initial events, with a first call to
some form of subscribe() method,
- then, subscribe to updates in a second time later, using a second call
to the same subscribe() method.
Unfortunately, this is wrong, and opens a window for a very small race:
- first call to subscribe() to get the initial events
- new updates are emitted in the receiver, that lead to new events
- second call to subscribe() to get the receiver, and subscribe to it
In this case, the new updates would be lost by an observer.
The patch consists in refactoring timeline initialization, such that the
initial events and receiver are created at the same time; if there are
some updates happening after the now single subscribe() call, the
updates are accumulated and will be observable by external users.
This also has the nice benefit of tidying up the number of background
task handles for non-live timelines: there should be at most one such
focus task, which is now cleanly reflected in the timeline drop handles.
The issue is that when the most recent message was an live location event that started as live and later transitioned to a stopped state, the room list summary would ignore it entirely, even though the timeline still showed it as the latest item.
That behaviour feels incorrect. At most, the client should update the displayed description based on whether isLive is true or not.
This patch prevents the stopped live location events from being filtered out in the latest events.
This extracts the `/capabilities` logic to its own `HomeserverCapabilities` component in the SDK that can be manually asked to fetch, cache locally and return these capabilities.
### Expose sync v2 API through FFI via `Client.sync()` and
`Client.sync_once()` #6348
Mobile clients can now sync using the traditional `/sync` v2 endpoint
through the FFI bindings, without requiring Sliding Sync (MSC4186)
support on the homeserver.
This PR introduces a new API (non-breaking change).
#### Implementation notes
I chose to expose only the **list of room IDs** (invited, joined, left,
knocked) in the `SyncResponse`, rather than forwarding the full per-room
event payloads. This keeps the FFI surface simple. Clients that need
room details can query them through the existing `Room` APIs after being
notified of changes via the listener.
Two entry points are provided:
- **`Client.sync(settings, listener)`** starts a continuous sync loop,
returning a `TaskHandle` for cancellation. The `SyncListener` callback
fires after each successful sync response.
- **`Client.sync_once(settings)`** performs a single sync call, useful
for initial sync or one-off use cases.
`SyncSettings` exposes `timeout_ms` and `full_state`.
Signed-off-by: Philippe Bertin <pbertin@teladochealth.com>