Commit Graph

16439 Commits

Author SHA1 Message Date
hayaksi1 bc20e64c61 Do not notify about a redaction whose target event is unknown
A redaction push whose redacts field the SDK could not map was reported as
an unknown error. The result processor only suppresses filtered-out and
redacted events; every other exception becomes a visible "you have N
notifications" fallback and also raises the battery optimisation banner.

So a deleted message could produce a notification about itself, which is
the opposite of what a redaction means, plus an unrelated banner.

The branch now throws EventFilteredOut, which the processor already drops
silently, and logs at warning level so the SDK gap still shows up in push
history.

Relates to https://github.com/element-hq/element-x-android/issues/5766
2026-08-09 04:09:35 +03:00
hayaksi1 4b85e2d31e Turn a matrix: URI in a message into a pill
A permalink written as a matrix: URI stayed plain text, while the same
link in matrix.to form became a pill. The pillifier only scanned
Patterns.WEB_URL, which cannot match a URI with no web scheme, even though
the permalink parser already understands matrix: URIs.

Those URIs are now scanned for as well, before the web pass, since
Patterns.WEB_URL otherwise claims the bare domain inside the URI and
whichever pass runs first wins the range. Each match also gets a URLSpan:
the timeline only reports URLSpans as clicks, so without one the pill
would look right and do nothing.

The composer path is untouched, since it pillifies without permalinks.

Relates to https://github.com/element-hq/element-x-android/issues/5319
2026-08-09 04:09:32 +03:00
hayaksi1 1024323661 Send a message with Enter on a physical keyboard, Shift+Enter for a new line
With a hardware keyboard attached, Enter inserted a newline and the only
way to send was to reach for the send button, which is the opposite of
what every desktop chat client does.

MarkdownEditText gains an optional Enter listener and consumes Enter when
it comes from a physical keyboard without Shift. Shift+Enter keeps
inserting a newline, and a key event from the on-screen keyboard is
identified by its VIRTUAL_KEYBOARD device id and left alone, so nothing
changes for touch users. The key release is consumed as well, so no
newline leaks out on key repeat.

TextComposer passes its existing send lambda through, guarded by the same
canSendTextMessage check the send button already uses, so Enter cannot
send an empty message.

Relates to https://github.com/element-hq/element-x-android/issues/860
2026-08-09 04:09:30 +03:00
hayaksi1 717efe46c5 Do not offer to start a call in a DM with no other member
A DM whose other member has left still offered the call button. Starting
that call put the user alone in a room nobody could join, with no way out
of the call screen.

The presenter now clears canStartCall for a DM with no other active
member. activeMembersCount counts joined and invited members, so a fresh
DM whose peer has been invited but has not joined yet can still start a
call. Joining an already ongoing call is untouched, so a call started
before the other member left stays reachable.

Relates to https://github.com/element-hq/element-x-android/issues/6189
2026-08-09 04:09:27 +03:00
hayaksi1 1be87994b1 Never re-encode a video at a higher bitrate than the source
The compression config computed a target bitrate purely from the output
resolution and frame rate, ignoring the bitrate already extracted from the
source. A clip that is small because it was efficiently encoded, rather
than because it is short, was therefore re-encoded upwards: the upload got
slower and the resulting file was larger than the original.

The target is now clamped to the source bitrate when that is known.
METADATA_KEY_BITRATE is the container total, video plus audio, so it is a
safe upper bound for the video track alone. An unknown or zero bitrate
still falls back to the calculated value.

Relates to https://github.com/element-hq/element-x-android/issues/4191
2026-08-09 04:09:24 +03:00
hayaksi1 0ccb9b23cc Linkify URLs whose host is a bracketed IPv6 address
Patterns.WEB_URL, which LinkifyCompat uses to find links, has no
production for a bracketed IPv6 authority, so a URL such as
http://[2001:db8::1]:8008/path was never turned into a link. Worse, the
phone number matcher claimed the digit runs inside the address, leaving a
tel: link over part of it.

