Commit Graph
1550 Commits
Author SHA1 Message Date
spacedandy-agents-simplex 06c816de10 review: round 1 fixes
badge-service: a Play charge whose clipped period start leaves its month
already spent is answered as period over, not internal (R1-A1).
docs: the per-store answer classes list Play's 410 and the App Store
subscription check (R1-A2).
tests: a held receipt with no attempt yet blocks an invoice (R1-B2); a
renewing report keeps an ended status (R1-B3); a test comment names
[google] (run 005 C2-R2-1).
ios: a subscription refused because this Apple ID subscribed before
shows its sentence, not the error's name (R1-C2); ios, android, desktop:
the Check your order footnotes share one helper (R1-C3).

Run: 006-subscriptions-branch-review, review round 1
2026-10-15 15:50:21 +00:00
spacedandy-agents-simplex 7670357383 review: round 3 fixes
ios: a subscription refused because this Apple ID subscribed before has
its own error, and Check your order says why Pay is disabled (R3-2).
android: skip the subscriptions query only when Play does not support
subscriptions, so a disconnected client fails the sweep or Restore
rather than reading as no subscriptions (R3-1).

Run: 003-badge-subscriptions-ui, review round 3
2026-10-15 09:42:21 +00:00
spacedandy-agents-simplex 2c83d0fe45 review: run 003 round 2 and run 004 round 1 app fixes
ios: buy a subscription only while it is still for sale, after re-reading
the Apple ID's transactions, and disable Pay once it is not, so a Check
your order screen opened before another profile or device subscribed
cannot buy one Apple folds into the earlier subscription (run 003 R2-1,
run 004 R1-4). android: skip the subscriptions query only on a device
whose Play does not support subscriptions, so Restore no longer says
"Nothing to restore" when the query failed (run 003 R2-2).

Run: 003-badge-subscriptions-ui round 2; 004-badge-subscriptions-review round 1
2026-10-15 09:36:17 +00:00
spacedandy-agents-simplex 18617ade60 review: round 1 fixes
ios: stop selling a subscription once this device has seen one, so a
second profile is not charged for a subscription Apple folds into the
first (R1-12). Continue pins the chosen period on both apps (R1-13).
Only a device with a subscription asks its store for products and status
when reporting, and the purchases are marked checked before the report
(R1-14, R1-5: Kotlin now loads the products, so the price shows after a
restart). Restore says "Nothing to restore" after a cancelled purchase
(R1-7). Android keeps sweeping one-time purchases when the subscriptions
query fails (R1-6). The freshness comment in requestBadgeIssue states the
service's one-hour repeat of its last check (R1-1).

Run: 003-badge-subscriptions-ui, review round 1
2026-10-15 09:25:48 +00:00
spacedandy-agents-simplex 1b336bc23d docs: describe the one badge alert banner in the apps' chat-list specs
Both chat-list specs described two hand-written badge banners (expired,
renewal failed); the chat list now has one banner for the current badge
alert of any kind. Also moves the line links this run shifted.

Run: 003-badge-subscriptions-ui, slice 13
2026-10-15 07:24:45 +00:00
spacedandy-agents-simplex 648dccd7c4 android, desktop: sell badge subscriptions and show their state on Your badge
The Kotlin port of the iOS screens. How long and Check your order offer
monthly and annual with Google Play's subscription disclosure, the privacy
policy link and Restore purchases. Your badge shows the subscription's state
with the same texts as iOS, the store named Google Play with a store lane and
"the store" without one, and Manage subscription and Restore purchases only
with a store lane on the local host. The chat list shows one banner for the
current badge alert of any kind. Desktop shows the state, footers and banners
without store rows or a price.

Run: 003-badge-subscriptions-ui, slice 12
2026-10-15 07:22:47 +00:00
spacedandy-agents-simplex 812518eeb4 android: hand Play subscriptions to the core and report their renewal state
The Kotlin port of the iOS store change. A Play subscription was
acknowledged uncredited; every badge product now goes through a core
invoice and is handed over. The sweep queries subscriptions as well as
one-time products, and the sweep and purchases listener hand over as listed,
so another device on the Google account does not claim them; Restore claims
them for this profile. A subscription is bought on its base plan's own
offer, and the app never acknowledges one itself: the service does when it
credits it, so Play still refunds one the service never credits.

