OXYGENHUB
◆ v0.1.9 oxygenhub-android / app / src / main / java / io / oxygenhub / android / MainActivity.kt
4.5 KiB · last changed oxygenhub.io links open in the app (closes #36) 1 day ago source blame history raw
57c08243 Andy McCall ↶ 1
package io.oxygenhub.android
2
ff65ea45 Andy McCall ↶ 3
import android.content.Intent
57c08243 Andy McCall ↶ 4
import android.os.Bundle
5
import androidx.activity.ComponentActivity
6
import androidx.activity.compose.setContent
7
import androidx.activity.enableEdgeToEdge
144cbf7b Andy McCall ↶ 8
import androidx.compose.runtime.getValue
9
import androidx.compose.runtime.key
ff65ea45 Andy McCall ↶ 10
import androidx.compose.runtime.mutableStateOf
b610bc6e Andy McCall ↶ 11
import androidx.glance.appwidget.updateAll
12
import androidx.lifecycle.compose.collectAsStateWithLifecycle
13
import androidx.lifecycle.lifecycleScope
ff65ea45 Andy McCall ↶ 14
import io.oxygenhub.android.alerts.LandAlerts
15
import io.oxygenhub.android.ui.nav.ProposalRoute
144cbf7b Andy McCall ↶ 16
import io.oxygenhub.android.ui.nav.SignedInApp
17
import io.oxygenhub.android.ui.nav.rememberViewModel
cccf0646 Andy McCall ↶ 18
import io.oxygenhub.android.ui.nav.routeFor
144cbf7b Andy McCall ↶ 19
import io.oxygenhub.android.ui.signin.SignInScreen
20
import io.oxygenhub.android.ui.signin.SignInViewModel
57c08243 Andy McCall ↶ 21
import io.oxygenhub.android.ui.theme.OxygenHubTheme
b610bc6e Andy McCall ↶ 22
import io.oxygenhub.android.widget.HubWidget
aa627197 Andy McCall ↶ 23
import io.oxygenhub.android.widget.WidgetTaps
b610bc6e Andy McCall ↶ 24
import kotlinx.coroutines.launch
57c08243 Andy McCall ↶ 25
import uniffi.rust_core.oxygenGreeting
26
27
class MainActivity : ComponentActivity() {
ff65ea45 Andy McCall ↶ 28
    /** A proposal a notification asked to open (#20), until it is shown. */
aa627197 Andy McCall ↶ 29
    /** A screen to open, as a notification or the widget asks: a route of the app's navigation. */
30
    private val opening = mutableStateOf<Any?>(null)
ff65ea45 Andy McCall ↶ 31
57c08243 Andy McCall ↶ 32
    override fun onCreate(savedInstanceState: Bundle?) {
33
        super.onCreate(savedInstanceState)
aa627197 Andy McCall ↶ 34
        if (savedInstanceState == null) opening.value = routeIn(intent)
57c08243 Andy McCall ↶ 35
        enableEdgeToEdge()
144cbf7b Andy McCall ↶ 36
        val container = (application as OxygenHubApp).container
37
        val sessions = container.sessions
57c08243 Andy McCall ↶ 38
        setContent {
39
            OxygenHubTheme {
144cbf7b Andy McCall ↶ 40
                val session by sessions.session.collectAsStateWithLifecycle()
41
                val signedIn = session
42
                val api = signedIn?.let { sessions.api() }
43
                if (signedIn == null || api == null) {
44
                    SignInScreen(
45
                        rememberViewModel { SignInViewModel(sessions, container::deviceAuth, container.clientName, DEFAULT_HUB) },
46
                    )
57c08243 Andy McCall ↶ 47
                } else {
144cbf7b Andy McCall ↶ 48
                    // A new session starts the signed-in app afresh: nothing of the last account's is kept.
49
                    key(signedIn) {
50
                        SignedInApp(
51
                            session = signedIn,
52
                            api = api,
53
                            nativeCore = { oxygenGreeting(signedIn.username) },
54
                            onSignOut = { sessions.signOut() },
ff65ea45 Andy McCall ↶ 55
                            open = opening.value,
56
                            onOpened = { opening.value = null },
144cbf7b Andy McCall ↶ 57
                        )
58
                    }
57c08243 Andy McCall ↶ 59
                }
60
            }
61
        }
b610bc6e Andy McCall ↶ 62
    }
63
64
    /** The widget (#28) shows what the app knows now, whenever the app comes to the front. */
65
    override fun onResume() {
66
        super.onResume()
67
        lifecycleScope.launch { runCatching { HubWidget().updateAll(this@MainActivity) } }
ff65ea45 Andy McCall ↶ 68
    }
69
70
    override fun onNewIntent(intent: Intent) {
71
        super.onNewIntent(intent)
aa627197 Andy McCall ↶ 72
        routeIn(intent)?.let { opening.value = it }
ff65ea45 Andy McCall ↶ 73
    }
74
cccf0646 Andy McCall ↶ 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)
aa627197 Andy McCall ↶ 77
cccf0646 Andy McCall ↶ 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
ff65ea45 Andy McCall ↶ 96
    private fun proposalIn(intent: Intent?): ProposalRoute? {
97
        val repository = intent?.getStringExtra(LandAlerts.EXTRA_REPOSITORY) ?: return null
98
        val number = intent.getLongExtra(LandAlerts.EXTRA_NUMBER, 0)
99
        if ('/' !in repository || number <= 0) return null
100
        return ProposalRoute(repository.substringBefore('/'), repository.substringAfter('/'), number)
57c08243 Andy McCall ↶ 101
    }
102
}