mirror of
https://github.com/pawelorzech/Swoosh.git
synced 2026-03-31 11:55:47 +00:00
docs: add open-source project files (README, license, contributing)
Add professional open-source scaffolding: - README.md with badges, features, architecture, and setup guide - LICENSE (PolyForm Noncommercial 1.0.0) - CONTRIBUTING.md with guidelines - CHANGELOG.md for v1.0.0 - GitHub issue and PR templates - Updated .gitignore
This commit is contained in:
parent
7da55c4b35
commit
74f42fd2f1
8 changed files with 409 additions and 9 deletions
29
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
29
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
---
|
||||||
|
name: Bug report
|
||||||
|
about: Report a bug to help improve Swoosh
|
||||||
|
title: ''
|
||||||
|
labels: bug
|
||||||
|
assignees: ''
|
||||||
|
---
|
||||||
|
|
||||||
|
**Describe the bug**
|
||||||
|
A clear description of what the bug is.
|
||||||
|
|
||||||
|
**Steps to reproduce**
|
||||||
|
1. Go to '...'
|
||||||
|
2. Tap on '...'
|
||||||
|
3. See error
|
||||||
|
|
||||||
|
**Expected behavior**
|
||||||
|
What you expected to happen.
|
||||||
|
|
||||||
|
**Screenshots**
|
||||||
|
If applicable, add screenshots.
|
||||||
|
|
||||||
|
**Device info**
|
||||||
|
- Device: [e.g. Pixel 7]
|
||||||
|
- Android version: [e.g. 14]
|
||||||
|
- App version: [e.g. 1.0]
|
||||||
|
|
||||||
|
**Additional context**
|
||||||
|
Any other context about the problem.
|
||||||
19
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
19
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
---
|
||||||
|
name: Feature request
|
||||||
|
about: Suggest an idea for Swoosh
|
||||||
|
title: ''
|
||||||
|
labels: enhancement
|
||||||
|
assignees: ''
|
||||||
|
---
|
||||||
|
|
||||||
|
**Problem**
|
||||||
|
What problem does this solve?
|
||||||
|
|
||||||
|
**Proposed solution**
|
||||||
|
How do you think it should work?
|
||||||
|
|
||||||
|
**Alternatives considered**
|
||||||
|
Any alternative solutions you've thought about.
|
||||||
|
|
||||||
|
**Additional context**
|
||||||
|
Any other context, mockups, or references.
|
||||||
12
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
12
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
## Summary
|
||||||
|
|
||||||
|
Brief description of the changes.
|
||||||
|
|
||||||
|
## Changes
|
||||||
|
|
||||||
|
-
|
||||||
|
|
||||||
|
## Testing
|
||||||
|
|
||||||
|
- [ ] Unit tests pass (`./gradlew test`)
|
||||||
|
- [ ] Tested on device/emulator
|
||||||
38
.gitignore
vendored
38
.gitignore
vendored
|
|
@ -1,11 +1,31 @@
|
||||||
|
# Gradle
|
||||||
|
.gradle/
|
||||||
|
build/
|
||||||
|
/app/build/
|
||||||
|
|
||||||
|
# IDE
|
||||||
*.iml
|
*.iml
|
||||||
.gradle
|
.idea/
|
||||||
/local.properties
|
*.swp
|
||||||
/.idea
|
*~
|
||||||
.DS_Store
|
|
||||||
/build
|
# Local properties
|
||||||
/captures
|
|
||||||
.externalNativeBuild
|
|
||||||
.cxx
|
|
||||||
local.properties
|
local.properties
|
||||||
/app/build
|
|
||||||
|
# Android
|
||||||
|
/captures
|
||||||
|
.externalNativeBuild/
|
||||||
|
.cxx/
|
||||||
|
|
||||||
|
# macOS
|
||||||
|
.DS_Store
|
||||||
|
|
||||||
|
# Keystore (do not commit signing keys)
|
||||||
|
*.jks
|
||||||
|
*.keystore
|
||||||
|
|
||||||
|
# Debug logs
|
||||||
|
firebase-debug.log
|
||||||
|
|
||||||
|
# Secrets
|
||||||
|
*.env
|
||||||
|
|
|
||||||
24
CHANGELOG.md
Normal file
24
CHANGELOG.md
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
# Changelog
|
||||||
|
|
||||||
|
All notable changes to this project will be documented in this file.
|
||||||
|
|
||||||
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
||||||
|
|
||||||
|
## [1.0.0] - 2024-12-01
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Ghost Admin API integration with JWT authentication
|
||||||
|
- Post creation with title and body
|
||||||
|
- Image upload from gallery and camera
|
||||||
|
- Link preview extraction via Open Graph
|
||||||
|
- Scheduled publishing
|
||||||
|
- Offline-first architecture with Room database
|
||||||
|
- Background sync via WorkManager with exponential backoff
|
||||||
|
- Encrypted credential storage (AES-256-GCM)
|
||||||
|
- Setup wizard for Ghost blog configuration
|
||||||
|
- Feed screen with pull-to-refresh
|
||||||
|
- Post detail view
|
||||||
|
- Settings screen with logout
|
||||||
|
- Material 3 UI with Jetpack Compose
|
||||||
|
- Comprehensive unit test suite (116 tests)
|
||||||
42
CONTRIBUTING.md
Normal file
42
CONTRIBUTING.md
Normal file
|
|
@ -0,0 +1,42 @@
|
||||||
|
# Contributing to Swoosh
|
||||||
|
|
||||||
|
Thanks for your interest in contributing! Here's how you can help.
|
||||||
|
|
||||||
|
## Getting started
|
||||||
|
|
||||||
|
1. Fork the repository
|
||||||
|
2. Clone your fork: `git clone https://github.com/YOUR_USERNAME/Swoosh.git`
|
||||||
|
3. Create a feature branch: `git checkout -b feature/your-feature`
|
||||||
|
4. Make your changes
|
||||||
|
5. Run the tests: `./gradlew test`
|
||||||
|
6. Commit and push to your fork
|
||||||
|
7. Open a Pull Request
|
||||||
|
|
||||||
|
## Development setup
|
||||||
|
|
||||||
|
- Android Studio Hedgehog (2023.1.1) or later
|
||||||
|
- JDK 17
|
||||||
|
- Android SDK 34
|
||||||
|
|
||||||
|
## Guidelines
|
||||||
|
|
||||||
|
- Follow existing code style and patterns (MVVM, Repository, Compose)
|
||||||
|
- Write tests for new functionality
|
||||||
|
- Keep commits focused — one logical change per commit
|
||||||
|
- Use descriptive commit messages
|
||||||
|
|
||||||
|
## Reporting bugs
|
||||||
|
|
||||||
|
Open an [issue](https://github.com/pawelorzech/Swoosh/issues) with:
|
||||||
|
|
||||||
|
- Steps to reproduce
|
||||||
|
- Expected vs actual behavior
|
||||||
|
- Android version and device info
|
||||||
|
|
||||||
|
## Feature requests
|
||||||
|
|
||||||
|
Open an [issue](https://github.com/pawelorzech/Swoosh/issues) with a description of the feature and why it would be useful.
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
By contributing, you agree that your contributions will be licensed under the [PolyForm Noncommercial License 1.0.0](LICENSE).
|
||||||
135
LICENSE
Normal file
135
LICENSE
Normal file
|
|
@ -0,0 +1,135 @@
|
||||||
|
# PolyForm Noncommercial License 1.0.0
|
||||||
|
|
||||||
|
<https://polyformproject.org/licenses/noncommercial/1.0.0>
|
||||||
|
|
||||||
|
## Acceptance
|
||||||
|
|
||||||
|
In order to get any license under these terms, you must agree
|
||||||
|
to them as both strict obligations and conditions to all
|
||||||
|
your licenses.
|
||||||
|
|
||||||
|
## Copyright License
|
||||||
|
|
||||||
|
The licensor grants you a copyright license for the
|
||||||
|
software to do everything you might do with the software
|
||||||
|
that would otherwise infringe the licensor's copyright
|
||||||
|
in it for any permitted purpose. However, you may
|
||||||
|
only distribute the software according to [Distribution
|
||||||
|
License](#distribution-license) and make changes or new works
|
||||||
|
based on the software according to [Changes and New Works
|
||||||
|
License](#changes-and-new-works-license).
|
||||||
|
|
||||||
|
## Distribution License
|
||||||
|
|
||||||
|
The licensor grants you an additional copyright license
|
||||||
|
to distribute copies of the software. Your license
|
||||||
|
to distribute covers distributing the software with
|
||||||
|
changes and new works permitted by [Changes and New Works
|
||||||
|
License](#changes-and-new-works-license).
|
||||||
|
|
||||||
|
## Notices
|
||||||
|
|
||||||
|
You must ensure that anyone who gets a copy of any part of
|
||||||
|
the software from you also gets a copy of these terms or the
|
||||||
|
URL for them above, as well as copies of any plain-text lines
|
||||||
|
beginning with `Required Notice:` that the licensor provided
|
||||||
|
with the software. For example:
|
||||||
|
|
||||||
|
> Required Notice: Copyright Paweł Orzech (https://pawelorzech.pl)
|
||||||
|
|
||||||
|
## Changes and New Works License
|
||||||
|
|
||||||
|
The licensor grants you an additional copyright license to
|
||||||
|
make changes and new works based on the software for any
|
||||||
|
permitted purpose.
|
||||||
|
|
||||||
|
## Patent License
|
||||||
|
|
||||||
|
The licensor grants you a patent license for the software that
|
||||||
|
covers patent claims the licensor can license, or becomes able
|
||||||
|
to license, that you would infringe by using the software.
|
||||||
|
|
||||||
|
## Noncommercial Purposes
|
||||||
|
|
||||||
|
Any noncommercial purpose is a permitted purpose.
|
||||||
|
|
||||||
|
## Personal Uses
|
||||||
|
|
||||||
|
Personal use for research, experiment, and testing for
|
||||||
|
the benefit of public knowledge, personal study, private
|
||||||
|
entertainment, hobby projects, amateur pursuits, or religious
|
||||||
|
observance, without any anticipated commercial application,
|
||||||
|
is use for a permitted purpose.
|
||||||
|
|
||||||
|
## Noncommercial Organizations
|
||||||
|
|
||||||
|
Use by any charitable organization, educational institution,
|
||||||
|
public research organization, public safety or health
|
||||||
|
organization, environmental protection organization,
|
||||||
|
or government institution is use for a permitted purpose
|
||||||
|
regardless of the source of funding or obligations resulting
|
||||||
|
from the funding.
|
||||||
|
|
||||||
|
## Fair Use
|
||||||
|
|
||||||
|
You may have "fair use" rights for the software under the
|
||||||
|
law. These terms do not limit them.
|
||||||
|
|
||||||
|
## No Other Rights
|
||||||
|
|
||||||
|
These terms do not allow you to sublicense or transfer any of
|
||||||
|
your licenses to anyone else, or prevent the licensor from
|
||||||
|
granting licenses to anyone else. These terms do not imply
|
||||||
|
any other licenses.
|
||||||
|
|
||||||
|
## Patent Defense
|
||||||
|
|
||||||
|
If you make any written claim that the software infringes or
|
||||||
|
contributes to infringement of any patent, your patent license
|
||||||
|
for the software granted under these terms ends immediately. If
|
||||||
|
your company makes such a claim, your patent license ends
|
||||||
|
immediately for work on behalf of your company.
|
||||||
|
|
||||||
|
## Violations
|
||||||
|
|
||||||
|
The first time you are notified in writing that you have
|
||||||
|
violated any of these terms, or done anything with the software
|
||||||
|
not covered by your licenses, your licenses can nonetheless
|
||||||
|
continue if you come into full compliance with these terms,
|
||||||
|
and take practical steps to correct past violations, within
|
||||||
|
32 days of receiving notice. Otherwise, all your licenses
|
||||||
|
end immediately.
|
||||||
|
|
||||||
|
## No Liability
|
||||||
|
|
||||||
|
***As far as the law allows, the software comes as is, without
|
||||||
|
any warranty or condition, and the licensor will not be liable
|
||||||
|
to you for any damages arising out of these terms or the use
|
||||||
|
or nature of the software, under any kind of legal claim.***
|
||||||
|
|
||||||
|
## Definitions
|
||||||
|
|
||||||
|
The **licensor** is the individual or entity offering these
|
||||||
|
terms, and the **software** is the software the licensor makes
|
||||||
|
available under these terms.
|
||||||
|
|
||||||
|
**You** refers to the individual or entity agreeing to these
|
||||||
|
terms.
|
||||||
|
|
||||||
|
**Your company** is any legal entity, sole proprietorship,
|
||||||
|
or other kind of organization that you work for, plus all
|
||||||
|
organizations that have control over, are under the control of,
|
||||||
|
or are under common control with that organization. **Control**
|
||||||
|
means ownership of substantially all the assets of an entity,
|
||||||
|
or the power to direct its management and policies by vote,
|
||||||
|
contract, or otherwise. Control can be direct or indirect.
|
||||||
|
|
||||||
|
**Your licenses** are all the licenses granted to you for the
|
||||||
|
software under these terms.
|
||||||
|
|
||||||
|
**Use** means anything you do with the software requiring one
|
||||||
|
of your licenses.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
Required Notice: Copyright (c) 2024 Paweł Orzech (https://pawelorzech.pl)
|
||||||
119
README.md
Normal file
119
README.md
Normal file
|
|
@ -0,0 +1,119 @@
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
[](https://developer.android.com)
|
||||||
|
[](https://kotlinlang.org)
|
||||||
|
[](https://developer.android.com/jetpack/compose)
|
||||||
|
[](LICENSE)
|
||||||
|
|
||||||
|
## 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](https://ghost.org) blog with Admin API access
|
||||||
|
|
||||||
|
### Ghost setup
|
||||||
|
|
||||||
|
1. In your Ghost admin panel, go to **Settings → 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/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
|
||||||
|
|
||||||
|
```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
|
||||||
|
```
|
||||||
|
|
||||||
|
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](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)
|
||||||
Loading…
Reference in a new issue