Commit Graph
100 Commits
Author SHA1 Message Date
Barry DeenandGitHub f4c716551b Merge pull request #490 from barrydeen/fix/quoted-note-emoji-picker
fix: use user's emoji picker for quoted/referenced notes
2026-04-23 10:18:43 -04:00
Barry Deen 69e49eb648 fix: use user's emoji picker for quoted/referenced notes
Quoted notes nested inside another note were using the default unicode
emoji fallback instead of the user's sorted-by-frequency picker with
their custom emojis. Plumb resolvedEmojis, unicodeEmojis, and the
onOpenEmojiLibrary callback through NoteActions so nested PostCard /
GalleryCard renders in RichContent.QuotedNote pick up the same emoji
state as their parent.
2026-04-23 10:03:41 -04:00
Barry DeenandGitHub 642b68e854 Merge pull request #489 from barrydeen/feat/drawer-avatar-opens-profile-edit
feat: open edit profile when tapping drawer avatar
2026-04-23 09:50:07 -04:00
Barry Deen 0d8e34fe02 feat: open edit profile when tapping drawer avatar 2026-04-23 09:49:44 -04:00
Barry DeenandGitHub 05e14914b4 Merge pull request #488 from barrydeen/fix/media-downloader-oom
fix: stream media downloads to avoid OOM on large files
2026-04-23 09:44:22 -04:00
Barry Deen 7a29f976df fix: stream media downloads to avoid OOM on large files 2026-04-23 09:43:34 -04:00
Barry DeenandGitHub 5853db286b Merge pull request #487 from barrydeen/feat/persistent-audio-player
feat: persistent audio mini-player docked above bottom nav
2026-04-22 22:26:04 -04:00
Barry Deen 06ec5592d3 feat: persistent audio mini-player docked above bottom nav
Replaces the basic inline audio widget with a global mini-player that persists
across feed scrolling and tab navigation. Playback continues with system
notification / lock-screen transport controls via MediaSessionService.

The dock has two states: a collapsed row showing the author's avatar and name
with rewind-15 / play-pause / forward-15; swipe up to expand for a scrub slider,
speed cycling, and close. Single ExoPlayer is owned by AudioPlayerController
and shared with the inline tap-to-play widget, which now reflects global
playback state.
2026-04-22 22:21:41 -04:00
Barry DeenandGitHub ebeebccbe9 Merge pull request #486 from barrydeen/fix/persist-settings-across-account-switch
fix: preserve local relay and emoji frequency across account switches
2026-04-22 21:56:22 -04:00
Barry Deen e245b2fbde fix: preserve local relay and emoji frequency across account switches
Two repos called clear() during resetForAccountSwitch() were doing
`prefs.edit().clear().apply()` on their SharedPreferences files while
those files were still pointing at the outgoing account:

- CustomEmojiRepository wipes its own per-pubkey file, erasing the
  "most used" emoji frequency map. No relay mirror, so the data was
  lost for good.
- BlossomRepository shares `wisp_prefs_{pubkey}` with KeyRepository, so
  its full-file wipe also took out local_relay, relays, dm_relays, etc.
  Most of those keys came back via replaceable-event refetches, but
  local_relay has no network source and stayed null.

