Commit Graph

6857 Commits

Author SHA1 Message Date
hayyaksi 7341feeed8 Model the fake voice recorder on a cancellable recording job (#7466)
* Model the fake voice recorder on a cancellable recording job

FakeVoiceRecorder pushed a whole recording synchronously from a single
suspending call, which made it both weaker and stricter than
DefaultVoiceRecorder.

Every level emission carried the same elapsed time and the emissions were
coalesced by Molecule, so no intermediate recording state was observable and
the level-limit test had to skip half the emissions to compensate. Each level
now advances the test time source and suspends for its share of the recording
duration, so the states arrive one at a time and that magic number is gone.

Call verification moved to the constructor lambdas the rest of the repo uses,
in place of hand-rolled counters and assertCalls. The counters discarded the
argument, so nothing pinned that cancelling a recording stops it with
cancelled = true; that is now asserted. Truth is no longer needed by the
fixture module.

A second startRecord() no longer raises an error where production only warns
and returns, and stopping or deleting terminates an in-flight emission loop
the way cancelling the real recording job does, so a stale recording state can
no longer arrive after the recording has finished.

* Keep each recording's level loop to its own recording

The level loop checked a single isRecording flag, which cannot tell "this
recording was cancelled" from "a later recording has started". After a cancel
followed by a new start, the first loop resumed, saw the flag set again, and
advanced the shared test time source, so the new recording reported the elapsed
time of both. Each recording now carries an id and its loop stops as soon as
that id is no longer the active one.
2026-08-19 13:44:11 +02:00
hayyaksi 6bd841d838 Close the invite screen once the invite has been declined (#7440)
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.
2026-08-19 12:52:11 +02:00
hayyaksi ee1348e19e Give the room name in the timeline top bar a 48dp tap target (#7450)
* 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.
2026-08-19 12:29:24 +02:00
Jorge Martin Espinosa a1e86ad499 Use the right base URL for the ESS config/well known endpoints (#7469)
* 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
2026-08-19 09:24:22 +02:00
Jenna Vassar 891c077786 Merge remote-tracking branch 'origin/develop' into feature/account-provider-selection 2026-08-18 17:49:31 -07:00
Jenna Vassar 1b2d5b9c92 Complete account providers without the https scheme and include the enterprise allow-list 2026-08-18 17:03:39 -07:00
Benoit Marty dfbc75a9e1 Merge pull request #7428 from element-hq/feature/bma/timeoutInReadyToScanScreen
[LinkNewDevice] Ensure the notice screen is also protected by the timeout.
2026-08-18 10:07:36 +02:00
Benoit Marty 3c21af2a57 Merge pull request #7437 from hayaksi1/fix/4594-leave-room-not-found
Show an error when the room to leave cannot be found
2026-08-18 10:06:01 +02:00
Benoit Marty c3442d3a03 Merge pull request #7439 from hayaksi1/fix/5153-sanitize-carriage-return
Exclude carriage returns from the login and password fields
2026-08-18 10:05:40 +02:00
Benoit Marty a36ccbaae2 Merge pull request #7455 from hayaksi1/fix/4582-autoscroll-focused-field
Keep the focused login field visible above the keyboard
2026-08-18 10:03:22 +02:00
hayaksi1 0aa283729c Cover every branch of the forward pagination gate
Codecov reported 55.55% patch coverage on the previous commit: four of the nine
measured lines were only partially covered. No test paginates forwards in a
thread timeline, and the focus states Requested, Loading and Failure were never
live when a forward pagination arrived, so only the Success branch of
isPending() was ever evaluated both ways.

Add a test per uncovered state: a forward pagination is deferred while the focus
request is still being debounced and while the focused timeline is being
created, it is performed again once the request has failed, and it is dropped in
a thread timeline while a backward one still goes through.

The pagination recorder now also sits on the live timeline, and the presenter is
built on that same timeline. Before the detached timeline exists, a pagination
that escaped the gate would go to the live one, so without this the new guards
would pass against the unfixed presenter. The deferred cases end on the emitted
state rather than on cancelAndIgnoreRemainingEvents for the same reason: the
recorder throws from inside the presenter coroutine and cancelling swallows it.

Verified by reverting the gate: the three deferred-pagination tests then fail
with "This lambda should never be called."
2026-08-18 00:49:03 +03:00
hayyaksi cb6ac751cc Refresh the room members when a mention is started (#7438)
* 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.
2026-08-17 21:10:08 +02:00
Jenna Vassar 7c48e737c4 Merge remote-tracking branch 'origin/develop' into feature/account-provider-selection 2026-08-17 11:18:46 -07:00
Jenna Vassar a6c7042482 Configure the account provider homeserver only once when signing in 2026-08-17 10:37:27 -07:00
Jenna Vassar bbd6ce134b Fix account provider dropped on first Continue and address review comments 2026-08-17 10:31:17 -07:00
Benoit Marty ad502c07ef Merge branch 'develop' into fix/1270-verification-request-timeout 2026-08-17 18:49:02 +02:00
hayaksi1 03c330ee07 Rename PreviewParameterProvider subclasses to the PreviewParam suffix
The `Provider` suffix reads as a dependency provider rather than as preview
data, and it collides with the real providers in the codebase — `StringProvider`,
`PickerProvider`, the login feature's `AccountProvider` — so the name says
nothing about which of the two a class is. `PreviewParam` says it.

195 classes are renamed, along with the 185 files named after them, the konsist
rule that enforces the convention, the presentation-class file templates and the
onboarding documentation.

This cannot be split. `Konsist.scopeFromProduction()` scans the whole project, so
flipping the assertion before every class has moved leaves the rule red, and a
rule that accepted either suffix during a transition would be exactly the kind of
compatibility layer this convention change is meant to remove.

Two judgement calls in the rule itself. The `name.endsWith("PreviewProvider")`
exclusion is dropped: its only job was to reject a redundant `Preview` before
`Provider`, and the new suffix already contains it; no class currently ends with
`PreviewProvider`, so removing it changes nothing today. And
`EditableAvatarViewUriProvider` is renamed rather than deleted from the exclusion
list even though no such class exists in this repository, since it presumably
comes from the modules overlaid for the enterprise build.

Nothing keyed off the old suffix: no snapshot filename contains a provider class
name, so no Paparazzi image changes, and the Kover variants match on `*Presenter`,
`*State` and `*ViewKt`, so coverage bounds are unaffected.
2026-08-17 17:40:33 +03:00
hayaksi1 8e02f03543 Cover the branches left untested by the uri short circuit
An intent carrying uris is now accepted before the mime type list is
reached, so the image check that every uri share used to exercise is only
covered by an intent which has nothing to send. Add one case per listed
mime type without a uri.

Cover the rest of the handler while it is under test: an intent with no
resolvable type, a send multiple without a stream, an action which is
neither send nor send multiple, an empty caption, a plain text intent
without text, the mime type reported by the content resolver for the uri,
and the explicit intent built for the application which will read it, both
when the read permission can be granted and when it cannot.
2026-08-17 16:35:31 +03:00
Jorge Martin Espinosa 8b2c207728 Move the :libraries:wellknown logic into enterprise modules (#7429)
* 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
2026-08-17 13:21:47 +00:00
hayaksi1 11e3cb9b19 Keep a focused timeline focused until the event has been rendered
Opening a room from a notification asks the timeline to focus the notified
event. When that event is outside the loaded live window the controller
creates a detached timeline for it, and a detached timeline always carries a
forward loading indicator as its last chronological item. The items list is
reversed for display, so that indicator is the bottom-most row and is composed
on first layout, which unconditionally emits a forward pagination request
nobody asked for. Because a notified event sits close to the live end, that one
page reaches the end, and the controller responds by closing the detached
timeline. The live window replaces the item list while it is still anchored at
the bottom, so the user lands on the newest message and the focus request is
discarded.

Defer automatic forward pagination while a focus request is still pending. Once
the focused event has been rendered the viewport has moved off the indicator
row, so only a real scroll back to the live end switches to the live timeline,
which is what the controller's existing behaviour is for. Backward pagination
and the explicit jump-to-live action are untouched.
2026-08-17 16:20:43 +03:00
Cipherd f94566e44f Fix outgoing session verification stuck with incomplete recovery setup (#7433) 2026-08-17 15:14:45 +02:00
hayaksi1 5bfb614bdb Restore the UnusedImports suppression on the outgoing verification test
ktlint reports the TestScope import as unused because the type only appears in
a context parameter, which the rule does not look at. The file carried a
file-level suppression for exactly that before this branch dropped it.
2026-08-17 15:37:11 +03:00
Benoit Marty 054d592391 Sync again 2026-08-17 12:10:39 +02:00
Benoit Marty 5ac1fe2409 Remove temporary string. 2026-08-17 12:10:18 +02:00
Benoit Marty a740423343 Sync strings. 2026-08-17 11:34:52 +02:00
hayaksi1 9a4daa19b2 Keep the focused login field visible above the keyboard
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.
2026-08-17 11:33:10 +03:00
hayaksi1 fcecc7acba Give up on a verification request the other session never accepts
The outgoing verification flow had no client side timeout: if the other
session never answered, the screen waited on "Waiting to accept request"
for as long as the user left it open, with no indication that the
request could no longer succeed.

Bound the wait to the ten minutes the Matrix specification gives a
verification request. Past that the other session can no longer accept
it, so cancel the request and move to the canceled state, which already
offers to start again.
2026-08-17 11:33:10 +03:00
Benoit Marty 2ac11ebe14 Clarify the comments 2026-08-17 10:30:57 +02:00
Benoit Marty d0a1011638 Add documentation on LinkNewDesktopHandler and LinkNewMobileHandler 2026-08-17 10:06:26 +02:00
Benoit Marty aa6f70530a [LinkNewDevice] Move the timeout management when linking a new desktop device to the LinkNewDeviceFlowNode so that it can also be used for the DesktopNotice screen. 2026-08-17 10:06:25 +02:00
hayaksi1 39afaa1fe4 Do not render in-chat key verification requests in the timeline
A m.key.verification.request sent from a client that supports in-chat
verification carries a plain text body for clients that do not. Element X
has no msgtype of its own for it, so it fell through to OtherMessageType
and the timeline printed that body, telling the user their client does
not support in-chat key verification right after a verification they had
just completed.

Drop the event when building the timeline items, as Element X iOS does.
2026-08-17 03:44:53 +03:00
hayaksi1 c901b902b1 Exclude carriage returns from the login and password fields
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.
2026-08-16 22:44:48 +03:00
hayaksi1 04dcc14eaa Show an error when the room to leave cannot be found
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.
2026-08-16 22:44:29 +03:00
hayaksi1 2c0da1cadf Share a file whose mime type is not one of the supported ones
handleIncomingShareIntent only accepted an intent whose resolved mime type
started with image/, video/, audio/, application/, file/, text/ or */. An
ACTION_SEND carrying EXTRA_STREAM with any other top level type, such as the
message/rfc822 that some apps use when attaching a file, fell through to null
and the share was dropped before the room picker ever appeared, even though
the manifest filter accepts */*.

The uris are extracted before that check, so their presence is enough to know
the intent carries something to send. Accept the intent when it has uris and
keep the mime type list for the case where it does not.
2026-08-16 22:44:11 +03:00
Benoit Marty 23b75c3423 Fix outdated documentation. (#7430) 2026-08-15 11:05:43 +02:00
Benoit Marty e1adc938fd Merge pull request #7424 from element-hq/revert-7378-fix/6853-remember-revealed-images
Revert "Keep manually revealed media visible when re-entering a room"
2026-08-14 17:37:31 +02:00
Jenna Vassar 54ba43a8ec Use the correct license header on the new account provider history files 2026-08-14 08:12:51 -07:00
Jenna Vassar 89e2abaeeb Merge develop into feature/account-provider-selection 2026-08-14 07:51:17 -07:00
bxdxnn 67b48ae184 Fix build failure 2026-08-14 12:55:53 +00:00
Benoit Marty 9e32801d02 Merge pull request #7426 from element-hq/feature/bma/documentation
Add KDoc to all the interfaces of the api modules
2026-08-14 13:46:28 +02:00
Benoit Marty 1ab401482a Fix formatting issues 2026-08-14 12:20:49 +02:00
Benoit Marty 9822b3d4f7 Add KDoc to the single-interface feature API modules
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>
2026-08-14 12:00:42 +02:00
Benoit Marty 1b4d6c07fa Add KDoc to the authentication, logout, preferences and share API interfaces
Cover the remaining interfaces of features/login, features/logout,
features/preferences and features/share, along with their members and parameters.

Points recorded here: AccountProviderAccessControl returns true on a build with no
enterprise restriction, ExtraDeveloperOptionsRenderer is bound to a no-op in the
standard build, DirectLogoutView draws nothing until a logout event is sent, and
CacheService exists because clearing a cache destroys the client and the app has
to react.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-14 11:53:37 +02:00
Benoit Marty fa123d941b Add KDoc to the features/invite API interfaces
Document AcceptDeclineInviteEvents, AcceptDeclineInviteView and the
SeenInvitesStore interface.

The view doc explains why it is a shared component rather than part of one screen:
it is embedded everywhere an invitation can be acted on, so the confirmation
dialogs behave identically in the invite list and in a room preview.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-14 11:51:32 +02:00
Benoit Marty c4c7dac9cf Add KDoc to the features/rageshake API interfaces
Document RageshakeFeatureAvailability, LogFilesRemover and the BugReporter
interface, and complete the docs of its remaining members.

The BugReporter doc records that progress and the outcome arrive through the
listener passed to sendBugReport rather than through a return value or an
exception.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-14 11:48:59 +02:00
Benoit Marty 57658640e1 Add KDoc to the features/location API interfaces
Document LocationService, StaticMapUrlBuilder, TileServerStyleUriBuilder and the
members of ActiveLiveLocationShareManager that had none.

The two URL builders now say what happens when no map provider is configured for
the build, which is the case LocationService.isServiceAvailable exists to guard.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-14 11:48:58 +02:00
Benoit Marty c32f81f696 Revert "Keep manually revealed media visible when re-entering a room" 2026-08-14 10:49:24 +02:00
Benoit Marty 055fe408a6 Add KDoc to the features/roommembermoderation API interfaces
Document RoomMemberModerationState, RoomMemberModerationEvents and
RoomMemberModerationRenderer along with their members and parameters.

The renderer doc states that it draws nothing until the host screen asks for a
member's actions, and that onSelectAction exists so the host can navigate for the
actions that need a screen of their own.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-14 10:06:53 +02:00
Benoit Marty 50214fe01a Add KDoc to the features/poll API interfaces
Document PollContentStateFactory, SendPollResponseAction and EndPollAction along
with their members and parameters.

The two action interfaces exist to wrap a plain timeline call, so their docs say
what they add: both capture an analytics event on success, which is the reason
callers should go through them rather than calling the timeline directly.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-14 10:06:47 +02:00
Benoit Marty 76411b07fb Add KDoc to the features/leaveroom API interfaces
Document LeaveRoomState, LeaveRoomEvent and LeaveRoomRenderer.

The renderer doc records the two things a host screen needs to know, both taken
from LeaveRoomPresenter and LeaveRoomView: it draws nothing until a leave event is
sent, and onSelectNewOwners fires specifically when the user is the last owner of
a room that still has other members.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-14 10:05:31 +02:00