LinkifyHelper now runs its own pass for those URLs. It requires both a
scheme and the brackets, so array syntax like values[0]:1 is not matched,
and it runs after LinkifyCompat.addLinks, which strips any span set before
it, but before the pre-existing spans are restored, so real anchors and
pill spans keep their precedence. Any span Linkify left inside the address
is evicted, and the same trailing punctuation trimming as the other links
is applied.

Relates to https://github.com/element-hq/element-x-android/issues/2614
2026-08-09 03:51:49 +03:00
hayaksi1 75ab17af57 Stop a right to left sender name from reordering a room list preview
A room list preview is one paragraph, and its direction is resolved from
the first strong character. A sender whose display name is Arabic or
Hebrew therefore flipped the whole line: the message body moved to the
wrong side of the name and the separating colon jumped to the front.

The sender's display name is now wrapped in Unicode isolate characters
before it is used as a prefix, so its own direction cannot escape it. Both
places that interpolate the name are covered: the prefix path and the
emote path, which bypasses it.

prefixWith itself is deliberately left alone, since the pinned messages
banner shares it and only ever passes localised nouns. The "You" prefix is
localised rather than user-provided and is not isolated.

Relates to https://github.com/element-hq/element-x-android/issues/3338
2026-08-09 03:51:49 +03:00
hayaksi1 b5e95e27d4 Do not group timeline messages sent more than five minutes apart
Consecutive messages from the same sender were grouped into one bubble
block no matter how far apart they were sent, so a reply hours later
looked like part of the earlier burst and lost its own timestamp header.

computeGroupPosition now folds a five minute limit into the two
groupability flags it already computes. The delta is symmetric between a
pair of neighbours, so both items always agree on where the block splits
and every branch of the existing decision table keeps working unchanged.

Breaking a group on reactions, which the iOS client also does, is a
separate divergence and is not part of this.

Relates to https://github.com/element-hq/element-x-android/issues/4757
2026-08-09 03:51:48 +03:00
hayaksi1 e63c897ec2 Ignore a second voice recording start while one is already running
The composer emits Start whenever the voice message state is Idle, and the
state only leaves Idle once the recorder has produced its first audio
buffer. A second tap inside that window started a second recording, which
overwrote the output file, re-initialised the encoder while the first one
was still encoding, and orphaned the first job together with its
AudioReader.

The orphan kept the microphone open and kept emitting Recording for the
rest of the session, so Stop and Delete appeared to do nothing until the
room was left and re-entered, and re-initialising the encoder under an
active encode could crash natively.

DefaultVoiceRecorder.startRecord now runs under the mutex it already owns
and returns early when a recording job exists, so the second start is a
no-op: no file, no encoder re-init and no second AudioReader.

Relates to https://github.com/element-hq/element-x-android/issues/5780
2026-08-09 03:51:48 +03:00
hayaksi1 de0e628512 Show the account a UnifiedPush registration belongs to in the distributor
A distributor such as ntfy or DAVx5 lists every registration it holds, but
Element registered each one with no message for the distributor, so an
account added from a second session was indistinguishable from the first.

RegisterUnifiedPushUseCase.execute now takes the session id and passes it
as messageForDistributor, which the connector has accepted since 3.x. The
value is the raw Matrix ID, which is not personal data by the project's
own logging rules, and no new string resource is needed.

UnifiedPushProvider already has the MatrixClient in hand at the only call
site, so the PushProvider interface is unchanged and nothing outside the
module moves.

Relates to https://github.com/element-hq/element-x-android/issues/6426
2026-08-09 03:51:48 +03:00
hayaksi1 17365a50d1 Keep saving files to Downloads once 32 files share the same name
MediaStore de-duplicates the display name of a new file itself, but its
uniquifier gives up after 32 collisions and throws IllegalStateException.
Saving then failed with "Sorry, an error occurred" and wrote nothing, and
because image.png is the name most screenshots arrive with, a user who
saves media regularly could reach a state where that name never saved
again without deleting files from Downloads by hand.

