One GET to our own Gitea per launch is nothing, and it makes the updater
predictable: publish a release, users see the banner on next open.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
ntfy.sh silently blocks Matrix gateway traffic, which is why the embedded
provider never delivered despite a sound code path. Existing installs
re-register against the new server automatically on next app open
(ensurePusherIsRegistered runs every launch).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
mautrix-discord nests server/DM spaces inside a top-level Discord space;
filtering on the container's direct children matched no rooms, so the rail
tap looked dead. The selection filter now walks child spaces recursively
(cycle-guarded), matching element-web's SpaceStore behavior.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Rail: desktop parity (element-web rootSpaces) — spaces nested inside another
joined space no longer get a rail entry; their rooms stay reachable through
the parent space. Nested set persisted for clean cold starts.
Updater: new libraries/blapupdate module checks the git.utn.lol release feed
(6h throttle), offers a banner at the top of the chat list, downloads the
ABI-matched APK and hands it to the system installer. Per-version dismissal.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Match desktop's SpaceStore.showInHomeSpace exactly: Home = orphaned rooms +
all DMs (bridged included) + invites. Space-owned non-DM rooms stay inside
their spaces. Replaces the previous too-aggressive rule that also hid
bridged DMs, and no longer exempts filter chips (desktop does not).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Space rail: selecting a space while another is selected kept serving the old
filter (unkeyed remember in SpaceFiltersPresenter) — key it on the space id.
Home: track child lists of all spaces (not just the selected one) and hide
space-owned rooms at Home, Discord-style. Filter chips still search everything;
the owned set is persisted so Home is clean on cold start. Voice rooms now
classify in every space without visiting it first.
ntfy: reconnect immediately when the default network returns instead of
waiting out up to 5 minutes of backoff, and surface the socket state
(Connected/Reconnecting) in the foreground-service notification.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Upstream's non-enterprise build hardcoded Posthog+Sentry providers into the
APK (opt-in prompt, Element endpoints). Analytics is now always
AnalyticsConfig.Disabled: the no-op service compiles in, the provider
modules never enter the dependency graph.
- The rail's new name labels were dead zones (click lived only on the avatar),
which shifted and broke taps across the whole rail — the entire item
(avatar + label) is one click target now
- Drag-to-arrange is an explicit mode entered from the room long-press menu
("Reorder rooms"): whole rows drag, a banner with Done exits. The previous
avatar long-press handle fired the context menu at the same time
- Space selection now unions the space's real child list (spaceRoomList) into
the SDK descendants filter: mautrix-telegram spaces (children are DM portals)
showed an empty room list, and DMs vanished inside every space
- Long-press-drag the avatar to manually reorder rooms within a section,
persisted per space (desktop parity); long-press elsewhere keeps the
context menu
- Home starts with Text/Voice sections collapsed (unread rooms still poke
through) so DMs stay in reach; inside a space sections start expanded
- Call participant rows show resolved display names + real avatars
- Space rail items get name labels (identical bridge logos were
indistinguishable)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The participants row was gated on the voice-room classification, which only
happens after the room's space was opened once — so live calls showed nobody.
Now any room with active call participants lists them, with initial-letter
avatars instead of plain dots.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Login/onboarding: Element swirl logo replaced with the purple five-dot mark,
onboarding + migration backgrounds regenerated as purple gradients
- Space rail: Discord-style animated selection pill on the left edge, corner
morph + accent ring on the selected item (there was no visible cue before)
- DM rows: bridged DMs (Discord/Telegram/WhatsApp/Signal/Slack/IRC/XMPP,
detected from the ghost user's mxid prefix) get a colored network badge
on the avatar
- Room list: section order now matches desktop everywhere — Text, Voice,
DMs last (the DMs-first-at-Home special case is gone)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Drops upstream's CalVer versionCode entirely; one-time downgrade means
pre-1.0.4 installs need a single uninstall/reinstall (accepted).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
versionCode stays on the monotonic CalVer formula (Android forbids downgrades);
only the user-visible version name changes.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Everything from port rounds 1-5 plus today's fixes, on top of upstream develop:
- Branding: Blap name/id (lol.utn.blap), purple #7c66e0 accent (both colorGreen*
and colorAlphaGreen* Compound ramps remapped), Hanken Grotesk, squircle
avatars, five-dot notification icon, de-branded strings across all locales
- Push: new libraries/pushproviders/ntfy module — FGS websocket to an ntfy
server's Matrix gateway, no Google. Includes base64 payload decode, restart
on boot/update/app-open, background-FGS-start crash guard, and a proactive
battery-optimization banner (Doze kills the socket without the exemption)
- Spoilers (MSC2010, interops with Blap desktop 1.0.3): render + tap-to-reveal,
Discord ||text|| send syntax, SPOILER_ filename convention for media both ways
- Home: Discord-style space rail, client-side room-list sections, DM-first sort
- Calls: embedded Element Call fork 0.20.3 assets (camera-off joins, bottom strip)
- Threads on by default; RTC ping timeline items hidden; reply-quote restyle
- URLs now point at git.utn.lol/enki/blap (was codeberg); version 26.07.2
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* Announce expanded/collapsed state on the timeline group header
GroupHeaderView (the accordion-style header used for grouped state
events in the timeline) uses toggleable() combined with
clearAndSetSemantics { contentDescription = text }. The
clearAndSetSemantics block discards the state information that
toggleable() would otherwise expose, so TalkBack never announces
whether the group is currently expanded or collapsed.
Add an explicit stateDescription (two new a11y_state_expanded /
a11y_state_collapsed strings in temporary.xml) alongside the existing
contentDescription so the expanded/collapsed state is communicated to
assistive technology.
Internal note: this single-file/single-root-cause fix addresses three
separate BITV findings raised in the same accessibility audit against
this component's toggle semantics.
* Update screenshots
---------
Co-authored-by: ElementBot <android@element.io>
* Add content scanner support to media gallery and viewer
* Improve UI and previews
* Remove default content validation state in media content views
* Disable click for invalid media items in the gallery events
* Update screenshots
---------
Co-authored-by: ElementBot <android@element.io>
Pro-only PRs (labelled pr-element-pro) leaked into Element X release
notes, causing confusion. They now group into a single Element Pro
section instead of scattering through Features/Bugfixes. Granularity is
dropped on purpose for these changes.
* Fix#7181: Remove back arrow from device verified screen and use 'Done' text
* Update screenshots
* Fix failing Maestro test by tapping 'Done' instead of 'Continue'
---------
Co-authored-by: ElementBot <android@element.io>
Co-authored-by: thirumani-vihaan <your-github-email@example.com>
* Simplify how event content with captions are displayed
The caption component will now be added in `TimelineItemEventContentView` instead of separately in each `TimelineItem__View` component
* Make sure `CoilMediaFetcher` methods to fetch media throw errors
We need to catch them later to check if the content scanner marked some thumbnails or medias as invalid/unsafe in `AsyncImage` instances
* Add a `ContentScannerService` that allows us to manually scan a list of medias in an event and then update and store the results
The results take the form of `ContentValidationValue`, stored in a `ContentValidationState` instance tied to the event
* Create `EventContentValidationCache` to keep the `ContentValidationStates` for events in a room
* Expose `EventContentValidationCache` to Compose using `LocalEventContentValidationState`
Also add a couple of helper functions to avoid having to manually remember the states
* Use the new components to display invalid content in the timeline items
* Add `blurhash` to most media items so we can use it while validating the thumbnails/medias
* Fix custom layout issues with screenshot and UI tests
* Also check the validation state for replied-to events in the composer
* Fix and add tests
* Handle unrecoverable content validation errors too: display a 'not found' UI
* Improve the performance of `EqualWidthColumn` for the single item case
* Update screenshots
---------
Co-authored-by: ElementBot <android@element.io>
Several clickable elements on the login and onboarding flows (the
account provider list items, the search clear icon, the login clear
icon, and the hidden dev-mode version tap) use plain
Modifier.clickable without a semantics role. Screen readers announce
these as generic elements instead of buttons, so users relying on
TalkBack cannot tell they are interactive.
Add role = Role.Button to each clickable modifier, and reuse the
existing clear-icon content description as onClickLabel where one is
available.
FormattingOption used clearAndSetSemantics with only a contentDescription,
so the Bold/Italic/Underline toggle buttons never exposed whether they
were currently active to TalkBack. Add a stateDescription reflecting the
selected/unselected state alongside the existing contentDescription.
New a11y_active / a11y_inactive strings added to temporary.xml for
Localazy import.
This can only happen when the app was killed by the OS and then you received some notification.
This notification action creates a new `DefaultSessionPreferencesStore` when trying to fetch `isSendPublicReadReceiptsEnabled`, which would contain a different session coroutine scope than the one created when instantiating the navigation graph (`@SessionCoroutineScope`), resulting in flows that never emit any items and close automatically as 'completed'.
This in turn prevented the timeline items subscription in `TimelinePresenter` from progressing, since we're also checking `isRenderReadReceiptsEnabled` there, which is closed and in turn closes the timeline items flow.
* Allow HS to disable encryption in Element Pro
Add `force_disable_e2ee` support in the Element well known retriever and cache to allow a homeserver to disable encrypted room creation and enabling encryption in an existing room in Element Pro clients
* Bump enterprise repo back to `main` branch