Commit graph

89 commits

Author SHA1 Message Date
Paweł Orzech
c55881e7a8 feat: display file attachments in Feed and Detail screens
- Extend FeedPost with fileUrl and fileName fields
- Parse mobiledoc file cards in FeedViewModel.extractFileCardFromMobiledoc()
- Map LocalPost file fields to FeedPost in toFeedPost()
- Create FileAttachmentCard composable with file type icon colors and tap-to-download
- Integrate file card into PostCardContent (FeedScreen) and DetailScreen
2026-03-20 00:48:01 +01:00
Paweł Orzech
74dac1db6f feat: add file attachment support in Composer, MobiledocBuilder, and PostUploadWorker
- Add file card support to MobiledocBuilder with Ghost's native file card format
- Add file card tests to MobiledocBuilderTest
- Add file state fields to ComposerUiState (fileUri, fileName, fileSize, fileMimeType, uploadedFileUrl)
- Add addFile()/removeFile() methods to ComposerViewModel with 50MB size validation
- Add file picker button and FileAttachmentComposerCard in ComposerScreen
- Update PostUploadWorker to upload files via repository.uploadFile() and include in mobiledoc
2026-03-20 00:46:06 +01:00
Paweł Orzech
2f9b7dac09 feat: add file upload API endpoint, model, and repository method
- Create FileModels.kt with FileUploadResponse and UploadedFile data classes
- Add uploadFile() multipart endpoint to GhostApiService
- Add uploadFile(uri) method to PostRepository following the same pattern as uploadImage()
2026-03-20 00:43:10 +01:00
Paweł Orzech
807c6d559e merge: integrate Phase 2 (Tags CRUD) with existing phases 2026-03-20 00:39:31 +01:00
Paweł Orzech
7d199e9fe9 merge: integrate Phase 3 (Members API) with existing phases 2026-03-20 00:37:02 +01:00
Paweł Orzech
a81a65281f feat: add tag statistics section in Stats screen
StatsViewModel fetches tags from TagRepository, computes most used tag
and posts-without-tags count. StatsScreen shows "Tags" section with
horizontal progress bars (LinearProgressIndicator per tag, colored by
accent_color), most used tag, total tags, and posts without tags count.
2026-03-20 00:35:23 +01:00
Paweł Orzech
33647d41d6 feat: add Member detail screen with profile, subscriptions, activity, and labels
MemberDetailScreen shows scrollable profile: large avatar header with name
and email, 3 quick stat tiles (status, open rate, emails sent), subscription
details for paid members (tier, price, renewal date, cancellation status),
activity section (joined date, last seen, geolocation), newsletters list
with read-only checkboxes, labels as FlowRow of AssistChips, email activity
with open rate progress bar, and member notes.
2026-03-20 00:35:01 +01:00
Paweł Orzech
0752238578 merge: integrate Phase 1 (Site Metadata) with Phase 7 (Pages) 2026-03-20 00:34:46 +01:00
Paweł Orzech
aaf29f1512 feat: add tag filter chips in Feed with popular tags LazyRow
FeedViewModel fetches tags on refresh(), takes top 10 by post count.
FeedScreen shows LazyRow of FilterChip below status filter: "All tags"
first, then popular tags with post counts. Tapping filters posts by tag.
Post cards now show tags in compact labelSmall format joined by dots.
2026-03-20 00:33:57 +01:00
Paweł Orzech
ac461c3e6f feat: show "Publishing to" chip in Composer for multi-account users
When more than one account is configured, display an informational
AssistChip at the top of the Composer showing the active blog name
and site icon. Uses SiteMetadataCache for the blog title, falls back
to account name. Non-clickable, only shown for disambiguation.
2026-03-20 00:33:16 +01:00
Paweł Orzech
afa0005a47 feat: add Members list screen with search, filter, pagination, and nav routes
MembersViewModel manages members list state with loading, pagination,
filter (All/Free/Paid), and debounced search. MembersScreen shows
TopAppBar with total count, search field, segmented filter buttons,
and LazyColumn with member rows (avatar via Coil or colored initial,
name, email, open rate progress bar, relative time, PAID/NEW badges).
Add Routes.MEMBERS and Routes.MEMBER_DETAIL to NavGraph (not in
bottomBarRoutes). Wire "See all members" button from Stats screen.
2026-03-20 00:32:45 +01:00
Paweł Orzech
0679b18b8e feat: show blog name and site icon in Feed top bar
Replace account name with blog title from SiteMetadataCache in the Feed
TopAppBar. Show site icon (24dp, circular) before the title. Truncate
blog name to 20 characters with ellipsis. Falls back to account name
or "Swoosh" if no cached site data exists.
2026-03-20 00:32:24 +01:00
Paweł Orzech
11b20fd42a feat: add Tags management screen with list/edit modes
TagsViewModel manages tag CRUD state. TagsScreen shows searchable list
of OutlinedCards with accent dot, name, count, description. Edit mode
supports name, slug (read-only), description, accent_color hex,
visibility radio. Wired into NavGraph via Routes.TAGS and accessible
from Settings screen via "Tags" row.
2026-03-20 00:31:53 +01:00
Paweł Orzech
b829ff5963 Merge branch 'worktree-agent-a5a483ec' into claude/ghost-microblog-android-utau1 2026-03-20 00:31:46 +01:00
Paweł Orzech
471fea6183 feat: add blog info section in Settings with site metadata
Display cached Ghost site metadata (logo/icon, title, description, URL,
version, locale) in a card above the Current Account section. Add "Open
Ghost Admin" button that launches the blog's admin panel in browser.
Show version warning banner if Ghost version is older than v5.
2026-03-20 00:31:22 +01:00
Paweł Orzech
83b779155e feat: add Pages list and editor screen with Settings navigation
Add PagesViewModel with CRUD operations and edit/create state management.
Add PagesScreen with dual-mode UI (list with long-press context menu and
editor with title/content/slug/status fields). Wire navigation from
Settings via "Static Pages" row. Pages use slide-in-horizontal transition
consistent with other detail screens.
2026-03-20 00:31:22 +01:00
Paweł Orzech
e99d88e10a feat: show member stats tiles in Stats screen with animated counters
StatsViewModel now fetches members via MemberRepository and computes
MemberStats. StatsScreen shows a 2x3 grid of ElevatedCard tiles when
memberStats is available: Total, New this week, Open rate, Free, Paid,
MRR. Includes animated counters and a "See all members" navigation button.
Member fetch failure is non-fatal (tiles simply hidden).
2026-03-20 00:29:50 +01:00
Paweł Orzech
be37f6284f feat: fetch site metadata on setup and show confirmation card
After successful connection test, fetch Ghost /site/ endpoint to get
blog name, description, icon, and version. Show a confirmation card
with site details before completing setup. Warn if Ghost version < 5.
Cache site metadata per account via SiteMetadataCache. Falls back to
existing behavior if site fetch fails.
2026-03-20 00:29:09 +01:00
Paweł Orzech
532e04e571 feat: add tag autocomplete in Composer with suggestions and chips
ComposerViewModel fetches available tags from TagRepository on init,
filters suggestions as user types, supports addTag/removeTag. ComposerScreen
shows tag input field with dropdown suggestions (name + post count),
"Create new" option, and FlowRow of InputChip tags with close icons.
2026-03-20 00:28:21 +01:00
Paweł Orzech
64a573a95c feat: add MemberRepository with fetchMembers, fetchAllMembers, and getMemberStats
MemberRepository follows the same pattern as PostRepository: Context constructor,
AccountManager, ApiClient. Includes fetchMembers (paged), fetchMember (single),
fetchAllMembers (all pages, max 20), and getMemberStats (pure function computing
total/free/paid/newThisWeek/avgOpenRate/MRR). Comprehensive tests for getMemberStats.
2026-03-20 00:28:10 +01:00
Paweł Orzech
a558a2f289 feat: add PageRepository for Ghost Pages CRUD operations
Follows PostRepository pattern with AccountManager-based auth,
Dispatchers.IO coroutine context, and Result<T> return types.
Exposes fetchPages, createPage, updatePage, deletePage methods
plus getBlogUrl for constructing page URLs in the UI.
2026-03-20 00:28:01 +01:00
Paweł Orzech
d83309f8bc feat: add Pages API model, endpoints, and model tests
Introduce GhostPage, PagesResponse, PageWrapper data classes for
Ghost CMS static pages. Add CRUD endpoints (getPages, createPage,
updatePage, deletePage) to GhostApiService. Include comprehensive
unit tests for serialization and default values.
2026-03-20 00:27:33 +01:00
Paweł Orzech
492ee1ca11 feat: add SiteMetadataCache for per-account site metadata storage
SharedPreferences-based cache for GhostSite metadata keyed by account ID.
Supports save/get/getVersion/remove operations with Gson serialization.
Includes Robolectric tests for round-trip, overwrite, multi-account
isolation, and removal.
2026-03-20 00:26:46 +01:00
Paweł Orzech
689b8cc8c2 feat: add Member model, API endpoints, and model parsing tests
Add MemberModels.kt with GhostMember, MemberLabel, MemberNewsletter,
MemberSubscription, SubscriptionPrice, and SubscriptionTier data classes.
Add getMembers() and getMember() endpoints to GhostApiService.
Add comprehensive JSON parsing tests for all member model types.
2026-03-20 00:26:32 +01:00
Paweł Orzech
2dbb4ad005 feat: add TagRepository for tag CRUD operations
Follows PostRepository pattern: constructor takes Context, creates
AccountManager, uses ApiClient.getService, wraps calls in
withContext(Dispatchers.IO), returns Result<T>.
2026-03-20 00:26:15 +01:00
Paweł Orzech
d0019947f8 feat: add extended tag model (GhostTagFull) and tag CRUD API endpoints
Add TagModels.kt with GhostTagFull, TagsResponse, TagWrapper, TagCount
data classes for full Ghost tag management. Add getTags, getTag,
createTag, updateTag, deleteTag endpoints to GhostApiService.
2026-03-20 00:25:34 +01:00
Paweł Orzech
6761eae351 feat: add GhostSite model and /site/ API endpoint
Add GhostSite data class for Ghost CMS site metadata (title, description,
logo, icon, accent color, URL, version, locale). Add getSite() endpoint
to GhostApiService. Include unit tests for Gson deserialization and
version parsing.
2026-03-20 00:24:50 +01:00
Paweł Orzech
8326d06861 feat: add DB migration v3→v4 with new LocalPost columns for email, media, files 2026-03-20 00:21:28 +01:00
Paweł Orzech
c9f77d8e25
fix: add proguard rule to suppress missing errorprone annotations in release build 2026-03-19 15:37:24 +01:00
Paweł Orzech
11f4e2f8f6
fix: extract avatar from post authors instead of /users/me/ (404)
Ghost Admin API /users/me/ returns 404. Instead, extract
profile_image from the first post's authors array which is
already fetched on every refresh.
2026-03-19 15:33:42 +01:00
Paweł Orzech
05f5518bdb
fix: fetch Ghost avatar for existing accounts on app launch 2026-03-19 15:30:28 +01:00
Paweł Orzech
ccd729e82f
feat: show app version in Settings, fix composer NPE crash, bump to v0.2.0
- Settings: shows "Swoosh v0.2.0" at bottom
- Fix: NPE crash in composer error display (AnimatedVisibility exit)
- Version bumped to 0.2.0 (versionCode 2)
- CLAUDE.md: added versioning process documentation
2026-03-19 15:27:58 +01:00
Paweł Orzech
dcb9c50c02
feat: fetch Ghost profile avatar for account icon, fallback to colored initial 2026-03-19 15:25:47 +01:00
Paweł Orzech
edca4dd0c5
feat: add refresh button to stats screen top bar 2026-03-19 15:22:23 +01:00
Paweł Orzech
4a2a18282c
fix: stats screen shows layout instantly, only numbers animate (no stagger entrance) 2026-03-19 14:59:28 +01:00
Paweł Orzech
3da3e97e77
feat: move search to top bar, replace with Stats tab in bottom nav
- Bottom tabs: Home / Stats / Settings (was Home / Search / Settings)
- Search icon back in feed top bar
- Stats screen: no back button, tab-style fade transitions
- Removed Stats link from Settings screen
2026-03-19 14:57:44 +01:00
Paweł Orzech
c91ccd0afb
fix: code review findings - @Stable on FeedPost, derivedStateOf, deduplicate dismiss logic 2026-03-19 14:54:30 +01:00
Paweł Orzech
f3ab562a6c
perf: remove StaggeredItem animations from LazyColumn for smooth scrolling
StaggeredItem wrapped every list item in AnimatedVisibility with
slideInVertically + fadeIn + LaunchedEffect delays, causing jittery
scrolling due to excessive recompositions and layout passes.
2026-03-19 14:51:03 +01:00
Paweł Orzech
c3fb3c7c98
feat: composer redesign, bottom tab bar, bug fixes, animation optimization
- Composer: auto-focus with keyboard, send button in top-right with dropdown
  (Publish/Draft/Schedule), smaller 120dp image thumbnails with fullscreen preview
