Coverage / app/src/main/java/io/oxygenhub/android/MainActivity.kt 0.0%
0 of 48 lines run, 0 of 13 functions, 0 of 34 branches · run #1667 on main · run missed
| 1 | package io.oxygenhub.android | |
| 2 | ||
| 3 | import android.content.Intent | |
| 4 | import android.os.Bundle | |
| 5 | import androidx.activity.ComponentActivity | |
| 6 | import androidx.activity.compose.setContent | |
| 7 | import androidx.activity.enableEdgeToEdge | |
| 8 | import androidx.compose.runtime.getValue | |
| 9 | import androidx.compose.runtime.key | |
| 10 | import androidx.compose.runtime.mutableStateOf | |
| 11 | import androidx.glance.appwidget.updateAll | |
| 12 | import androidx.lifecycle.compose.collectAsStateWithLifecycle | |
| 13 | import androidx.lifecycle.lifecycleScope | |
| 14 | import io.oxygenhub.android.alerts.LandAlerts | |
| 15 | import io.oxygenhub.android.ui.nav.ProposalRoute | |
| 16 | import io.oxygenhub.android.ui.nav.SignedInApp | |
| 17 | import io.oxygenhub.android.ui.nav.rememberViewModel | |
| 18 | import io.oxygenhub.android.ui.nav.routeFor | |
| 19 | import io.oxygenhub.android.ui.signin.SignInScreen | |
| 20 | import io.oxygenhub.android.ui.signin.SignInViewModel | |
| 21 | import io.oxygenhub.android.ui.theme.OxygenHubTheme | |
| 22 | import io.oxygenhub.android.widget.HubWidget | |
| 23 | import io.oxygenhub.android.widget.WidgetTaps | |
| 24 | import kotlinx.coroutines.launch | |
| 25 | import uniffi.rust_core.oxygenGreeting | |
| 26 | ||
| 27 | class MainActivity : ComponentActivity() { | |
| 28 | /** A proposal a notification asked to open (#20), until it is shown. */ | |
| 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) | |
| 31 | ||
| 32 | override fun onCreate(savedInstanceState: Bundle?) { | |
| 33 | super.onCreate(savedInstanceState) | |
| 34 | if (savedInstanceState == null) opening.value = routeIn(intent) | |
| 35 | enableEdgeToEdge() | |
| 36 | val container = (application as OxygenHubApp).container | |
| 37 | val sessions = container.sessions | |
| 38 | setContent { | |
| 39 | OxygenHubTheme { | |
| 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 | ) | |
| 47 | } else { | |
| 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() }, | |
| 55 | open = opening.value, | |
| 56 | onOpened = { opening.value = null }, | |
| 57 | ) | |
| 58 | } | |
| 59 | } | |
| 60 | } | |
| 61 | } | |
| 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) } } | |
| 68 | } | |
| 69 | ||
| 70 | override fun onNewIntent(intent: Intent) { | |
| 71 | super.onNewIntent(intent) | |
| 72 | routeIn(intent)?.let { opening.value = it } | |
| 73 | } | |
| 74 | ||
| 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) | |
| 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 | ||
| 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) | |
| 101 | } | |
| 102 | } |