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