Commit Graph

11031 Commits

Author SHA1 Message Date
Vitor Pamplona 45f1d79410 Adding compiled libs and customizing the log message. 2026-04-01 13:50:36 -04:00
Claude bc24434f1c refactor: remove duplicate android_logger from native Arti wrapper
All log messages go through send_log_to_java() → Kotlin ArtiLogCallback
→ Log.d("TorService"), which already writes to logcat. The android_logger
module was a second FFI call to __android_log_write that duplicated
every line.

https://claude.ai/code/session_01BApgDd5udqBzMqysSRMpZu
2026-04-01 17:32:38 +00:00
Claude 2429e695ce chore: bump Arti to 2.2.0 (arti-client/tor-rtcompat 0.41)
All features and APIs verified present in 0.41:
- tokio, rustls, compression, onion-service-client, static-sqlite
- TorClient::create_bootstrapped, from_directories, connect()

https://claude.ai/code/session_01BApgDd5udqBzMqysSRMpZu
2026-04-01 17:18:25 +00:00
Claude 53ae87aa9d chore: trim unnecessary Arti features to reduce binary size
- Set default-features = false on arti-client and tor-rtcompat
- Removed bridge-client (UI doesn't expose bridge config yet)
- Narrowed tokio features from "full" to only what the SOCKS proxy
  needs: rt-multi-thread, net, io-util, time, macros

Kept: tokio, rustls, compression, onion-service-client, static-sqlite
(all required for Amethyst's .onion relay support)

https://claude.ai/code/session_01BApgDd5udqBzMqysSRMpZu
2026-04-01 17:12:35 +00:00
Claude 35bf16b63e docs: add README for Arti Android build tools
Covers prerequisites, build commands, output verification, version
updates, architecture decisions, Cargo features, and troubleshooting.

https://claude.ai/code/session_01BApgDd5udqBzMqysSRMpZu
2026-04-01 17:03:47 +00:00
Claude 035c570902 chore: bump Arti version to 1.9.0 (arti-client/tor-rtcompat 0.38)
https://claude.ai/code/session_01BApgDd5udqBzMqysSRMpZu
2026-04-01 16:55:03 +00:00
Claude e50ae0fb1e feat: replace arti-mobile-ex with custom-built Arti native library
The Guardian Project's arti-mobile-ex AAR has three problems:
1. No 16KB page-aligned binaries (required for Google Play)
2. ArtiProxy's stop()+start() causes state file lock conflicts
   (lock is tied to TorClient object lifetime, released only on GC)
3. ~140MB AAR size

Replace with a custom JNI bridge built from Arti source, following
BitChat's proven approach:

Build tooling (tools/arti-build/):
- build-arti.sh: Clones official Arti, compiles with cargo-ndk
  for ARM64 + x86_64, NDK 25+ for 16KB page alignment
- Cargo.toml: Minimal deps with size-optimized release profile
- src/lib.rs: Custom SOCKS5 proxy with proper lifecycle:
  - initialize() creates TorClient once (holds state lock forever)
  - startSocksProxy() binds port and accepts connections
  - stopSocksProxy() aborts listener only (TorClient stays alive)
  This cleanly separates "stop routing traffic" from "destroy client"

Kotlin side:
- ArtiNative.kt: JNI declarations + ArtiLogCallback interface
- TorService.kt: Uses ArtiNative directly, start() initializes +
  starts proxy, stop() only stops proxy (no lock issues)
- TorManager.kt: Restored stop() calls for OFF/EXTERNAL modes
  since our native stop is now safe

Removed: arti-mobile-ex dependency from build.gradle and version catalog

Native libraries must be built separately:
  cd tools/arti-build && ./build-arti.sh

https://claude.ai/code/session_01BApgDd5udqBzMqysSRMpZu
2026-04-01 16:37:44 +00:00
Vitor Pamplona abe1082121 Fixes the default port. 2026-04-01 11:03:35 -04:00
Claude 4f92878146 fix: never stop ArtiProxy — Arti's lock is tied to object lifetime
Arti's state file lock is released when the TorClient object is
garbage collected, not when stop() is called. Calling stop()+start()
on the same ArtiProxy creates a new internal TorClient that conflicts
with the old lock that hasn't been GC'd yet.

Solution: start ArtiProxy once, let it run for the process lifetime.
When the user turns Tor OFF or EXTERNAL, TorManager simply stops
emitting Active status — OkHttp stops routing through the proxy.
The idle proxy uses negligible resources and drops circuits when no
SOCKS connections are active.

This removes stop(), Mutex, NonCancellable, CompletableDeferred — all
the complexity that was trying to work around a fundamental Arti
design constraint.

https://claude.ai/code/session_01BApgDd5udqBzMqysSRMpZu
2026-04-01 13:29:22 +00:00
Claude 14f8bf1245 fix: create ArtiProxy once and reuse — never recreate
The root cause of file lock conflicts was creating new ArtiProxy
objects on each start. Even after stop() confirmed, build() could
race with OS-level lock release.

Now ArtiProxy is created once in the TorService constructor and
reused for the app's lifetime. start() and stop() just toggle it
on/off on the same instance. No more file lock conflicts.

https://claude.ai/code/session_01BApgDd5udqBzMqysSRMpZu
2026-04-01 13:25:28 +00:00
Claude 7cac95726b fix: wait for Arti to confirm stop before allowing restart
The fixed 2s delay was insufficient — Arti's native layer releases
file locks asynchronously. Now stop() waits for the actual
"state changed to Stopped" log confirmation via CompletableDeferred,
with a 10s timeout as safety net. This ensures the file lock is
truly released before start() creates a new ArtiProxy instance.

https://claude.ai/code/session_01BApgDd5udqBzMqysSRMpZu
2026-04-01 13:21:33 +00:00
Claude 388a02b60c fix: stop Arti when switching to EXTERNAL Tor mode
EXTERNAL means another Tor process (e.g., Orbot) is running on the
device. No reason to keep our internal Arti alive alongside it.

Also removed the fallback that started Arti when the external port
was invalid — if the user chose EXTERNAL with a bad port, Tor should
be off, not silently falling back to internal.

https://claude.ai/code/session_01BApgDd5udqBzMqysSRMpZu
2026-04-01 13:11:29 +00:00
Claude 1c33dde81a fix: restore service.stop() on explicit Tor OFF for safety
Users in restrictive countries need Tor circuits torn down when they
switch to OFF — an idle proxy still maintains detectable connections.

stop() is now called only on explicit OFF toggle (user action), not on
flow pause/resume (app lifecycle). This avoids file lock races on
resume while ensuring OFF truly disconnects from the Tor network.

https://claude.ai/code/session_01BApgDd5udqBzMqysSRMpZu
2026-04-01 13:09:22 +00:00
Claude dd3f90aee9 refactor: remove unused lastLogTime from TorService
Dead code from the earlier callbackFlow version that had a bootstrap
stall monitor. No longer needed with the MutableStateFlow design.

https://claude.ai/code/session_01BApgDd5udqBzMqysSRMpZu
2026-04-01 13:04:44 +00:00
Claude d94d8776eb fix: keep ArtiProxy alive across mode switches to avoid file lock conflicts
ArtiProxy holds an exclusive filesystem lock. Destroying it on OFF and
recreating on INTERNAL caused lock conflicts because the native layer
needs time to release the lock.

Instead, create ArtiProxy once and never destroy it. When Tor is OFF
or EXTERNAL, the proxy sits idle with no SOCKS connections — negligible
resource usage. This eliminates all file lock race conditions.

Also wrap start/stop in NonCancellable to prevent transformLatest
cancellation from leaking half-initialized proxy instances.

https://claude.ai/code/session_01BApgDd5udqBzMqysSRMpZu
2026-04-01 13:01:31 +00:00
Claude c83256bac2 fix: singleton ArtiProxy lifecycle to prevent state file lock conflicts
The callbackFlow-based TorService created a new ArtiProxy on every flow
collection. When the app paused and resumed, the old instance's file lock
wasn't released before the new one started, causing "Another process has
the lock on our state files" errors.

Redesigned TorService to own a single ArtiProxy with explicit start/stop:
- ArtiProxy is created once and reused across flow re-collections
- State exposed via MutableStateFlow instead of callbackFlow
- Mutex guards start/stop to prevent races
- TorManager calls service.start() and service.stop() explicitly when
  switching between INTERNAL/OFF/EXTERNAL modes
- stop() includes a 2s settle delay for native file lock release

https://claude.ai/code/session_01BApgDd5udqBzMqysSRMpZu
2026-04-01 12:44:24 +00:00
Claude c7176805b2 feat: route zap push notification tap to notification screen with scroll and highlight
When a zap push notification is tapped, the app now navigates to the
Notifications screen and scrolls to the specific zap event, highlighting
it briefly to draw the user's attention.

- Change Route.Notification from object to data class with optional scrollToEventId
- Include zap/reaction event ID in notification URI (scrollTo param)
- Parse scrollTo from URI in uriToRoute() and pass through navigation
- Scroll to matching card in the feed and animate a highlight that fades

https://claude.ai/code/session_01Dk9vVKQKDtLLgvJPUCfKSs
2026-04-01 04:16:18 +00:00
Claude d067d5c3b7 feat: add blockquote gutter and table styling to Markdown renderer
- Add themed blockquote gutter using BarGutter with primary color at 45% opacity
- Add table border styling using theme-consistent subtle borders
- Set table cell padding to 10sp for comfortable reading

https://claude.ai/code/session_01PPExHNAdLqddiYsGZi1BgW
2026-04-01 04:07:37 +00:00
Claude 842bb57a03 feat: improve Markdown renderer typography and styling
- Increase body text line height from 1.30em to 1.50em for better readability
- Increase paragraph spacing from 18sp to 20sp for more breathing room
- Add explicit fontWeight to headings: Bold for H1-H2, SemiBold for H3-H4, Medium for H5-H6
- Add negative letterSpacing to H1-H2 for tighter display-style headings
- Widen heading size range (32sp-15sp vs 32sp-18sp) for clearer visual hierarchy
- Add internal padding to code blocks (16dp horizontal, 12dp vertical) so text isn't flush against borders
- Add vertical margin (4dp) around code blocks for separation from surrounding text
- Add line height (1.45em) to code block text for better readability
- Add letter spacing (0.3sp) to inline code for better monospace readability
- Fix light theme code block using DarkColorPalette instead of LightColorPalette for background

https://claude.ai/code/session_01PPExHNAdLqddiYsGZi1BgW
2026-04-01 04:01:47 +00:00
Claude 04b497add4 fix: resolve Context and Activity memory leaks across the app
- MainActivity: use applicationContext instead of Activity ref in GlobalScope
- ChoreographerHelper: add stop() method and running flag to allow unregistering the perpetual FrameCallback
- MediaSessionPool: replace GlobalScope with class-scoped CoroutineScope, cancel on destroy
- ExoPlayerPool: cancel scope after destroy completes
- PlaybackServiceClient: add shutdown() for the ExecutorService thread pool
- LocalCache: replace GlobalScope with app-scoped coroutine for payment callbacks
- TextToSpeechEngine: clear all listener lambdas in destroy() to prevent capturing UI scope
- NotificationReplyReceiver: scope CoroutineScope to each onReceive call and cancel after use
- NotificationUtils: use SingletonImageLoader instead of creating new ImageLoader per notification
- AppModules: clean up BackgroundMedia and PlaybackServiceClient on terminate

https://claude.ai/code/session_01RR2kqsV23JKKdNGQVj7YaQ
2026-04-01 03:40:31 +00:00
Claude 2ae045b768 feat: add post action buttons to Polls, Pictures, Shorts, and Longs screens
Add expandable FAB buttons to create new content from each feed screen:
- Polls: composite FAB with Regular Poll and Zap Poll options via new
  dedicated routes (Route.NewPoll, Route.NewZapPoll) and PollPostScreen
- Pictures: expandable FAB with camera and gallery options
- Shorts: expandable FAB with video recording and gallery options
- Longs: expandable FAB with video recording and gallery options

The poll creation screens reuse ShortNotePostViewModel with the
appropriate poll type pre-enabled. Media screens use the existing
NewMediaModel/NewMediaView upload flow.

https://claude.ai/code/session_01NGMh9KM9yTtdBP6vW8MU1q
2026-04-01 00:37:31 +00:00
Claude 293fd39a68 fix: harden TorService with bootstrap timeout, thread safety, and error recovery
Address gaps found in code review:
- Use AtomicBoolean/AtomicLong for state accessed from native Arti
  log callback thread (was a data race)
- Add bootstrap timeout monitor (120s) that restarts Arti once if
  bootstrapping stalls, following BitChat's inactivity pattern
- Clean up failed ArtiProxy instances before port retry
- Detect "Another process has the lock" fatal error from Arti logs

https://claude.ai/code/session_01BApgDd5udqBzMqysSRMpZu
2026-04-01 00:23:52 +00:00
Vitor Pamplona cd11503b1e v1.07.5 2026-03-31 20:18:34 -04:00
Vitor Pamplona 9b2fbcbf56 Fixes image uploading crash 2026-03-31 20:17:14 -04:00
Vitor Pamplona 5cd83bbaa4 v1.07.4 2026-03-31 19:19:24 -04:00
Vitor Pamplona 91dfda3480 Merge pull request #2061 from vitorpamplona/l10n_crowdin_translations
New Crowdin Translations
2026-03-31 19:13:59 -04:00
Crowdin Bot b1b2825dd6 New Crowdin translations by GitHub Action 2026-03-31 23:12:49 +00:00
Vitor Pamplona 48d90a8252 Fixes Wallet import encoding bug 2026-03-31 19:10:15 -04:00
Claude 11af50e0ad feat: migrate Tor implementation from tor-android to Arti (Rust)
Replace Guardian Project's tor-android (C Tor) and jtorctl with
arti-mobile-ex, a Rust-based Tor implementation. This eliminates
the Android Service binding complexity in favor of an in-process
ArtiProxy object.

Key changes:
- TorService: Replace ServiceConnection to org.torproject.jni.TorService
  with direct ArtiProxy.Builder/start/stop API. Bootstrap state detected
  via log parsing (following BitChat's pattern).
- TorServiceStatus: Remove TorControlConnection field (Arti doesn't
  support jtorctl control protocol).
- RelayProxyClientConnector: Remove DORMANT/ACTIVE/NEWNYM control
  signals. Arti manages its own circuit lifecycle internally.
- Dependencies: Replace tor-android + jtorctl with arti-mobile-ex 1.2.3.

TorManager's external API (status/activePortOrNull StateFlows) and all
downstream consumers (DualHttpClientManager, TorSettings, UI) are
unchanged.

https://claude.ai/code/session_01BApgDd5udqBzMqysSRMpZu
2026-03-31 22:00:48 +00:00
Vitor Pamplona 69099728b2 v1.07.3 2026-03-31 17:32:23 -04:00
Vitor Pamplona 190b99d55a Merge pull request #2060 from vitorpamplona/l10n_crowdin_translations
New Crowdin Translations
2026-03-31 17:31:30 -04:00
Crowdin Bot 95adb53640 New Crowdin translations by GitHub Action 2026-03-31 21:29:37 +00:00
davotoula 25a4b68958 update translations: CZ, DE, PT, SE 2026-03-31 23:26:48 +02:00
David Kaspar e91c793f73 Merge pull request #2059 from vitorpamplona/l10n_crowdin_translations
New Crowdin Translations
2026-03-31 23:21:41 +02:00
David Kaspar 5b477c64cf Merge branch 'main' into l10n_crowdin_translations 2026-03-31 23:21:32 +02:00
Crowdin Bot 11ca2c14be New Crowdin translations by GitHub Action 2026-03-31 21:07:39 +00:00
Vitor Pamplona 1b39bf1d52 Merge branch 'main' of https://github.com/vitorpamplona/amethyst 2026-03-31 17:05:26 -04:00
Vitor Pamplona a4e3625f26 Migrates to the new 10008 profile badges kind 2026-03-31 16:52:24 -04:00
davotoula 92cb0fbe67 Merge branch 'main-upstream' into ci-use-built-in-gradle-cache 2026-03-31 22:43:46 +02:00
Crowdin Bot e75b5d173b New Crowdin translations by GitHub Action 2026-03-31 20:25:02 +00:00
Vitor Pamplona 027cc660e2 Merge pull request #2058 from vitorpamplona/l10n_crowdin_translations
New Crowdin Translations
2026-03-31 16:24:28 -04:00
Vitor Pamplona 49850e773f Adds a space after inserting the username to avoid issues in some keyboards. 2026-03-31 16:22:57 -04:00
Vitor Pamplona 44d100f60a Fixes file name 2026-03-31 16:11:45 -04:00
Crowdin Bot f110436853 New Crowdin translations by GitHub Action 2026-03-31 19:47:41 +00:00
Vitor Pamplona aebbe0974a Fixes wrong filter 2026-03-31 15:45:34 -04:00
Vitor Pamplona a79ceb527f Adding filters by community and location to the new side feeds 2026-03-31 15:23:50 -04:00
Vitor Pamplona 29bb0d2682 Dynamic filters for Longs, Shorts, Polls and Pictures 2026-03-31 14:44:56 -04:00
Vitor Pamplona 794af6eb2b Adds Long Video Menu item 2026-03-31 13:24:55 -04:00
Vitor Pamplona 3e83762761 Adds new TopNav Filter settings 2026-03-31 13:24:37 -04:00
Vitor Pamplona c6e1dc9d79 Fixes dal filters for Shorts 2026-03-31 12:58:53 -04:00