Commit Graph

9931 Commits

Author SHA1 Message Date
nrobi144 e037254b39 fix(highlights): shared store, context menu, link rendering, publish, profile tabs
- Share DesktopHighlightStore and DesktopDraftStore at app level instead
  of per-column to fix cross-deck reactivity and draft persistence
- Replace broken clipboard-based highlight creation with
  LocalContextMenuRepresentation that piggybacks on Copy to get selected text
- Render highlights as highlight:// links instead of bold/italic markers
- Add collapsible highlights panel in article reader with edit/delete/publish
- Publish highlights to relays as NIP-84 events via HighlightPublishAction
- Add Reads tab (kind 30023) and Highlights tab (kind 9802) to profile
- Rewrite MarkdownToolbar with MarkdownEditorState for selection-aware
  toggle, Material icons, and keyboard shortcuts (Cmd+B/I/E/K)
- Wire DraftsScreen "New Draft" button to ArticleEditorScreen navigation

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 06:59:41 +02:00
nrobi144 efa294ea72 feat(highlights): add article highlights and note-taking system
Phase 1: HighlightData model + DesktopHighlightStore (Preferences-based)
Phase 2: Text selection highlight via Cmd+H/Cmd+Shift+H, inline bold/italic
         rendering, HighlightAnnotationDialog, SelectionContainer wrapping
Phase 3: MyHighlightsScreen with grouped view, HighlightPublishAction for
         NIP-84 (kind 9802), deck/sidebar/menu wiring

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 12:16:54 +02:00
nrobi144 c75176891f feat(reads): integrate long-form into deck layout with zoom and reactions
- Wire Article, Editor, Drafts into DeckColumnType + DeckColumnContainer
- Add Drafts to sidebar nav, Add Column dialog, and Window menu
- Add article navigation (onNavigateToArticle) in SinglePaneLayout
- Add NoteActionsRow to ReadsScreen LongFormCards (zaps, reactions, replies)
- Add Cmd+/Cmd- zoom in ArticleReaderScreen via fontScale on RenderMarkdown
- Add kind 30023 to ProfileSubscription for long-form in user profiles
- Add fontScale param to RenderMarkdown using scaled LocalDensity

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 11:18:37 +02:00
nrobi144 328fcf86d7 refactor(reads): address all review findings — security, performance, simplicity
P1 Critical:
- Add 300ms debounce on editor preview to prevent AST re-parse per keystroke
- Hoist Regex constants in ReadingTimeCalculator and TableOfContents
- Add URI scheme allowlist to editor onLinkClick (was missing vs reader)
- Add MAX_CONTENT_BYTES (100KB) validation before publish

P2 Important:
- Delete MarkdownSpikeScreen (278 LOC spike artifact)
- Delete HighlightCreator (95 LOC, zero callers — YAGNI)
- Delete DraftLongTextNoteEvent (162 LOC, no consumers — YAGNI)
- Replace ArticleMediaRenderer interface with onLinkClick lambda
- Extract inline subscription to FilterBuilders.longFormByAddress()
- Replace SimpleDateFormat with thread-safe DateTimeFormatter
- Remove dead placeholders (bookmark button, reactions row, unused param)
- Cache draft index in memory to avoid redundant disk reads
- Add TODO for publish-before-relay-ack issue

