Commit Graph

6804 Commits

Author SHA1 Message Date
Eric Bailey 010ede1de7 Copy updates from Darrin 2026-01-28 19:15:43 +02:00
Samuel Newman 290ac55d8e restore postgates 2026-01-28 19:15:43 +02:00
Samuel Newman c00d92ede8 save/restore captions 2026-01-28 19:15:43 +02:00
Samuel Newman e9ff3ae941 restore videos 2026-01-28 19:15:43 +02:00
Samuel Newman 0cdc120ae6 clean up orphaned media 2026-01-28 19:15:43 +02:00
Samuel Newman 468fe2f2ed update atproto api 2026-01-28 19:15:43 +02:00
Samuel Newman e15c6c3c64 convert useLoadDraft() hook to regular async function
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-28 19:15:18 +02:00
Samuel Newman 6d46a70b7a Fix native draft media filename encoding
The previous approach replaced both / and : with _, but the reverse
transformation couldn't distinguish between them. This caused cache
misses for paths containing both characters.

Use encodeURIComponent/decodeURIComponent for a proper reversible
encoding.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-28 19:15:18 +02:00
Samuel Newman 57d7223e42 Replace idb with idb-keyval for draft media storage
Simplifies web IndexedDB storage by using idb-keyval instead of the
full idb library. This reduces bundle size and aligns with the pattern
used in src/storage/archive/db/index.web.ts.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-28 19:15:18 +02:00
Samuel Newman e807e49b09 use border_transparent 2026-01-28 19:15:18 +02:00
Samuel Newman c726e3cf67 fix detection rebase change 2026-01-28 19:15:18 +02:00
Eric Bailey 83b47db1b6 Prevent runaway pagination 2026-01-28 19:15:18 +02:00
Samuel Newman cd7a39ecd7 remove extraneous comments 2026-01-28 19:15:18 +02:00
Samuel Newman a346f40d77 Add comment about headers 2026-01-28 19:15:18 +02:00
Samuel Newman c50074fb4f Enable pagination 2026-01-28 19:15:18 +02:00
Samuel Newman 834632ce1c Use minimal media mode for draft display - REVERT IF NEEDED 2026-01-28 19:15:18 +02:00
Samuel Newman 11aee73940 Delete PLAN.md 2026-01-28 19:15:18 +02:00
Samuel Newman 04a3ecf25e More CLAUDE.md updates 2026-01-28 19:15:18 +02:00
Samuel Newman 3164e5d22e docs: add notes on platform files and paginated APIs
- Platform-specific files (.web.ts, .native.ts) are resolved by the
  bundler automatically - just import normally, don't use require()
- Paginated APIs should use useInfiniteQuery, not useQuery

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-28 19:15:18 +02:00
Samuel Newman 4a141e6363 fix type errors 2026-01-28 19:15:18 +02:00
Samuel Newman 9fcaa8ff39 refactor: pass full draft data instead of re-fetching
The useLoadDraft and useDeleteDraftMutation hooks were fetching drafts
via getDrafts() to look up a draft by ID. This was problematic because
getDrafts is paginated, so drafts not on the first page wouldn't be
found.

Changes:
- Add full Draft object to DraftSummary type
- useLoadDraft now takes Draft directly (only loads local media)
- useDeleteDraftMutation now takes {draftId, draft} to avoid re-fetch
- Update DraftItem and DraftsListDialog to pass full draft data

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-28 19:15:18 +02:00
Samuel Newman ca3fcfe89c simplify threadgate/postgate handling 2026-01-28 19:15:17 +02:00
Samuel Newman 92824b4b3a infinite query, rename file to queries 2026-01-28 19:15:17 +02:00
Samuel Newman 2f731146f8 ensure media unavaiable message is contrasty enough 2026-01-28 19:15:17 +02:00
Samuel Newman ad848c0000 Fix draft button behaviour when publishing, tweak buttons 2026-01-28 19:15:17 +02:00
Samuel Newman e5b700a3d2 fix: prevent double query string in GIF draft hydration
When loading a GIF from a draft, the URL was being corrupted with
double query strings like:
`?ww=498&hh=498?hh=498&ww=498`

This happened because:
1. serializeGif() adds ?ww=X&hh=Y&alt=Z to the Tenor URL
2. parseGifFromUrl() returned the full URL including our params
3. resolveGif() in resolve.ts then appends MORE params via string
   concatenation, creating a second ?

Fix: Strip our custom params (ww, hh, alt) from the URL in
parseGifFromUrl() before returning it, so the reconstructed GIF
has a clean base URL.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-28 19:15:17 +02:00
Samuel Newman f396bac685 fix: handle invalid GIF dimensions gracefully
Fix NaN aspectRatio when rehydrating GIFs from drafts by:

1. Adding validation in parseTenorGif to reject invalid dimensions
   (NaN, zero, or negative values)
2. Adding defensive checks in GifEmbed to fallback to 1:1 aspect
   ratio if dimensions are invalid
3. Adding defensive checks in composer ExternalEmbedGif to fallback
   to 16:9 if gif.media_formats.gif.dims is missing or invalid

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-28 19:15:17 +02:00
Samuel Newman 5a67dc9110 move state to colo with composer 2026-01-28 19:15:17 +02:00
Samuel Newman c6539dd033 delete left-over file 2026-01-28 19:15:17 +02:00
Samuel Newman 451d7f6b1b log unknown errors 2026-01-28 19:15:17 +02:00
Samuel Newman 1d6123888b make storage functions async to match web 2026-01-28 19:15:17 +02:00
Samuel Newman c374441cca refactor: use typed error check for draft limit
Replace manual error object inspection with the proper
AppBskyDraftCreateDraft.DraftLimitReachedError type check for
cleaner and more reliable error handling.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-28 19:15:17 +02:00
Samuel Newman f21757f264 style: add bottom padding to drafts list
Add pb_xl padding to the drafts list content container for better
visual spacing at the bottom of the list.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-28 19:15:17 +02:00
Samuel Newman 095ce2865d fix: update save prompt copy when editing existing draft
When editing an existing draft (vs creating a new one), use "Save
changes" instead of "Save draft" in the save/discard prompts. This
provides clearer context to the user about what action they're taking.

