Jelajahi Sumber

Added coroutine exception handler

Vadik Sirekanyan 2 tahun lalu
induk
melakukan
7afcb0f6aa

+ 28 - 2
app/src/main/java/org/sirekanyan/outline/MainState.kt

@@ -1,5 +1,7 @@
 package org.sirekanyan.outline
 
+import android.util.Log
+import android.widget.Toast
 import androidx.compose.material3.DrawerState
 import androidx.compose.material3.DrawerValue
 import androidx.compose.runtime.Composable
@@ -9,19 +11,43 @@ import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.remember
 import androidx.compose.runtime.rememberCoroutineScope
 import androidx.compose.runtime.setValue
+import androidx.compose.ui.platform.LocalContext
+import kotlinx.coroutines.CoroutineExceptionHandler
 import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.SupervisorJob
 import kotlinx.coroutines.launch
+import kotlinx.coroutines.plus
 import org.sirekanyan.outline.api.OutlineApi
 import org.sirekanyan.outline.api.model.Key
 import org.sirekanyan.outline.feature.keys.KeysErrorState
 import org.sirekanyan.outline.feature.keys.KeysLoadingState
 import org.sirekanyan.outline.feature.keys.KeysState
 import org.sirekanyan.outline.feature.keys.KeysSuccessState
+import java.net.ConnectException
+import java.net.UnknownHostException
 
 @Composable
 fun rememberMainState(api: OutlineApi): MainState {
-    val scope = rememberCoroutineScope()
-    return remember { MainState(scope, api) }
+    val context = LocalContext.current
+    val scope = rememberCoroutineScope {
+        CoroutineExceptionHandler { _, throwable ->
+            if (throwable is UnknownHostException) {
+                Log.e("OUTLINE", "Uncaught exception: ${throwable.message}")
+            } else {
+                Log.e("OUTLINE", "Uncaught exception", throwable)
+            }
+            when (throwable) {
+                is UnknownHostException, is ConnectException -> {
+                    Toast.makeText(context, "Check network connection", Toast.LENGTH_SHORT).show()
+                }
+                else -> {
+                    Toast.makeText(context, "Something went wrong", Toast.LENGTH_SHORT).show()
+                }
+            }
+        }
+    }
+    val supervisor = remember { SupervisorJob() }
+    return remember { MainState(scope + supervisor, api) }
 }
 
 class MainState(val scope: CoroutineScope, private val api: OutlineApi) {

+ 6 - 1
app/src/main/java/org/sirekanyan/outline/ui/DrawerContent.kt

@@ -1,6 +1,7 @@
 package org.sirekanyan.outline.ui
 
 import android.net.Uri
+import android.util.Log
 import androidx.compose.foundation.layout.padding
 import androidx.compose.material.icons.Icons
 import androidx.compose.material.icons.filled.Add
@@ -37,7 +38,11 @@ fun DrawerContent(api: OutlineApi, dao: ApiUrlDao, state: MainState) {
         apiUrls.forEach { apiUrl ->
             val selected = state.selected == apiUrl
             val serverName by produceState(Uri.parse(apiUrl).host.orEmpty()) {
-                value = api.getServerName(apiUrl)
+                try {
+                    value = api.getServerName(apiUrl)
+                } catch (exception: Exception) {
+                    Log.d("OUTLINE", "Cannot fetch server name", exception)
+                }
             }
             NavigationDrawerItem(
                 icon = { Icon(Icons.Default.Done, null) },

+ 6 - 2
app/src/main/java/org/sirekanyan/outline/ui/EditKeyContent.kt

@@ -37,15 +37,19 @@ fun EditKeyContent(api: OutlineApi, state: MainState, dialog: EditKeyDialog) {
             onCloseClick = { state.dialog = null },
             action = "Save" to {
                 state.scope.launch {
-                    try {
+                    val isSuccess = try {
                         val newName = draft.text.ifBlank { accessKey.defaultName }
                         api.renameAccessKey(dialog.selected, accessKey.id, newName)
                         state.dialog = null
+                        true
                     } catch (exception: Exception) {
                         exception.printStackTrace()
                         error = "Check name or try again"
+                        false
+                    }
+                    if (isSuccess) {
+                        state.refreshCurrentKeys(showLoading = false)
                     }
-                    state.refreshCurrentKeys(showLoading = false)
                 }
             },
         )