- Create MediaModels.kt with MediaUploadResponse and UploadedMedia data classes
- Add uploadMedia() and uploadMediaThumbnail() to GhostApiService
- Add uploadMediaFile(uri) to PostRepository with MIME detection
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.
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.
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.
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.
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.
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.
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.
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.
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.
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).
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.
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.
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.
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.
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.
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.
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.
Add TagModels.kt with GhostTagFull, TagsResponse, TagWrapper, TagCount
data classes for full Ghost tag management. Add getTags, getTag,
createTag, updateTag, deleteTag endpoints to GhostApiService.
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.
- 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
StaggeredItem wrapped every list item in AnimatedVisibility with
slideInVertically + fadeIn + LaunchedEffect delays, causing jittery
scrolling due to excessive recompositions and layout passes.
- 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
- 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