- Navigation: bottom tab bar (Home/Search/Settings), hidden on detail screens
- Share now copies link to clipboard instead of opening share sheet
- Fix: pinned label no longer shows twice
- Fix: drafts now appear in feed
- Fix: schedule picker blocks past dates, no more NPE crash
- Animations: snappier springs (1500f stiffness), shorter tweens (150-200ms),
  @Immutable on data classes, Coil crossfade 150ms with cache config,
  LazyColumn contentType for better reuse
2026-03-19 14:43:21 +01:00
Paweł Orzech
2470f9a049
refactor: extract ConfirmationDialog, fix animation efficiency issues 2026-03-19 14:32:24 +01:00
Paweł Orzech
15c678556e
feat: add counter, buttons, hashtag, and preview animations in composer 2026-03-19 14:25:16 +01:00
Paweł Orzech
4a7005ce1e
feat: add content reveal and animated delete dialog in detail 2026-03-19 14:24:30 +01:00
Paweł Orzech
5183862533
feat: add account card animation and disconnect dialogs in settings 2026-03-19 14:24:21 +01:00
Paweł Orzech
a6429f16d3
feat: add staggered stats cards and count-up animations 2026-03-19 14:24:05 +01:00
Paweł Orzech
188c62f076
feat: add image, link, schedule, and error animations in composer 2026-03-19 14:23:25 +01:00
Paweł Orzech
0713bd912e
feat: add expand, queue chip, and account switcher animations
- F4: AnimatedContent with expand/shrink transitions on "Show more" text
- F6: Pulsing alpha animation on queue chip when status is UPLOADING
- F10: Staggered slideInHorizontally + fadeIn entrance for account switcher items
2026-03-19 14:21:12 +01:00
Paweł Orzech
5ab2cbafdc
feat: Bluesky-inspired feed redesign - opaque surface for swipe, large icons with labels, clean layout 2026-03-19 14:20:03 +01:00
Paweł Orzech
71d58008c6
feat: add empty state, filter, and overlay animations in feed 2026-03-19 14:18:31 +01:00
Paweł Orzech
64662f6bd4
feat: add staggered card entrance animation in feed 2026-03-19 14:13:03 +01:00
Paweł Orzech
677846a748
feat: add bouncy FAB entrance and press animations 2026-03-19 14:10:46 +01:00