833 Commits

Author SHA1 Message Date
callebtc
3ed46222ba Fade Wear chat at screen contour 2026-08-26 11:56:00 +02:00
callebtc
898cfde066 Restore Wear chat edge fading 2026-08-26 11:39:16 +02:00
callebtc
ed617f0f1b Fix Wear chat autoscroll and focal scaling 2026-08-24 21:13:07 +02:00
callebtc
34f94882f5 Restore Wear chat content space 2026-08-24 20:57:24 +02:00
callebtc
45915fab8f Tune Wear header boundary by screen shape 2026-08-24 20:15:17 +02:00
callebtc
f744038318 Preserve width for Wear Material cards 2026-08-24 20:08:44 +02:00
callebtc
4a1de47ed6 Cover transformed Wear header boundary 2026-08-24 20:04:46 +02:00
callebtc
5d66b69129 Clip Wear messages below the chat header 2026-08-24 20:01:46 +02:00
callebtc
7788328917 Keep Wear chat rows clear of controls 2026-08-24 19:58:03 +02:00
callebtc
2e41dabd07 Add round-screen responsive Wear insets 2026-08-24 19:54:20 +02:00
callebtc
5852fca9b5 Fix Wear content clipping on watch shapes 2026-08-24 19:38:26 +02:00
callebtc
eab894ce78
Merge pull request #743 from aharshit123456/fix/geohash-signature-verification-733
fix: verify Schnorr signatures on incoming geohash Nostr events
2026-08-24 19:17:25 +02:00
GitHub Action
d55754d824 Automated update of relay data - Sun Aug 23 06:09:25 UTC 2026 2026-08-23 06:09:25 +00:00
callebtc
09b481f1ef
Merge pull request #876 from qutad/feat/announce-capability-bits
feat: Add announce capability bit assignments
2026-08-17 21:05:02 +02:00
callebtc
db97c60af1 Merge remote-tracking branch 'origin/main' into feat/announce-capability-bits 2026-08-17 20:40:43 +02:00
callebtc
2318b51630
Merge pull request #897 from permissionlesstech/codex/fix-command-processor-test-brace
Fix CommandProcessor test syntax
2026-08-17 20:38:39 +02:00
callebtc
03d1da5423 Fix CommandProcessor test syntax 2026-08-17 20:13:19 +02:00
callebtc
646044cd81 Clarify capability authentication scope 2026-08-17 19:14:05 +02:00
callebtc
35ed4417f0
Merge pull request #841 from phuctoan123/codex-fix-geohash-join-channel-routing
Fix geohash join channel routing
2026-08-17 19:09:26 +02:00
callebtc
9167013ac4
Merge pull request #863 from areebahmeddd/fix/preserve-wire-payload
feat: preserve original bytes during re-encoding of packets with foreign encoders
2026-08-17 19:08:01 +02:00
GitHub Action
b028270cc4 Automated update of relay data - Sun Aug 16 06:08:32 UTC 2026 2026-08-16 06:08:32 +00:00
wollow
22f87a493a Add announce capability bit assignments 2026-08-13 15:11:54 +03:00
callebtc
5156f7de89 Restore PRIVACY_POLICY.md 2026-08-12 01:55:05 +02:00
callebtc
93e9594bad
Merge pull request #873 from permissionlesstech/codex/bump-version-2.0.1
Prepare Android 2.0.1 release
v2.0.1
2026-08-11 21:09:03 +02:00
callebtc
16a22316b2 Disable nondeterministic Compose group mapping 2026-08-11 20:42:26 +02:00
callebtc
c549bdb03f Bump Android release to 2.0.1 2026-08-11 20:08:57 +02:00
callebtc
c9938a36ea
Merge pull request #872 from permissionlesstech/codex/fix-reproducible-aab-mapping
Fix reproducible R8 mapping output
2026-08-11 19:57:31 +02:00
callebtc
6c5d7d1ef0 Fix reproducible R8 mapping output 2026-08-11 19:33:44 +02:00
callebtc
1a0d8713e4
Merge pull request #871 from permissionlesstech/watch-release-0.1.0
Prepare Wear 0.1.0 reproducible release
v2.0.0
2026-08-11 18:14:29 +02:00
callebtc
c9a4e68157 Serialize reproducible release modules 2026-08-11 15:38:15 +02:00
callebtc
7e8ea63230 Prepare reproducible Wear 0.1.0 release 2026-08-11 15:19:39 +02:00
callebtc
47e725a4d8
Merge pull request #870 from permissionlesstech/bump-version-2.0.0
Bump phone app to 2.0.0
2026-08-11 15:12:58 +02:00
callebtc
920eed52d7 Bump phone app to 2.0.0 2026-08-11 12:13:16 +02:00
callebtc
fcb4562bd5
Merge pull request #812 from moehamade/fix/apk-download-and-rate-limit
fix: make APK sharing local-first and rate-limit safe
2026-08-11 09:51:39 +02:00
Kane Waldo
4007bae1e2 Fix syntax error in CommandProcessorTest 2026-08-11 09:20:39 +07:00
Moe Hamade
8f21ad5be3 fix(apk): keep the local APK shareable across a restart mid-download
Codex is right about this one. The downloader observer builds Downloading
out of whatever status it replaces, reading shareableFallback from an
existing Downloading or a current Ready. A ViewModel restored onto work
that is already active starts from Loading, so neither cast matches and
the fallback is null. WorkManager keeps a download running across process
death, so this is the ordinary case: background the app during a 42 MB
transfer over Tor, come back, and the row drops to "Prepare App for
Sharing" while Share via Hotspot and Share via Quick Share disappear
entirely. The installed APK never moved - it was on disk and shareable a
moment earlier - and it stays hidden until the download ends.

