Commit Graph
6916 Commits
Author SHA1 Message Date
spaced4ndy d3e2157dca Merge branch 'master' into f/badge-subscriptions 2026-10-27 12:08:14 +04:00
Evgeny @ SimpleX Chat 91675ec5ab docs: Swift functions inside types, extensions only where required (#7901) 2026-10-27 07:46:01 +00:00
Evgeny @ SimpleX Chat b72379c640 desktop: ask before replacing a file, do not suggest hidden file names (#7877)
* desktop: ask before replacing a file, do not suggest hidden file names

* desktop: test the file name suggested by the Save dialog
2026-10-26 20:19:21 +00:00
Evgeny @ SimpleX Chat f7f42e70e5 ci: reduced build on pushes to master and stable in forks (#7882)
* ci: reduced build on pushes to master and stable in forks

* ci: test retry message only when retrying

* ci: pull request changes against the current base

* ci: deploy the website only from simplex-chat/simplex-chat
2026-10-26 19:12:01 +00:00
Evgeny @ SimpleX Chat ec8884f465 core: ignore relay join requests in groups without relays (#7875) 2026-10-26 18:28:09 +00:00
Evgeny @ SimpleX Chat 3de946b7d4 ci: upload app builds for manual tests (#7880) 2026-10-26 18:19:24 +00:00
Evgeny @ SimpleX Chat a0730ae8b8 ci: skip freeing disk space in reduced builds (#7884) 2026-10-26 12:42:31 +00:00
Evgeny @ SimpleX Chat 85ba221d79 ci: reduced build of changed scopes on drafts and manual runs (#7870)
* ci: reduced build of changed scopes on drafts and manual runs

* ci: tests only when selected in reduced builds

* ci: test selection and retries in scripts/ci/run-tests.sh
2026-10-26 11:19:50 +00:00
Evgeny @ SimpleX Chat c3b709a807 docs: CLAUDE.md importing the contributing and CI guides (#7871) 2026-10-26 10:34:31 +00:00
spaced4ndy a210246910 update sqlite schema 2026-10-26 12:58:45 +04:00
spacedandy-agents-simplex 2d2d3abeda Merge branch 'master' into f/badge-subscriptions
# Conflicts:
#	simplex-chat.cabal
#	src/Simplex/Chat/Store/Postgres/Migrations.hs
#	src/Simplex/Chat/Store/SQLite/Migrations.hs
2026-10-26 07:20:22 +00:00
Evgeny @ SimpleX ChatandEvgeny Poberezkin 7810fc4752 core, ui: terminal chat layout for LLM and service bot chats (#7811)
* plan: UI improvements to improve LLM usage via SimpleX

* core, ui: types for chat layout

* core, ui: settings for alternative terminal-like chat layout for managing LLMs or other service bots

* plan: message priority

* fixes

* query plan

* update plans

* remove silent messages plan

* rename migrations

* implement layout

* amend

* fix

* fix

* fix

* improve

* time on the right, sender name in blue

* no avatar in direct chats

* better previews

* update, fixes

* update

* time gap

* changes

* ui: terminal layout line heights, gaps and time placement

* ui: simplify terminal meta layout, correct its docs and tests

* ui: right-to-left emoji edge in terminal rows, time placement tests

* android, desktop: raise Kotlin compiler memory to 4 GB

* ui: terminal captions as follow-up text, classic event separators

* ui: terminal media edge and overlay time, plan decisions

* ui: simplify terminal row separation, correct doc line references

* ui: keep the media time inside terminal rows, restore caption conditions

* ui: terminal heading capitals at large font scales, idle live message time

* ui: rename the classic voice-with-text flag, correct the meta copy docs

* ui: smaller terminal layout diff, sender gap and meta names

* ui: terminal row as tall as the media time

* docs: remove the chat layout section from the bots readme

* docs: shorten the terminal layout section of the chat view

* core: address settings API as on master, /auto_accept reads the stored layout

* ui: smaller terminal headings

* ui: classic sender rows and avatar rule as on master

* ui: classic reply quote text colour as on master

* ios: keep the chat layout setting with other UI settings

* ui: go-to button at the end of terminal rows, no gutter in direct chats

* ui: forwarded arrow on the header line of terminal rows, above the time

* ui: forwarded arrow centred above the time line of terminal rows

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2026-10-25 18:03:11 +00:00
Evgeny @ SimpleX Chat 4f81c6f632 tests: read chat started in any order with subscription notices (#7869) 2026-10-25 17:25:27 +00:00
Evgeny @ SimpleX Chat a5cf718b3c core, tests: fix flaky tests; use simplexmq with one thread per agent worker (#7812)
* tests: fix group tests

* fix test

* fix

* fix delivery worker fix

* watch ci

* debug

* fix delivery worker not forwarding to moderators during host acceptance

* add script, update simplexmq

* debug lines

* more debug

* rerun

* debug

* fix, debug

* simplexmq

* simplexmq

* fix

* debug: log member-not-found call sites, restore hang diagnostics, use simplexmq fork

* tests: do not prompt for migration confirmation in strict tables test

* ci: run tests with one capability; simplexmq: end inactive sessions without closing under readers

* ci: run tests on all capabilities

* remote: close the HTTP2 client before its TLS connection

* cabal: use warp that kills timed out connection threads without closing their sockets

* remove diagnostics: member-not-found log, thread dump, CI watchdog; update simplexmq

* badge-service: prevent interleaving of concurrent log lines

* tests: wait for badge group broadcasts before closing members

* tests: log contact connected events received twice

* tests: log member connected events received twice

* core: use simplexmq that logs connections emitting CON twice

* core: keep the team contact above notes in a new user's chat list

* ci: skip macOS and Windows builds while hunting a Linux-only flake

* core: use simplexmq that logs the history of connections emitting CON twice

* tests: remove the logging of connected events received twice

* ci: run macOS and Windows builds again

* core: use simplexmq that runs one thread per agent worker

* core: use the merged simplex-chat/wai warp and the updated simplexmq

* core: use the merged simplexmq

* core: update simplexmq

* core, badge service: comment single writes of terminal segments and log lines
2026-10-25 15:37:06 +00:00
EvgenyandEvgeny @ SimpleX Chat ea679e6e95 scripts: manage in-app prices (#7735)
* scripts: manage in-app prices

* better

* move scripts to one folder

* shorter token

* workbook generator script

* gitignore

* gitignore, package.json

* update script

* faster calculation

* fix workbook

* gitignore

---------

Co-authored-by: Evgeny @ SimpleX Chat <259188159+evgeny-simplex@users.noreply.github.com>
2026-10-25 06:03:52 +00:00
Narasimha-sc d5bab6d9d7 desktop: stop the gsettings theme monitor when the app exits (#7747)
* desktop: stop the gsettings theme monitor when the app exits

On Linux the theme detector library starts `gsettings monitor` to
follow the system theme and never stops it. The process outlived the
app, one per run, each holding a D-Bus connection until the next
theme change. A shutdown hook now stops it.

* plans: gsettings theme monitor left running after the app exits

* desktop: install the gsettings shutdown hook on Linux only

* plans: correct the Ctrl-C note for the gsettings monitor

* plans: gsettings ignores SIGPIPE; the monitor lives until killed or logout
2026-10-24 22:56:23 +01:00
spaced4ndy 74ef79d1ef core: show a raised badge tier to contacts at once, hold back a lower one 2026-10-23 21:10:55 +04:00
spaced4ndy c3f5b6177b update plans 2026-10-23 20:57:33 +04:00
spaced4ndy 5dab5e274f core: show a changed badge tier to contacts as soon as it is granted 2026-10-23 20:10:29 +04:00
sh 66e381bf55 ci: bump Corretto to 17.0.21.0.10 (#7804) 2026-10-23 10:39:04 +01:00
sh 31c4b68189 ui: don't reconnect calls with peers before v22 (#7785) 2026-10-23 10:06:33 +01:00
sh 773434a561 ci: pin build image dependencies (#7791) 2026-10-23 09:37:36 +01:00
sh 236893e1ac ci: add kotlin and ios build workflow (#7710)
* ci: add kotlin and ios build workflow

* ci: compile desktop kotlin without native lib

* ci: build apps kotlin targets sequentially

* ci: use node 24 actions in apps workflow

* ci: build kotlin and ios apps in build workflow

* ci: skip core jobs for app-only pull requests

* ci: choose builds to run from changed paths
2026-10-23 09:15:01 +01:00
spaced4ndy 8cdfed8f27 update badge subscriptions docs (#7802) 2026-10-23 06:59:32 +00:00
spaced4ndy 3fc72af5e8 badge subscription review fixes (#7799) 2026-10-23 06:15:58 +00:00
EvgenyandEvgeny @ SimpleX Chat d63906ad55 mcp server: fixes (#7793)
Co-authored-by: Evgeny @ SimpleX Chat <259188159+evgeny-simplex@users.noreply.github.com>
2026-10-22 21:33:25 +01:00
Narasimha-sc cfcce1b43c ui: create one group on a double click of Create group (#7759)
* desktop: open a pending connection's "Learn more" and "Incognito" pages once

On desktop the connection view stays clickable in the center pane, so each
click on these rows pushed another modal onto the right pane. Close the
right-pane modals first, as ChatView does when the connection opens. The page
is closed and shown again in one event, so its content is keyed by its
ModalData to start fresh.

Desktop only: on Android the view can itself be the open modal of the shared
manager ("Set contact name"), and the new page already covers the row.

Fixes #6270

* ui: open a modal once when its button is double-clicked

A modal slides in over 250 ms, and until it covers the button that opened it the button still takes clicks, so a double click opened two copies (left-pane pages and most stacked center and right-pane pages on desktop, animated modals on Android). When a modal opens, the page it covers draws an empty pointerInput box over itself while it slides out; when a pane's first modal slides in, the empty page sliding out covers the view under the pane. The page sliding in already takes clicks, and nothing is blocked when a page closes.

* ui: add isTopModalOpen, which ignores modals that are sliding out

A modal closed with animation stays in modalViews until it has slid out, and isLastModalOpen counts it. A check-then-closeModal() on it would close the modal under it. Uses the same index as isLastModal; isLastModalOpen and its callers are unchanged.

* desktop: don't open a second badges page or profile form

These buttons stay clickable on desktop while their page is shown in another pane, so each click opened another copy:
- "Support SimpleX" in the chat's large-file and badge alerts (Badges on the right): the alerts skip while Badges is open, on desktop only, as on Android the page covers the button;
- "+ Add profile" in Your chat profiles and "Create chat profile" in the picker (form in the center): skip while the form is on top, keeping what was typed, before asking for authentication; the picker row still hides the picker.

* desktop: replace a page of the same kind on top instead of stacking another

These buttons stay clickable on desktop while their page is shown in another pane, so each click pushed another copy:
- the chat banner's bio "Read more" (right pane);
- a markdown file clicked in a support chat (viewer in the center);
- message "Info" in the main chat while a support or reports chat is open on the right.
Their content depends on what was clicked and the pane can hold other pages (a support chat), so a page of the same kind on top is replaced. The new page is drawn where the old one was, so its content is keyed by its ModalData to start fresh. The markdown file and Info load on a background thread; their close and show now run on the main thread. The markdown check is desktop only, as on Android the viewer covers its file once it has loaded.

* plans: a page opens again on every click of its button (#6270)

* ui: create one group on a double click of Create group

"Create group" creates the group, opens it and only then closes its
page, and the core does not deduplicate, so a double click created two
groups. The page now ignores a click while its create is in progress,
on desktop and Android.

* plans: a double click on "create group" creates two groups

* plans: D2 is valid at 80 ms only

* ui: ignore a click on Create group until its page has closed after a create
2026-10-22 18:48:32 +01:00
spacedandy-agents-simplex 8017631dec badge-service: break a tie between issuances by their period, so both databases agree 2026-10-22 17:37:20 +00:00
spaced4ndy 7ea7bfd053 update postgres schema 2026-10-22 21:32:29 +04:00
spaced4ndy c3deb5163b unfocus test 2026-10-22 21:13:41 +04:00
spacedandy-agents-simplex 9d947a983a tests: hold the move with no charge to grant, not with the purchase's store check 2026-10-22 17:11:22 +00:00
spacedandy-agents-simplex 814b98bb4d ios: choose a badge on the site, not in the app 2026-10-22 17:09:40 +00:00
spacedandy-agents-simplex eb2ed9d078 ios, android, desktop: open the badge page on the site again 2026-10-22 17:07:33 +00:00
spaced4ndy 9335eefdf8 fix api 2026-10-22 21:04:54 +04:00
spaced4ndy ee28a4fc83 fix compilation 2026-10-22 21:00:20 +04:00
spaced4ndy 2c8db2b293 core: make the badge subscription tests fail on the defects they name (#7798) 2026-10-22 16:51:24 +00:00
spacedandy-agents-simplex 04e316bec5 fixup! docs: tell the badge subscriptions story with tier changes and restore 2026-10-22 20:39:05 +04:00
spacedandy-agents-simplex 0ac50cd4c3 fixup! docs: describe badge tier changes and restore as the service handles them 2026-10-22 20:39:05 +04:00
spacedandy-agents-simplex a8c1b0e228 fixup! docs: tell the badge subscriptions story with tier changes and restore 2026-10-22 20:39:05 +04:00
spacedandy-agents-simplex e9f859759d fixup! docs: describe badge tier changes and restore as the service handles them 2026-10-22 20:39:05 +04:00
spacedandy-agents-simplex 5e2ac775ff docs: tell the badge subscriptions story with tier changes and restore
The summary now covers the whole lifecycle: buying, renewing, changing
tier, moving to another device or profile, and ending. The badge retires
as soon as the store says the subscription ended, a lapsed iOS subscriber
can resume the retired badge, an App Store raise is granted at once and
a lower tier at the renewal, and a Play plan change is a new purchase.
The known limits and the before-sale list follow the code.

The seven diagrams are updated, with stale file and line references
dropped, and two are added: a tier change and a restore. The page now
points at the diagram files instead of carrying copies of them.
2026-10-22 20:39:05 +04:00
spacedandy-agents-simplex a43a44f2ee docs: describe badge tier changes and restore as the service handles them
The RPC document splits a store tier change by store and direction: the
app never starts one, an App Store raise seen within a day of its charge
is sent as upgradeBadgeSubscription, every other change waits for the
renewal check, and a Play plan change is a new token, a new purchase.
transferBadge and its limits are checked against the handlers, and the
upgrades that are not built are marked so.

The overview admits what Restore discloses: the service links the two
purchase keys, a store receipt moves its subscription to whoever presents
it within the move limit, and a new badge or tier is shown as soon as it
is issued. The Android gap names what remains of Restore.
2026-10-22 20:39:05 +04:00
spaced4ndy 7a93b63385 badge-service: let a restore ask the store without waiting for the purchase's own check 2026-10-22 20:00:25 +04:00
spacedandy-agents-simplex ca4c70c93e core: test that an App Store change to a lower tier waits for the renewal
A Supporter charge handed over while Legend is shown is answered from the record and sends nothing, and the renewal check grants Supporter, shown once the Legend credential expires; a record an older build held for a lower tier settles with no request. Both fail if every change of tier is sent at once again.

Run: 016-tier-change-direction
2026-10-22 08:11:12 +00:00
spacedandy-agents-simplex a0ef455aea core: apply an App Store tier change at once only when it raises the tier
Apple keeps charging the old plan to the end of the period, so applying a downgrade at once took away a badge the subscriber had already paid for. A charge of another tier is now held and sent at once only from supporter to legend; a lower tier, or one that is not ranked (investor, unknown), is answered from the record and the renewal check grants it, as badges-rpc.md says. A record already held for such a change settles silently.

Run: 016-tier-change-direction
2026-10-22 07:24:53 +00:00
spacedandy-agents-simplex 0c901f9917 review: round 3 fixes
- R3-1: a tier change whose answer says the subscription ended is not credited, as a resume is not, so the credit's clearing of a stored ended never drops the one this answer carries.
- R3-2: the changeTier comment in two lines.

Run: 015-badge-fixes, review round 3
2026-10-21 21:37:26 +00:00
Narasimha-sc cc3f49f794 android, desktop: fix chat preview and unread counter updating wrong chat (#7072)
* android, desktop: fix chat preview and unread counter updating wrong chat

While "Chat with admins", a member support chat or the reports view was
open, ChatsContext.addChatItem in the secondary context looked up the
chat's index in its own list but read and wrote the main chat list at
that index (chatsContext.chats[i]), so an unrelated chat in the main
list got the message as its preview and its unread count went up.

Use the context's own list at all four sites again. The main-list
qualifier had also made a pending invitee's sent support messages reach
the group's preview in the main list (at a secondary-list index), so
send that update to the main list explicitly: addSentChatItem passes a
sent item to the main chat list context as well when it is sent from a
secondary view and belongs in the main list (inMainChatList, the same
rule addChatItem uses for previews). Count unread stats only in the
main chat list context, so the revert does not make the open secondary
view count main-list messages in its own list.

* plans: wrong-chat preview and unread fix
2026-10-21 22:36:34 +01:00
Narasimha-sc 87e3f8c3f6 ui: open a page once when its button is clicked again or double-clicked (#7725)
* desktop: open a pending connection's "Learn more" and "Incognito" pages once

On desktop the connection view stays clickable in the center pane, so each
click on these rows pushed another modal onto the right pane. Close the
right-pane modals first, as ChatView does when the connection opens. The page
is closed and shown again in one event, so its content is keyed by its
ModalData to start fresh.

Desktop only: on Android the view can itself be the open modal of the shared
manager ("Set contact name"), and the new page already covers the row.

Fixes #6270

* ui: open a modal once when its button is double-clicked

A modal slides in over 250 ms, and until it covers the button that opened it the button still takes clicks, so a double click opened two copies (left-pane pages and most stacked center and right-pane pages on desktop, animated modals on Android). When a modal opens, the page it covers draws an empty pointerInput box over itself while it slides out; when a pane's first modal slides in, the empty page sliding out covers the view under the pane. The page sliding in already takes clicks, and nothing is blocked when a page closes.

* ui: add isTopModalOpen, which ignores modals that are sliding out

A modal closed with animation stays in modalViews until it has slid out, and isLastModalOpen counts it. A check-then-closeModal() on it would close the modal under it. Uses the same index as isLastModal; isLastModalOpen and its callers are unchanged.

* desktop: don't open a second badges page or profile form

These buttons stay clickable on desktop while their page is shown in another pane, so each click opened another copy:
- "Support SimpleX" in the chat's large-file and badge alerts (Badges on the right): the alerts skip while Badges is open, on desktop only, as on Android the page covers the button;
- "+ Add profile" in Your chat profiles and "Create chat profile" in the picker (form in the center): skip while the form is on top, keeping what was typed, before asking for authentication; the picker row still hides the picker.

* desktop: replace a page of the same kind on top instead of stacking another

These buttons stay clickable on desktop while their page is shown in another pane, so each click pushed another copy:
- the chat banner's bio "Read more" (right pane);
- a markdown file clicked in a support chat (viewer in the center);
- message "Info" in the main chat while a support or reports chat is open on the right.
Their content depends on what was clicked and the pane can hold other pages (a support chat), so a page of the same kind on top is replaced. The new page is drawn where the old one was, so its content is keyed by its ModalData to start fresh. The markdown file and Info load on a background thread; their close and show now run on the main thread. The markdown check is desktop only, as on Android the viewer covers its file once it has loaded.

* plans: a page opens again on every click of its button (#6270)

* plans: D2 is valid at 80 ms only
2026-10-21 22:35:29 +01:00
spacedandy-agents-simplex cb1134f0bb review: round 2 fixes
- R2-1: a granted tier change clears an ended state the device reported before it. A renewing report never replaces ended, and a charge of the new tier granted proves the subscription has not ended, so without this the worker retired the new tier's badge at its paid-through while the subscription renewed.
- R1-B3: test a tier change whose credential does not verify: the failure stays on the receipt record, not the purchase, and Supporter stays shown.
- R2-3: the refused tier change's test buys Supporter through an invoice, so it shows the refusal announces nothing.
- R2-2: the changeTier comment says what follows each way the record settles.

Run: 015-badge-fixes, review round 2
2026-10-21 21:14:49 +00:00
spacedandy-agents-simplex 5096b3b698 review: round 1 fixes
The App Store tier-change hold, reviewed for the first time:

- R1-B2: a tier change's credit now shows its purchase again (shown_badge_id) in the same transaction, as a resume's does, so a retire that ran while the change was with the service cannot leave a paid purchase unshown and never renewed.
- R1-B5: a tier change of a shown purchase is held whatever other receipt is held, as the worker serves it while the badge is shown; only a resume waits for other held receipts.
- R1-B3: test a tier change the store does not vouch for: refused in silence, the badge kept, and answered from the record after.
- R1-B8: the changeTier comment names when the record settles.

Run: 015-badge-fixes, review round 1
2026-10-21 20:33:29 +00:00