# Swoosh

A native Android microblogging client for [Ghost CMS](https://ghost.org). Write, publish, and manage short-form posts from your phone — with offline support, image uploads, link previews, and scheduled publishing.

[![Android](https://img.shields.io/badge/Android-8.0%2B-3DDC84?logo=android&logoColor=white)](https://developer.android.com)
[![Kotlin](https://img.shields.io/badge/Kotlin-1.9-7F52FF?logo=kotlin&logoColor=white)](https://kotlinlang.org)
[![Jetpack Compose](https://img.shields.io/badge/Jetpack%20Compose-Material%203-4285F4?logo=jetpackcompose&logoColor=white)](https://developer.android.com/jetpack/compose)
[![License](https://img.shields.io/badge/License-PolyForm%20Noncommercial-blue)](LICENSE)

## Screenshots

<p align="center">
  <img src="pics/feed.png" width="200" alt="Feed" />
  <img src="pics/newsletter.png" width="200" alt="Newsletter" />
  <img src="pics/stats.png" width="200" alt="Statistics" />
  <img src="pics/settings.png" width="200" alt="Settings" />
</p>

## Features

- **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
- **Pin posts** — Feature/pin important posts to the top of your blog
- **Newsletter integration** — Send posts as newsletters to your Ghost subscribers
- **Members management** — View and manage your Ghost blog members
- **Static pages** — Create, edit, and manage Ghost pages from the app
- **Tag management** — Browse, create, and manage tags with per-tag post counts
- **Statistics dashboard** — Post counts, word counts, reading time, tag breakdown, and more
- **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, green-tinted design with polished animations and Light/Dark/System themes

## 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), PostStats, GhostAccount
│   └── repository/     # PostRepository, OpenGraphFetcher
├── ui/
│   ├── animation/      # SwooshMotion shared animation specs
│   ├── components/     # Reusable composables (dialogs, placeholders)
│   ├── composer/       # Post creation with images, links, hashtags, scheduling
│   ├── detail/         # Full post view with pin toggle
│   ├── feed/           # Post feed with search and filtering
│   ├── members/        # Ghost members/subscribers management
│   ├── newsletter/     # Newsletter configuration and subscriber info
│   ├── pages/          # Static pages CRUD
│   ├── preview/        # HTML post preview
│   ├── settings/       # App settings, account management, theme toggle
│   ├── setup/          # Configuration wizard and add-account flow
│   ├── stats/          # Statistics dashboard with animated counters
│   ├── tags/           # Tag management
│   ├── navigation/     # Compose Navigation with bottom nav bar
│   └── theme/          # Material 3 theming (Light/Dark/System)
└── worker/             # PostUploadWorker (WorkManager)
```

**Data flow:** Compose UI &rarr; ViewModel &rarr; Repository &rarr; Room (local) + Retrofit (remote). Posts are persisted to Room first, then queued for upload via WorkManager.

**Navigation:** Bottom bar with four tabs — Home (Feed), Newsletter, Stats, and Settings. Composer, Detail, Pages, Members, and Tags screens slide in as overlays.

## Getting started

### Prerequisites

- Android Studio Hedgehog (2023.1.1) or later
- JDK 17
- Android SDK 34
- A [Ghost](https://ghost.org) blog with Admin API access

### Ghost setup

1. In your Ghost admin panel, go to **Settings &rarr; Integrations**
2. Create a new **Custom Integration**
3. Copy the **Admin API Key** (format: `id:secret`)
4. Note your Ghost blog URL (e.g. `https://yourblog.com`)

### Build and run

```bash
git clone https://github.com/nicekid1/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

```bash
./gradlew assembleDebug          # Debug APK
./gradlew assembleRelease        # Release APK (ProGuard enabled)
```

## Testing

The project includes unit tests with JUnit 4 and Robolectric:

```bash
./gradlew test                   # Run all tests
./gradlew app:testDebugUnitTest  # Debug variant only
```

31 test classes covering JWT generation, mobiledoc building, URL normalization, data model serialization, auth interceptors, time formatting, hashtag parsing, account management, feed preferences, newsletter preferences, member models, and theme modes.

## Tech stack

| Layer | Technology |
|-------|-----------|
| UI | Jetpack Compose, Material 3 |
| Navigation | Compose Navigation |
| Architecture | MVVM, StateFlow, Repository pattern |
| Networking | Retrofit 2, OkHttp 4 |
| Images | Coil |
| Media | Media3 ExoPlayer |
| Database | Room |
| Background | WorkManager |
| Auth | JJWT (HS256), EncryptedSharedPreferences |
| Link parsing | Jsoup |
| Testing | JUnit 4, Robolectric, MockWebServer |

## Contributing

Contributions are welcome! Please see [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.

## License

This project is licensed under the [PolyForm Noncommercial License 1.0.0](LICENSE) — you can use, modify, and share it for any non-commercial purpose. Commercial use requires permission from the author.

## Author

**Paweł Orzech** — [pawelorzech.pl](https://pawelorzech.pl)