A new saveWithUniqueFileName helper in androidutils retries the insert
once with a suffixed name when the platform reports it cannot build a
unique one; a second failure propagates so genuine errors still surface.
withFileNameSuffix builds that name by inserting the suffix before the
extension, and handles names without one.

Both call sites are fixed: AndroidLocalMediaActions and DefaultFileSave
carried byte-identical logic and therefore the identical defect. While in
AndroidLocalMediaActions, a null output uri from ContentResolver.insert
now throws instead of reporting success without writing anything.

The pre-Android-Q path is untouched: it overwrites rather than
uniquifying, so it never reaches this limit.

Relates to https://github.com/element-hq/element-x-android/issues/6371
2026-08-09 01:59:25 +03:00
hayaksi1 e8ca16b74f Ignore a room list filter that is incompatible with an already selected one
Some room list filters are mutually exclusive, and the UI expresses that
by hiding the incompatible chips rather than disabling them. Nothing
enforced the rule on the write path, so two chips tapped in the same
frame, before the list could recompose, both applied. The room list then
matched nothing while the offending chip was hidden, leaving no way to
see or undo what was filtering the rooms.

DefaultFilterSelectionStrategy.select() now ignores a filter that is
incompatible with one already selected, so the same table buildFilters()
uses to hide chips also governs the selection itself. The currently
applied filters win and the late tap is dropped, which matches the
existing design where an incompatible chip is already on its way out of
the UI when it is tapped.

toggle(), deselect(), clear() and the FilterSelectionStrategy interface
are unchanged.

Relates to https://github.com/element-hq/element-x-android/issues/5383
2026-08-09 01:59:25 +03:00
hayaksi1 c7d8973507 Do not append the application MapTiler key to a custom map style url
When a homeserver publishes a map_style_url in its .well-known file, the
app appended its own MapTiler API key to it, producing a URL with two
query strings that the tile server rejects. The map then failed to load
for every user of that homeserver, with no way for the operator to opt
out.

MapTilerTileServerStyleUriBuilder.build() now appends ?key= only to the
URL it composes itself from the bundled base url and map ids. A non
blank customMapStyleUrl is returned verbatim, so the operator's own
credentials survive. This matches Element Web and the self-hosted tile
server documentation, both of which treat map_style_url as complete.

The two existing tests that pinned the old behaviour are updated, and
cases are added for a custom URL that already carries a key, one that
carries an unrelated query string, and a blank url falling back to the
built-in style.