checkStatus() could not repair it because its guard conflated two things:
not letting a resolved status overwrite active work, which is right, and
not looking at local state at all during a download, which is not. Both
orderings lost. If the observer arrived first the guard returned early. If
checkStatus() arrived first it suspended on disk IO, the observer flipped
the state underneath it, and the re-check discarded the status it had just
resolved.

Resolves the local artifact either way and decides inside the same state
update, where the active download is visible: the download keeps the
status it owns, and adopts the artifact only when it is carrying none.
Metadata is still skipped while work is active, so this costs no extra API
budget.

Verified on a Pixel 9a by starting a download, force-stopping mid-transfer
and reopening: the row holds "App Ready for Offline Sharing" with both
sharing rows present, where it previously showed neither.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-09 15:49:22 +03:00
Moe Hamade
52f14cc5b5 fix(apk): stop a reset header alone from marking a 403 rate limited
GitHub sends X-RateLimit-Reset on every REST response, an ordinary 403
included, and it always points at the current window. Feeding it through
retryAtMillis() therefore produced a non-null deadline for any 403, and
the classifier accepted that as proof of a limit. A permissions failure
with the quota untouched came back as RateLimited, so the caller persisted
a cooldown on that route and served stale metadata until a reset window
the failure had nothing to do with.

Classification now looks only at signals that actually mean this request
was the one refused: a spent quota, or an explicit Retry-After. Nothing
real is lost, because GitHub marks a primary limit with
X-RateLimit-Remaining: 0 and a secondary limit with Retry-After. The reset
header keeps its job of supplying the deadline once a limit is
established some other way.

ApkDownloadSourceTest already claimed this contract - its name is "403 is
only treated as a limit when response headers say so" - but its
permissions case passed no reset header at all, which is the one input
that hides the bug. Adds the case it was missing, which fails without this
change, and pins the secondary-limit path so tightening the reset header
cannot blind the client to a Retry-After.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-09 15:16:51 +03:00
Moe Hamade
7b86bafbac fix(apk): give the persisted store sole ownership of rate-limit cooldowns
The cooldown was tracked in two places. ApkRateLimitStore persisted it per
scope and per route, and the ViewModel kept a second copy in
downloadRetryAtMillis plus a retryAtMillis on Resumable and Error, frozen
into WorkManager output data on the way through. The copy was the weaker
of the two: it lived in memory, so a cold start lost it, and the deadline
it froze belonged to whichever route earned it, which is exactly the drift
the per-route store exists to prevent.

It also could not expire on its own. downloadRetryBlocked was computed
with System.currentTimeMillis() during composition, so nothing recomposed
when the deadline passed; scheduleRetryUnlock papered over that with a
viewModelScope delay that died with the process. Meanwhile the disabled
row and icon gave the user no countdown to read, so a tap simply did
nothing.

Drops the copy. The store is consulted where the request is actually made
and the UI stays enabled, which costs a worker that fails in well under a
tenth of a second without touching the network.

RateLimitedWithWait goes with it. Its "try again in %2$s min" was computed
at failure time and baked into static text that never ticked down, so it
was wrong within a minute; RateLimited says "try again later" and stays
true. Removing it leaves nothing pre-formatted, so Resumable and Error now
carry an ApkFailureMessage of string id plus arguments and the row
resolves it during composition. Failure text follows the device locale
rather than the locale the worker happened to run under.

