Commit Graph

6154 Commits

Author SHA1 Message Date
another-simple-pixel e178e8924e formula dev tools: add pattern + bg-lightness controls for dark/black
LIGHT had three pattern/background controls — Pattern depth, Pattern
chroma, BG Lightness — that DARK and BLACK didn't expose. Without them
the founder couldn't tune the wallpaper pattern's brightness/saturation
or nudge the background's lightness independently of the bubble cluster
in those themes. Add the same three sliders to DARK and BLACK.

generateSchemeDark / generateSchemeBlack gain three new optional params
that pass through generateDarkFromSlots:
- patternDepth: when set, replaces the slot's hard-coded lightnessMult
  (and patternIntensity multiplier) directly, matching LIGHT's semantic
  of "multiplier on effStep".
- patternChroma: when set, overrides the pattern slot's chroma — taking
  precedence over BLACK's max-pin behaviour so the user can pull it back
  from the gamut edge.
- bgLOffset: nudges only the background slot's L (other slots stay at
  their formula-computed L), mirroring LIGHT.

null defaults preserve the existing behaviour, so nothing changes for
callers that don't pass the new params.

Defaults derivation in FormulaDevTools picks up patternDepth and
patternChroma from the preset's stored tint slot (same shape as LIGHT,
with the sign of the depth swapped because dark themes have the pattern
brighter than the bg, not darker). bgLOffset stays at its existing 0f
fallback.

Slider ranges: BLACK pattern depth uses 0..15 because the default
lightnessMult for BLACK pattern is 9.0 — the LIGHT/DARK 0..10 wouldn't
give meaningful headroom.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-05-13 14:48:23 -07:00
another-simple-pixel 143653005d chat theme: Set default uses SCHOOL preset's recalibrated colors
ThemeModeOverride.withFilledAppDefaults — backing the "Set default theme"
button in Chat info > Chat theme — set the wallpaper to the SCHOOL
preset but passed null for presetWallpaperTheme when filling colors. The
five-source priority chain therefore fell through to LightColorPalette /
DarkColorPalette / SimplexColorPalette / BlackColorPalette: the base
palette colors that predate this PR's preset recalibration.

Result: a chat reset via "Set default theme" showed the SCHOOL pattern
on top of pre-recalibration bubble colors that no longer match it. Pass
preset.colors[base] so the priority chain picks up SCHOOL's tuned colors
for the chosen mode, matching what the wallpaper expects.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-05-13 14:11:02 -07:00
another-simple-pixel 7ceac22dc0 refactor: switch theme dispatch from boolean pair to DefaultTheme
Two clarity fixes from the audit.

- ChatWallpaper: the private color helper was named gen — too short to
  carry its purpose. Rename to colorForElement, the term it actually
  computes (a single oklch Color from preset + mode + element params).

- Appearance.FormulaDevTools: both the generateScheme dispatch and the
  slider rendering branched via `when { isLight -> ; isBlack -> ; else
  -> dark }` and `if (isLight) { } else { ; if (!isBlack) ... }`. Two
  parallel dispatches over the same proposition, expressed as boolean
  pairs. DefaultTheme already carries that proposition with a name;
  switch to `when (baseTheme)` so each branch states which theme it is
  and lists its sliders / scheme call. Black's three-slider set becomes
  its own branch instead of negative gates inside the dark branch.

The isLight/isBlack locals stay for the small conditionals inside the
defaults map computation (where the ternaries read fine inline).

Pure refactor — no behavior change.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-05-13 13:48:50 -07:00
another-simple-pixel d947050f31 refactor: extract repeated theme/color resolution patterns
Three duplicated patterns surfaced by the audit, each consolidated into
a single named helper.

1. ThemeOverrides.toColors and toAppColors had the same five-source
   priority chain (per-chat → per-user → own → preset → base) inlined
   for nine non-bubble fields. Move it into resolveColor so each call
   site states the data, not the resolution rule. (Bubble fields keep
   their wallpaper-aware logic — different rule, separate concern.)

2. The chat's effective theme — chatInfo.uiThemes.preferredMode resolved
   through ThemeManager.currentColors — was computed inline in ChatView
   (for SimpleXThemeOverride) and again in App.ActiveChatThemeProvider
   (for the chatlist column / Android modal stack). Pull both into a
   shared rememberActiveChatTheme. Both call sites also adopt the wider
   remember key (whole theme, not just base) that the toolbar fix
   already needed; behavior is unchanged when the chat has no override.

