Declining an invite from the full screen invite left the user on that
same screen, so they had to press back themselves to get to the room
list. Both decline paths are affected: the plain decline handled by
AcceptDeclineInviteView, and the decline and block sub screen, which
navigated up into the join room flow instead of out of it.
Navigate up from the join room flow on a successful decline, and give
DeclineInviteAndBlockEntryPoint a callback so the sub screen can report
a successful decline separately from a back press. The room list flow
supplies the same callback, popping the sub screen once the invite has
been declined.
* Give the room name in the timeline top bar a 48dp tap target
The row carrying the room avatar and name is the control that opens the
room details, but it is only as tall as its content, which is under the
48dp minimum recommended for a touch target. Constrain it to a minimum
height of 48dp. The children stay centred inside the app bar, so nothing
moves visually.
* Update screenshots
The accessibility snapshot of the timeline is the only one the change
affects: the node which opens the room details now reports a 48dp tall
bounding box. The room name, the avatar and the icons stay where they
were.
* Rename `UrlContentFetcher` to `ClientUrlContentFetcher` and add missing base URL data (server name, homeserver URL)
* Avoid passing the `homeserverUrl/serverName` around.
Calculate the URL in `DefaultRemoteEnterpriseConfigRetriever` using the newly added `homserver` and `server` values as the possible base URLs, depending on the remote config source
* Make sure we don't perform blocking requests to fetch the remote config when restoring a session
Add a `needsRefresh` parameter to `RemoteEnterpriseConfigResult.NotFound` to handle this, and store a `no-config` value in the store to indicate an endpoint has been checked and no config was found
* Bump enterprise module
* Don't restart the sync service if the client is shutting down
This was causing issues when clearing the cache:
1. The client would ask the SDK to clear the caches.
2. The SDK would stop the sync service, clear the caches and set the `pos` value of sliding sync to 0 so the HS returns all the required state the next time the client is used.
3. However, between the sync service being stopped with the `pos=0` change and the client being destroyed, there was enough time for the `SyncOrchestrator` to decide the sync service was stopped for no good reason since there is network connectivity and the app is on foreground, so it restarted the sync, with `pos=0`.
4. This value was persisted, and the next time the new client did an 'initial sync' it had a `pos != 0`, which the HS uses to avoid returning some required state it already fetched.
5. The room list now lacks state events for lots of rooms and room names, avatars, members, etc. are now missing.
---------
Co-authored-by: Benoit Marty <benoitm@element.io>
* Refresh the room members when a mention is started
The mention suggestions read room.membersStateFlow, which is a cache filled
only by an explicit updateMembers() call. Nothing calls it while a room is
open, so a member who joined after the room was opened never appears in the
suggestion list until the room is left and entered again.
Call updateMembers() when a mention search starts. The trigger is
distinctUntilChanged on "the current suggestion is a mention", so it fires
once per mention rather than on every keystroke, and fetchRoomMembers already
no-ops while a fetch is in flight.
* Resolve the real image format before choosing the encoder
The upload pre-processor picks the encoder from the mime type it is
given. When an image is shared from another app that type is often
broader than the image really is, so a transparent PNG shared as a
wildcard image type is re-encoded as JPEG and its alpha channel is
flattened to black.
Read the format from the image header when the declared type is not
already a concrete PNG or JPEG, and use that to decide both whether the
image can be compressed at all and which encoder to use.
* Cover the mime type fallbacks the wildcard resolution introduced
resolveImageMimeType now decides whether an image is compressible, so two of
its outcomes had no test: a GIF shared with a wildcard type has to be
recognised and left uncompressed rather than recompressed into a still, and a
file the decoder cannot read at all has to fall back to the type it was shared
with.
The isMimeTypeImage() guard on the decoded type is dropped with them. The
BitmapFactory decoders only ever report an image type in outMimeType, so the
guard could not fire and there was no way to exercise it.
* Update dependency org.matrix.rustcomponents:sdk-android to v26.08.17
* Fix API breaks:
- `ClientBuildException.WellKnownLookupDisabled` should be handled now.
- `Client.sendReply` returns a `Result<SendHandle>` now. We can ignore it like we do for `Client.send`.
---------
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Jorge Martín <jorgem@element.io>
* Extract `IsEnterpriseBuild` use case
Having it inside `EnterpriseService` made having DI cycles with the `BuildMeta` provider too easy
* Rename `EnterpriseService.defaultHomeserverList()` to `homeserverAllowList()`
This seems more aligned with the way this list works
* Move most of the logic from `:libraries:wellknown` to `:enterprise:feature:enterprise`, both `shared` and `impl` modules
Ideally I would have added everything into `impl`, but some of the classes needed to be shared between the different `:enterprise:features` modules, and those are in the `shared` module, lacking a better name/strategy
* Add `EnterpriseService.isElementProEnforced`
With this, we don't need to provide the `RemoteEnterpriseConfig` anymore to any consumers, everything goes through `EnterpriseService` or other providers
* Remove `EnterpriseService.overriddenElementWellKnown`
This leaks the remote enterprise config/element well known contents to the app in a public interface.
* Create `CustomMapTilerConfigProvider` to avoid leaking the `RemoteEnterpriseConfig` in public APIs
This commit also starts moving some of the well-known related values to the enterprise modules
* Add missing docs to `EnterpriseService` and `SessionEnterpriseService`
* Fix tests
* Fix lint issues
* Bump enterprise module
* Explain a rate limiting push gateway in the notification troubleshooter
The push loop back test printed whatever HTTP status the gateway
answered, so a user throttled by the public ntfy.sh gateway was told
"Error: HTTP 507", which reads as a server fault rather than as a quota
they can wait out or move away from.
Map the two statuses that mean the notification was throttled onto a
typed failure and give the troubleshooter a message that says what to do.
* Import strings from localazy, remove `temporary.xml` in `:libraries:push:impl`
---------
Co-authored-by: Jorge Martín <jorgem@element.io>
Images are downscaled against a 640px reference, which makes inSampleSize
halve the source one step further than the documented intent: the KDoc
says images should be sent at up to 1280x1280, but a 12000x3916 photo is
sent as 3006x979. Text in screenshots and detail in photos is lost at
that size.
Raise the reference to 1280. inSampleSize is a power of two, so this
moves each image one step up rather than to an exact size.
On shorter screens the software keyboard can cover the field the user is
typing into on the login and account provider screens, because nothing
scrolls the content back into the reduced viewport once the keyboard is
shown.
Apply the existing bringIntoViewOnImeVisible modifier to those fields,
the same way the recovery key screen already does.
A slash is valid in the local part of a user id, but in a permalink it
also separates the identifier from an event id, so the SDK could not tell
the two apart and the link fell back to opening matrix.to in a browser.
Only a user id can start with an @, so recover it before handing the URI
to the SDK, and only when the identifier really contains a slash so every
other permalink keeps taking the same path.
fix-pg-map-id.py rewrites the pg_map_id of a dex file, but the dex
format changed and its regex no longer matches anything, so the step is
a no-op and the F-Droid build is reproducible without it. inplace-fix.py
only existed to drive it; none of its other commands are used here.
The removed call also re-ran zipalign -P 16 on each APK. AGP aligns the
release APKs at packaging time and apksigner is already invoked with
--alignment-preserved, so the signed output stays 16 KB aligned.
Adding or editing a media caption from the plain composer sent the
caption as text only: the composer has no HTML to pass, and the media
caption edit was built by hand with a null formatted body, so the
markdown was never rendered. Sending a caption with the same markdown
does render it, because the SDK builds the formatted body there.
Build the edit with the SDK's createCaptionEdit, which runs the caption
through the same markdown conversion the send path uses.
The sanitize() helper applied to the login, password and account deactivation
password fields promises to remove "any new line characters" but only removes
LF. A value pasted from a source with CRLF endings keeps its CR, which is
invisible in the field and is sent to the homeserver as part of the password,
so the login is rejected while typing the same characters by hand works.
Drop every line separator instead of LF only, in both copies of the helper.
Whitespace that can legitimately be part of a password, such as spaces and
tabs, is left untouched.
showLeaveRoomAlert ran its whole body inside client.getRoom(roomId)?.use { }.
When getRoom returned null, which happens for a room the client can no longer
resolve, the body was skipped without writing any state: leaveAction stayed
Uninitialized, so no confirmation dialog and no error was displayed and
Leave room appeared to do nothing at all.
Handle the missing room explicitly and surface it as a failure, which
AsyncActionView already renders with the generic error dialog. leaveRoom used
a !! for the same lookup, so it reported the miss as a NullPointerException;
it now throws the same named exception.
Cover the last remaining interfaces across libraries/audio, libraries/cachestore,
libraries/indicator, libraries/slashcommands, libraries/voiceplayer and
services/apperror, with their members and parameters.
This completes the effort: all 222 in-scope interfaces and their 820 members in
the 60 api modules that hold any now carry documentation.
Notable points: CacheStore applies no expiry of its own and only records when each
entry was written, leaving staleness to the caller; SlashCommandService.parse
never throws, returning NotACommand for ordinary text and an error case for a
malformed command.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Cover the last remaining interfaces across features/announcement, cachecleaner,
call, contentscanner, createroom, knockrequests, lockscreen, rolesandpermissions,
startchat, userprofile and viewfolder, with their members and parameters.
Grouped into one commit rather than eleven near-empty ones, per the AGENTS.md rule
about tiny commits.
This completes every features/* api module.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>