parent
48e20d5464
commit
a302c2d13c
|
|
@ -43,10 +43,13 @@ import chat.revolt.api.HitRateLimitException
|
|||
import chat.revolt.api.RevoltAPI
|
||||
import chat.revolt.api.RevoltHttp
|
||||
import chat.revolt.api.api
|
||||
import chat.revolt.api.routes.microservices.health.healthCheck
|
||||
import chat.revolt.api.routes.onboard.needsOnboarding
|
||||
import chat.revolt.api.schemas.HealthNotice
|
||||
import chat.revolt.api.settings.Experiments
|
||||
import chat.revolt.api.settings.LoadedSettings
|
||||
import chat.revolt.api.settings.SyncedSettings
|
||||
import chat.revolt.components.generic.HealthAlert
|
||||
import chat.revolt.ndk.NativeLibraries
|
||||
import chat.revolt.persistence.KVStorage
|
||||
import chat.revolt.screens.DefaultDestinationScreen
|
||||
|
|
@ -132,6 +135,8 @@ class MainActivityViewModel @Inject constructor(
|
|||
viewModelScope.launch {
|
||||
Log.d("MainActivity", "Hydrating Experiments from KV")
|
||||
Experiments.hydrateWithKv()
|
||||
Log.d("MainActivity", "Performing health check")
|
||||
doHealthCheck()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -219,6 +224,30 @@ class MainActivityViewModel @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
val activeAlert = MutableStateFlow<HealthNotice?>(null)
|
||||
val isAlertActive = MutableStateFlow(false)
|
||||
|
||||
private fun doHealthCheck() {
|
||||
viewModelScope.launch {
|
||||
try {
|
||||
val health = healthCheck()
|
||||
if (health.alert != null) {
|
||||
activeAlert.emit(health)
|
||||
isAlertActive.emit(true)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Log.e("MainActivity", "Failed to perform health check", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun onDismissHealthAlert() {
|
||||
viewModelScope.launch {
|
||||
activeAlert.emit(null)
|
||||
isAlertActive.emit(false)
|
||||
}
|
||||
}
|
||||
|
||||
init {
|
||||
Log.d("MainActivity", "Starting up")
|
||||
doPreStartupTasks()
|
||||
|
|
@ -273,6 +302,9 @@ class MainActivity : FragmentActivity() {
|
|||
windowSizeClass,
|
||||
viewModel.nextDestination.collectAsState().value,
|
||||
viewModel.isConnected.collectAsState().value,
|
||||
viewModel.activeAlert.collectAsState().value,
|
||||
viewModel.isAlertActive.collectAsState().value,
|
||||
viewModel::onDismissHealthAlert,
|
||||
viewModel::checkLoggedInState,
|
||||
viewModel::updateNextDestination
|
||||
)
|
||||
|
|
@ -299,6 +331,9 @@ fun AppEntrypoint(
|
|||
windowSizeClass: WindowSizeClass,
|
||||
nextDestination: String?,
|
||||
isConnected: Boolean,
|
||||
healthNotice: HealthNotice?,
|
||||
isHealthAlertActive: Boolean,
|
||||
onDismissHealthAlert: () -> Unit = {},
|
||||
onRetryConnection: () -> Unit,
|
||||
onUpdateNextDestination: (String) -> Unit = {}
|
||||
) {
|
||||
|
|
@ -313,6 +348,12 @@ fun AppEntrypoint(
|
|||
.fillMaxSize(),
|
||||
color = MaterialTheme.colorScheme.background
|
||||
) {
|
||||
if (isHealthAlertActive) {
|
||||
healthNotice?.let {
|
||||
HealthAlert(notice = healthNotice, onDismiss = onDismissHealthAlert)
|
||||
}
|
||||
}
|
||||
|
||||
NavHost(
|
||||
navController = navController,
|
||||
startDestination = "default",
|
||||
|
|
|
|||
|
|
@ -0,0 +1,12 @@
|
|||
package chat.revolt.api.routes.microservices.health
|
||||
|
||||
import chat.revolt.api.RevoltHttp
|
||||
import chat.revolt.api.RevoltJson
|
||||
import chat.revolt.api.schemas.HealthNotice
|
||||
import io.ktor.client.request.get
|
||||
import io.ktor.client.statement.bodyAsText
|
||||
|
||||
suspend fun healthCheck(): HealthNotice {
|
||||
val response = RevoltHttp.get("https://health.revolt.chat/api/health").bodyAsText()
|
||||
return RevoltJson.decodeFromString(HealthNotice.serializer(), response)
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
package chat.revolt.api.schemas
|
||||
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class HealthNotice(
|
||||
val version: String? = null,
|
||||
val alert: Alert? = null
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class Alert(
|
||||
val text: String? = null,
|
||||
@SerialName("dismissable")
|
||||
val dismissible: Boolean? = null,
|
||||
val actions: List<Action>? = null
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class Action(
|
||||
val text: String? = null,
|
||||
val type: String? = null,
|
||||
val href: String? = null
|
||||
)
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
package chat.revolt.components.generic
|
||||
|
||||
import androidx.browser.customtabs.CustomTabColorSchemeParams
|
||||
import androidx.browser.customtabs.CustomTabsIntent
|
||||
import androidx.compose.material3.AlertDialog
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextButton
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.graphics.toArgb
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.core.net.toUri
|
||||
import chat.revolt.R
|
||||
import chat.revolt.api.schemas.HealthNotice
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun HealthAlert(notice: HealthNotice, onDismiss: () -> Unit) {
|
||||
val context = LocalContext.current
|
||||
val backgroundColour = MaterialTheme.colorScheme.background
|
||||
|
||||
AlertDialog(
|
||||
onDismissRequest = {
|
||||
// Purposefully empty
|
||||
},
|
||||
title = {
|
||||
Text(stringResource(R.string.service_health_alert))
|
||||
},
|
||||
text = {
|
||||
Text(notice.alert?.text ?: stringResource(R.string.service_health_alert_body_default))
|
||||
},
|
||||
confirmButton = {
|
||||
notice.alert?.actions?.firstOrNull()?.let { action ->
|
||||
when (action.type) {
|
||||
"external" -> TextButton(
|
||||
onClick = {
|
||||
val customTab = CustomTabsIntent.Builder()
|
||||
.setShowTitle(true)
|
||||
.setDefaultColorSchemeParams(
|
||||
CustomTabColorSchemeParams.Builder()
|
||||
.setToolbarColor(backgroundColour.toArgb())
|
||||
.build()
|
||||
)
|
||||
.build()
|
||||
customTab.launchUrl(context, action.href?.toUri() ?: return@TextButton)
|
||||
}
|
||||
) {
|
||||
Text(
|
||||
action.text
|
||||
?: stringResource(R.string.service_health_alert_actions_default)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
TextButton(onClick = onDismiss) {
|
||||
Text(stringResource(R.string.service_health_alert_actions_dismiss))
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
|
@ -25,6 +25,11 @@
|
|||
<string name="resend">Resend</string>
|
||||
<string name="send_email">Send email</string>
|
||||
|
||||
<string name="service_health_alert">Currently ongoing</string>
|
||||
<string name="service_health_alert_body_default">We are currently experiencing issues with our services. Please check our status page for more information.</string>
|
||||
<string name="service_health_alert_actions_default">Learn more</string>
|
||||
<string name="service_health_alert_actions_dismiss">Dismiss</string>
|
||||
|
||||
<string name="login_heading">Let\'s log you in</string>
|
||||
<string name="password_forgot">Forgot password?</string>
|
||||
<string name="resend_verification">Resend a verification email</string>
|
||||
|
|
|
|||
Loading…
Reference in New Issue