Relates to https://github.com/element-hq/element-x-android/issues/7289
2026-08-09 01:59:25 +03:00
Jenna Vassar d7e6b64265 Dismiss the keyboard on continue and restore it after an error 2026-08-07 12:46:11 -07:00
Jenna Vassar 8c2cf9d95e Reference the Figma design on the account provider screen 2026-08-07 12:04:01 -07:00
Benoit Marty e66efcfc43 [LinkNewDevice] Disable QrCode rotation
#7303
2026-08-07 17:46:47 +02:00
Benoit Marty 2b2d86a804 Use Kotlin Duration. 2026-08-07 17:46:46 +02:00
Benoit Marty 4485c8a4c0 [LinkNewDevice] Fix second and next attempts to unlock using biometric failures.
`cipher.doFinal` cannot be called several times.
2026-08-07 17:46:46 +02:00
Benoit Marty 33979b6574 [LinkNewDevice] Add a 2 minutes timer to scan a QrCode
#7303
2026-08-07 17:46:46 +02:00
Benoit Marty 044737a3a7 Merge pull request #6719 from element-hq/feature/bma/qrCodeLoginIteration
QR code login iteration
2026-08-07 17:31:50 +02:00
Benoit Marty 668243f658 Use value instead of first(). 2026-08-07 16:43:52 +02:00
Benoit Marty 8f8c3af8c5 [LinkNewDevice] Log continuation / cancellation failure. 2026-08-07 16:42:49 +02:00
ganfra 06862ff3b2 Test synchronizes on profile persistence instead of advanceUntilIdle 2026-08-07 16:30:03 +02:00
bxdxnn d36daca242 Fix 2026-08-07 13:44:43 +00:00
bxdxnn 221f13269e Fix 2026-08-07 13:42:16 +00:00
bxdxnn a04078aa9d Address review 2026-08-07 13:38:20 +00:00
ganfra 7d5877c659 Merge pull request #7330 from element-hq/renovate/constraintlayout.compose
Update dependency androidx.constraintlayout:constraintlayout-compose to v1.1.2
2026-08-07 14:44:47 +02:00
ganfra 9b39843e69 Add withProfilesExtension override to FakeFfiSyncServiceBuilder 2026-08-07 14:22:52 +02:00
renovate[bot] df925c29e4 Update dependency org.jsoup:jsoup to v1.23.1 (#7332)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Benoit Marty <benoitm@element.io>
2026-08-07 14:06:22 +02:00
Benoit Marty 64ba29f91a Merge branch 'develop' into feat/polls-max-selections 2026-08-07 14:03:17 +02:00
Benoit Marty 07ca468847 Merge pull request #7136 from element-hq/fix/a11y-invite-people
Announce checked/unchecked state for user rows in invite screen
2026-08-07 14:00:01 +02:00
ElementBot b7c0374c7c Update screenshots 2026-08-07 09:53:47 +00:00
ganfra 14c0944d22 Merge branch 'develop' into feature/fga/user_status_last_pieces 2026-08-07 11:35:19 +02:00
Benoit Marty 293faec03b Merge pull request #7175 from element-hq/renovate/androidx.compose.material3-material3-1.x
Update dependency androidx.compose.material3:material3 to v1.5.0-alpha23
2026-08-07 10:45:22 +02:00
ganfra 8d2686d1a9 Merge branch 'develop' into feature/fga/user_status_last_pieces 2026-08-07 10:12:32 +02:00
renovate[bot] e1daec6728 Update dependency androidx.constraintlayout:constraintlayout-compose to v1.1.2 2026-08-07 08:06:16 +00:00
renovate[bot] 8a164228bd Update dependency com.google.firebase:firebase-bom to v34.17.0 (#7333)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Benoit Marty <benoitm@element.io>
2026-08-07 10:02:28 +02:00
Benoit Marty b5e9f42058 Fix compilation issue 2026-08-07 09:52:54 +02:00
ElementBot 0e1cb2df5e Update screenshots 2026-08-07 07:20:49 +00:00
ElementBot ed44cd776c Update Gradle Wrapper from 9.6.1 to 9.7.0 (#7335)
Signed-off-by: gradle-update-robot <gradle-update-robot@regolo.cc>
Co-authored-by: gradle-update-robot <gradle-update-robot@regolo.cc>
2026-08-07 09:12:21 +02:00
renovate[bot] e3ce557576 Update metro to v1.4.0 (#7334)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-08-07 09:08:52 +02:00
Benoit Marty 701cf4b2f9 Merge branch 'develop' into renovate/androidx.compose.material3-material3-1.x 2026-08-07 09:06:19 +02:00
Jenna Vassar d04a3853b4 Add inline autocomplete for the account provider field 2026-08-06 12:11:18 -07:00
Jenna Vassar c2b3b0fe0f Remove the account provider search screen and homeserver resolver 2026-08-06 11:31:32 -07:00
Jenna Vassar df6ccd9dc3 Consolidate account provider selection into a single editable screen 2026-08-06 11:31:25 -07:00
renovate[bot] d3f35cb90c Update dependency io.element.android:element-call-embedded to v0.23.0 (#7323)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-08-06 18:39:06 +02:00
renovate[bot] 73119273c2 Update dependency org.maplibre.gl:android-sdk to v13.4.1 (#7305)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-08-06 18:38:49 +02:00
renovate[bot] 87b56861e6 Update dependency io.sentry:sentry-android to v8.51.0 (#7301)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-08-06 18:38:21 +02:00
Benoit Marty e568f1ec7a Fix deprecation warning on androidx.compose.material3.ListItem 2026-08-06 18:37:25 +02:00
Benoit Marty c8c8971889 Fix detekt false positive 2026-08-06 18:35:18 +02:00