Drop the disk wipe from both clear() methods. The subsequent
reload(newPubkey) already repoints prefs to the incoming account's file.
2026-04-22 21:54:40 -04:00
Barry DeenandGitHub b0455b1ea6 Merge pull request #485 from barrydeen/fix/compose-mention-ux
fix: stop mention insert from breaking compose cursor and keyboard
2026-04-22 21:04:50 -04:00
Barry Deen ad8c1c4d11 fix: stop mention insert from breaking compose cursor and keyboard
Mentions used to be stored in the text field as raw nostr:nprofile URIs
rendered as @Name via an OutputTransformation. The visual/underlying
offset mismatch made the cursor jump, the IME desync on rapid typing,
forced a trailing space after every mention (so '@name's' was impossible),
and turned a single backspace into a silent delete of the whole mention.

Store '@Name' directly in the text field and track mention ranges
out-of-band in the ViewModel; splice nostr:nprofile URIs back in at
publish time. Editing is now plain text — identity offset mapping, no
forced space, and breaking a mention drops only that mention, not the
surrounding text.
2026-04-22 21:04:13 -04:00
Barry DeenandGitHub f0f728d2fc Merge pull request #484 from barrydeen/fix/trending-reconnect-race
fix: trending feed not reconnecting after app resume
2026-04-22 20:51:24 -04:00
Barry Deen 6582c16d88 fix: trending feed not reconnecting after app resume
Remove the preConnectEphemeral optimization from the reconnect path. It
created a race where the ephemeral was mid-connect when subscribeTrendingFeed
fired its REQ, leaving the subscription stuck on Connecting. The direct
metric-switch path (no preConnect) worked fine, so match it.
2026-04-22 20:50:52 -04:00
Barry DeenandGitHub f9cc586804 Merge pull request #483 from barrydeen/fix/pull-self-deletions-on-startup
fix: pull own NIP-09 deletions on startup so deleted sets stay gone
2026-04-22 20:14:00 -04:00
Barry Deen 359e64385b fix: fetch and apply own deletion events on startup
Relays sometimes keep serving hashtag sets (and other addressable
events) after the user publishes a NIP-09 kind 5 deletion, so sets
reappeared on app reload — especially after a fresh install or on a
second device where the local DeletedEventsRepository was empty.

Self-data subscription now also requests our own kind 5 events, and
EventRouter routes them through EventRepository (marking deletion
coords/ids) and sweeps any matching interest sets out of
InterestRepository so a late-arriving deletion still wins.
2026-04-22 20:12:12 -04:00
Barry DeenandGitHub fbc18d385b Merge pull request #482 from barrydeen/feat/delete-note-confirmation
feat: confirm before deleting a note
2026-04-22 20:01:36 -04:00
Barry Deen 984ef213e0 feat: confirm before deleting a note from the 3-dot menu 2026-04-22 20:01:10 -04:00
Barry DeenandGitHub 499af910f4 Merge pull request #481 from barrydeen/feat/broadcast-mentions-to-inbox
feat: broadcast notes to inbox relays of mentioned pubkeys
2026-04-21 09:18:53 -04:00
Barry Deen ea80c46d2c feat: broadcast notes to inbox relays of all mentioned pubkeys
When publishing a kind-1 note (root or reply) that mentions pubkeys via
nostr: references, also deliver the event to each mentioned pubkey's
read (inbox) relays per NIP-65. Inbox URLs are deduplicated across
targets and against our own write relays, so shared inboxes only
receive the event once.
2026-04-21 09:18:19 -04:00
Barry DeenandGitHub 38c8323eca Merge pull request #480 from barrydeen/docs/readme-rewrite-v1
docs: rewrite README for v1.0.0 feature set
2026-04-19 14:26:29 -04:00
Barry Deen 6b7515804b docs: rewrite README for v1.0.0 feature set 2026-04-19 14:26:05 -04:00
Barry DeenandGitHub 58e4b5c14e Merge pull request #479 from barrydeen/chore/bump-version-1.0.0
chore: bump version to 1.0.0
2026-04-19 14:21:14 -04:00
Barry Deen b0851706a2 chore: bump version to 1.0.0 2026-04-19 14:20:54 -04:00
Barry DeenandGitHub 8740154b01 Merge pull request #478 from barrydeen/fix/group-join-auth-race
fix: wait for NIP-42 AUTH before group 9021/9007/9009 and surface admin failures
2026-04-19 14:18:48 -04:00
Barry Deen c20a2c6d20 fix: wait for NIP-42 AUTH before group 9021/9007/9009 and surface admin failures
Group joins and admin actions (create group / invite / edit metadata / put user /
remove user / leave / delete) previously fired their events as soon as the signer
returned, racing the relay's NIP-42 AUTH challenge. On an auth-gated relay the
unauthenticated event hits first and the relay either responds "auth-required:"
or silently downgrades the request — a 9021 with a valid invite code returns
"restricted: group is closed, you need an invite code", a 9007 can fail silently,
a 9009 then fires against a ghost group and gets "blocked: group doesn't exist",
and the admin never sees any of it because the publishes were fire-and-forget.

attemptJoin now waits up to 5s for authCompleted before sending the 9021, and
still retries once on an auth-required rejection as a safety net. A new
publishAdminEvent helper wraps the admin kinds with the same auth-wait, awaits
the relay's OK, and emits an AdminError on rejection or timeout. createGroup
additionally rolls back its local placeholder if the relay rejects 9007 so we
don't keep trying to issue invites for a group the relay doesn't know about.

A new adminErrors SharedFlow on GroupListViewModel is collected by DmListScreen
and rendered as an AlertDialog showing the step (e.g. "createGroup/9007") and
the relay's message, so silent admin failures become visible.
2026-04-19 14:15:58 -04:00
Barry DeenandGitHub 242b809916 Merge pull request #477 from barrydeen/fix/account-switch-social-graph-notifications
fix: preserve social graph and notifications across account switches
2026-04-19 12:43:35 -04:00
Barry Deen 7d5b988005 fix: preserve social graph and notifications across account switches
The social graph (ExtendedNetworkRepository + SocialGraphDb) was wiped
on every account switch because clear() deleted both the SharedPreferences
cache and SQLite tables, and SocialGraphDb used a single shared DB file.
Now SocialGraphDb uses per-account files with a one-time legacy migration,
and clear() no longer touches persistent state (only in-memory). Notification
events from account A were leaking into account B because the ObjectBox
seeding coroutine fired after the switch and NotificationRepository had no
reload(). Adds reload() to NotificationRepository/SafetyPreferences
with a stale-pubkey rejection guard and proper job cancellation.
2026-04-19 12:42:29 -04:00
Barry DeenandGitHub 3e27713078 Merge pull request #476 from barrydeen/fix/group-metadata-preserve-permissions
fix: preserve group permission flags on metadata edit
2026-04-19 11:57:26 -04:00
Barry Deen 2e0c193f04 fix: preserve group permission flags on metadata edit 2026-04-19 11:36:29 -04:00
Barry DeenandGitHub 92f99593d8 Merge pull request #473 from barrydeen/feat/increase-onboarding-timeout
feat: increase onboarding EOSE timeout to 8s and add relays
2026-04-19 10:42:10 -04:00
Barry Deen 91ac6d8f20 feat: increase onboarding EOSE timeout to 8s and add relay.wisp.talk, pyramid.fiatjaf.com
Bump collectUntilEose timeout from 3000ms to 8000ms across all suggestion
queries (active now, news, profile fetches) to handle slow connections.

Add relay.wisp.talk and pyramid.fiatjaf.com to ACTIVE_RELAYS so more
users appear in the 'Active right now' onboarding section.
2026-04-19 10:41:03 -04:00
Barry DeenandGitHub a5ae58d3f6 Merge pull request #472 from barrydeen/fix/persist-deletes-drafts-hashtag-sets
delete hashtags, drafts, thread drops
2026-04-18 15:22:32 -04:00
Barry Deen b802c124d9 delete hashtags, drafts, thread drops 2026-04-18 15:20:31 -04:00
Barry DeenandGitHub 5f6eb0ca7d Merge pull request #471 from barrydeen/feat/nip29-group-config
feat: NIP-29 group config — flags, invites, roles, AUTH prompts
2026-04-18 13:20:38 -04:00
Barry Deen c4900142b3 feat: NIP-29 group config — flags, invites, roles, AUTH prompts
Expands group support beyond open/unrestricted creation:

- Create dialog exposes the 4 NIP-29 config flags (private, closed,
  restricted, hidden) as plain-English toggles; the follow-up kind:9002
  is only sent when the user actually customizes posture, with a 1.5s
  delay after the 9007 so the relay can mark us admin first.
- Group Detail shows per-flag icon + label + description rows plus a
  header badge chip (defaults to "Public" when fully open), so every
  room's posture is legible at a glance.
- Admin-only invite code section generates kind:9009 events and
  surfaces copy-code / copy-invite-link actions; Join dialog parses
  `relay'groupId?code=...` and plumbs the code through kind:9021.
- Per-member "Assign role" action sends kind:9000 with free-form role
  tags; admins list parses role strings without breaking call sites.
- Join flow waits on the relay's OK response before adding the room
  locally — rejections surface as a dialog instead of a broken
  chat screen with no messages.
- Joined chat relays now get tier-2 AUTH prompts (prompt-and-remember)
  instead of silently discarding challenges; after AUTH completes we
  re-fire group REQs and clear stale "auth-required" banners.
- Raw 39000/39001/39002 events logged so relay-side behavior can be
  inspected directly from logcat.
- Default group relay switched from groups.0xchat.com to
  chat.wisp.talk.

Known: chat.wisp.talk omits non-admin pubkeys from kind:39002 on
closed groups, so the local member list stays sparse until the relay
behavior is fixed. To be addressed server-side.
2026-04-18 13:19:21 -04:00
Barry DeenandGitHub d3f511b7e2 Merge pull request #470 from barrydeen/feat/nspam-v2.2-lightgbm
feat: upgrade nspam model to v2.2 LightGBM
2026-04-18 11:32:33 -04:00
Barry Deen 799c52cd5b tune: raise nspam hide threshold from 0.5 to 0.7
Reduces false positives against real users that still show up with
the v2.2 model, at the cost of letting through some borderline
spam. Applied to both reply notifications and thread rendering.
2026-04-18 11:28:13 -04:00
Barry Deen c1a1c8dab1 feat: upgrade nspam model to v2.2 LightGBM
Replaces the v0.9 logistic-regression reply-spam classifier with
the v2.2 gradient-boosted tree model (500 trees, 63 leaves). Ships
model.txt + calibration.npz and adds a pure-Kotlin LightGBM tree
walker. Feature extraction is unchanged; tree-walk output matches
LightGBM's C++ predict bit-exactly against the published parity
fixtures.
2026-04-18 11:18:35 -04:00
Barry DeenandGitHub cf672a80c5 Merge pull request #469 from barrydeen/feat/for-you-feed
feat: add For You feed (extended/follows + trending + hashtags)
2026-04-16 22:55:28 -04:00
Barry Deen 764aac6322 feat: add For You feed blending extended/follows with trending and hashtags
New default feed type that combines three streams into one sorted list:
- Main author subscription (extended network if cached, follow feed otherwise)
- Top-reactions and top-replies trending notes (today timeframe)
- Notes for all followed hashtags, batched 10 at a time against the search
  relay over a 24h window

Supplementary fetches are one-shot per feed-generation and self-close on
EOSE + drain; events flow through EventRepository.addEvent() for dedup and
in-order insertion alongside the main feed. Pagination paginates only the
author subscription; trending and hashtag batches are initial-load only.
2026-04-16 22:06:53 -04:00
Barry DeenandGitHub 4c0e6b952b Merge pull request #468 from barrydeen/fix/zap-count-zero-display
fix: always show zap count on post cards, including 0
2026-04-16 21:35:54 -04:00
Barry Deen 4da5a087eb fix: always show zap count on post cards, including 0 2026-04-16 21:33:52 -04:00
Barry DeenandGitHub 7849c04965 Merge pull request #467 from barrydeen/fix/back-minimizes-app
fix: allow back button to minimize app from FEED
2026-04-16 21:29:24 -04:00
Barry Deen 221275e29d fix: allow back button to minimize app from FEED
Users expect pressing back from the home screen to minimize the app.
The BackHandler was swallowing the press on FEED; disable it there
so Android's default behavior handles it.
2026-04-16 21:28:59 -04:00
Barry DeenandGitHub 1b51a4b1fe Merge pull request #466 from barrydeen/fix/video-replay-autoplay-disabled
fix: replay inline video after it ends when autoplay is off
2026-04-16 21:24:40 -04:00
Barry Deen 8f90324c7a fix: seek to 0 when replaying ended video with autoplay off
ExoPlayer in STATE_ENDED stays at the end position, so calling play()
on the overlay tap had no effect after the video finished once. Seek
back to 0 before playing if the player has ended.
2026-04-16 21:23:33 -04:00
Barry DeenandGitHub 4b927b335a Merge pull request #465 from barrydeen/feat/media-compression-and-formats
feat: render HLS/HEIC inline + compress uploads + transcode GIFs
2026-04-16 21:19:00 -04:00
Barry Deen 17c17a6648 feat: compress images and transcode GIFs before Blossom upload
Every upload path (profile picture, compose attachment, DM attachment)
now runs through a shared preprocessing pipeline:

- image/gif -> transcoded to H.264 MP4 via MediaCodec + MediaMuxer
  through an EGL input surface (typical 5-20x size reduction)
- other image/* -> decoded with ImageDecoder (handles HEIC on API 28+),
  EXIF-rotated when needed, proportionally scaled, JPEG re-encoded
- videos and other types -> passed through unchanged

Profile pictures cap at 400px wide / JPEG quality 75. Compose and DM
uploads cap at 1920px / quality 82. imeta dim and Kind 15 size/dim
tags are recomputed from post-pipeline bytes so clients see accurate
metadata. Gallery-mode video/image mixing check treats GIFs as video
since they become MP4s.
2026-04-16 21:16:56 -04:00
Barry Deen 93d658c98e feat: render .m3u8 (HLS) and .heic/.heif URLs inline in notes
Extends the content parser's extension and MIME sets so HLS streams and
Apple HEIF images route to the existing video/image renderers instead of
falling through to plain links. HLS plays via the media3-exoplayer-hls
module that's already on the classpath; HEIC decodes via Coil3 ->
ImageDecoder on API 28+.
2026-04-16 21:16:45 -04:00
Barry DeenandGitHub 973eadf312 Merge pull request #464 from barrydeen/feat/onboarding-overhaul
feat: onboarding overhaul — topics screen + first-post coach
2026-04-16 20:48:15 -04:00
Barry Deen 0446301917 fix: bulk-publish onboarding topics as one event, match post-now UX
Two onboarding polish fixes:

- Topic selections were racing: createInterestSet launched a coroutine
  to publish an empty kind 30015, then a for-loop called followHashtag
  for each tag. Each followHashtag read the repo synchronously before
  the prior coroutines landed, so each call produced its own event
  with just one tag, and the later events with equal created_at did
  not overwrite the first one in the repo. Add a bulk followHashtags
  that takes a Set and publishes a single event with a proper title.
- First-post bottom bar now matches ComposeScreen: during the send
  countdown, an Undo button cancels and a 'Post now (Ns)' button
  publishes immediately, instead of a single button that only canceled.
2026-04-16 20:44:56 -04:00
Barry Deen ee1eb546c4 fix: treat new onboarding routes as non-app routes
The nonAppRoutes set is used to decide whether the post-process-death
redirect-to-LOADING effect should fire. With ONBOARDING_TOPICS and
ONBOARDING_FIRST_POST missing from the set, that effect treated them
as regular app screens and kicked users from the topic/first-post
screens to LOADING mid-flow.
2026-04-16 20:35:28 -04:00
Barry Deen 8240c1e5ee feat: extend onboarding with topic follows and first-post coach
New flow after profile: People suggestions → Topics → First post → Feed.

- Topic screen fetches a curated 'trending' set and an 'all' set from
  feeds.nostrarchives.com (kind 30015) so users can pick hashtags via
  autocomplete or tap popular chips. Selections are saved through the
  existing InterestRepository / followHashtag path (kind 30015 interest
  set named 'Interests').
- First-post screen pre-fills #introductions and reuses the existing
  ComposeViewModel.publish flow. The feed subscription kicks off on
  screen entry so the feed is ready by the time the user finishes.
- Skip handler on the People screen now calls finishOnboarding with an
  empty selection, so skippers still get a kind 3 event that at least
  self-follows — their own posts will show up in their feed.
2026-04-16 20:30:16 -04:00
Barry DeenandGitHub 2bb95fe282 Merge pull request #463 from barrydeen/fix/fresh-signup-feed-empty
fix: resubscribe feed when fresh signup returns empty
2026-04-16 20:18:18 -04:00
Barry Deen f9d0971bc3 fix: resubscribe feed when fresh signup returns empty
On fresh signup the feed subscription fires before author NIP-65 relay
lists have fully propagated, so outbox routing defaults to pinned relays
that may not carry the followed authors' posts. The existing late-
arrival safety net only covered the opposite case (follows arriving
after initial subscribe). Add a symmetric retry: if the initial subscribe
had a non-empty follow list but the feed is still empty after 5s, resub
once so routing uses the now-known per-author relays.
2026-04-16 20:17:19 -04:00
Barry DeenandGitHub 71a2c72ef0 Merge pull request #462 from barrydeen/feat/fiat-mode
Normie Mode (fiat)
2026-04-16 20:10:14 -04:00
Barry Deen 150a267b7f feat: add Fiat Mode
Opt-in display mode that renders zap and wallet amounts in a fiat currency
(default USD) instead of satoshis. Rates are fetched once at startup from
CoinGecko and cached in SharedPreferences as a fallback.

- FiatPreferences + ExchangeRateRepository for the toggle, currency
  selection, and cached rates across 26 fiat currencies
- AmountFormatter centralizes sat→fiat display across feed zap pills,
  wallet balance / transactions / invoice confirm + receive screens,
  zap dialog, DM bubbles, notifications stats, and lightning invoice cards
- Fiat Mode section lives inside the Interface settings screen
- Fiat Mode forces the bolt (voltage) icon everywhere so the ₿ symbol is
  never shown while fiat amounts are displayed
- Receive screen accepts fiat amounts with a decimal key and a dedicated
  "Generate invoice" button; converts fiat→sats before creating the invoice
- Zap dialog preset chips keep their sat values internally and relabel as
  fiat; "Send Zap" copy flips to "Send Money"
- Wallet balance-unit selector (SATS / BITCOIN / LIGHTNING) is hidden in
  Fiat Mode since it only applies to sat rendering
- New npub signups default to Fiat Mode + USD; nsec / npub / signer logins
  never touch the preference, so returning users keep their choice
2026-04-16 20:09:01 -04:00
Barry DeenandGitHub b4a40ac3e6 Merge pull request #461 from barrydeen/chore/bump-version-0.18.0
chore: bump version to 0.18.0
2026-04-16 01:06:25 -04:00
Barry Deen a04eac0874 chore: bump version to 0.18.0 2026-04-16 01:05:59 -04:00
Barry DeenandGitHub 3bba8f7d0b Merge pull request #460 from barrydeen/fix/strip-nostr-prefix-search
fix: strip nostr: prefix from search queries
2026-04-16 01:03:53 -04:00
Barry Deen 2e9d3261ea fix: strip nostr: prefix from search queries 2026-04-16 01:01:16 -04:00
Barry DeenandGitHub c5af40c2cc Merge pull request #459 from barrydeen/fix/subcompose-intrinsic-crash
fix: replace SubcomposeAsyncImage to prevent intrinsic measurement crash
2026-04-16 00:57:36 -04:00
Barry Deen efb07902e6 fix: replace SubcomposeAsyncImage to prevent intrinsic measurement crash
SubcomposeAsyncImage (SubcomposeLayout) crashes when rendered inside
chat bubble columns that use IntrinsicSize.Max for shrink-wrap sizing.
Switch to AsyncImage with loading state overlay instead.
2026-04-16 00:56:38 -04:00
Barry DeenandGitHub 0bc46e50ec Merge pull request #458 from barrydeen/fix/show-more-media-sizing
Fix show-more truncation distorting media sizing
2026-04-16 00:46:35 -04:00
Barry Deen eceda19ec0 fix: skip collapsible show-more for posts with media
The heightIn constraint used for "show more" truncation propagated
down to video/image players, causing them to resize and shift position
when toggling show more/less. Posts with media now render at full
height; only text-heavy posts get the collapsible behavior.
2026-04-16 00:45:54 -04:00
Barry DeenandGitHub d1e78dc806 Merge pull request #457 from barrydeen/feat/remember-last-feed
feat: persist last-viewed feed across app sessions
2026-04-16 00:26:38 -04:00
Barry DeenandClaude Opus 4.6 c65b995af3 feat: persist last-viewed feed across app sessions
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 00:25:47 -04:00
Barry DeenandGitHub 14abc621d0 Merge pull request #456 from barrydeen/feat/wot-filter
feat: Web of Trust global content filter
2026-04-16 00:02:58 -04:00
Barry Deen 1d35706a32 feat: add Web of Trust global content filter
When enabled in Settings → Safety → Filters, events from pubkeys
outside the user's qualified social graph (self + follows + extended
network) are silently dropped at the EventRepository and
NotificationRepository ingestion layer. This covers notes, reactions,
zaps, and reposts.

Exempt kinds: profiles (0), contact lists (3), relay lists (10002),
DM-related kinds (4, 1059, 13, 14), and DM relay lists (10050).
The filter fails open when the social graph is not computed or stale.
Toggling the filter triggers an immediate feed rebuild.
2026-04-16 00:00:37 -04:00
Barry DeenandGitHub 102b840b6f Merge pull request #455 from barrydeen/feat/nspam-classifier
feat: on-device AI spam detection for replies
2026-04-15 23:53:05 -04:00
Barry Deen 2604894ca6 feat: add on-device AI spam detection for thread replies and notifications
Ports the nspam v0.9 logistic regression model (~937KB) to pure Kotlin
for on-device classification of likely-bot authors. The model runs
MurmurHash3 feature hashing over character and word n-grams plus
structural note features — no ML runtime needed.

Spam filtering is applied only to replies from non-followed authors in
threads and notifications. Suspected spam replies appear at the bottom
of threads behind a toggle. Users can mark authors as "not spam" to
permanently safelist them. The classifier improves over time by
rescoring authors when more of their notes become available.

Adds a new Filters tab to Safety settings with toggles for the spam
filter (on by default) and Web of Trust filter (off, gated by social
graph — implementation in follow-up PR).
2026-04-15 23:49:42 -04:00
Barry Deen 4d3673f2ba Revert "Merge pull request #446 from fiatjaf/ktlint"
This reverts commit 1b346197c8, reversing
changes made to 80fb1da0e7.
2026-04-15 21:48:04 -04:00
Barry DeenandGitHub 1b346197c8 Merge pull request #446 from fiatjaf/ktlint
run ktlint after every change
2026-04-15 20:47:30 -04:00
Barry DeenandGitHub 80fb1da0e7 Merge pull request #452 from roguehashrate/feature/dm-image-save
feat: fullscreen image viewer with save for encrypted DMs
2026-04-15 20:46:53 -04:00
Barry DeenandGitHub 3d5d25c380 Merge pull request #454 from greenart7c3/main
feat: add BlurHash support and enhance media metadata parsing
2026-04-15 20:31:47 -04:00
Barry DeenandGitHub 18938bf358 Merge pull request #453 from roguehashrate/fix/kind20-custom-emoji
fix: display custom emoji images in Kind 20, 21, 22 notes
2026-04-15 19:51:44 -04:00
Barry DeenandGitHub ad71f6c3f0 Merge pull request #451 from barrydeen/chore/bump-version-0.17.6
chore: bump version to 0.17.6
2026-04-12 13:13:24 -04:00
Barry Deen 6f0f68b85f chore: bump version to 0.17.6 (72) 2026-04-12 13:12:42 -04:00
Barry DeenandGitHub 40e516c938 Merge pull request #450 from barrydeen/fix/navigation-lockup-revert-safe-guard
fix: revert navigateSafe guard that caused UI lockup
2026-04-12 13:02:06 -04:00
Barry Deen cb29c718e3 fix: revert navigateSafe guard that caused UI lockup on slower phones
The lifecycle RESUMED check silently swallowed navigation calls when
the back stack entry hadn't reached RESUMED state yet, making the
entire interface unresponsive — especially on older/slower devices.

Reverts the blanket navigateSafe wrapper from #425. The original
double-tap crash was a narrow edge case; this revert restores reliable
navigation for all users.
2026-04-12 13:01:17 -04:00
Barry DeenandGitHub ec822ef245 Merge pull request #449 from barrydeen/fix/nip18-nevent-unresolved-ref
fix: capture neventEncode return value in Nip18
2026-04-12 12:53:46 -04:00
Barry Deen 41c71c50a3 fix: capture neventEncode return value in Nip18.appendNoteUri
The neventEncode result was being discarded and the return
statement referenced a nonexistent `id` variable, causing a
compilation error.
2026-04-12 12:53:09 -04:00
Barry DeenandGitHub 872fce1d93 Merge pull request #447 from NielLiesmons/main
Chat UI/UX proposal
2026-04-12 12:50:58 -04:00
Barry Deen adb45541a0 chore: remove junk files and add to gitignore
Remove accidentally committed .kotlin/errors/ log and .vscode/ config
files. Add both directories to .gitignore to prevent future commits.
2026-04-12 12:46:44 -04:00
Barry DeenandGitHub e7a6986bf0 Merge pull request #445 from fiatjaf/no-note1
stop producing useless deprecated "note1" codes
2026-04-11 12:31:14 -04:00
Barry DeenandGitHub 32f973f814 Merge pull request #444 from fiatjaf/autoprefix-naddr
also autoprefix naddr1 codes
2026-04-08 18:47:40 -04:00
Barry DeenandGitHub db6aead115 Merge pull request #443 from barrydeen/fix/focus-requester-crash
fix: catch FocusRequester not initialized crash
2026-04-08 12:36:50 -04:00
Barry Deen 1d56c1204e fix: catch FocusRequester not initialized crash
Guard all LaunchedEffect { requestFocus() } calls against the race
where the FocusRequester node is not yet attached — particularly in
Scaffold subcomposition (SearchScreen) and dialog content.

Reported on HONOR DNY-NX9, Android 36.
2026-04-08 12:36:22 -04:00
Barry DeenandGitHub eb3cd609cd Merge pull request #442 from barrydeen/fix/reply-count-lru-eviction
fix: reply count lost after LRU cache eviction
2026-04-08 11:31:09 -04:00
Barry Deen 8b3915090d fix: reply count lost after LRU cache eviction
countedReplyIds was a ConcurrentHashMap that never evicted, while
replyCounts was an LruCache. When replyCounts evicted an entry, the
permanent dedup set prevented re-counting on re-fetch. Align
countedReplyIds with the same LruCache pattern used by
countedReactionIds and countedZapIds so both evict together.

Bump to 0.17.5 (71).
2026-04-08 11:29:42 -04:00
Barry DeenandGitHub a8dbe9daa3 Merge pull request #441 from barrydeen/feat/emoji-frequency-sorting
feat: sort emoji picker by usage frequency
2026-04-08 10:45:55 -04:00
Barry DeenandClaude Opus 4.6 b881925f4c feat: sort emoji picker by usage frequency
Track emoji usage counts in SharedPreferences and sort the reaction
picker by most-used first. Both unicode and custom image emojis are
included in the unified sorted list, so frequently used custom emojis
appear before less-used unicode ones.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 10:44:55 -04:00
Barry DeenandGitHub 87c5603fd0 Merge pull request #440 from barrydeen/feat/inline-header-action-icons
Inline action icons in chat message headers
2026-04-08 10:10:22 -04:00
Barry Deen 651ccb5154 feat: inline action icons in chat message headers
Move reply/react/zap icons into the username/timestamp header row
so they're always visible without tapping. Removes the tap-to-reveal
action bar and its 5s auto-dismiss timer. Zero extra vertical space.
2026-04-08 10:09:03 -04:00
Barry DeenandGitHub 84f2b3d42f Merge pull request #438 from barrydeen/fix/blocked-users-quoted-notes-and-list-names
Fix blocked users, notifications, chat UX, and live stream toggle
2026-04-07 16:47:59 -04:00
Barry DeenandClaude Opus 4.6 538b4ad9ab chore: bump version to 0.17.4 (70)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 16:47:19 -04:00
Barry DeenandClaude Opus 4.6 050e0ce603 feat: tap-to-show action bar and colored usernames in chat rooms
Hide reply/react/zap action bar behind a tap gesture with 5s auto-dismiss
to reduce visual clutter in group and live stream chats. Assign each chat
member a deterministic color based on their pubkey for easier distinction,
keeping the user's own name in the theme primary color.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 16:47:19 -04:00
Barry DeenandGitHub 4b13a94586 Merge pull request #437 from barrydeen/fix/blocked-users-quoted-notes-and-list-names
Fix notifications, blocked user quotes, list names, and live stream toggle
2026-04-07 16:31:40 -04:00
Barry Deen 1d8f28ca9c feat: add toggle to hide live streams from feed
Adds a "Hide live streams" switch in Interface settings under the
Media section, with translations for all 10 supported locales.
2026-04-07 16:29:57 -04:00