An unofficial native Android client for the Nextcloud Collectives app — wiki-style markdown notebooks hosted on your own Nextcloud server.
100 % AI-written. Every line of source, every test, every CI workflow, this README, and almost every commit message in this repository was written by Claude Code under direction from a human reviewer. No code in this repository was hand-typed.
Unofficial. This project is not affiliated with, endorsed by, or supported by Nextcloud GmbH or the Nextcloud Collectives team. "Nextcloud" and "Collectives" are trademarks of their respective owners.
- Browse collectives and nested page trees
- Render markdown pages, including images, links, task lists, tables, syntax-highlighted fenced code blocks (Prism4j, themed against the app's M3 colour scheme), Nextcloud Text callouts (
> [!INFO]/[!WARN]/[!ERROR]/[!SUCCESS]), and==text==highlights - View-first by default with a per-page edit toggle. Two editors ship side-by-side: a native markdown editor with formatting toolbar + live preview swap that works offline (default), and a collaborative WebView editor backed by Nextcloud Text (beta — multi-user real-time editing, callouts, multi-line tables, math, etc.) used when the server supports it and you're online. Choose the default under Settings → Editor (Prefer plain markdown / Prefer collaborative).
- Offline read cache and offline edit queue (last-write-wins on conflict; local edits preserved as drafts attached to the page)
- Full-text search via the Nextcloud unified-search provider
- Favourites and recent searches, persisted across sessions
- Per-page tags, emoji, rename, and move (folder pages supported)
- Long-press to drag pages and reorder them within their parent — same
subpageOrderthe web Collectives UI uses - Attachments: view inline images, upload from camera or gallery
- Trash + restore, with pre-commit undo on a snackbar
- Share-intent quick capture from any app (text, URLs, single or multiple images)
- Backlinks: collapsible "linked from" row under every page that shows which other pages reference it
- Wikilink support:
[[Page Name]]and relative.mdlinks resolve in-app - Light, Dark, or System theme; Material 3 styling
- Configurable background sync cadence (Off, 1h, 6h, 12h, daily), plus pull-to-refresh on the collective and page lists and a "Sync now" button in Settings that reports when sync last succeeded or why it failed
- Pages revalidate their content against the server on open (
If-None-Match, so an unchanged page costs a 304), which is what keeps edits made elsewhere from staying invisible - Adaptive launcher icon with a monochrome layer for Android 13+ themed icons
- Splash screen via
androidx.core:core-splashscreen - In-app update check: on startup, polls the GitHub Releases API at most once per 24 hours and posts a notification when a newer version is published. Tapping the notification opens the release page in your browser. Distribution is sideload-only, so this is how you hear about updates.
- Android 10 (API 29) or newer
- A Nextcloud instance with the Collectives app installed and accessible to your account, served over HTTPS
- Download the latest
app-release.apkfrom the Releases page. - On the phone, allow the browser (or the file manager you opened the APK with) to install apps. Android usually prompts the first time; the toggle also lives under Settings → Apps → Special app access → Install unknown apps.
- Tap the downloaded APK to install. Android will surface the Play Protect scanning prompt — it can flag unrecognised installers but the install itself is safe to proceed with.
- Open the app, paste your Nextcloud server URL (e.g.
https://cloud.example.com), and approve the device in the browser tab that opens. The device-scoped app password is stored in encrypted shared preferences; your real account password is never seen by the app.
The app checks api.github.com/repos/megamaced/nc_collectives_android/releases/latest at most once every 24 hours on launch and posts a notification when a newer non-pre-release tag is available. Tap the notification to open the release page in your browser and download the new APK; install it over the existing app (same signing key from v1.0.0 onwards, so it's an in-place upgrade). No notification is shown if the request fails, if you're already on the latest version, or if you've already been notified about that tag. On Android 13+ the notification needs POST_NOTIFICATIONS granted to your app under Settings → Apps → NC Collectives → Notifications.
You can also force a check at any time via Settings → About → Check for updates — that bypasses the 24h throttle, opens the release page directly if an update exists, or shows a "you're on the latest version" toast if not.
Login uses the standard Nextcloud Login Flow v2. You provide your server URL and authorise the app from your browser. The app stores only the device-scoped app password returned by your server — your account password is never seen, transmitted, or stored. You can revoke the device at any time from your Nextcloud security settings.
- The app talks only to the Nextcloud server you configure, plus one third-party request to
api.github.comon launch (at most once per 24 hours) for the in-app update check. The GitHub call uses a separate OkHttp client so it never carries your Nextcloud credentials. There are no analytics endpoints, no telemetry, no crash reporters, no third-party SDKs that phone home. The release APK has been confirmed clean of anycom.google.android.gmsorcom.google.firebaseclasses. - No Google Play Services dependencies; no Firebase; no advertising IDs.
- Plaintext (
http://) Nextcloud server URLs are refused at login; the app ships withcleartextTrafficPermitted="false"in the network-security config. - The device-scoped app password is stored in
EncryptedSharedPreferences(Tink-backed). Sign-out wipes the keystore entry along with every Room table and DataStore value. - Network requests trust the system certificate store. There is no certificate pinning yet — if your Nextcloud server uses a self-signed CA you'll need to install that CA on your device.
- Kotlin 2.x + Jetpack Compose + Material 3 (single-Activity, type-safe Compose Navigation)
- Hilt for dependency injection
- Retrofit 3 + OkHttp 5 + kotlinx.serialization (OCS REST + WebDAV against one shared authenticated OkHttp client)
- Room 2.8 for the offline cache, edit queue, and attachment upload queue
- WorkManager for background sync and queued-edit / attachment-upload flush
- Coil 3 for image loading (reuses the authenticated OkHttp client via a
SingletonImageLoader.Factory) - Markwon for markdown rendering (with Prism4j for syntax-highlighted code blocks) — themed directly against the M3 colour scheme via
AndroidView - System
WebView+androidx.webkit(WebSettingsCompat) for the beta collaborative editor against the Nextcloud TextdirectEditingOCS endpoint - Tink (
androidx.security:security-crypto) for the encrypted credential store androidx.core:core-splashscreenfor the launcher splash- The system camera intent (via a scoped FileProvider) for in-app photo capture — no CAMERA permission
./gradlew assembleDebugDebug APK lands at app/build/outputs/apk/debug/app-debug.apk.
For a release build:
./gradlew assembleReleaseWithout signing env vars set, this produces an unsigned APK at app/build/outputs/apk/release/app-release-unsigned.apk. The signing setup (keystore generation, GitHub Actions secret names, local env vars) is documented in docs/SIGNING.md.
R8 minification is on for release builds and the output is deterministic — two consecutive assembleRelease runs at the same commit produce byte-identical APKs (matching SHA-256). Release builds are around 4.9 MB; debug builds, which include the full debug tooling, are around 73 MB.
Issues and pull requests welcome. For larger changes, please open an issue first.
AGPL-3.0-or-later — same family as Nextcloud server and the Collectives app.





