diff --git a/CLAUDE.md b/CLAUDE.md index 7cd266c..cd1eebc 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -27,9 +27,20 @@ MVVM with Repository pattern, single-module Gradle project. - **`data/api/`** — Retrofit service (`GhostApiService`), JWT auth (`GhostJwtGenerator`, `GhostAuthInterceptor`), and `ApiClient` singleton with dynamic base URL - **`data/db/`** — Room database with `LocalPost` entity and `LocalPostDao` -- **`data/model/`** — Three model layers: `GhostPost` (API), `LocalPost` (Room entity), `FeedPost` (UI display). Enums: `PostStatus`, `QueueStatus` +- **`data/model/`** — Three model layers: `GhostPost` (API), `LocalPost` (Room entity), `FeedPost` (UI display). Additional models: `PostStats`, `OverallStats`, `GhostAccount`. Enums: `PostStatus`, `QueueStatus`, `PostFilter`, `SortOrder` - **`data/repository/`** — `PostRepository` coordinates local DB and remote API; `OpenGraphFetcher` parses link previews via Jsoup -- **`ui/`** — Jetpack Compose screens (Feed, Composer, Detail, Setup, Settings) with ViewModels using `StateFlow` +- **`data/`** (root utilities) — `AccountManager` (multi-account, up to 5), `CredentialsManager`, `FeedPreferences`, `HashtagParser`, `MobiledocBuilder`, `ShareUtils`, `UrlNormalizer` +- **`ui/animation/`** — `SwooshMotion` shared animation specs (bouncy, snappy, gentle, quick) +- **`ui/components/`** — Reusable composables: `AnimatedDialog`, `ConfirmationDialog`, `PulsingPlaceholder` +- **`ui/feed/`** — Post feed with search, filtering (All/Published/Draft/Scheduled), sorting +- **`ui/composer/`** — Post creation/editing with image uploads, link previews, hashtags, scheduling +- **`ui/detail/`** — Full post view with animated delete dialog +- **`ui/preview/`** — HTML post preview +- **`ui/stats/`** — Statistics dashboard with animated counters (total posts, word counts, reading time) +- **`ui/settings/`** — Settings, account management, theme toggle, disconnect +- **`ui/setup/`** — Initial configuration wizard and add-account flow +- **`ui/theme/`** — Material 3 theming with `ThemeMode` (Light/Dark/System), `ThemeViewModel`, `ThemePreferences` +- **`ui/navigation/`** — Compose Navigation graph with bottom nav (Feed, Stats, Settings) - **`worker/`** — `PostUploadWorker` (WorkManager) handles offline queue with exponential backoff **Key data flow:** Posts are saved to Room first → queued for upload → `PostUploadWorker` syncs to Ghost API when network is available. @@ -40,6 +51,10 @@ MVVM with Repository pattern, single-module Gradle project. - **Content format:** Posts use Ghost's mobiledoc JSON format, built by `MobiledocBuilder` (supports text paragraphs and bookmark cards) - **Credentials:** Stored in `EncryptedSharedPreferences` (AES256-GCM) via `CredentialsManager` - **API client:** Base URL is configured at runtime during setup; `ApiClient` rebuilds Retrofit instance when URL changes +- **Multi-account:** `AccountManager` supports up to 5 Ghost accounts with UUID-based IDs, per-account credentials, and migration from legacy single-account format +- **Avatars:** Fetched from Ghost post authors (`posts[0].authors[0].profile_image`), not `/users/me/` (which returns 404 for integrations) +- **Permissions:** INTERNET, ACCESS_NETWORK_STATE, CAMERA +- **ProGuard:** Release build suppresses missing `com.google.errorprone.annotations` (pulled in by Google Tink via EncryptedSharedPreferences) - **Min SDK 26, Target/Compile SDK 34, Kotlin 1.9.22, Java 17** ## Versioning diff --git a/README.md b/README.md index 737ab31..e11cca1 100644 --- a/README.md +++ b/README.md @@ -11,13 +11,17 @@ A native Android microblogging client for [Ghost CMS](https://ghost.org). Write, - **Ghost Admin API** — Full integration via JWT authentication (HS256) - **Offline-first** — Posts are saved locally and synced when connectivity returns +- **Multi-account** — Connect up to 5 Ghost blogs and switch between them - **Image uploads** — Attach photos from your gallery or camera - **Link previews** — Automatic Open Graph metadata extraction (title, description, thumbnail) +- **Hashtag support** — Auto-extracted hashtags converted to Ghost tags - **Scheduled publishing** — Set a future publish date for your posts +- **Statistics dashboard** — Post counts, word counts, reading time, and more with animated counters +- **Search & filtering** — Filter by status (Published, Draft, Scheduled) and sort by date - **Mobiledoc format** — Native Ghost content format with text paragraphs and bookmark cards - **Encrypted credentials** — API keys stored with AES-256-GCM via AndroidX Security - **Background sync** — WorkManager handles upload queue with exponential backoff -- **Material 3 UI** — Clean, modern interface built entirely with Jetpack Compose +- **Material 3 UI** — Bluesky-inspired feed design with polished animations and Light/Dark/System themes ## Screenshots @@ -32,21 +36,27 @@ com.swoosh.microblog/ ├── data/ │ ├── api/ # Retrofit client, JWT auth, interceptors │ ├── db/ # Room database, DAOs, type converters -│ ├── model/ # GhostPost (API), LocalPost (DB), FeedPost (UI) +│ ├── model/ # GhostPost (API), LocalPost (DB), FeedPost (UI), PostStats, GhostAccount │ └── repository/ # PostRepository, OpenGraphFetcher ├── ui/ -│ ├── feed/ # Post list with pull-to-refresh -│ ├── composer/ # Post creation and editing +│ ├── animation/ # SwooshMotion shared animation specs +│ ├── components/ # Reusable composables (dialogs, placeholders) +│ ├── feed/ # Post feed with search and filtering +│ ├── composer/ # Post creation with images, links, hashtags, scheduling │ ├── detail/ # Full post view -│ ├── setup/ # Initial configuration wizard -│ ├── settings/ # App settings and logout -│ ├── navigation/ # Compose Navigation graph -│ └── theme/ # Material 3 theming +│ ├── preview/ # HTML post preview +│ ├── stats/ # Statistics dashboard +│ ├── setup/ # Configuration wizard and add-account flow +│ ├── settings/ # App settings, account management, theme toggle +│ ├── navigation/ # Compose Navigation with bottom nav bar +│ └── theme/ # Material 3 theming (Light/Dark/System) └── worker/ # PostUploadWorker (WorkManager) ``` **Data flow:** Compose UI → ViewModel → Repository → Room (local) + Retrofit (remote). Posts are persisted to Room first, then queued for upload via WorkManager. +**Navigation:** Bottom bar with three tabs (Feed, Stats, Settings). Composer and Detail screens slide in as overlays. + ## Getting started ### Prerequisites @@ -89,7 +99,7 @@ The project includes unit tests with JUnit 4 and Robolectric: ./gradlew app:testDebugUnitTest # Debug variant only ``` -Test coverage includes JWT generation, mobiledoc building, URL normalization, data model serialization, auth interceptors, and time formatting. +24 test classes covering JWT generation, mobiledoc building, URL normalization, data model serialization, auth interceptors, time formatting, hashtag parsing, account management, feed preferences, and theme modes. ## Tech stack