Prevent crash and better discovery page
This commit is contained in:
parent
c65322fbf7
commit
d783455ed8
|
|
@ -72,8 +72,8 @@ android {
|
|||
applicationId = "com.zekochat"
|
||||
minSdk = 24
|
||||
targetSdk = 36
|
||||
versionCode = Integer.parseInt("001_003_107".replace("_", ""), 10)
|
||||
versionName = "1.3.6b"
|
||||
versionCode = Integer.parseInt("001_003_109".replace("_", ""), 10)
|
||||
versionName = "1.3.6d"
|
||||
|
||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||
vectorDrawables {
|
||||
|
|
|
|||
|
|
@ -1,12 +1,18 @@
|
|||
package chat.zekochat
|
||||
|
||||
import android.app.Application
|
||||
import android.os.Looper
|
||||
import android.util.Log
|
||||
import chat.zekochat.api.PeptideHttp
|
||||
import chat.zekochat.api.realtime.DisconnectionState
|
||||
import chat.zekochat.api.realtime.RealtimeSocket
|
||||
import chat.zekochat.persistence.KVStorage
|
||||
import com.google.android.material.color.DynamicColors
|
||||
import dagger.hilt.android.HiltAndroidApp
|
||||
import logcat.AndroidLogcatLogger
|
||||
import logcat.LogPriority
|
||||
import java.io.IOException
|
||||
import java.net.SocketException
|
||||
|
||||
@HiltAndroidApp
|
||||
class PeptideApplication : Application() {
|
||||
|
|
@ -17,9 +23,57 @@ class PeptideApplication : Application() {
|
|||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
AndroidLogcatLogger.installOnDebuggableApp(this, minPriority = LogPriority.VERBOSE)
|
||||
installNetworkUncaughtExceptionHandler()
|
||||
PeptideHttp // Trigger initialization
|
||||
}
|
||||
|
||||
/**
|
||||
* Prevents app crashes when OkHttp's WebSocket reader thread throws uncaught
|
||||
* network exceptions (e.g. SocketException: Software caused connection abort)
|
||||
* that are not propagated to our coroutine try/catch in connectWS().
|
||||
*/
|
||||
private fun installNetworkUncaughtExceptionHandler() {
|
||||
val previousHandler = Thread.getDefaultUncaughtExceptionHandler()
|
||||
Thread.setDefaultUncaughtExceptionHandler { thread, throwable ->
|
||||
if (isNetworkRelatedFromBackgroundThread(thread, throwable)) {
|
||||
Log.w(
|
||||
"PeptideApplication",
|
||||
"Suppressing uncaught network exception from background thread (e.g. WebSocket connection abort): ${throwable.message}",
|
||||
throwable
|
||||
)
|
||||
try {
|
||||
if (isWebSocketRelated(throwable)) {
|
||||
RealtimeSocket.updateDisconnectionState(DisconnectionState.Disconnected)
|
||||
}
|
||||
} catch (_: Throwable) {
|
||||
// Avoid double-fault when updating state
|
||||
}
|
||||
return@setDefaultUncaughtExceptionHandler
|
||||
}
|
||||
previousHandler?.uncaughtException(thread, throwable)
|
||||
}
|
||||
}
|
||||
|
||||
private fun isNetworkRelatedFromBackgroundThread(thread: Thread, throwable: Throwable): Boolean {
|
||||
if (thread == Looper.getMainLooper().thread) return false
|
||||
var t: Throwable? = throwable
|
||||
while (t != null) {
|
||||
when (t) {
|
||||
is SocketException -> return true
|
||||
is IOException -> return true
|
||||
else -> t = t.cause
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
private fun isWebSocketRelated(throwable: Throwable): Boolean {
|
||||
val stack = throwable.stackTraceToString()
|
||||
return stack.contains("okhttp3.internal.ws") ||
|
||||
stack.contains("WebSocketReader") ||
|
||||
stack.contains("RealWebSocket")
|
||||
}
|
||||
|
||||
init {
|
||||
instance = this
|
||||
DynamicColors.applyToActivitiesIfAvailable(this)
|
||||
|
|
|
|||
|
|
@ -50,6 +50,7 @@ import kotlinx.serialization.SerialName
|
|||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.cbor.Cbor
|
||||
import kotlinx.serialization.json.Json
|
||||
import java.io.IOException
|
||||
import java.net.SocketException
|
||||
import chat.zekochat.api.schemas.Channel as ChannelSchema
|
||||
|
||||
|
|
@ -314,6 +315,9 @@ object PeptideAPI {
|
|||
} catch (e: SocketException) {
|
||||
Log.d("PeptideAPI", "Socket closed, probably no big deal /// " + e.message)
|
||||
RealtimeSocket.updateDisconnectionState(DisconnectionState.Disconnected)
|
||||
} catch (e: IOException) {
|
||||
Log.d("PeptideAPI", "WebSocket connection abort/reset (network): " + e.message)
|
||||
RealtimeSocket.updateDisconnectionState(DisconnectionState.Disconnected)
|
||||
} catch (e: Exception) {
|
||||
Log.e("PeptideAPI", "WebSocket error", e)
|
||||
RealtimeSocket.updateDisconnectionState(DisconnectionState.Disconnected)
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ import androidx.compose.ui.Alignment
|
|||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.layout.ContentScale
|
||||
import androidx.compose.ui.graphics.ColorFilter
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
|
|
@ -71,31 +72,30 @@ fun DiscoverServersList(
|
|||
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.padding(top = 24.dp, start = 16.dp, end = 16.dp),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
.padding(top = 12.dp, start = 16.dp, end = 16.dp),
|
||||
) {
|
||||
Image(
|
||||
modifier = Modifier
|
||||
.padding(8.dp),
|
||||
painter = painterResource(R.drawable.discover_character_image),
|
||||
contentDescription = null,
|
||||
)
|
||||
|
||||
Text(
|
||||
text = stringResource(R.string.discover_servers),
|
||||
style = MaterialTheme.typography.headlineMedium
|
||||
)
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(12.dp),
|
||||
) {
|
||||
Image(
|
||||
modifier = Modifier
|
||||
.size(72.dp)
|
||||
.padding(4.dp),
|
||||
painter = painterResource(R.drawable.discover_character_image),
|
||||
contentDescription = null,
|
||||
contentScale = ContentScale.Fit,
|
||||
)
|
||||
Text(
|
||||
text = stringResource(R.string.discover_servers_description),
|
||||
style = MaterialTheme.typography.bodySmall,
|
||||
modifier = Modifier.weight(1f),
|
||||
)
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
|
||||
Text(
|
||||
text = stringResource(R.string.discover_servers_description),
|
||||
textAlign = TextAlign.Center,
|
||||
style = MaterialTheme.typography.bodyMedium
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
|
||||
when {
|
||||
uiState.isLoading -> {
|
||||
Box(
|
||||
|
|
|
|||
Loading…
Reference in New Issue