The app reports Play's isAutoRenewing to the core as renewing or cancelled.

Run: 003-badge-subscriptions-ui, slice 11
2026-10-15 07:16:25 +00:00
spaced4ndy 59c588932e badge-service: verify App Store and Google Play purchases (#7654) 2026-10-13 15:24:07 +00:00
spaced4ndy cf3d6c45d0 ios, android: tell the buyer once a run when a swept purchase cannot be handed over (#7674) 2026-10-09 11:59:39 +00:00
spaced4ndy 57ab333a2b Merge branch 'master' into badge-in-app-checkout 2026-10-09 15:00:36 +04:00
spaced4ndy 7c2c7503f2 ui: do not show "No relays" while leaving a channel (#7673) 2026-10-09 10:56:00 +00:00
EvgenyandEvgeny @ SimpleX Chat 9c9c86f9c0 core, ui: fix profiles, add error alerts (#7663)
* core, ui: fix profiles, add error alerts

* simplify

* query plans

---------

Co-authored-by: Evgeny @ SimpleX Chat <259188159+evgeny-simplex@users.noreply.github.com>
2026-10-08 22:53:59 +01:00
EvgenyandEvgeny @ SimpleX Chat 96970373b0 core: add status when switching queue (#7664)
* core: add status when switching queue

* fix

---------

Co-authored-by: Evgeny @ SimpleX Chat <259188159+evgeny-simplex@users.noreply.github.com>
2026-10-08 16:31:29 +01:00
spaced4ndy 75e6fe8f5d ios, android: tell the buyer a badge was added when the store purchase completes off screen (#7662) 2026-10-08 15:29:05 +00:00
shandspaced4ndy efab293609 desktop: deep links on macOS, Windows and Linux (#7605)
* tests: close the walk stream in withTempDir

* desktop: receive app links from args and macOS

* desktop: forward an app link to the running app

* desktop: initialize the desktop platform lazily

* tests: share the temp directory helper

* desktop: register simplexchat scheme in packages

* desktop: register simplexchat scheme at runtime

* ui: end the badge page with a link on desktop

* desktop: raise the window over other apps

* docs: describe desktop deep links in the spec

* docs: plan desktop deep links

* docs: report on desktop deep links

* desktop: open simplex connection links

* docs: describe simplex links on desktop

* desktop: keep a link from opening twice

* desktop: retry taking a signal held open

* desktop: keep the user's AppImage link handler

* desktop: register Windows links through Capabilities

* desktop: add %u to the deb entry only once

* docs: describe the review fixes

* ui: open the badge link screen on the left

* ui: import moko accessors in the badge screens

---------

Co-authored-by: spaced4ndy <8711996+spaced4ndy@users.noreply.github.com>
2026-10-08 14:48:50 +00:00
EvgenyandEvgeny @ SimpleX Chat 0c1ffa65bc core: group fixes/improvements (#7660)
* core: group fixes/improvements

* Large messages dropped by relays and hosts (the same 15602 limit was applied, without accounting for forwarding header)
* Members below v18 did not receive forwarded messages or history in p2p groups.
* Join confirmations near the size limit could fail.
* SMP servers are limited to 2 host names each.

* simplify

* remove legacy forwarding and history support

* only restrict p2p groups

---------

Co-authored-by: Evgeny @ SimpleX Chat <259188159+evgeny-simplex@users.noreply.github.com>
2026-10-08 15:06:18 +01:00
spaced4ndy b4f1249436 core, ios, android: name the resolved store purchase so the app finishes it without a sweep (#7659) 2026-10-08 13:46:27 +00:00
spaced4ndy c0c5ba8393 Merge branch 'master' into badge-in-app-checkout 2026-10-08 16:49:27 +04:00
sh dd7768e543 android, desktop: upgrade moko-resources to 0.27.1 (#7661) 2026-10-08 12:32:57 +00:00
spaced4ndy 80b7f96a96 merge master into badge-in-app-checkout 2026-10-08 14:31:30 +04:00
spaced4ndy 27d12f230d core, ui: buy a badge with an App Store or Google Play purchase (#7590) 2026-10-07 14:32:48 +00:00
sh 40478c1c45 android: target API 36, AGP 8.10.1 (#7656)
* android: migrate back handling to callbacks

* android: target API 36, AGP 8.10.1

* android: opt out of predictive back app-wide
2026-10-07 10:30:26 +01:00
spaced4ndyandEvgeny Poberezkin 86671a1699 core, ui: confirm before connecting a call answered without e2e encryption (#7647)
Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2026-10-05 09:45:57 +01:00
a9322ff32c android: prevent access to chat list when accepting call in locked state (#7627)
* android: prevent access to chat list when accepting call in locked state

* android: request auth on resume during a call

---------

Co-authored-by: Evgeny @ SimpleX Chat <259188159+evgeny-simplex@users.noreply.github.com>
Co-authored-by: shum <github.shum@liber.li>
2026-10-04 12:07:39 +01:00
shandNarasimha-sc be05a46628 android: StrongBox for new keystore keys, show key storage level (#7637)
* android: create new keystore keys in StrongBox

* android: show keystore key storage level

* ui: save keystore key before marking it stored

* android: show keystore storage level in the footer text instead of a separate row

* android: return keystore storage label, drop enum

---------

Co-authored-by: Narasimha-sc <166327228+Narasimha-sc@users.noreply.github.com>
2026-10-04 10:47:46 +01:00
1a969a6cb9 core, ui: remove database backups after key changes (#7628)
* core, ui: remove database backups after key changes

* ui: delete database backups on chat start without delaying encryption marker reset

Keeping encryptionStartedAt set until chat start made DatabaseErrorView show
"The attempt to change database passphrase was not completed" with a Restore
button after every successful passphrase change when the passphrase is not
stored. Restore the marker handling from master and delete backups
unconditionally after chat starts.

* another flag

---------

Co-authored-by: Evgeny @ SimpleX Chat <259188159+evgeny-simplex@users.noreply.github.com>
Co-authored-by: Narasimha-sc <166327228+Narasimha-sc@users.noreply.github.com>
2026-10-03 16:56:58 +01:00
SimpleX Chat 51630d61ef 7.1-beta.6: android 386, desktop 167, ios 362 2026-10-03 13:33:46 +00:00
Evgeny Poberezkin 6b596c0c35 Merge branch 'stable' 2026-10-03 08:05:19 +01:00
EvgenyandNarasimha-sc 53e6d435bc android, desktop: blur media thumbnails in reply quotes and the chat list (#7639)
"Blur media" hid images and videos in a chat but showed the same media
sharp as the thumbnail of a quoted message and as the last message's
image, video or link preview in the chat list.

Small views are now blurred with the same reveal as chat media. They are
resampled relative to the width they are drawn at, so a thumbnail is
blurred as much on screen as media in a chat, and drawn as the centre
crop the thumbnail shows. In-chat media keeps the same blur.

Blurring the chat list also needs: each last message gets its own blur
state, loaded chat-list videos use it and hide their full-screen play
button while blurred, a right-click on a thumbnail no longer leaves it
revealed on desktop, and leaving a chat mid-scroll no longer undoes
reveals in the list on Android.

Co-authored-by: Narasimha-sc <166327228+Narasimha-sc@users.noreply.github.com>
2026-10-03 07:17:20 +01:00
EvgenyandEvgeny @ SimpleX Chat a1cf69e9a9 desktop: allow only one connection from call page (#7619)
Co-authored-by: Evgeny @ SimpleX Chat <259188159+evgeny-simplex@users.noreply.github.com>
2026-10-02 17:06:48 +01:00
EvgenyandEvgeny @ SimpleX Chat 806943bd62 android, desktop: do not show caller profile in hidden preview mode (#7620)
Co-authored-by: Evgeny @ SimpleX Chat <259188159+evgeny-simplex@users.noreply.github.com>
2026-10-02 17:02:24 +01:00
Narasimha-sc 205d17e2fa android, desktop: make media blur much lighter on CPU (#7483)
* ui: blur media by resampling the preview, not a per-frame effect

Modifier.blur put a BlurEffect on a display-sized graphics layer, so the
Gaussian was re-evaluated on every frame the media was drawn. It also
requires RenderEffect, which Android applies only from API 31, so below
Android 12 media was drawn unblurred while the setting read as on.

A blur and a downscale discard the same thing - detail finer than their
radius - so the preview is now resampled to about one pixel per radius and
stretched back. That runs once when the item composes, needs no
RenderEffect, and removes the detail irreversibly rather than convolving
it. The first resampling step bounds both sides, so no image, however
shaped, can produce a large intermediate.

While the blur hides the media the file is also left unread, so an image
scrolled past is no longer read, decoded at its full size and kept in the
image cache only to be hidden again. blurHidesMedia() is the single
definition that both the drawing and the loading decision use, so they
cannot disagree about whether the media is on screen.

* plans: blur media by resampling the preview

* ui: shorten comments in media blur

* ui: smooth the media blur and match its strength to the old one

Stretching the resampled preview straight to the screen showed its pixel grid. Double it back
up until its longest side is at least half the reference width before drawing, so the last
stretch is short and the tents compose into a bell. The reference width moves from 360 to 400:
fitted against Gaussians, 360 blurred 5-75% more than Modifier.blur did, 400 is within 10% at
every setting.

(cherry picked from commit c0344a9a61)
2026-10-02 15:59:38 +01:00
SimpleX Chat 2158f3039a 7.1-beta.5: android 383, desktop 165, ios 360 2026-09-30 15:58:31 +00:00
EvgenyandEvgeny @ SimpleX Chat 80f8757449 core: remove .exported db files when database is removed (#7615)
Co-authored-by: Evgeny @ SimpleX Chat <259188159+evgeny-simplex@users.noreply.github.com>
2026-09-30 10:09:18 +01:00
EvgenyandEvgeny @ SimpleX Chat 3d3dd421ff desktop: prevent desktop being locked after the call (#7505)
Co-authored-by: Evgeny @ SimpleX Chat <259188159+evgeny-simplex@users.noreply.github.com>
2026-09-30 09:28:58 +01:00
EvgenyandEvgeny @ SimpleX Chat 485bec5d5d android, desktop: reduce logging (#7618)
Co-authored-by: Evgeny @ SimpleX Chat <259188159+evgeny-simplex@users.noreply.github.com>
2026-09-30 09:18:26 +01:00
EvgenyandEvgeny @ SimpleX Chat 25d4bb8966 ui: add error constructor (#7610)
* ui: add error constructor

* string

---------

Co-authored-by: Evgeny @ SimpleX Chat <259188159+evgeny-simplex@users.noreply.github.com>
2026-09-29 19:25:14 +01:00
spaced4ndy 36da024394 ui: buy a badge in the browser, with a deep link back on mobile (#7592) 2026-09-29 10:30:57 +00:00
SimpleX Chat b3907c9de7 7.0.3: android 381, desktop 164, ios 359 2026-09-26 14:28:35 +00:00
Narasimha-scandEvgeny Poberezkin 294fbf1b7d desktop: fix crash at startup on Windows when WMI does not answer (#7581)
Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2026-09-26 13:42:02 +01:00
Evgeny Poberezkin 2f6e4d556d Merge branch 'stable' 2026-09-26 13:31:47 +01:00
Evgeny e33163ee92 android: fix SimpleX links (#7596) 2026-09-26 13:31:16 +01:00
Narasimha-scandEvgeny 8e35c05fc0 android: match app links by exact path so simplex.chat pages open in the browser (#7565)
* android: match app links by exact path so simplex.chat pages open in the browser

* simpler

---------

Co-authored-by: Evgeny <evgeny@poberezkin.com>
2026-09-26 13:23:54 +01:00
Narasimha-scandEvgeny 11ecd0f5b7 android: match app links by exact path so simplex.chat pages open in the browser (#7565)
* android: match app links by exact path so simplex.chat pages open in the browser

* simpler

---------

Co-authored-by: Evgeny <evgeny@poberezkin.com>
2026-09-26 13:21:05 +01:00
Narasimha-sc b85313b61f desktop: fix app freeze when a video is stopped during format negotiation (#7582)
video().track() in the buffer format callback takes the libvlc input lock,
which stop() holds while it waits for the decoder thread running that
callback. Take the video track from the media info only.
2026-09-26 13:14:13 +01:00
Narasimha-scandEvgeny Poberezkin 67c619acff android, desktop: open group member profile without waiting for the core (#7485)
* android, desktop: open group member profile without waiting for the core

Tapping a member avatar awaited apiGroupMemberInfo and apiGetGroupMemberCode
before the profile modal was created. Both are single-row queries, 1-2 ms when
the core is idle, but sendCmd is serialized against everything else the core is
doing, so while it is busy - startup, a batch of incoming events, a long database
operation - the tap produces nothing at all until the core drains.

The modal is now opened first and the two values arrive in state the tap handler
creates, so the profile opens at the speed of the UI. The card is shown from the
member that is already known at the tap, preferring the model's copy once it is
there, so the member no longer has to be written to the model before the modal
can be shown.

* plans: open member profile without waiting for the core

* android, desktop: keep member profile rows in place while they load

The security code and the connection stats arrive after the profile is shown, so
"Verify security code" and the Servers section appeared under the already
visible card and pushed the rows below them down.

They are now rendered from the first frame in their final positions, disabled,
and enabled in place when the data arrives - SectionItemView already drops the
clickable modifier when disabled, so nothing moves. Only what can be decided from
the member known at the tap is reserved: "Fix connection" is not, as it applies
only while a ratchet needs syncing and a placeholder for it would disappear on
nearly every open.

* android, desktop: reserve the network status row with the servers

The reserved Servers section had three rows where the loaded one has four, so
everything below it - "Block member" - moved down by one row when the stats
arrived.

Network status looks like agent state that cannot be predicted before loading,
but connSubStatus returns Just whenever the connection has receiving queues, and
that is the same list that decides whether "Receiving via" is rendered. The two
rows appear together, so the status row is now reserved with them.

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2026-09-26 13:13:36 +01:00
Narasimha-sc c0344a9a61 android, desktop: make media blur much lighter on CPU (#7483)
* ui: blur media by resampling the preview, not a per-frame effect

Modifier.blur put a BlurEffect on a display-sized graphics layer, so the
Gaussian was re-evaluated on every frame the media was drawn. It also
requires RenderEffect, which Android applies only from API 31, so below
Android 12 media was drawn unblurred while the setting read as on.

A blur and a downscale discard the same thing - detail finer than their
radius - so the preview is now resampled to about one pixel per radius and
stretched back. That runs once when the item composes, needs no
RenderEffect, and removes the detail irreversibly rather than convolving
it. The first resampling step bounds both sides, so no image, however
shaped, can produce a large intermediate.

While the blur hides the media the file is also left unread, so an image
scrolled past is no longer read, decoded at its full size and kept in the
image cache only to be hidden again. blurHidesMedia() is the single
definition that both the drawing and the loading decision use, so they
cannot disagree about whether the media is on screen.

* plans: blur media by resampling the preview

* ui: shorten comments in media blur

* ui: smooth the media blur and match its strength to the old one

Stretching the resampled preview straight to the screen showed its pixel grid. Double it back
up until its longest side is at least half the reference width before drawing, so the last
stretch is short and the tents compose into a bell. The reference width moves from 360 to 400:
fitted against Gaussians, 360 blurred 5-75% more than Modifier.blur did, 400 is within 10% at
every setting.
2026-09-26 12:49:36 +01:00
Narasimha-scandEvgeny Poberezkin ef66e5e520 desktop: fix laggy bars blur by blurring a narrower offscreen copy (#7556)
Skia's raster blur runs at full resolution, so each bar blurred width x (bar + 6 sigma) pixels every frame: about
80 ms per frame for the two bars of a chat at the default radius, which cut scrolling to 5-9 fps on the software
renderer. Scaling the layer cannot help, because a layer's filter is evaluated in device space and the scale is
applied to the sigma too. The bar is now drawn into an offscreen surface up to 8x narrower and blurred there, which
measured 5-6x cheaper and within 0.25/255 of the original.

Blurring a copy means the bar no longer follows the content on its own, so the scroll containers bump a version on
the app bar handler and the bar depends on it.

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
2026-09-26 12:42:36 +01:00
sh 7596b4f850 ui: news channel (#7594)
* ui: wefunder utm link, news channel in help

* android: close modals when opening chat via link
2026-09-26 11:06:47 +01:00
sh 02fa39e766 ui: news channel (#7594)
* ui: wefunder utm link, news channel in help

* android: close modals when opening chat via link
2026-09-26 10:37:13 +01:00