OXYGENHUB
◆ v0.1.0 oxygenhub-android / README.md
5.5 KiB · Markdown · last changed Land proposals from the phone (closes #17) 10 days ago renderedsource blame history raw

📱 OxygenHub Android

flow

Status: Early development Platform: Android CI: Flow

The launcher icon: as a circle, a squircle and a themed icon

The official native Android client for OxygenHub, designed for modern devices and fully optimized for foldables like the Pixel 10 Pro Fold.

Built with Kotlin, Jetpack Compose, and deep Rust interop (via uniffi-rs) to execute native oxy commands directly on your device.


The dashboard on a phone Signing in: the code to approve, dark The inbox, dark

Repositories and a repository's issues side by side on an open foldable Repositories on a tablet, dark

✅ What works today

  • 🔑 Sign in with your browser to oxygenhub.io or any hub (#2). The app shows a code; you approve it on the hub's /device page, signed in there with your password and second factor, so the app never sees either. The device token is sealed with a key in the Android Keystore (StrongBox where the phone has one), never written in the clear, logged or backed up. Signing out (Account) revokes it on the hub.
  • 🏠 Dashboard: a greeting with your avatar, your newest repositories, the unread count. Your avatar is the picture you uploaded to the hub, or the hub's identicon for you (#13).
  • 📚 Repositories: yours or all you can see, filtered as you type; a repository's issues (open, closed, all; pinned first). An issue opens on the hub's web page for now (#4 brings it into the app).
  • 🔀 Proposals: a repository's proposals beside its issues; a proposal's checks, approvals, changes and what stands in the way, and Land (or land when its checks pass) from the phone (#17).
  • 📥 Inbox: notifications, unread first, with a badge on the navigation; opening one marks it read, and the whole inbox can be marked read.
  • 📱 Phone, foldable and tablet: a navigation bar on a phone, a rail when wider; repositories and their issues side by side from a medium width up, so a foldable opened (Pixel 10 Pro Fold) shows both, kept off the hinge.
  • 🌗 Light and dark, with the wallpaper's colours (dynamic colour), or the hub's own palette.
  • Pull to refresh everywhere, with loading, empty and error states.

The screenshots are rendered from Compose previews with made-up data, no emulator: scripts/screenshots.sh.

🛣️ Planned

The plan is the repository's issues: browse code, history and drops (#3), issues and proposals (#4), Flow runs and live logs (#5), trust and sealed approvals (#6), releases (#7), and the phone as an OxygenFlow runner (#8–#11).

  • 🧬 Commutative History: Native visualization of the change graph.
  • 🔀 Offline-First Conflicts: Resolve conflicts on the go; they're just data.
  • 🌊 Job Flow Control: Orchestrate OxygenFlow CI/CD pipelines right from your phone.

🔑 Signing in

  1. Open the app. The hub is https://oxygenhub.io unless you change it (any HTTPS address of a hub works; the last one is remembered).
  2. Tap Sign in. The app shows a code such as BCDF-GHJK.
  3. Tap Open the hub to approve (or open /device on the hub from a computer and type the code), sign in there if you need to, check what the app asks for, and approve it. You may untick scopes.
  4. The app signs in on its own within a few seconds.

The app asks for repo:read and user:read. The token lasts while it is used and ends after 90 days without use; it is listed on the hub under Settings, Tokens as "device: OxygenHub for Android on" and the phone's model.

🛠️ Setup

  1. Clone the repository with oxy clone, and fetch the pinned Oxygen sources: oxy submodule update --init (rust-core builds over oxygen/).
  2. Install the Android SDK with an NDK (Android Studio's SDK manager), and point local.properties at it (sdk.dir=…) or set ANDROID_HOME.
  3. Install the Rust side: cargo install cargo-ndk and rustup target add aarch64-linux-android x86_64-linux-android.
  4. Build, test and lint; the build compiles rust-core for arm64-v8a and x86_64 and generates its Kotlin bindings itself:
    ./gradlew :app:assembleDebug :app:testDebugUnitTest :app:lintDebug
    

🧭 Layout of the code

Under app/src/main/java/io/oxygenhub/android:

  • api/: the hub's JSON types (by hand, from oxygenhub's hub-api), the HubApi client over OkHttp, and the device sign-in (DeviceAuth).
  • auth/: the session, KeystoreSessionStore (the sealed token) and SessionManager (sign in, sign out, a refused token).
  • ui/: one package per screen, each a view model and its composables; ui/nav holds the routes and the adaptive navigation; ui/common the loading, empty and error states.

The unit tests (app/src/test) run the client against MockWebServer with JSON fixtures written from hub-api's types, and the view models against a fake hub.

🏗️ CI/CD

We dogfood OxygenFlow for our builds. The pipeline is defined in .flow/pipeline.kdl.