P3 Nice-to-have:
- Remove timestamp from subscription subId for stability
- Remove redundant slug ".." removal (regex handles it)
- Add metadata field length limits (title 256, summary 1024)
- Fix identical isMacOS branches in editor
- Validate image URLs (http/https only) in ArticleHeader

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 11:03:29 +02:00
nrobi144 4fcbffdb3b feat(reads): Phase 2 — editor, drafts, publish, highlights
- Create DraftLongTextNoteEvent (kind 30024) in quartz with EventFactory registration
- Create LongFormPublishAction for signing + publishing kind 30023 events
- Create split-pane ArticleEditorScreen with live markdown preview
- Create MarkdownToolbar (bold, italic, heading, link, image, code, quote)
- Create MetadataPanel (title, summary, banner, tags, slug)
- Create DesktopDraftStore with JSON index + .md files, atomic writes, slug sanitization
- Create DraftsScreen with draft list, delete, new draft button
- Create HighlightCreator dialog for kind 9802 highlight creation
- Add Drafts nav rail entry and Editor/Drafts screen routing

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 10:59:52 +02:00
nrobi144 5ef36363cd feat(reads): Phase 1 — article reader with markdown, ToC, reading time
- Add richtext-commonmark deps to commons for shared markdown rendering
- Create RenderMarkdown composable with URL scheme allowlist (security)
- Create ArticleMediaRenderer interface for platform-specific media
- Create ArticleHeader with banner, title, author, reading time metadata
- Create TableOfContents with heading extraction and scroll-spy
- Create ReadingTimeCalculator (238 WPM prose, 80 WPM code, image decay)
- Create ArticleReaderScreen with Medium-style typography (680dp, 1.58x)
- Add DesktopScreen.Article navigation with address tag routing
- Update ReadsScreen to navigate via address tags instead of event IDs
- Responsive ToC sidebar (shown when window > 1100dp)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 10:59:52 +02:00
David Kaspar 6f3308e45c Merge pull request #1923 from vitorpamplona/l10n_crowdin_translations
New Crowdin Translations
2026-03-24 09:00:06 +01:00
Crowdin Bot 1dbe552821 New Crowdin translations by GitHub Action 2026-03-24 07:35:59 +00:00
davotoula 6436668808 update skill 2026-03-24 08:32:56 +01:00
davotoula 346a7ecac2 update translations: CZ, DE, PT, SE 2026-03-24 08:27:32 +01:00
Vitor Pamplona 7874893938 v1.06.1 2026-03-23 18:19:42 -04:00
Vitor Pamplona 51fa28f22a no message 2026-03-23 18:16:24 -04:00
Vitor Pamplona ec4f949782 Leaves some space to click when their is no space or new lines on the poll. 2026-03-23 18:15:36 -04:00
Vitor Pamplona 4c9f2de6f7 - Improves rendering of the completed polls
- Doesn't render quoted polls
2026-03-23 18:01:41 -04:00
Vitor Pamplona e5aeb49a4b Solves some of the crashes of concurrent modification exception 2026-03-23 17:59:14 -04:00
Vitor Pamplona da84848df7 Merge pull request #1911 from vitorpamplona/l10n_crowdin_translations
New Crowdin Translations
2026-03-23 17:46:06 -04:00
Crowdin Bot 3d488165c3 New Crowdin translations by GitHub Action 2026-03-23 21:40:20 +00:00
Vitor Pamplona f99543dc3b Merge pull request #1913 from greenart7c3/claude/add-url-crash-tests-J8Omf
Claude/add url crash tests j8 omf
2026-03-23 17:38:51 -04:00
Claude 7ea5557828 test: fix UrlTest to use 今北産業 as the crash input (PR #1907)
https://claude.ai/code/session_013rJ9iYndYVJgpYK2VazxL2
2026-03-23 21:02:41 +00:00
Claude 3a93c4b075 test: add UrlTest for getPart() boundary conditions fixed in PR #1907
Tests the StringIndexOutOfBoundsException fix in Url.getPart() by directly
constructing Url objects with UrlMarker indices that exceed the trimmed
originalUrl length — the exact scenario that occurs when readEnd() strips
a trailing character (e.g. ':') while the PORT/QUERY marker still points
to the original buffer position.

https://claude.ai/code/session_013rJ9iYndYVJgpYK2VazxL2
2026-03-23 20:57:49 +00:00
Claude 9ebc4a1e67 style: remove trailing blank line in UrlMarkerTest
https://claude.ai/code/session_013rJ9iYndYVJgpYK2VazxL2
2026-03-23 20:56:58 +00:00
Claude 9202b60dcf test: add regression tests for 今北産業 URL crash (PR #1907)
Verifies that the Japanese phrase "今北産業" does not cause a
StringIndexOutOfBoundsException in Url.getPart() and is not
detected as a URL.

https://claude.ai/code/session_013rJ9iYndYVJgpYK2VazxL2
2026-03-23 20:46:59 +00:00
Claude e31e3829a6 test: add regression tests for PR #1907 URL crash fix
Tests cover the StringIndexOutOfBoundsException in Url.getPart() that
occurred when readEnd() trimmed trailing characters (e.g. ':') from a
detected URL but urlMarker indices remained pointing past the trimmed
string's end.

- UrlMarkerTest: three cases testing PORT/QUERY index at or beyond
  string length (the boundary conditions fixed by minOf clamping and
  the startIndex >= length guard)
- UrlsDetectorTest: regression for "今北産業" (no crash, 0 URLs) and
  for a bare "example.com:" host
- UrlParserTest: end-to-end regression for "今北産業" and "example.com:"

https://claude.ai/code/session_013rJ9iYndYVJgpYK2VazxL2
2026-03-23 20:31:28 +00:00
Vitor Pamplona f553489ddf Improves the wording of the Last Seen 2026-03-23 15:51:35 -04:00
Vitor Pamplona 2b920fc47a Merge pull request #1907 from greenart7c3/claude/fix-android-runtime-exception-auFbS
Fix URL parsing bounds checking in Url.kt
2026-03-23 15:51:07 -04:00
Vitor Pamplona 306d76f793 Tries to fix
IllegalArgumentException: 1.06.0-PLAY

| Prop | Value |
|------|-------|
| Manuf |Google |
| Model |Pixel 8a |
| Prod |akita |
| Android |16 |
| SDK Int |36 |
| Brand |google |
| Hardware |akita |
| Device | akita |
| Host | r-0123456789abcdef-0123 |
| User | android-user |

```
java.lang.IllegalArgumentException: Cannot disable reuse from root if it was caused by other groups
    androidx.compose.runtime.PreconditionsKt.throwIllegalArgumentException(r8-map-id-eb237b6d0af50dd04fa25285a72672c5149c195876ad0d708b61d757d31f3d90:3)
    androidx.compose.runtime.ComposerImpl.endReuseFromRoot(r8-map-id-eb237b6d0af50dd04fa25285a72672c5149c195876ad0d708b61d757d31f3d90:19)
    androidx.compose.runtime.PausedCompositionImpl.resume(r8-map-id-eb237b6d0af50dd04fa25285a72672c5149c195876ad0d708b61d757d31f3d90:369)
    androidx.compose.ui.layout.LayoutNodeSubcompositionsState$precomposePaused$2.resume(r8-map-id-eb237b6d0af50dd04fa25285a72672c5149c195876ad0d708b61d757d31f3d90:50)
    androidx.compose.foundation.lazy.layout.PrefetchHandleProvider$HandleAndRequestImpl.performPausableComposition(r8-map-id-eb237b6d0af50dd04fa25285a72672c5149c195876ad0d708b61d757d31f3d90:49)
    androidx.compose.foundation.lazy.layout.PrefetchHandleProvider$HandleAndRequestImpl.executeRequest(r8-map-id-eb237b6d0af50dd04fa25285a72672c5149c195876ad0d708b61d757d31f3d90:128)
    androidx.compose.foundation.lazy.layout.PrefetchHandleProvider$HandleAndRequestImpl.execute(r8-map-id-eb237b6d0af50dd04fa25285a72672c5149c195876ad0d708b61d757d31f3d90:33)
    androidx.compose.foundation.lazy.layout.AndroidPrefetchScheduler.runRequest(r8-map-id-eb237b6d0af50dd04fa25285a72672c5149c195876ad0d708b61d757d31f3d90:36)
    androidx.compose.foundation.lazy.layout.AndroidPrefetchScheduler.run(r8-map-id-eb237b6d0af50dd04fa25285a72672c5149c195876ad0d708b61d757d31f3d90:113)
    android.os.Handler.handleCallback(Handler.java:1070)
    android.os.Handler.dispatchMessage(Handler.java:125)
    android.os.Looper.dispatchMessage(Looper.java:333)
    android.os.Looper.loopOnce(Looper.java:263)
    android.os.Looper.loop(Looper.java:367)
    android.app.ActivityThread.main(ActivityThread.java:9331)
    java.lang.reflect.Method.invoke(Native Method)
    com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:566)
    com.android.internal.os.ZygoteInit.main(ZygoteInit.java:837)
```
2026-03-23 13:47:00 -04:00
Vitor Pamplona eeca86e542 Fixes comparator to avoid Comparison method violates its general contract! 2026-03-23 13:16:32 -04:00
Claude 951610d9ca fix: prevent StringIndexOutOfBoundsException in Url.getPart()
When UrlDetector.readEnd() trims the last character from URLs ending
with characters like '.', ',', etc., the urlMarker indices remain
based on the original buffer length. This caused getPart() to call
substring() with an end index beyond the trimmed URL's length.

Fix by clamping the end index to originalUrl.length and guarding
against an out-of-bounds start index.

https://claude.ai/code/session_014Q2SvTE5vKgUm1w8dPVjYo
2026-03-23 17:10:56 +00:00
Vitor Pamplona 590bd21f62 UriParser might crash, wraps in a try catch 2026-03-23 13:03:43 -04:00
Vitor Pamplona 81380a32ae Fixes POCO phone's removal of the + sign in NWC 2026-03-23 13:03:18 -04:00
Vitor Pamplona 943f1256a7 Improves zap-store settings 2026-03-23 12:41:30 -04:00
Vitor Pamplona 7af1be7363 v1.06.0 2026-03-23 11:23:44 -04:00
Vitor Pamplona a39688dabb remove warnings 2026-03-23 10:46:55 -04:00
Vitor Pamplona 33ec43a5c3 Removing warnings 2026-03-23 10:39:56 -04:00
Vitor Pamplona 1f5841d090 Merge branch 'main' of https://github.com/vitorpamplona/amethyst
* 'main' of https://github.com/vitorpamplona/amethyst:
  New Crowdin translations by GitHub Action
  update translations: CZ, DE, PT, SE
  New Crowdin translations by GitHub Action
2026-03-23 10:31:22 -04:00
Vitor Pamplona 9d086df37a Updating all dependencies 2026-03-23 10:28:33 -04:00
Vitor Pamplona ed3390f64a Fixes weird import 2026-03-23 10:16:59 -04:00
Vitor Pamplona e659651dd4 Merge pull request #1906 from vitorpamplona/l10n_crowdin_translations
New Crowdin Translations
2026-03-23 09:26:59 -04:00
Crowdin Bot 0cc06f424e New Crowdin translations by GitHub Action 2026-03-23 13:12:22 +00:00
davotoula 11176a4679 update translations: CZ, DE, PT, SE 2026-03-23 14:08:14 +01:00
Vitor Pamplona d964816fd3 Fixes build dependency bug: Spotless needs vlcSetup for... something... 2026-03-23 09:06:52 -04:00
Vitor Pamplona bbb75afed9 Merge pull request #1904 from vitorpamplona/l10n_crowdin_translations
New Crowdin Translations
2026-03-23 08:27:58 -04:00
Crowdin Bot 2eb3ebd365 New Crowdin translations by GitHub Action 2026-03-23 12:25:24 +00:00
Vitor Pamplona c75881d928 Merge pull request #1903 from nrobi144/fix/chess-interop
fix(chess): normalize SAN for cross-client Jester interop
2026-03-23 08:23:51 -04:00
nrobi144 9d8d0e249d fix(chess): encode required fields in Jester content JSON
JesterContent fields version, fen, and history were omitted from
serialized JSON because kotlinx.serialization skips default values.
Jester's isStartGameEvent checks arrayEquals(json.history, []) which
fails when the field is absent (undefined !== []).

Added @EncodeDefault to version, fen, and history so they are always
included in the JSON output regardless of value.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 09:08:28 +02:00
nrobi144 677bc6c34a fix(chess): add offchain.pub relay for jester interop
jester.nyo.dev uses offchain.pub as one of its relays. Adding it gives
us 2 shared relays (relay.damus.io + offchain.pub) instead of 1,
improving challenge visibility between Amethyst and Jester clients.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 08:26:09 +02:00
nrobi144 3eaf3d38a5 fix(chess): normalize SAN for cross-client interop
ChessEngine.makeMove() now normalizes SAN notation before passing to
chesslib, fixing games against jester.nyo.dev and other clients that
use different notation:

- Castling: 0-0 → O-O, 0-0-0 → O-O-O (zeros to letters)
- Annotations: strips !, ?, !!, ??, !?, ?! suffixes

Previously, chesslib rejected 0-0/0-0-0 causing ChessStateReconstructor
to mark games as desynced and skip remaining moves. Games appeared
permanently stuck, even after app restart.

Also fixes discoverUserGames() silently dropping games classified as
spectator — now adds them to spectatingGames instead.

23 new interop tests covering SAN variants, reconstruction, spectator
detection, and missing start event handling.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 07:21:17 +02:00
Vitor Pamplona d4fd8088f1 lint 2 2026-03-22 21:04:11 -04:00
Vitor Pamplona 3e7633ea6b lint 2026-03-22 20:02:13 -04:00
Vitor Pamplona 11ed878111 Removing unnecessary XML loading. 2026-03-22 19:43:00 -04:00