Add isEditingDraft prop to DraftsButton and ComposerTopBar, and
update both prompts (in DraftsButton and Composer) with conditional
copy based on whether we're editing an existing draft.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-28 19:15:17 +02:00
Samuel Newman 7c129c0aec fix: load draft preview images and get dimensions
Fix draft preview images not showing on web and add proper aspect
ratio support:

1. Try to load all images regardless of the exists cache flag, which
   may be stale due to async cache population timing
2. Use Image.loadAsync() from expo-image to get image dimensions
3. Pass dimensions to viewImages for proper aspect ratio in previews

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-28 19:15:17 +02:00
Samuel Newman 0992c9376e fix: complete Gif object reconstruction for draft rehydration
Fix "Cannot read property 'url' of undefined" error when rehydrating
drafts with GIFs. The Gif object was missing required properties like
url, content_description, and media_formats.preview that are needed
by useResolveGifQuery and other components.

Also preserve alt text through serialization by storing it in URL
query params alongside dimensions.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-28 19:15:17 +02:00
Samuel Newman 28da42fd61 fix: ensure media cache is populated before checking exists
On iOS (and web), the media cache wasn't populated before the drafts
query ran, causing drafts with local media to incorrectly show as
"missing media" on app restart. The issue would resolve itself after
closing and reopening the composer because by then the cache was ready.

This fix adds ensureMediaCachePopulated() and awaits it in useDrafts
before checking which media exists locally.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-28 19:15:17 +02:00
Samuel Newman a0ed43d903 refactor: use drafts-specific logger in hooks and storage
Switch from the generic logger to the new drafts-specific logger
for better log categorization.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-28 19:15:17 +02:00
Samuel Newman 12763bee76 feat: add drafts-specific logger
Add a Drafts context to the logger system for better log categorization
and debugging of draft-related operations.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-28 19:15:17 +02:00
Samuel Newman 9c8533c05e Migrate storage.ts from expo-file-system/legacy to expo-file-system
Use the new object-based expo-file-system API (SDK 54+) with Directory
and File classes instead of the legacy function-based API. The new API
provides synchronous operations for file/directory existence checks,
creation, copying, deletion, and listing.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-28 19:15:17 +02:00
Samuel Newman 476a01a78f attempt to fix blob mangement 2026-01-28 19:15:17 +02:00
Samuel Newman 666e1318b2 Migrate drafts from local storage to server API
Replace local-only draft storage with the new `app.bsky.draft.*` server API:
- getDrafts, createDraft, updateDraft, deleteDraft endpoints

Key changes:
- Add api.ts with type converters (ComposerState <-> server Draft)
- Update hooks.ts to use server API instead of local storage
- Simplify storage.ts/storage.web.ts for local media caching only
- Media stored locally via localRef pattern (filepath in server draft)
- GIFs stored as external embeds with Tenor URL + dimensions
- Hide drafts button when replying (reply drafts not supported)
- Show "different device" note when media is missing locally

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-28 19:15:17 +02:00
Samuel Newman 2dbee371f3 fix import 2026-01-28 19:15:17 +02:00
Samuel Newman 31cd18f6e1 fix import 2026-01-28 19:14:42 +02:00
Samuel Newman d89fb09e6c add vertical option to prompt, change copy 2026-01-28 19:14:42 +02:00
Samuel Newman 813d972fdf Fix re-saving drafts with existing media
When re-saving a draft, the code was trying to copy media files that
were already in drafts storage to new locations, causing copy errors.

Changes:
- Add extractLocalIdFromPath() to detect if a path is already in drafts
- Track loadedMediaMap in ComposerState for identifying reusable media
- Only delete old media that wasn't reused during re-save
- Pass loadedMediaMap when saving to enable media reuse detection
- Disable pointer events on draft media preview

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-28 19:14:42 +02:00
Samuel Newman ec554210dc Apply dirty tracking to Drafts button prompt
Only show the save/discard prompt when pressing the Drafts button if
the composer has unsaved changes (isDirty). If the content is unchanged
from a loaded draft or was just saved, go directly to the drafts list.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-28 19:14:42 +02:00
Samuel Newman 4cccaf5d8e Mark composer as clean after saving draft
Add mark_saved action that resets isDirty to false and updates the
draftId. This is dispatched after successfully saving a draft, allowing
the user to close the composer without a discard prompt since their
changes have been saved.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-28 19:14:42 +02:00
Samuel Newman 794891db1e Improve drafts dialog platform handling
- Render header outside FlatList on native, inside on web
- Use web() helper for conditional web-only props
- Replace ItemSeparatorComponent with mt_lg margin on items
- Add minHeight on web for better dialog sizing
- Simplify header structure

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-28 19:14:42 +02:00
Samuel Newman 9a681a22ef Use real image embed components for draft preview
Replace custom image preview with AutoSizedImage for single images
and ImageLayoutGrid for multiple images. This gives drafts the same
polished image display as regular posts.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-28 19:14:42 +02:00