FeedViewModel was created at NavGraph scope, so its init block called refresh() before credentials existed when starting on the setup screen. Guard the init refresh with an isConfigured check and explicitly trigger refresh after setup completes. |
||
|---|---|---|
| .github | ||
| app | ||
| gradle/wrapper | ||
| .gitignore | ||
| build.gradle.kts | ||
| CHANGELOG.md | ||
| CLAUDE.md | ||
| CONTRIBUTING.md | ||
| gradle.properties | ||
| gradlew | ||
| LICENSE | ||
| README.md | ||
| settings.gradle.kts | ||
Swoosh
A native Android microblogging client for Ghost CMS. Write, publish, and manage short-form posts from your phone — with offline support, image uploads, link previews, and scheduled publishing.
Features
- Ghost Admin API — Full integration via JWT authentication (HS256)
- Offline-first — Posts are saved locally and synced when connectivity returns
- Image uploads — Attach photos from your gallery or camera
- Link previews — Automatic Open Graph metadata extraction (title, description, thumbnail)
- Scheduled publishing — Set a future publish date for your posts
- 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
Screenshots
Coming soon — contributions welcome!
Architecture
MVVM with Repository pattern, single-module Gradle project.
com.swoosh.microblog/
├── data/
│ ├── api/ # Retrofit client, JWT auth, interceptors
│ ├── db/ # Room database, DAOs, type converters
│ ├── model/ # GhostPost (API), LocalPost (DB), FeedPost (UI)
│ └── repository/ # PostRepository, OpenGraphFetcher
├── ui/
│ ├── feed/ # Post list with pull-to-refresh
│ ├── composer/ # Post creation and editing
│ ├── detail/ # Full post view
│ ├── setup/ # Initial configuration wizard
│ ├── settings/ # App settings and logout
│ ├── navigation/ # Compose Navigation graph
│ └── theme/ # Material 3 theming
└── 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.
Getting started
Prerequisites
- Android Studio Hedgehog (2023.1.1) or later
- JDK 17
- Android SDK 34
- A Ghost blog with Admin API access
Ghost setup
- In your Ghost admin panel, go to Settings → Integrations
- Create a new Custom Integration
- Copy the Admin API Key (format:
id:secret) - Note your Ghost blog URL (e.g.
https://yourblog.com)
Build and run
git clone https://github.com/pawelorzech/Swoosh.git
cd Swoosh
./gradlew assembleDebug
Install the debug APK on your device or emulator, then follow the setup wizard to connect your Ghost blog.
Building
./gradlew assembleDebug # Debug APK
./gradlew assembleRelease # Release APK (ProGuard enabled)
Testing
The project includes unit tests with JUnit 4 and Robolectric:
./gradlew test # Run all tests
./gradlew app:testDebugUnitTest # Debug variant only
Test coverage includes JWT generation, mobiledoc building, URL normalization, data model serialization, auth interceptors, and time formatting.
Tech stack
| Layer | Technology |
|---|---|
| UI | Jetpack Compose, Material 3 |
| Navigation | Compose Navigation |
| Architecture | MVVM, StateFlow, Repository pattern |
| Networking | Retrofit 2, OkHttp 4 |
| Images | Coil |
| Database | Room |
| Background | WorkManager |
| Auth | JJWT (HS256), EncryptedSharedPreferences |
| Link parsing | Jsoup |
| Testing | JUnit 4, Robolectric, MockWebServer |
Contributing
Contributions are welcome! Please see CONTRIBUTING.md for guidelines.
License
This project is licensed under the PolyForm Noncommercial License 1.0.0 — you can use, modify, and share it for any non-commercial purpose. Commercial use requires permission from the author.
Author
Paweł Orzech — pawelorzech.pl