3. The toolbar code-output copy in Appearance reimplemented oklch
   conversion inline (Color → Oklab → atan2 → degrees) instead of
   calling the existing Color.toOklch() extension. Replace with the
   extension, which also adds a small near-zero-chroma guard the inline
   version was missing.

Pure refactor — no user-visible behavior change.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-05-13 13:45:42 -07:00
another-simple-pixel 19318576f3 docs: clarify formula derivation and dev-only state
Three documentation/marker additions surfaced by an engineer-v1 audit:

- ChatWallpaper.kt: the per-mode/per-element constants used by the theme
  color formula were a wall of magic numbers. Add a header explaining
  what each parameter controls and where the values came from
  (empirically tuned via the dev UI in Appearance.kt).
- Appearance.kt: surround the module-level FormulaDevTools state
  (formulaSavedParams, patternScaleDragging) with a prominent banner
  marking it dev-only. The dev UI is shipped in the current build but
  must be removed before reaching end users; the search-tag makes that
  trivial later.
- Color.kt: solveCubic had no docstring; the 1e-10f thresholds looked
  like magic. Document Cardano's method, the maxChromaForMatrix caller
  context, and the numerical-stability rationale for the thresholds.

Pure comment additions; no behavior change.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-05-13 13:36:33 -07:00
another-simple-pixel bd9d31c5f4 toolbar: respect per-chat theme override
The toolbar background was always computed from the global CurrentColors
state flow, so a chat with a custom theme override (its own wallpaper or
color scheme) showed a toolbar tinted to the global Appearance scheme
rather than the chat's. On desktop two-pane the chatlist toolbar sat
next to the chat toolbar in different colors; on Android the chat info
and chat-customize modals kept the global tint above and below the
chat-themed content.

