The wallpaper-picker preview already draws the SIMPLEX sunrise gradient
as its background, but the sample message bubbles stayed flat: bubbles
anchor their gradient to the chat viewport, which the preview never
provided. Give the preview its own viewport (with the same expanded
axis the preview background uses), so the sample bubbles show the same
gradient they do in a real chat, aligned with the background.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
A chat whose last message is a file showed the file icon in the chat
wallpaper's warm tint, so it turned yellow under the "cats" wallpaper.
In the chat list the icon should match the neighbouring list icons, so
on SIMPLEX it now uses the theme's secondary colour there; inside the
chat, over the gradient, the icon keeps the warm tint.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The group banner and the feature-change notices show feature icons; a
feature that is off draws in the model's secondary colour — a blue on
SIMPLEX — which reads cold over the sunrise gradient while the label
beside it already uses the warm tint. On SIMPLEX, route the off
(secondary) feature icon through simplexSecondaryTint(), in both the
collapsed icon row and the full notice. The green "on" and yellow
"partly on" colours, and every other theme, are untouched. This also
warms the "you changed a feature" notice icon, which passed a flat
secondary.
The website link-preview card shows the page URL under the title in
the flat secondary colour — a blue on SIMPLEX — which reads cold over
the sunrise gradient while the card's title uses content colour and
the message link itself the accent. Route that URL line through
simplexSecondaryTint() on SIMPLEX; other themes keep secondary. The
compose-bar preview is left as-is — it sits on the flat sent-message
colour, not the gradient.
Sweeping the message area for the remaining secondary-role content
that read cold over the sunrise gradient — SIMPLEX secondary is a
blue (#8B99D6) and the file/link icons used the grey FileDark /
FileLight. This covers the chat-link preview card (avatar, short
description, info line) and the file / voice / chat-link icons shown
inside a quoted reply. Route them through simplexSecondaryTint() on
SIMPLEX; every other theme keeps its exact colours.
On the SIMPLEX theme the raw secondary colour is a cool blue
(#8B99D6) and the framed-header icons drew in the grey FileDark /
FileLight — both read cold over the warm sunrise gradient, while the
text around them already uses the warm tint. Route the framed-header
icon (forward / flag / moderation / deleted markers) and the resting
go-to arrow (jump-to-source on forwarded items, jump-to search hit)
through simplexSecondaryTint() on SIMPLEX. Every other theme keeps
its exact colours.
On the SIMPLEX theme these two elements still drew in the flat
secondary colour over the sunrise gradient, while every sibling —
the quoted author above the caption, the feature label beside the
icon — already switched to the warm tint made to stay legible on
that gradient. Route both through simplexSecondaryTint(), which
returns the unchanged secondary colour for every other theme.
Making links a static accent left LocalSimplexLinkColor providing
exactly what linkStyle already falls back to (the primary colour),
so the CompositionLocal, its provider in FramedItemView, and the
elvis fallback no longer change anything. Remove all three.
Also clean up two comments the earlier subtraction left behind: the
axis comment still said secondary text samples the gradient (it uses
a flat tint now), and an orphaned line that had introduced the
removed LINK_STOPS.
Links now use the flat accent colour and default avatars the same
semi-transparent warm tint as dates and delivery ticks, instead of
sampling the sunrise gradient by on-screen position.
The sampling machinery did real work on every frame: link colour
recomposed as items scrolled, and each default avatar rendered
through an offscreen compositing layer to mask the gradient onto the
icon. Both are gone — links are a plain span colour, avatars set
their icon tint directly. Bubbles keep the position-sampled gradient
(they can't be flat-tinted: the wallpaper pattern would show through
and hurt text legibility). Non-SIMPLEX themes are unaffected.
Paints the SIMPLEX chat over one screen-spanning "sunrise" gradient:
- bubbles, avatars and links sample the gradient by on-screen position (a shared
20°-tilted axis anchored to the chat viewport);
- small text (dates, delivery checks, names, quoted authors, event notices,
call/voice/deleted secondary text) uses a per-wallpaper semi-transparent warm
tint, so it stays evenly legible over the gradient;
- decryption/integrity-error and deleted/marked-deleted bubbles use the received
gradient instead of a flat grey;
- wallpaper stops and secondary colours resolve from the composition, so per-chat
wallpaper overrides and the wallpaper-picker preview render correctly.
Side effects for all themes (details in the PR): event/feature text follows the
active theme instead of a start-up-frozen colour, and the via-proxy meta icon
matches the meta row on media bubbles.
Each preset wallpaper in the SIMPLEX theme now paints a per-wallpaper colour
gradient behind the chat (the pattern still shows on top) instead of a flat
background — the "sunrise" look the theme was designed around. Other themes
are unchanged. Bubble/text colours and the pattern-image refresh follow in
later PRs.
Opening a video full screen could crash with NoSuchElementException from
VLC native-library discovery. Each MediaPlayerFactory() runs a JDK
ServiceLoader (not thread-safe), and the second preview factory added in
#6924 let the render thread and preview thread construct factories
concurrently. Serialize the two constructions behind a shared lock.
* android, desktop, ios: remove left padding on consecutive received messages in channels
In channels, a received message that does not show an avatar (a consecutive post from the same sender) drops the avatar-sized left padding and sits flush-left. Applies to both owner broadcasts (ChannelRcv) and contributor posts (GroupRcv); the first message of each run still shows the avatar. Gated on ChatInfo.isChannel, so regular groups, business and direct chats, sent messages, and avatar-shown messages are unchanged.
* docs: add plan justifying removing left padding on consecutive received messages in channels
* ios: fix right gap on consecutive received messages in channels
Removing the avatar-sized left padding from no-avatar received messages
(this PR) shifted those bubbles ~44pt left, but maxWidth still reserved
the avatar inset, so consecutive messages stopped ~44pt short of the
first (avatar) message on the right.
Widen maxWidth for no-avatar channel-received items so their right edge
matches the avatar-shown first message. The no-avatar predicate reuses
the exact shouldShowAvatar expression from the render path (lifted to a
file-scope function so the maxWidth site can call it), so the width and
the rendered layout can never disagree.
Android is unaffected: Compose derives content width from padding, so
reducing the start padding already widened the row there.
* ios: increase left padding
* kotlin: increase left gap
---------
Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com>
* android, desktop: fix crash on opening chat with extremely wide image
An image with an extreme aspect ratio (e.g. 4000x1) made the chat
unopenable: the framed item's Box clamped its aspectRatio only on the
low side (coerceAtLeast(1f / 2.33f)), leaving very wide images
unbounded. During an intrinsic measure pass Compose derives
width = height * ratio, which for a 4000:1 image overflows Constraints
and throws IllegalArgumentException on every render.
Add the symmetric upper bound (coerceIn(1f / 2.33f, 2.33f)), matching
the existing tall-image height cap in PriorityLayout
(constraints.maxWidth * 2.33f).
* docs: add plan justifying wide-image chat crash fix
The armv7a-android cross-compiler GHC refuses to disambiguate the bare
record update m {memberRole = role} (the field is shared by many record
types), failing the lib:simplex-chat build with "Record update is
ambiguous, and requires a type signature".
Annotate the updated record as (m :: GroupMember), matching the existing
workaround already used a few lines below in the same function.
* Fix group link use after admin demotion
* fix: group role change
* size limit
* fix
* allow delete
* do not remove link
* query plan
* relay test
* refactor
---------
Co-authored-by: Paul Bottinelli <paul.bottinelli@trailofbits.com>
Co-authored-by: Evgeny @ SimpleX Chat <259188159+evgeny-simplex@users.noreply.github.com>
* desktop: fix updater deleting the download before "Open file location"
The in-app updater downloads to a temp UUID file via createTmpFileAndDelete,
then relies on `file.renameTo(newFile)` to move the bytes to the asset name so
they survive that helper's `finally { tmpFile.delete() }`. The rename's return
value was ignored: if it failed, the bytes stayed at the UUID path and the
finally block deleted the only copy, so the "Download completed" dialog appeared
but "Open file location" opened an empty /tmp/simplex.
Use Files.move with REPLACE_EXISTING instead. It performs the same in-place
rename when possible (verified: inode preserved, no copy), falls back to
copy+delete when an atomic rename isn't possible, and throws on genuine failure
- which the existing outer catch handles - instead of silently losing the file.
* docs: plan for updater open-file-location fix
* docs: plan - note Whonix compatibility (updater previously failed there)