oxygenhub.io links open in the app (closes #36) cccf06468345
- Author
- Andy McCall @andymccall <[email protected]>
- via
- agent
agent:claude@andymccall <[email protected]> · keyless, under your grant for changes,refs,seal · key 3357126ec6a5
- When
- · 2026-11-04 00:17 UTC
- Signature
- ◈ sealed by agent:claude@andymccall
- Hash
cccf06468345bc2bf5ce84816e98451830668fa96220fdc0fa4cb45486a9b200- Depends on
- 144cbf7bf2b5 57c0824300db aa627197ec18 c1b5d82f16cd e0e4a1c48a77 ff65ea456ff1
- Depended on by
- nothing yet
- In bookmarks
- main
- In tags
- v0.1.9
- Edits
- 6 atoms, 0 tree operations, 3 files
Browse the tree at this change
modified CHANGELOG.md +1 −0
| … | 1 unchanged lines |
||
| 2 | 2 | ||
| 3 | 3 | ## Unreleased |
|
| 4 | 4 | ||
| 5 | + | - **oxygenhub.io links open in the app (#36):** a link to an issue, a proposal, a Flow run, a change, a file, a history or a board, tapped anywhere (mail, chat, a browser), opens the app on that screen, once the hub vouches for the app (oxygenhub#370, `/.well-known/assetlinks.json`). One the app cannot show, while signed in to another hub say, goes to the browser. Android › Apps › OxygenHub › Open by default turns it off. |
|
| 5 | 6 | - **The changelog is checked on the WASM tier:** a `changelog` job runs OxygenFlow's checks module on any runner with the WASM tier, failing when the changelog is out of shape or the version in gradle.properties has no section. |
|
| 6 | 7 | ||
| 7 | 8 | ## 0.1.8 (2026-11-03) |
|
| … | 65 unchanged lines |
modified app/src/main/AndroidManifest.xml +16 −0
| … | 33 unchanged lines |
||
| 34 | 34 | ||
| 35 | 35 | <category android:name="android.intent.category.LAUNCHER" /> |
|
| 36 | 36 | </intent-filter> |
|
| 37 | + | <!-- App Links (#36): oxygenhub.io's links to what the app shows open |
|
| 38 | + | it there; the hub vouches for the app in assetlinks.json |
|
| 39 | + | (oxygenhub#370). Only the paths the app has a screen for. --> |
|
| 40 | + | <intent-filter android:autoVerify="true"> |
|
| 41 | + | <action android:name="android.intent.action.VIEW" /> |
|
| 42 | + | <category android:name="android.intent.category.DEFAULT" /> |
|
| 43 | + | <category android:name="android.intent.category.BROWSABLE" /> |
|
| 44 | + | <data android:scheme="https" android:host="oxygenhub.io" /> |
|
| 45 | + | <data android:pathAdvancedPattern="/[^/]+/[^/]+/issue/[0-9]+" /> |
|
| 46 | + | <data android:pathAdvancedPattern="/[^/]+/[^/]+/proposal/[0-9]+" /> |
|
| 47 | + | <data android:pathAdvancedPattern="/[^/]+/[^/]+/flow/[0-9]+" /> |
|
| 48 | + | <data android:pathAdvancedPattern="/[^/]+/[^/]+/change/.+" /> |
|
| 49 | + | <data android:pathAdvancedPattern="/[^/]+/[^/]+/changes/.+" /> |
|
| 50 | + | <data android:pathAdvancedPattern="/[^/]+/[^/]+/file/.+" /> |
|
| 51 | + | <data android:pathAdvancedPattern="/projects/[^/]+/[0-9]+" /> |
|
| 52 | + | </intent-filter> |
|
| 37 | 53 | </activity> |
|
| 38 | 54 | <service |
|
| 39 | 55 | android:name=".runner.RunnerService" |
|
| … | 41 unchanged lines |
modified app/src/main/java/io/oxygenhub/android/MainActivity.kt +21 −2
| … | 14 unchanged lines |
||
| 15 | 15 | import io.oxygenhub.android.ui.nav.ProposalRoute |
|
| 16 | 16 | import io.oxygenhub.android.ui.nav.SignedInApp |
|
| 17 | 17 | import io.oxygenhub.android.ui.nav.rememberViewModel |
|
| 18 | + | import io.oxygenhub.android.ui.nav.routeFor |
|
| 18 | 19 | import io.oxygenhub.android.ui.signin.SignInScreen |
|
| 19 | 20 | import io.oxygenhub.android.ui.signin.SignInViewModel |
|
| 20 | 21 | import io.oxygenhub.android.ui.theme.OxygenHubTheme |
|
| … | 50 unchanged lines |
||
| 71 | 72 | routeIn(intent)?.let { opening.value = it } |
|
| 72 | 73 | } |
|
| 73 | 74 | ||
| 74 | - | /** A land alert's proposal, or the screen a tap on the widget's counts names (#31). */ |
|
| 75 | - | private fun routeIn(intent: Intent?): Any? = proposalIn(intent) ?: WidgetTaps.route(intent) |
|
| 75 | + | /** A land alert's proposal, the screen a tap on the widget's counts names (#31), or a link's (#36). */ |
|
| 76 | + | private fun routeIn(intent: Intent?): Any? = proposalIn(intent) ?: WidgetTaps.route(intent) ?: linkIn(intent) |
|
| 76 | 77 | ||
| 78 | + | /** |
|
| 79 | + | * An oxygenhub.io link opened in the app (App Links, #36): its screen, |
|
| 80 | + | * as links inside the app go. One the app cannot show (signed in to |
|
| 81 | + | * another hub, say) goes to the browser, which cannot hand it back. |
|
| 82 | + | */ |
|
| 83 | + | private fun linkIn(intent: Intent?): Any? { |
|
| 84 | + | if (intent?.action != Intent.ACTION_VIEW) return null |
|
| 85 | + | val url = intent.dataString ?: return null |
|
| 86 | + | val hub = (application as OxygenHubApp).container.sessions.session.value?.hub ?: DEFAULT_HUB |
|
| 87 | + | routeFor(url, hub)?.let { return it } |
|
| 88 | + | val browser = Intent(Intent.ACTION_VIEW, intent.data).apply { |
|
| 89 | + | selector = Intent.makeMainSelectorActivity(Intent.ACTION_MAIN, Intent.CATEGORY_APP_BROWSER) |
|
| 90 | + | addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) |
|
| 91 | + | } |
|
| 92 | + | runCatching { startActivity(browser) } |
|
| 93 | + | return null |
|
| 94 | + | } |
|
| 95 | + | ||
| 77 | 96 | private fun proposalIn(intent: Intent?): ProposalRoute? { |
|
| 78 | 97 | val repository = intent?.getStringExtra(LandAlerts.EXTRA_REPOSITORY) ?: return null |
|
| 79 | 98 | val number = intent.getLongExtra(LandAlerts.EXTRA_NUMBER, 0) |
|
| … | 4 unchanged lines |