Anchors the GitHub cooldown at the moment it is judged. now was sampled
before awaitRoute(), which can hold a request for the full 60-second route
timeout, so a relative Retry-After interpreted against it could land in
the past and let the very next check reach GitHub - the loop this branch
set out to close. Reads the clock again once the route is ready and once
the response arrives, and uses each where it applies.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-09 14:57:32 +03:00
Moe Hamade
000a8acdb9 fix: build each shared HTTP client once instead of racing to replace it
routedHttpClient() and webSocketClient() both did a plain check-then-set
on their AtomicReference: read, and if empty build a client and store it.
Two threads arriving together each saw an empty reference, each built a
full OkHttpClient, and the loser's client was dropped on the floor with
its connection pool and dispatcher threads already allocated. Nothing
closed it, so the leak lasted until the process died.

Moves construction inside a lock and re-checks the reference there, so
the second thread returns the first thread's client rather than building
its own. reset() takes the same lock, which is what makes the pairing
airtight: a build can no longer interleave with a reset and store a
client for the route that was just discarded. The fast path stays outside
the lock, so a warm client still costs a single volatile read.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-09 14:53:42 +03:00
GitHub Action
55fd6ad9bd Automated update of relay data - Sun Aug 9 06:17:04 UTC 2026 2026-08-09 06:17:04 +00:00
Toan Wizard
ca992d169c
Merge branch 'main' into codex-fix-geohash-join-channel-routing 2026-08-04 09:30:27 +07:00
Moe Hamade
99bed510de build: drop verification entries for the reverted material3 alpha
The alpha bump was reverted in 2c19d00d, but its verification metadata
stayed behind: 45 components for compose 1.12.0-beta01 and material3
1.5.0-alpha25 that no lockfile resolves. Regenerated from upstream's file
so only artifacts this branch actually pulls are trusted.

Trusting artifacts nothing resolves is the opposite of what this file is
for, and it made the branch look like a Compose beta upgrade in review.

gradle/verification-metadata.xml: +322 lines -> +8, one component
(mockwebserver3, the dependency 2c19d00d genuinely added).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-03 20:12:50 +03:00
Moe Hamade
a898c06114 build: relock :wear after mockwebserver entered the shared test bundle
CI failed at ':wear:compileDebugUnitTestKotlin' with okhttp, okio and
mockwebserver3 "not part of the dependency lock state". No test ran.

Adding okhttp-mockwebserver to the shared test bundle put okhttp and okio
on :wear's unit-test classpath as well, but only :app's lock state was
regenerated, so :wear/gradle.lockfile had no entry for any of them.

Regenerated lock state and verification metadata for debug and both
release variants per docs/reproducible-builds.md. No new components
needed trusting: the checksums already existed from the :app side, so
this is lockfile scope only.

Worth noting the local command that missed it was :app-scoped;
CI runs testDebugUnitTest at the root, which includes :wear.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-03 18:08:52 +03:00
callebtc
094657efa0
Merge pull request #861 from permissionlesstech/codex/delay-peer-availability-notification
Delay nearby peer notification to collect accurate count
2026-08-03 00:18:52 +02:00
callebtc
1376b55931 Delay nearby peer availability notification 2026-08-02 21:54:03 +02:00
callebtc
d852f3dc3a
Merge pull request #744 from aharshit123456/i18n/backfill-incomplete-locales
i18n: backfill 7 severely incomplete locale translations (he, pl, zh-rCN, zh-rTW, ms, ta, uk)
2026-08-02 21:34:49 +02:00
callebtc
94e46da234 Merge main into i18n backfill branch 2026-08-02 20:36:48 +02:00
callebtc
49753ccb88
Merge pull request #860 from permissionlesstech/feat/bubble-media-messages
feat(ui): wrap image and voice messages in bubble shells
2026-08-02 20:33:10 +02:00
callebtc
bc572cc2ea fix(ui): make media bubble shell long-clickable
Self and grouped voice-note bubbles had no long-press target: the sender
label is hidden and VoiceNotePlayer controls consume touches, so the
message action sheet was unreachable. combinedClickable on the shell
restores long-press for every media bubble.
2026-08-02 20:28:04 +02:00
Moe Hamade
2c19d00d17 fix(apk): preserve local sharing during update checks 2026-08-02 17:44:20 +03:00