Expose the current theme as a new LocalActiveTheme composition local,
provided by SimpleXTheme (global scope) and SimpleXThemeOverride (chat
scope). panelBackgroundColor reads everything — both the wallpaper-hue
tint and the elevation fallback — from this local, so it tints to
whatever scope it renders in. A small ActiveChatThemeProvider helper
propagates the active chat's effective theme to UI surfaces that sit
outside the chat's SimpleXThemeOverride: the chatlist column on desktop,
and the fullscreen modal stack on Android.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-05-13 13:25:21 -07:00
another-simple-pixel a920e50c28 add .gitattributes to enforce LF in Kotlin sources
Prevents CRLF from sneaking into .kt files when they get opened in
Android Studio on Windows during the dev loop. Without this, the file
on disk picks up CRLF after a save, the next edit commits it, and the
PR diff inflates with line-ending noise.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-05-13 09:49:19 -07:00
another-simple-pixel 62353d0e80 wallpapers: normalize line endings to LF
Four Kotlin files in this PR ended up with CRLF after a Windows-side
merge, which made the diff against master show thousands of unchanged
lines as modified. Convert them back to LF so reviewers see only the
real semantic changes.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-05-13 08:52:21 -07:00
Evgeny Poberezkin 7aa7d0ae4e Merge branch 'master' into ae/oklch-color-space-plan 2026-05-13 16:11:15 +01:00
another-simple-pixel 6c6f1aef69 Ae/wallpaper light n dark v4 (#6899)
* light wallpapers: v4 color formula

all 6 light wallpapers recalculated with the new formula: received
messages are white (read more often, max readability), sent messages
muted in the hue — same pattern as Telegram. tint/chroma tuned per
wallpaper on device.

the formula lives outside the app (node script), only the resulting
oklch constants are in kotlin. LIGHT is served from _background/_tint/
_colors; DARK/SIMPLEX/BLACK keep the generator.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* wallpapers: tune dark theme + refine light pattern intensity

Calibrated full dark theme palette for all 6 preset wallpapers using the
shared chroma formula (bg-anchored, two-cluster muted/color, per-hue P3
saturation). Each wallpaper now has its own dark bg, tint, and bubble
colors instead of a shared neutral gray. Hearts hue shifted from 15° to
5° (slightly cooler), school from 239° to 249° (slightly warmer); hearts,
school and travel had per-wallpaper saturation reduced for visual
balance. wallpaperBackgrounds() now accepts a dark color override.

Light pattern tint also refined for flowers/hearts/kids/school/travel
using a coverage+sharpness regression on the pattern textures, so dense
patterns like hearts read calmer and sparse ones like flowers read
clearer. Light bubbles and backgrounds unchanged from the v4 formula.

Cats remains the calibration anchor for both themes.

* wallpapers: tune black theme (#6912)

* wallpapers: tune black theme

Replaced the legacy hex-derived BLACK palette with calibrated values for
all 6 preset wallpapers. Pure black bg (#000000) replaces the near-black
gray (#070707) — with the chroma formula's "muted side at zero" rule the
BLACK theme now reads as truly hyper-contrast. Each wallpaper's tint and
bubble colors are tuned to its own hue (cats 70°, flowers 130°, hearts 5°,
kids 192°, school 249°, travel 315°) with chroma pulled to per-hue P3
boundary, capped to keep pattern visibility consistent across textures.

* fix color space

* wallpapers: recalibrate all presets + hue-tinted panels

Recalculated bg/tint/bubble colors for all 6 wallpapers across LIGHT/DARK/BLACK
using unified oklch formula. Added subtle hue tint to panel backgrounds (status bar,
top app bar, nav bar) so they pick up the wallpaper's color. Hearts and school use
different hues in dark themes, so added PresetWallpaper.hue(theme) to handle that.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* wallpapers: formula dev tools, normalized patterns, desktop fixes

- Formula dev UI (developer tools only): sliders for all color parameters
  per theme (LIGHT/DARK/BLACK), live preview, copyable Kotlin code output
- oklch color formula ported to Kotlin (generateSchemeLight/Dark/Black)
- sRGB gamut boundary for Desktop (maxChromaSRGB), P3 for Android
- Normalized pattern PNGs (consistent element size across wallpapers)
- Desktop pattern scale 0.55 + draft/final rendering (fast during drag,
  SCALE_SMOOTH on release)
- Hue-tinted toolbar via ThemeColor.TOOLBAR + AppColors.toolbar
- Received tint slider for light themes

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* wallpapers: fix toolbar color picker + received tint default

Toolbar color: direct replacement instead of alpha-mixing, picker
opens with actual visible toolbar color (panelBackgroundColor),
copy-code hint shows file and line number.

Received tint: default derived from hardcoded colors (fallback 0.005).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* wallpapers: extend pattern depth slider range to 10

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* wallpapers: add BG Lightness slider for light themes

Offset ±0.05 to formula background L, independent of other slots.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* wallpapers: denser hearts pattern + recalibrated LIGHT colors

Tuned LIGHT theme colors for all 6 presets via the formula sliders.
Hearts pattern PNG replaced with a denser variant (all four density
variants regenerated).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* wallpapers: revert iOS hearts variants to old format

The denser hearts PNG is shipped only as the multiplatform @4x file
(used by Android and Desktop). iOS still uses the old pattern renderer
which expects the old non-normalized layout, so the @1x/@2x/@3x
variants are reverted to their previous state to avoid visual breakage
on iOS.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2026-05-13 16:10:01 +01:00
Evgeny 7497b90e7c core, ui: allow indefinite deletion from history for public channel/group owners/moderators (#6972)
* Revert "core: forward compatible support for owners/admins/moderations deleting channel and public group messages without limitations (#6962)"

This reverts commit 08108ebabb.

* core, ui: allow indefinite deletion from history for public channel/group owners/moderators

* style

Co-authored-by: Evgeny <evgeny@poberezkin.com>

* refactor

* show error on deletion

* better alerts

* test

* plan

* simplify test

* bot api docs

* refactor

* test that removed from history is not delivered to the new subscribers

* fix, refactor

* fix

* rename

* rename predicate in UI

* rename

* do not forward channel deletions from history

* remove redundant check

---------

Co-authored-by: Evgeny @ SimpleX Chat <259188159+evgeny-simplex@users.noreply.github.com>
2026-05-13 15:24:52 +01:00
sh 7908f4aad2 simplex-support-bot: bump grok model (#6975) 2026-05-13 13:36:45 +01:00
sh 334a50dda5 desktop: add tray support (#6970)
* plans: design and implementation plan for desktop tray icon

Adds a system tray icon to the SimpleX desktop app with first-close
dialog and an Appearance toggle. Covered: minimize-to-tray on Linux,
Windows, and macOS via ComposeNativeTray; tri-state CloseBehavior
preference; unread-dot icon swap; show/quit menu.

The design plan covers the user-facing behavior, library choice
rationale (AWT/Compose Tray is broken on stock GNOME per JDK-8322750;
ComposeNativeTray uses platform-native APIs and is maintained), and
out-of-scope items. The implementation plan splits the work into 8
incremental commits, each leaving the build green.

* desktop: add CloseBehavior preference

* plans: switch tray to built-in Compose Tray with GNOME probe

* desktop: branch close handler on CloseBehavior preference

* desktop: first-close dialog for tray choice

* desktop: tray icon assets and menu strings

* desktop: system tray icon with show/quit menu

* desktop: unread indicator on tray icon

* desktop: Appearance toggle for minimize-to-tray

* desktop: tray feature fixes from audit

- Scope closedByError per application iteration; set before dispatchEvent.
- Short-circuit Ask to Quit when tray is unavailable.
- Sum users.unreadCount (pre-aggregated) instead of iterating chats.
- Replace dialog's captured lambdas with a top-level flag and
  ApplicationScope extension; wrap in SimpleXTheme.
- Probe SystemTray with real add/remove off the EDT.
- Drop duplicate ic_simplex_tray.svg; nudge unread dot to cy=34 to
  stop the r=6 circle clipping at the viewBox bottom.
- Use mkSafeEnumPreference, PreferenceToggle, SectionTextFooter.

* plans: sync desktop tray plans with implementation

* desktop: render close-behavior popup via AlertManager

Replaces the bespoke DialogWindow with AlertManager.shared.showAlertDialogButtonsColumn —
same in-app surface as e.g. the link-previews opt-in alert. Drops isAskingCloseBehavior,
the CloseBehaviorDialog Composable, the resetAskCloseBehavior helper, and the per-iteration
reset call: the alert's lifecycle is now bounded by AlertManager's single slot, so a crash
mid-dialog gets cleanly overwritten by the crash report.

* desktop: reset closeBehavior with 'Reset all hints'

Generalises AppPreferences.hintPreferences to a heterogeneous List<HintPref>
so non-Boolean prefs can participate. Adds closeBehavior to the list, so
'Reset all hints' brings the first-close dialog back.

* desktop: skip muted profiles in tray unread sum

Active profile still counts so the user can see their own unread; non-active
muted profiles contribute zero.

* desktop: dark-theme tray icons

Adds ic_simplex_tray_light and ic_simplex_tray_dot_light — copies of the
existing tray SVGs with the navy back-X swapped to white. Picks the variant
via isInDarkTheme() so the icon stays visible against dark tray backgrounds.
2026-05-13 08:58:42 +01:00
Narasimha-sc de573a2299 support bot: escalate to team when Grok's reply contains /team (#6968)
Detect the substring /team anywhere in Grok's AI reply (per-message and the
initial post-join reply) and run the same escalation as a customer /team:
invite the team members and switch the conversation to TEAM-PENDING. The reply
itself is still posted to the chat.
2026-05-12 16:48:43 +01:00
Narasimha-sc 1f25cec949 android, desktop: constrain image height in layout (#6959)
* android, desktop: constrain image height in layout

Clamp the image preview Box's aspect ratio so it never goes
below 1/2.33 (matching the height cap already enforced by
PriorityLayout). Prevents tall image previews from overflowing
into the caption area below.

Analogous to iOS #6732.

* plans: justify image text overlap fix
2026-05-12 16:48:25 +01:00
sh 6b93a940de simplex-chat-python: don't log routine async chat errors as ERROR (#6971)
Chat errors emitted via the Haskell `eToView` path (e.g. agent errors
on stale connections after a peer deletes a chat) were caught by the
broad `except Exception` arm in the bot receive loop, producing an
ERROR log with a full traceback for routine soft errors. Match the
desktop client policy (SimpleXAPI.kt:3332-3340): catch ChatAPIError
separately, escalate CRITICAL agent errors to ERROR, log the rest at
DEBUG.
2026-05-12 14:26:15 +01:00
spaced4ndy 24859e1281 core: announce added relay (#6956) 2026-05-12 12:36:23 +00:00
sh e63c403623 simplex-chat-python: add python library (#6954)
* docs: simplex-chat-python design and implementation plan

* bots: Python wire types codegen

* simplex-chat-python: package scaffold

* simplex-chat-python: native libsimplex loader

* simplex-chat-python: async FFI wrappers

* simplex-chat-python: ChatApi with 49 api methods

* simplex-chat-python: Bot class with decorators and dispatch

* simplex-chat-python: install CLI, example bot, README

* simplex-chat-python: audit fixes

* bots: regenerate API docs and types

Catches up the markdown, TypeScript and Python codegen outputs with two
upstream schema changes:

- APIConnectPlan.connectionLink became optional (from sh/python-lib audit
  fixes); cmdString and EBNF syntax now reflect optional parameter.
- APIAddGroupRelays command and CRGroupRelaysAdded/CRGroupRelaysAddFailed
  responses added in #6917 (relay management). The TS and markdown outputs
  were regenerated when #6917 landed but the Python types module only got
  the new entries with this regeneration.

* core: refresh SQLite query plans after relay_inactive_at migration

The M20260507_relay_inactive_at migration (#6917 / #6952) shifted the
query plans that 'Save query plans' verifies. Regenerated via the test
that owns those snapshots; no behavioral change.

* bots: keep APIConnectPlan connectionLink as required parameter

The prior audit-fixes commit changed the syntax expression to `Optional ...`
because the Haskell field is `connectionLink :: Maybe AConnectionLink`.
That misrepresents the API contract: the `Maybe` is purely an internal
signal for link-parsing failure (the handler returns `CEInvalidConnReq`
on `Nothing`), not API-level optionality. Callers MUST always pass a
connection link.

Revert the syntax expression to `Param "connectionLink"` and add a
comment so the intent is preserved next time someone audits.

Regenerates COMMANDS.md, commands.ts and _commands.py to match.
2026-05-12 12:32:01 +01:00
Narasimha-sc 5d597faf7e desktop: pick a free port for the call server if 50395 is in use (#6963)
* desktop: pick a free port for the call server if 50395 is in use

startServer() bound a hard-coded port (50395); when it was already in use,
NanoWSD threw "BindException: Address already in use: bind" and the call
failed. It now falls back to an OS-assigned free port, and WebRTCController
opens the browser at the actually-bound port (server.listeningPort) -- still
50395 in the normal case, so browser camera/mic permission stays put.

* plans: justify call server port-bind fix
2026-05-12 10:12:39 +01:00
Narasimha-sc eb4f601c8b core: keep whitelisted query parameters when removing link tracking (#6965)
* core: keep whitelisted query parameters when removing link tracking

In safe mode, "remove link tracking" stripped any query parameter whose
name started with a known tracking prefix in qsSafeBlacklist, ignoring
qsWhitelist. So "list" (e.g. YouTube playlist links) was dropped because
"li" (LinkedIn) is a prefix of it, and github's "ref" was dropped too.
Make the safe-mode filter consult the whitelist, like the other branches.

* docs: plan for keeping whitelisted query parameters when removing link tracking

Design doc for the safe-mode sanitizeUri change (PR #6965): why "?list=" was
stripped from YouTube links, the root cause (safe mode ignoring qsWhitelist),
the fix, what it does/doesn't change, and alternatives considered.
2026-05-12 10:11:26 +01:00
sh 8841c73fb2 support bot, simplex-chat-nodejs: fix bot command parsing (#6964)
ciBotCommand's regex was unanchored, so a customer message like
"follow/read blog posts?" parsed as a /read command and the Grok
handler silently dropped the message. Anchor the regex with ^ so a
command requires `/` at the start of the (trimmed) message.

In the support bot, filter customer command parsing by the registered
keyword set: any unknown `/word` from a customer (e.g. /help) is now
routed as plain text instead of being silently dropped by Grok. This
also makes /grok when Grok is disabled behave consistently as text,
removing the previous ad-hoc workaround.
2026-05-12 09:52:50 +01:00
Evgeny 78f987a448 docs: changelog (#6960)
* docs: changelog

* update

---------

Co-authored-by: Evgeny @ SimpleX Chat <259188159+evgeny-simplex@users.noreply.github.com>
2026-05-11 18:39:43 +01:00
Evgeny 08108ebabb core: forward compatible support for owners/admins/moderations deleting channel and public group messages without limitations (#6962)
* plan: delete channel messages

* core: allow deletion of own messages in public groups in channels to moderators-owners

---------

Co-authored-by: Evgeny @ SimpleX Chat <259188159+evgeny-simplex@users.noreply.github.com>
2026-05-11 15:00:37 +01:00
sh 5708fbbc04 support bot: accept YAML transcript in context (#6946)
* support bot: take Grok initial context as messages array

Generalizes GrokApiClient to take a list of seed messages instead of a
single system prompt. Behavior is unchanged.

* support bot: accept YAML transcript in --context-file

Plain text → single system message (existing behavior).
`.yaml`/`.yml` → parsed as harness transcript; only system and
assistant turns are included.
2026-05-11 14:37:03 +01:00
Evgeny Poberezkin ce891e4501 core: code style 2026-05-11 10:41:49 +01:00
Narasimha-sc e10cfd02e9 desktop: keep text selection on the originally selected message when a new message arrives (#6955)
* desktop: keep text selection on the originally selected message when a new message arrives or is sent

Selection stored positional indices into the merged-items list. When a new
message was appended, the reversed list shifted every index by one — but the
stored start/end indices did not — so the highlight slid onto neighboring
messages.

Anchor the selection to ChatItem IDs instead of list positions. Offsets are
already content-relative (character cursors in rendered text), so they stay
valid across list mutations. Positional indices are derived on read via
derivedStateOf, which keeps per-item reads O(1) amortized. If either
anchored item is removed from the list, a SideEffect synchronously clears
the selection so the copy button does not flash at a stale location.

* desktop: minimize selection fix — anchor ids in SelectionRange

Replaces the previous derivedStateOf-based approach with a surgical
diff: SelectionRange carries startItemId/endItemId alongside the
existing positional indices, and a SideEffect calls resyncIndices()
to translate ids back to current positions when the items list mutates.

All existing call sites of range.startIndex / range.endIndex remain
unchanged. Net diff vs master is +19/-2.

* plans: justify desktop text selection id-anchored fix
2026-05-08 13:55:58 +01:00
Narasimha-sc da9b69ca0b android, desktop: open correct image in fullscreen viewer (#6869)
* android, desktop: open correct image in fullscreen viewer

Fullscreen image viewer occasionally opened a different image than
the one clicked. Root cause: when the LaunchedEffect probe at
ImageFullScreenView.kt:48-55 calls getMedia(initialIndex - 1) to check
whether a previous media item exists, getMedia returns null for both
"no item" and "item found but failed to load" (e.g. undecodable bytes,
missing file, crypto error). The probe treated null as "no previous
item" and called scrollToStart(), which rewrote initialChatId to the
chat's oldest media item - making the viewer display that oldest item
instead of the clicked one.

Fix: scrollToStart() no longer rewrites initialChatId. The pager is
still repositioned to page 0; getMedia(0) resolves against the
already-set initialChatId (the clicked item) and renders it correctly.

* android, desktop: regression test for fullscreen viewer anchor preservation

Drives the public providerForGallery interface: moves the anchor away from
cItemId via currentPageChanged, calls scrollToStart, then reads the anchor
back through onDismiss's scrollTo callback. The pre-fix code rewrote
initialChatId to the chat's oldest showable, which would surface as
scrollTo(2); the fix preserves the anchor and produces scrollTo(1).

* plan: design doc for fullscreen viewer wrong-image fix

Documents the pager state model, the root cause of the wrong-image bug,
why the one-line deletion in scrollToStart fixes it for both call sites,
and why the wider getMedia null-overload refactor is deliberately out of
scope for this fix.
2026-05-08 12:18:45 +01:00
Narasimha-sc 4d43f2d41c desktop: fix copying selected text in reports (#6863)
* desktop: fix copying selected text in reports

Text selection in report items rendered a red reason prefix (e.g. "Spam: ")
before the user's comment but dropped the prefix when copying, because
selection offsets are in rendered-text space while copy extraction was
operating on ci.text / ci.formattedText directly.

Introduce itemPrefixText(ci) as the single source of truth for the rendered
prefix, and drive both selection copy and snap-to-segment from a unified
itemDisplaySegments list that prepends the prefix as a leading segment.
This also fixes mention/link snapping on the selection boundary inside
report comments.

* desktop: scope report-selection fix to report items

Inline a prefix preamble + offset shift in selectedItemCopiedText and
snapOffset instead of routing every item through itemDisplaySegments.
Non-report items now run the original pre-PR loop unchanged; reports
emit the selected slice of the rendered prefix and shift body offsets
by prefix.length.

* desktop: simplify report selection arithmetic

Selection offsets are in display-text space, which already includes the
leading itemPrefixText for reports. Treat the prefix as the leading
display segment and seed displayOffset with prefix.length, instead of
shifting body offsets by prefix.length in the inner loop and gating
snapOffset on offset <= prefix.length.

The inner loop body of selectedItemCopiedText becomes identical to
pre-PR for non-reports (prefix is "" so displayOffset starts at 0),
and snapOffset reduces to a one-line seed change. Same fix, smaller
diff, fewer intermediate variables.

* desktop: drop helper, inline report-prefix in selection only

Revert itemPrefixText helper extraction (TextItemView.kt and
FramedItemView.kt back to pre-PR). Inline the report-prefix expression
at its two use sites in TextSelection.kt directly.

PR diff is now confined to TextSelection.kt: +13/-6.

* desktop: extract itemPrefixText, drop dead defensive code

Re-introduce itemPrefixText(ci) helper in TextItemView.kt and migrate all
four sites that compute the report prefix (FramedItemView,
ChatPreviewView, TextSelection x2). The prefix expression now has one
definition and one place to change.

Also drop the unreachable sel.first.coerceAtLeast(0) on the prefix-slice
append — selectedRange guarantees sel.first >= 0.

* plans: justify desktop fix for copying selected text in reports

Add 2026-05-08-fix-select-in-reports.md covering the problem, the offset
flow, the minimal structural change (seed displayOffset with prefix.length),
the itemPrefixText single-source-of-truth migration across the four
prefix sites, the verified edge-case table, and the rollback path.
2026-05-08 12:15:52 +01:00
Narasimha-sc 8c9c6471a7 desktop: fix RTL text rendering under the send button (#6906)
* desktop: fix RTL text rendering under the send button (#4137)

The chat composer's text field reserved 50dp on the wrong horizontal side
when an RTL message was typed under an LTR system locale: BiDi auto-detection
right-aligned the text onto the BottomEnd edge where the send button sits,
hiding the first characters as they were typed.

The padding was originally written inside the CompositionLocalProvider(
LocalLayoutDirection provides Rtl) scope (#4675), where start resolved to
the right edge for RTL paragraphs. The "edge to edge design" refactor
(#5051) lifted the modifier out of that scope onto the outer BasicTextField,
so start began resolving against the global LTR direction and the
reservation drifted to the left.

Always reserve on the global end - the same side Alignment.BottomEnd in
SendMsgView resolves to - so the reservation tracks the send button
regardless of locale or typed-text direction. Behavior is byte-identical
for LTR text and for any RTL-locale combination; only the buggy
"RTL text + LTR system locale" pair changes.

* desktop: minimise diff of RTL fix to 2 lines (#4137)

The previous commit (bfc111cc6) renamed/removed several helper locals
and rewrote the comment block alongside the behaviour change. The
behaviour-changing part is just two lines: making startPadding always
0.dp and endPadding equal to startEndPadding.

Restore the surrounding code (startEndPadding name, startPadding decl,
PaddingValues argument, .padding modifier, and the original two-line
comment) to its master form so the PR's only effect on master is the
two-line fix.

Behaviour: cases 1, 3, 4 of the locale x text matrix are byte-identical
to master. Only case 2 (LTR locale + RTL text) flips the reservation
from the wrong side to the correct side.

* plans: desktop RTL composer fix (#4137)

* plans: align with surgical 2-line fix in PR (#4137)
2026-05-08 11:10:14 +01:00
spaced4ndy 828b8e8715 core: single relay checks interval (#6952) 2026-05-08 09:12:33 +00:00
spaced4ndy 2a4ce7ec9c docs: channel subscriber profiles plan (#6918) 2026-05-08 09:00:36 +00:00
spaced4ndy d986c00530 ui: disable relay management (#6951) 2026-05-08 08:37:55 +00:00
spaced4ndy 6f8a07e4ea core, ui: relay management - add, remove relays, synchronization to relay list (#6917) 2026-05-08 07:19:16 +00:00
spaced4ndy d9cfc9bd3d ui: adjust create channel ui (#6950) 2026-05-08 06:27:26 +00:00
Evgeny fb88a0e52c website: update home page (#6948)
* website: update home page

* update credits page

* update token page

* update community credits

* update texts

* downloads

* translate

* update

* community credits

* update

* french

---------

Co-authored-by: Evgeny @ SimpleX Chat <259188159+evgeny-simplex@users.noreply.github.com>
2026-05-07 21:04:46 +01:00
spaced4ndy 068c0a884e ios: fix link chat item not fitting into screen width (#6947) 2026-05-07 10:31:08 +00:00
sh fefdea8ed0 support bot, bots: paginate chat scan (#6935)
* bots: document APIGetChats command and CRApiChats response

* bots: regenerate API docs and TypeScript types

* simplex-chat-nodejs: add apiGetChats

* support bot: avoid OOM on large databases

apiListGroups / apiListContacts return every record in one response and
overflow V8's string allocation on large DBs. Replace list-then-find-by-id
patterns with apiGetChat(type, id, 0) lookups, and the one genuine scan
(refreshAllCards) with paginated apiGetChats, count=1000.

* support bot: update test assertions to match current message text

* bots: simplify PaginationByTime, expose only PTLast

* simplex-chat-nodejs: bump types and nodejs versions
2026-05-06 08:54:36 +01:00
sh db783d85d7 website: tweaks (#6945) 2026-05-05 17:32:26 +01:00
Evgeny Poberezkin a53b8b05cb Merge branch 'master' into ae/oklch-color-space-plan 2026-05-04 17:37:52 +01:00
sh e0f7d6fb55 flatpak: update metainfo (#6943) 2026-05-04 17:29:57 +01:00
Evgeny Poberezkin 79d21f06bf 6.5.1: android 347, desktop 142 v6.5.1 2026-05-02 20:30:43 +01:00
Evgeny Poberezkin d9a30289e6 6.5.1: ios 331 2026-05-02 19:51:44 +01:00
Evgeny Poberezkin bed583dee7 core: 6.5.1.1 2026-05-02 18:45:10 +01:00
Evgeny Poberezkin 60f4a4d60b core: fix migration 2026-05-02 17:59:03 +01:00
Evgeny Poberezkin b7c3d8a279 core: 6.5.1.0 (simplexmq 6.5.1.0) 2026-05-02 12:14:01 +01:00
Evgeny Poberezkin 991bc9f789 core: add preset chat realy 2026-05-02 11:56:34 +01:00
spaced4ndy 8f66a0cc98 core: fix relay request worker retry limit (#6931)
* core: fix relay request worker retry limit

* update plan

* update plan

* update plan

* wip

* schema

* wip

* wip

* schema

* update

* remove comment

* rework

* schema

* update

* schema

* update

* plans

* corrections

* add 1 second

* remove + 1

* add +1 to schedule

* changes

* updated schemas

---------

Co-authored-by: Evgeny @ SimpleX Chat <259188159+evgeny-simplex@users.noreply.github.com>
Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2026-05-02 11:31:03 +01:00
Evgeny @ SimpleX Chat f03584e09a website: fix directory (#6936) 2026-05-01 23:03:26 +01:00
spaced4ndy ce0e9c37c1 ui: improve channel creation ux (#6933)
* ui: improve channel creation ux

* update

* update

* update

* wip

* update
2026-05-01 20:42:15 +01:00
Evgeny 17b5e006d2 blog: v6.5, channels, consortium agreement, crowdfunding (#6930)
* blog: update v65 blog post

* typo

* update date

* update

* add footnotes support

* named footnotes

* improve footnotes

* fix footnotes style

* backrefs

* css

* paragraphs

* separator

* update

* update link

* add support for dark mode image in blogs list

* update

* smaller image

---------

Co-authored-by: Evgeny @ SimpleX Chat <259188159+evgeny-simplex@users.noreply.github.com>
2026-04-30 21:04:55 +01:00