OXYGENHUB
◆ main oxygenhub-android / README.md
5.5 KiB · Markdown · last changed Land proposals from the phone (closes #17) 10 days ago renderedsource blame history raw
1
# 📱 OxygenHub Android
2
3
[![flow].flow/stamp].flow/run
4
5
![Status: Early development]https://img.shields.io/badge/Status-Early%20development-blue
6
![Platform: Android]https://img.shields.io/badge/Platform-Android-green
7
![CI: Flow]https://img.shields.io/badge/CI-Flow-blue
8
9
<img src="docs/screenshots/launcher-icon.png" alt="The launcher icon: as a circle, a squircle and a themed icon" width="400">
10
11
The official native Android client for OxygenHub, designed for modern devices and fully optimized for foldables like the Pixel 10 Pro Fold. 
12
13
Built with **Kotlin**, **Jetpack Compose**, and deep **Rust interop** (via `uniffi-rs`) to execute native `oxy` commands directly on your device.
14
15
---
16
17
<p>
18
  <img src="docs/screenshots/dashboard-phone.png" alt="The dashboard on a phone" width="200">
19
  <img src="docs/screenshots/sign-in-code.png" alt="Signing in: the code to approve, dark" width="200">
20
  <img src="docs/screenshots/inbox-phone-dark.png" alt="The inbox, dark" width="200">
21
</p>
22
<p>
23
  <img src="docs/screenshots/repositories-foldable.png" alt="Repositories and a repository's issues side by side on an open foldable" width="400">
24
  <img src="docs/screenshots/repositories-tablet-dark.png" alt="Repositories on a tablet, dark" width="400">
25
</p>
26
27
## ✅ What works today
28
29
* 🔑 **Sign in with your browser** to oxygenhub.io or any hub (#2). The app
30
  shows a code; you approve it on the hub's `/device` page, signed in there
31
  with your password and second factor, so the app never sees either. The
32
  device token is sealed with a key in the Android Keystore (StrongBox where
33
  the phone has one), never written in the clear, logged or backed up.
34
  Signing out (Account) revokes it on the hub.
35
* 🏠 **Dashboard:** a greeting with your avatar, your newest repositories,
36
  the unread count. Your avatar is the picture you uploaded to the hub, or
37
  the hub's identicon for you (#13).
38
* 📚 **Repositories:** yours or all you can see, filtered as you type; a
39
  repository's **issues** (open, closed, all; pinned first). An issue opens on
40
  the hub's web page for now (#4 brings it into the app).
41
* 🔀 **Proposals:** a repository's proposals beside its issues; a proposal's
42
  checks, approvals, changes and what stands in the way, and **Land** (or
43
  land when its checks pass) from the phone (#17).
44
* 📥 **Inbox:** notifications, unread first, with a badge on the navigation;
45
  opening one marks it read, and the whole inbox can be marked read.
46
* 📱 **Phone, foldable and tablet:** a navigation bar on a phone, a rail when
47
  wider; repositories and their issues side by side from a medium width up,
48
  so a foldable opened (Pixel 10 Pro Fold) shows both, kept off the hinge.
49
* 🌗 **Light and dark**, with the wallpaper's colours (dynamic colour), or the
50
  hub's own palette.
51
* Pull to refresh everywhere, with loading, empty and error states.
52
53
The screenshots are rendered from Compose previews with made-up data, no
54
emulator: `scripts/screenshots.sh`.
55
56
## 🛣️ Planned
57
58
The plan is the repository's issues: browse code, history and drops (#3),
59
issues and proposals (#4), Flow runs and live logs (#5), trust and sealed
60
approvals (#6), releases (#7), and the phone as an OxygenFlow runner (#8–#11).
61
62
* 🧬 **Commutative History:** Native visualization of the change graph.
63
* 🔀 **Offline-First Conflicts:** Resolve conflicts on the go; they're just data.
64
* 🌊 **Job Flow Control:** Orchestrate OxygenFlow CI/CD pipelines right from your phone.
65
66
## 🔑 Signing in
67
68
1. Open the app. The hub is `https://oxygenhub.io` unless you change it (any
69
   HTTPS address of a hub works; the last one is remembered).
70
2. Tap **Sign in**. The app shows a code such as `BCDF-GHJK`.
71
3. Tap **Open the hub to approve** (or open `/device` on the hub from a
72
   computer and type the code), sign in there if you need to, check what the
73
   app asks for, and approve it. You may untick scopes.
74
4. The app signs in on its own within a few seconds.
75
76
The app asks for `repo:read` and `user:read`. The token lasts while it is
77
used and ends after 90 days without use; it is listed on the hub under
78
Settings, Tokens as "device: OxygenHub for Android on" and the phone's model.
79
80
## 🛠️ Setup
81
82
1. Clone the repository with `oxy clone`, and fetch the pinned Oxygen
83
   sources: `oxy submodule update --init` (rust-core builds over `oxygen/`).
84
2. Install the Android SDK with an NDK (Android Studio's SDK manager), and
85
   point `local.properties` at it (`sdk.dir=…`) or set `ANDROID_HOME`.
86
3. Install the Rust side: `cargo install cargo-ndk` and
87
   `rustup target add aarch64-linux-android x86_64-linux-android`.
88
4. Build, test and lint; the build compiles rust-core for arm64-v8a and
89
   x86_64 and generates its Kotlin bindings itself:
90
   ```bash
91
   ./gradlew :app:assembleDebug :app:testDebugUnitTest :app:lintDebug
92
   ```
93
94
## 🧭 Layout of the code
95
96
Under `app/src/main/java/io/oxygenhub/android`:
97
98
* `api/`: the hub's JSON types (by hand, from oxygenhub's `hub-api`), the
99
  `HubApi` client over OkHttp, and the device sign-in (`DeviceAuth`).
100
* `auth/`: the session, `KeystoreSessionStore` (the sealed token) and
101
  `SessionManager` (sign in, sign out, a refused token).
102
* `ui/`: one package per screen, each a view model and its composables;
103
  `ui/nav` holds the routes and the adaptive navigation; `ui/common` the
104
  loading, empty and error states.
105
106
The unit tests (`app/src/test`) run the client against MockWebServer with
107
JSON fixtures written from hub-api's types, and the view models against a
108
fake hub.
109
110
## 🏗️ CI/CD
111
112
We dogfood **OxygenFlow** for our builds. 
113
The pipeline is defined in `.flow/pipeline.kdl`.