* 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
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.
* Add a message search abstraction over the Rust SDK's local index
Wraps the SDK's search service so the rest of the app never sees MatrixRustSDK
types, following the existing convention in libraries/matrix.
- MessageSearch, MessageSearchService, MessageSearchResult and
MessageSearchPaginationState describe the surface in the api module.
- RustMessageSearch and RustMessageSearchService implement it, with
MessageSearchResultMapper and MessageSearchResultsProcessor turning SDK results
into Kotlin data classes.
- TantivyQueryEscaper escapes the query so a user typing ":)" or "AND" searches
for that literal text rather than tripping the tantivy parser, and joins every
word as a Must clause.
- Fakes and unit tests cover the mapping, the processor and the escaper, the last
checked against a real tantivy 0.26.1 parser.
* Attach the encrypted search index behind a disabled feature flag
Gives the client an on-device tantivy index encrypted with the session's client
secret, so encrypted rooms can be searched at all.
- The index store is attached at ClientBuilder time via withSearchIndexStore, in
a search-index directory alongside the session, keyed on the client secret. A
session without one gets no index.
- MatrixClient exposes isMessageSearchAvailable so callers gate on the real
indexing capability rather than on the raw flag, and getCacheSize() counts the
index directory so it stays visible in the settings figures.
- FeatureFlags.MessageSearch (feature.message_search) is off by default and
isFinished = false. It is read once at ClientBuilder time, so develop stays
releasable and nothing reaches a user.
* Simplify search index wiring following review
Tie search availability to the MessageSearch feature flag alone and let
the index be created without a client secret, encrypting it only when
the session has one, matching the SDK's SQLite stores. Make
getBaseClientBuilder take the flag as a required parameter and return
ClientBuilder directly again, dropping the BaseClientBuilder wrapper
and the mid-restore snapshot parameter. Check the flag through
FeatureFlagService in RustMatrixAuthenticationService instead of
caching it in a field, and revert the extra matrix_sdk_search tracing
target, which belongs in the SDK's defaults.
* Add a password strength estimator wrapping the SDK zxcvbn API
* Add tests for the password strength estimator SDK mapping
---------
Co-authored-by: ElementBot <android@element.io>
* Import Compound tokens from `v10.2.3`
* Remove manually added `bgSubtleTertiary` semantic color: it's in Compound now
* Bump enterprise module to a compatible commit
* Fix insets in several screens
UI components in the room list, room member list, etc. now have better insets based on `WindowInsets.safeDrawing`
* Update screenshots
---------
Co-authored-by: ElementBot <android@element.io>
* Make settings section separators visible in black theme
In the Black (OLED) theme the canvas is forced to pure black while the
section-separator divider keeps its standard-dark colour (outlineVariant,
~10% alpha white), leaving dividers in Settings and related screens almost
invisible. Add an OLED-aware listSectionDivider alias that lightens the
divider only when the black theme is active, and use it for the
ListSectionHeader divider. Light and standard-dark themes are unchanged.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Matt Van Horn <455140+mvanhorn@users.noreply.github.com>
* Set separatorSecondary for Black theme instead of a custom divider alias
Following review feedback: now that the global HorizontalDivider uses
separatorSecondary (#7054), give the Black/OLED theme a visible
separatorSecondary value in ElementTheme instead of carrying a bespoke
listSectionDivider alias. This fixes all separators on pure black, not
just section headers. The exact color is pending design confirmation.
* chore(theme): remove in-code design discussion comment
Move design discussion out of the code per review; the divider color
decision lives in the PR thread.
* Update screenshots
Signed-off-by: Matt Van Horn <455140+mvanhorn@users.noreply.github.com>
---------
Signed-off-by: Matt Van Horn <455140+mvanhorn@users.noreply.github.com>
Co-authored-by: Matt Van Horn <455140+mvanhorn@users.noreply.github.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: ElementBot <android@element.io>
Co-authored-by: Jorge Martin Espinosa <jorgem@element.io>
* Try making `HeaderFooterView` more robust
Create `HeaderFooterLayout` to properly calculate the content size when the component is scrollable so it's at least the size of the available space.
* Make `DesktopNoticeView` scrollable
For this, `NumberedListOrganism` can't be a `LazyColumn`, since that's a lazy layout with no intrinsic height and Compose doesn't know how to size it.
* Fix the case where no header or content composables are supplied
* Fix insets in non-scrollable UI
* Remove `movableContentOf`, suppress the warning instead since the `isScrollable` parameter should never toggle this behavior
* Update screenshots
---------
Co-authored-by: ElementBot <android@element.io>
* Use the right insets in the home screen UI
That's `WindowInsets.statusBar` for the `Scaffold` component, then `WindowInsets.navigationBar` for the `LazyColum.contentPadding`
* Apply it to other screens with long lists of items too
* Apply the insets to `PreferencePage` too
* Apply inset changes to other screens with scrollable content
* Add helper insets/padding values based on review suggestions.
* Use the newly added insets/padding values in several scaffold and scrollable columns
---------
Co-authored-by: ElementBot <android@element.io>
* When no URL is provided to `ContentValidationState.collectMediaState`, assume it's valid
That way we can do:
`if (validationState.isValid() && state.collectMediaState(possiblyNullUrl).isValid()) ...`
* Remove the `eventId` param from `ContentScannerService.scan`
It's not really used, since we then provide a state that can be mutated, and fetching that is what the previous parameter was used for
* Make sure to always validate the medias in the viewer, both the actual media and the thumbnail
* Update screenshots
---------
Co-authored-by: ElementBot <android@element.io>
* Remove no longer temporary string
These are now in localazy and the sync strings CI flow was failing because we have 2 conflicting values in `temporary.xml` and `localazy.xml`
* Use the right placeholder value in `screen_local_network_opt_in_subtitle`
* Localazy: improve search, parallelize checks
The search for XML files has been narrowed down and it's several times faster now, and processing the files is now done in parallel
* Improve script to also find and delete previous files
Also add the option of having a `-v|--verbose` flag to print which files we're modifying
* Use `LocalBuildMeta` to get the app name inside `LocalNetworkPermissionDialogView`
* Allow finding all the forbidden terms in the strings and translations and then return an error exit code instead of a success one
---------
Co-authored-by: ElementBot <android@element.io>