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
* 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>
* 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>
* Add read all messages feature: read all messages using Client.markAllRoomsAsRead() method
* Move the 'mark all rooms as read' footer as part of the list item
* Replace `showMarkAllRoomsAsReadConfirmation` and its associated event with `MarkAllRoomsAsRead(val needsConfirmation: Boolean)` and a `AsyncAction.Confirming` state
---------
Co-authored-by: Jorge Martín <jorgem@element.io>
* Make Vulkan a *not required* feature
* Add `DeviceHasVulkanSupport` helper to check this on runtime
* When trying to open a screen with a map in it, check if vulkan is supported and display a new error dialog in that case
* Fix random lint issue
* Update screenshots
---------
Co-authored-by: ElementBot <android@element.io>
* Notification settings: pick custom sounds for messages and call ringtones (#6702)
* Feature: add notification sound settings for messages and calls
* Add sound not available banner, accessibility checks
* Fix build and Konsist convention violations
- libraries:preferences:api now uses io.element.android-compose-library
so NotificationSound's @Immutable annotation can resolve, matching the
pattern in libraries:matrix:api.
- Rename SoundUnavailableBannerStateProvider to
NotificationSoundUnavailableStateProvider so the class name contains
the parameter type as required by KonsistClassNameTest.
* Suppress LargeClass on RoomListPresenterTest
The three new sound-unavailable tests pushed the class past Detekt's
default LargeClass threshold. Matches the suppression pattern already
used on five presenter test classes under features/messages/impl/test.
* NotificationSettingsView: guard ringtone-picker launchers in inspection mode
rememberLauncherForActivityResult requires a LocalActivityResultRegistryOwner,
which Paparazzi-driven preview snapshot tests don't provide, causing
NotificationSettingsViewPreview to throw IllegalStateException for every
preview parameter. Extract the click handlers into a helper that returns a
no-op when LocalInspectionMode.current is true; the runtime path is unchanged.
* Handle unresolved notification sounds mid session
* Quality checks, refactor mid session error ui
* Suppress detekt LargeClass on NotificationSettingsPresenterTest
* Remove notification sound resilience layer, replace with file copy
* Reselect element sound option, code cleanup
* Add element fade notification sound option
* Fix new file headers
* Revert to flowOf(Unit) for announcement service
* Add ringtone picker dialog to match message selector
* Update strings in conjunction with ios
* Update test to reflect new string
* Sync strings.
* Update screenshots
* Fix test
* Remove not properly located translations.
This will be fixed in the next String sync.
* Fix test on CI
---------
Co-authored-by: Jenna Vassar <jenna.vassar@toptal.com>
Co-authored-by: ElementBot <android@element.io>
Resolved conflicts:
- libraries/matrix/impl/.../fakes/FakeFfiSpaceRoomList.kt: took upstream's
direct return for rooms() — the simulateLongTask wrapper is for IO-style
operations like paginate/reset, not a quick read.
- libraries/ui-strings/src/main/res/values/temporary.xml: kept the file with
only the live strings (action_mark_as_read, a11y_jump_to_unread_messages).
Dropped common_black (upstream moved theme strings to module-local R.string)
and a11y_jump_to_unread_messages_count (badge count was removed earlier).
- RoomInfo.kt and its fixtures/tests: took upstream's version since both
branches independently added fullyReadEventId via the same SDK bump
(matrix-rust-components-kotlin 26.05.20).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* Attempt to fix room list item duplicates at midnight
This seems to happen because of a race condition between `RoomListDataSource.observeDateTimeChanges` and `RoomListDataSource.replaceWith` being called at almost the same time and the first one using the newly received items from observing the timeline items but not updating the cache which will be later reused by `replaceWith`, containing incorrect indices
* Set `DmRoomDefinition.TwoPeople` in `ClientBuilder`. This applies the 'direct and with at most 2 non-service members' rule to what the SDK should consider a DM.
* Map `RoomInfo.isDm` from the SDK
* Map `NotificationData.isDm` from `NotificationInfo.roomInfo.isDm`
* Remove `RoomIsDmCheck` file as its extension functions are now redundant. Move `Room.isDm` helper function to `BaseRoom`.
* Map `isDm` in `SpaceRoom` from the SDK too
* Replace `isDirect` with `isDm` where possible
* Map `RoomMember.isServiceMember` from the SDK and use it to tell apart normal members of a room from service members (i.e. `RoomMembersState.getDirectRoomMember`)