ChatPreviewView showed the status info text (e.g. a pending invitee's 'reviewed by admins')
whenever the last item's text was empty (hasMsgContent), which also caught caption-less media — so
a photo/voice/file support message showed the status text next to its already-rendered thumbnail.
Show the status only for true no-content items (events, msgContent == null); any message, including
caption-less media, falls through to render its content.
Editing in a member-support scope calls upsertChatItem on the active (secondary) context only, so
the primary context that owns the main-list preview was never updated (same asymmetry as sends).
Also update the primary context on edit when the active context is a member-support scope. iOS is
unaffected (single chats list).
upsertChatItem/removeChatItem gated their main-list preview update on groupChatScope()==null, so
once a pending invitee's support message was the preview, editing it left stale text and
deleting/moderating it left a phantom. Add the same memberPending exception addChatItem has (both
already match the preview item by id). On iOS, restrict the 'update preview for an item not in the
open scope' clause to main scope so a support item's status updates don't churn the preview.
A pending invitee's member-support no-content group events (SGEUserPendingReview on the
PendingApproval->PendingReview transition, member-connected/E2EE/feature items) are delivered
as new chat items in member-support scope. The pending preview took the newest item, so such
an event re-covered the first message and rendered as the static "reviewed by admins" text.
Prefer a content message: a no-content item no longer displaces an already-shown message.
Mirror the android/desktop fix: a pending invitee's received support message was
dropped from the main chat list preview by the group itemTs comparison (received
broker clock vs locally-stamped group-event clock - not comparable). Bypass the
comparison when memberPending so the received support item surfaces in the preview.
- Narrow the sent-item mirror (previous commit) to GroupChatScopeContext (member
support); the reports view has no compose, so it shouldn't trigger it.
- A pending invitee's RECEIVED support message was dropped from the main chat list
preview: the group preview keeps the higher-itemTs item, but a received message's
itemTs is the broker clock while the placeholder group event's itemTs is the local
device clock - an unreliable cross-clock comparison. Bypass it when memberPending
so received support items surface in the preview the same way sent ones do.
A message sent in a secondary scope (member support / "chat with admins") is
added only to the active context (ComposeView passes its own chatsCtx), unlike
received items which the NewChatItems handler delivers to both the primary and
secondary contexts. After the index-correct revert of #5909's chatsContext.chats[i]
write, a pending invitee's sent support message no longer appeared in the main
chat list preview.
Mirror the receive path: when adding a sent item on a secondary context, also
update the primary context, so the main chat list preview updates at the correct
index. Sent items are not RcvNew, so this adds no unread double-count.
When a member support chat or group reports view is open (a secondary chats
context is active), incoming messages could overwrite the last-message preview
of an unrelated chat in the main chat list, increment the wrong chat's unread
badge, and pop the wrong chat to the top.
ChatsContext.addChatItem computed the chat index against the receiver context's
own list via getChatIndex, but then read/wrote chatsContext.chats[i], which
always refers to the primary (main) chat list. On the secondary context the two
lists are ordered differently, so the index pointed at a different chat.
Use the receiver context's own list (chats[i]) consistently, matching every
other method in ChatsContext and the iOS implementation. No change for the
primary context, where chats and chatsContext.chats are the same list.
On an incoming call the desktop window blinked continuously (FileNotFoundException
from SoundPlayer.start writing into a missing ...\Temp\simplex).
Root cause: Files.desktop top-level val initializers run in any process that
touches the facade class, including a transient second instance (which reaches
acquireSingleInstance -> dataDir). Two of them deleted shared state used by the
running primary:
- tmpDir had .also { deleteOnExit() } - the second instance's normal exit deleted
...\Temp\simplex, so the primary then failed to write call sounds/recordings.
- preferencesTmpDir had .also { deleteRecursively() } - the second instance's
<clinit> wiped configPath\tmp (same anti-pattern, firing even earlier).
Make both declarations pure and do the destructive cleanup in Main, past the
single-instance check, so only the owning instance performs it (preferencesTmpDir
kept early, before any settings write). The remaining val-initializer side effects
are idempotent creations (mkdirs) that destroy nothing and are left in place.
Wide images size their preview box with a fixed width of DEFAULT_MAX_IMAGE_WIDTH
(500dp). #7125 switched the box from .aspectRatio() to a fixed .height() computed
from that nominal width; on screens narrower than 500dp, .width(500dp) is clamped
to the available width but the fixed height is not, so the top-aligned FillWidth
image is shorter than its box, leaving an empty strip below.
Compute the height from the width actually granted via a small Modifier.layout so
it tracks the clamped width, restoring the self-correcting behaviour .aspectRatio()
had. coerceAtMost(w) keeps the box within its nominal width (and bounds the
unbounded intrinsic-measurement pass), and coerceAtLeast(0) mirrors what
Modifier.width()'s SizeNode does for a negative w on a tiny window - so both
dimensions stay in range and the #7123 Constraints overflow crash cannot recur.
* ui: what's new in 7.0 (#7265)
* docs: add Hosting your own Chat Relay guide (#7263)
* docs: add Hosting your own Chat Relay guide
* cli: run headless relay without a terminal
--headless (no -e) now runs via simplexChatCore instead of the terminal
UI, so the relay runs as a systemd service without a TTY (withTerminal
requires one). Drains the event queue logging only errors, and sets
stdout to line-buffering so logs reach the journal.
* docs/chat-relay: debounce service
* Apply suggestions from code review
Co-authored-by: Evgeny <evgeny@poberezkin.com>
---------
Co-authored-by: Evgeny <evgeny@poberezkin.com>
* Translated using Weblate (Chinese (Traditional Han script))
Currently translated at 47.9% (179 of 373 strings)
Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/zh_Hant/
* Translated using Weblate (Turkish)
Currently translated at 63.0% (235 of 373 strings)
Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/tr/
* Translated using Weblate (Indonesian)
Currently translated at 95.7% (357 of 373 strings)
Translation: SimpleX Chat/SimpleX Chat website
Translate-URL: https://hosted.weblate.org/projects/simplex-chat/website/id/
---------
Co-authored-by: spaced4ndy <8711996+spaced4ndy@users.noreply.github.com>
Co-authored-by: Evgeny <evgeny@poberezkin.com>
Co-authored-by: HUGOALH <hugoalh@users.noreply.hosted.weblate.org>
Co-authored-by: Omer <abulomer2001@gmail.com>
Co-authored-by: Rafi <rafimuhmad90@protonmail.com>
* docs: add Hosting your own Chat Relay guide
* cli: run headless relay without a terminal
--headless (no -e) now runs via simplexChatCore instead of the terminal
UI, so the relay runs as a systemd service without a TTY (withTerminal
requires one). Drains the event queue logging only errors, and sets
stdout to line-buffering so logs reach the journal.
* docs/chat-relay: debounce service
* Apply suggestions from code review
Co-authored-by: Evgeny <evgeny@poberezkin.com>
---------
Co-authored-by: Evgeny <evgeny@poberezkin.com>
getLoadedImage subsampled with an OR cap on the larger side, so tall
images (e.g. phone screenshots) were reduced far below the display size
and rendered blurry. Mirror Android's calculateInSampleSize (keep the
smaller side at the target) so previews stay sharp, and add a decoded-
pixel ceiling so extreme aspect ratios can't blow up decode memory.
* desktop: show startup errors in a copyable window instead of bare "Failed to launch JVM"
When any exception escapes main() before the app window appears - a missing
DLL, a failed migration, broken AWT init - the jpackage launcher shows only
"Failed to launch JVM" and the cause is recorded nowhere: the launcher runs
without a console, so stderr is lost. Every report in #4146 stalled on this.
Catch the error and show it in a native Win32 window laid out like a message
box: an error icon and message, two clickable report links (the GitHub issue
tracker and the support email) above a read-only selectable box with the stack
trace, and an OK button. The links are SS_NOTIFY statics opened with
ShellExecute (browser for the URL, mail client for the email). Native, not
Swing, because broken AWT initialization is one of the failure causes. On
Windows the process then exits cleanly so the launcher does not also show its
own box; on other systems the error is rethrown to stderr.
* docs: plan justifying desktop startup error window (#4146)
* desktop: bundle jdk.accessibility to fix "Failed to launch JVM" when assistive technologies are enabled (#4146)
The jlinked runtime shipped in desktop packages did not include the
jdk.accessibility module. On Windows, when Java Access Bridge is enabled
(jabswitch -enable, "Enable Java Access Bridge" in Ease of Access, or a
screen reader creating %USERPROFILE%\.accessibility.properties), AWT
throws AWTError "Assistive Technology not found:
com.sun.java.accessibility.AccessBridge" during Toolkit init, before any
window or log output, and the jpackage launcher reports "Failed to
launch JVM".
* docs: plan justifying jdk.accessibility fix for Windows JVM launch (#4146)
* desktop: bundle jdk.accessibility only when building the Windows package
* cli: add --relay-address-server option for chat relay
New CLI flag --relay-address-server SERVER selects the SMP server used
for the chat relay address link created at startup. Only valid together
with --relay; errors out otherwise.
Threads Maybe SMPServerWithAuth through APICreateMyAddress to the new
agent createConnection parameter.
* cli: add --user-display-name option
Selects or creates the active user non-interactively:
- no active user: create one with the given display name
- active user with matching localDisplayName: continue
- active user with different name: exit with error
Mutually exclusive with --create-bot-display-name.
* cli: add --user-image-file option
Sets the active user's profile image from a .png/.jpg/.jpeg file at
startup. Reads file, base64-encodes as data URL, and updates the user
profile directly in the DB - no notification is sent to existing
contacts. Skips the update if the stored image already matches.
Requires --user-display-name.
* cli: address PR review comments
- rename APICreateMyAddress field srv_ to server_
- extract repeated `loop` and putStrLn from createActiveUser via
prompt where-clause
- fuse u_ inspection: validate active user display name in the same
case that creates the user when missing
* cli: enforce profile image size limit in --user-image-file
Reject the file if the encoded data URL exceeds 12500 bytes - matches
the cap mobile and desktop UIs pass to resizeImageToStrSize for profile
images. Without this, oversized images would be silently set on the
user profile.
* core: validate profile image size in chat commands
Enforced in CreateActiveUser, updateProfile_, newGroup, runUpdateGroupProfile
via checkProfileImageSize; max 12500 bytes (matches mobile UIs).
* fix: thread new ChatOpts/CoreChatOpts fields through bot/test constructors
* bots/docs: filter hidden params before type introspection
Hide APICreateMyAddress server_ field so the bot doc generator does not
try to introspect SMPServerWithAuth (an unregistered type).
* core: validate full encoded profile size
Add checkProfileSize / checkGroupProfileSize that encode the full
ChatMessage and check against maxEncodedInfoLength, so a long
displayName/bio combined with a near-max image is also caught at
command time instead of failing later at send time with CEException.
Run alongside the existing checkProfileImageSize (image-only cap of
12500 bytes, matching mobile UIs) in CreateActiveUser, updateProfile_,
newGroup, runUpdateGroupProfile. Update genProfileImg to fit the cap.
* cli: add --headless option for chat relay
Skips interactive prompts (relay address creation, display name) so the
chat relay can run non-interactively as a service. Requires --relay;
creating a new profile also requires --user-display-name.
* test: cover profile image size limit and address server
Adds tests for two new capabilities:
- profile image size validation rejects oversized images
- /_address with a server pins the address to the requested SMP server
* core: update simplexmq (pass optional SMP server to prepareConnectionLink)
* cli: add /set profile image file, fix image flag
Add "/set profile image file <path>" command to set the profile image
from a .png/.jpg/.jpeg file in a running session.
Make --user-image-file create-only: for an existing user it now no-ops
with a note instead of failing with "chat not started" (the update ran
before the chat controller was started).
* core: unify image loading and profile size checks
- loadImageFile (CLI) and readProfileImageFile (command) now share one
loadImageData; removes the duplicated mime/base64 encoding and its
decodeUtf8/safeDecodeUtf8 divergence. A missing --user-image-file no
longer crashes with an uncaught IOException, and empty files are rejected.
- checkProfileSize/checkGroupProfileSize share checkInfoSize.
- --relay-address-server/--headless requires-relay checks use
errorWithoutStackTrace, matching the adjacent validation (no callstack dump).
* bots/docs: document UpdateProfileImageFromFile as a CLI command
* website: fix broken GitHub links for project files in docs
* website: fix broken links across docs and pages
Render glossary tooltips through the shared replaceLink transform so
their relative links become absolute site URLs instead of 404ing when
injected across pages; add the English-only routes (downloads, faq,
jobs, reproduce, security, transparency) to supportedRoutes so the
language switcher stops emitting href="undefined"; passthrough-copy
docs/guide/images, docs/guide/diagrams and docs/themes.
Fix the SIMPLEX.md p2p anchor typo and correct image paths in CLI,
the v0.4 blog post and the fr/pl translation docs to point at the
existing shared assets.
* docs: add name resolution setup to SMP server guide
* docs: link SMP server names section to public names overview
* link
---------
Co-authored-by: Evgeny <evgeny@poberezkin.com>
* core, web: correctly process name verification for channels, show names in directory
* remove duplicate verification
* remove plan
* refactor
* remove comments
* stabilize tests
---------
Co-authored-by: Evgeny @ SimpleX Chat <259188159+evgeny-simplex@users.noreply.github.com>