Also, allow instantiating it using a factory: with this we can always decide where to take the config from and how to do it
Do the same for `ElementWellknownStore` so we can store and restore the values for different sources (endpoints) independently
This is an abstraction over an actual unauthenticated `Client` from the SDK that implements `GetUrlResolver`, and is supposed to be short-lived.
With this, we can use the SDK network stack to perform arbitrary GET url operations.
The `AutoCloseable` implementation makes it easier to clean up any leftover local config after using this temporary client.
* Expand the emoji picker to full height when the keyboard is shown
The picker content is rendered with fillMaxSize, so the sheet measures itself to
the full window height. That makes the partially expanded anchor available, and
the modal sheet auto-shows at that anchor, half way down the screen.
The sheet reserves the IME inset through its content window insets, but applies
that padding at its own bottom edge, which is off-screen while it rests half way
down. The band that is both on-screen and above the keyboard is then only about
a tenth of the screen, which is why the matching emoji end up behind it.
Expand the sheet while the keyboard is visible so its bottom edge returns to the
screen edge and the inset it already reserves lands on top of the keyboard.
Modifier.imePadding on the sheet content is not an option: the sheet applies the
insets with windowInsetsPadding, which consumes them, so a nested imePadding
reads zero.
* Cover the keyboard driven sheet expansion with a test
The IME reaction moves into ExpandSheetWhenImeIsVisible so a Robolectric test can
drive it: dispatching window insets to the composition flips
WindowInsets.isImeVisible, and the sheet state is observable from the test. Both
the shown and the hidden case are asserted, which is the patch coverage this
change was missing.
* Do not leave a blank strip below the expanded emoji search
The 10dp of bottom padding on the search bar separates the collapsed
field from the category tabs underneath it. It stayed applied once the
search bar expanded to fill the picker, so the picker stopped 10dp short
of its own bottom edge.
That strip used to sit below the visible part of a half height sheet.
Now that the sheet expands against the keyboard it reads as a gap
between the results and the keyboard, so only pad while collapsed.
* Add default `OAUTH_CLIENT_URL_PATH` alternative
Previously this was `null`, but we want to use `apps/android` instead to identify Element X Android. Element Pro will use a different value, and other custom apps based on EP will use `null` or their own custom value, if they provided one
* Suppress lint check so the pro app can be built
heroes is populated for any room whose name is derived from its members,
not only for direct messages, so a two person room that is not a DM
showed a member's Matrix ID as its subtitle.
Carry isDm on SelectRoomInfo and read the hero only when it is set. The
canonical alias still takes precedence, so nothing changes for a room
that has one.
When the replied to event could not be fetched, the reply preview rendered the
raw SDK error string in critical styling, and tapping it emitted a focus
request that could never succeed, so the user got a dead end dialog.
Render the localised error_message_not_found string in the neutral italic style
already used for redacted and undecryptable replies, and drop the click handler
for that case. The existing key is reused rather than adding a new one; a "you
do not have access" wording was rejected because this state covers any failure
to load the event, not only a permission problem.
MatrixClient had no way to read or write global account data although the
underlying client supports it.
Add getAccountData and setAccountData to the interface and implement them in
RustMatrixClient using the same withContext/runCatchingExceptions idiom as the
neighbouring methods. The content is the raw JSON string the SDK returns and
accepts: event types are open ended, so a typed wrapper belongs to whichever
caller needs one. Scope is limited to global account data; the room level
variant and the change notification APIs can follow when a feature needs them.
The forward and share room picker showed only a display name, so several
direct messages or rooms sharing a name were indistinguishable.
Render a secondary line: the canonical alias when the room has one, otherwise
the other person's Matrix ID for a direct message. No model change was needed,
because heroes is populated only for a direct message with exactly one hero,
so heroes.singleOrNull() is the peer.
The ExoPlayer backing voice messages was built without a wake mode, so it
defaulted to C.WAKE_MODE_NONE and held no wake lock. The CPU was free to
suspend once the screen turned off, cutting playback short.
Build it with C.WAKE_MODE_LOCAL instead. The media is a local file, so no
WifiLock is needed, and android.permission.WAKE_LOCK is already in the merged
manifest. The media viewer players are left alone: they already pause on
ON_PAUSE, so a wake lock there would keep the CPU awake for a player the user
has intentionally backgrounded.
The media viewer is edge to edge and the loading progress indicator was the
top-most child of a container that only applied navigation bar padding, so it
was laid out at y=0, behind the status bar and any display cutout.
Give it safeDrawing horizontal and top padding, reusing the idiom already used
by MediaViewerBottomBar in the same file. The inset deliberately does not come
from the scaffold content padding, which collapses to zero when the user taps
to hide the overlay.
Opening an image from the timeline replaces it with a full-screen page
reading "error". Two things go wrong. The viewer already holds the item
that was tapped, but building the surrounding media timeline can fail and
the failure overwrites that cached item, so the picture the user asked for
disappears. And the failure page renders the exception message straight
from the SDK, which is developer text with nothing actionable in it.
Emit the failure only when there is nothing cached, so a viewer opened on
a specific event keeps showing that event and stays usable while the rest
of the gallery is unavailable. Where there really is nothing to show, the
page now uses the same alert icon, title and message as the other error
states in this screen, built from strings that already exist.
The trade-off is that the timeline error is no longer surfaced in the
cache case; it is still logged. Swapping it for a snackbar would need a
new surface in the viewer and is left out.
With several accounts logged in, sending a message from one of them raises
a notification on every other account that shares the room. The device
notifies its owner about something the owner has just done, and the more
accounts share a room the more copies arrive.
Resolve the set of logged-in user ids once per push batch and drop an event
whose sender is one of the other accounts, using the filtered-out result
the notification pipeline already understands, so it is recorded in push
history rather than turned into a fallback notification.
The receiving session is removed from that set, which keeps the change a
strict no-op for a single account and protects the local echo that the
reply action pushes back through the same path. Filtering happens at the
one point that sees every kind of push, so messages, polls, call invites,
ringing calls and room invites are all covered.
Filtering is unconditional and has no setting; multiple accounts sit
behind an experimental flag that is off by default, so nothing changes for
a stock build.
A fediverse handle such as `@name@server.tld` contains a substring that
`Linkify.EMAIL_ADDRESSES` recognises as a valid address, so the timeline
renders `name@server.tld` as a tappable `mailto:` link. Tapping it opens a
mail composer addressed to an account that does not accept mail.
Drop a newly added `mailto:` span when the character immediately before it
is `@`. This mirrors what Android already does for web URLs, where
`Linkify.sUrlMatchFilter` rejects a match preceded by `@` — which is why
the handle currently produces exactly one stray mailto span and no partial
link is left behind once it is removed.
Author-supplied links are unaffected: spans that were already present
before linkification are excluded from the check and restored as before. A
genuine address written directly after an `@` — "mail me @support@element.io"
— is no longer linkified, which is the same trade-off Android already makes
for web URLs.