mirror of
https://github.com/JustinZeus/Wholphin.git
synced 2026-07-08 23:51:21 +02:00
Fix crash when changing seasons & improve error page (#94)
Related to #64 If an error occurred while querying for a season's episodes, the app would crash instead of display the error message. This PR fixes the app crash, but not the underlying query issue. It also changes the error page to show a button for sending logs to the server immediately.
This commit is contained in:
parent
50b0b0a508
commit
3ab9eafc7c
4 changed files with 88 additions and 42 deletions
|
|
@ -1,14 +1,39 @@
|
||||||
package com.github.damontecres.wholphin.ui.components
|
package com.github.damontecres.wholphin.ui.components
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.PaddingValues
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.lazy.LazyColumn
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
|
||||||
|
import androidx.lifecycle.ViewModel
|
||||||
|
import androidx.tv.material3.Button
|
||||||
import androidx.tv.material3.MaterialTheme
|
import androidx.tv.material3.MaterialTheme
|
||||||
import androidx.tv.material3.Text
|
import androidx.tv.material3.Text
|
||||||
|
import com.github.damontecres.wholphin.ui.detail.DebugViewModel.Companion.sendAppLogs
|
||||||
import com.github.damontecres.wholphin.util.LoadingState
|
import com.github.damontecres.wholphin.util.LoadingState
|
||||||
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
|
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||||
|
import org.jellyfin.sdk.api.client.ApiClient
|
||||||
|
import org.jellyfin.sdk.model.ClientInfo
|
||||||
|
import org.jellyfin.sdk.model.DeviceInfo
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
@HiltViewModel
|
||||||
|
class ErrorViewModel
|
||||||
|
@Inject
|
||||||
|
constructor(
|
||||||
|
@param:ApplicationContext private val context: Context,
|
||||||
|
private val api: ApiClient,
|
||||||
|
private val clientInfo: ClientInfo,
|
||||||
|
private val deviceInfo: DeviceInfo,
|
||||||
|
) : ViewModel() {
|
||||||
|
fun sendLogs() {
|
||||||
|
sendAppLogs(context, api, clientInfo, deviceInfo)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Displays an error message and/or exception
|
* Displays an error message and/or exception
|
||||||
|
|
@ -18,41 +43,49 @@ fun ErrorMessage(
|
||||||
message: String?,
|
message: String?,
|
||||||
exception: Throwable?,
|
exception: Throwable?,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
|
viewModel: ErrorViewModel = hiltViewModel(),
|
||||||
) {
|
) {
|
||||||
LazyColumn(
|
Column(
|
||||||
contentPadding = PaddingValues(16.dp),
|
|
||||||
verticalArrangement = Arrangement.spacedBy(16.dp),
|
verticalArrangement = Arrangement.spacedBy(16.dp),
|
||||||
modifier = modifier,
|
modifier = modifier.padding(16.dp),
|
||||||
) {
|
) {
|
||||||
|
Text(
|
||||||
|
text = "An error occurred! Press the button to send logs to your server.",
|
||||||
|
color = MaterialTheme.colorScheme.error,
|
||||||
|
style = MaterialTheme.typography.titleMedium,
|
||||||
|
)
|
||||||
|
Button(
|
||||||
|
onClick = {
|
||||||
|
viewModel.sendLogs()
|
||||||
|
},
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = "Send Logs",
|
||||||
|
)
|
||||||
|
}
|
||||||
message?.let {
|
message?.let {
|
||||||
item {
|
|
||||||
Text(
|
Text(
|
||||||
text = it,
|
text = it,
|
||||||
color = MaterialTheme.colorScheme.error,
|
color = MaterialTheme.colorScheme.error,
|
||||||
style = MaterialTheme.typography.titleLarge,
|
style = MaterialTheme.typography.titleLarge,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
exception?.localizedMessage?.let {
|
exception?.localizedMessage?.let {
|
||||||
item {
|
|
||||||
Text(
|
Text(
|
||||||
text = it,
|
text = it,
|
||||||
color = MaterialTheme.colorScheme.error,
|
color = MaterialTheme.colorScheme.error,
|
||||||
style = MaterialTheme.typography.titleMedium,
|
style = MaterialTheme.typography.titleMedium,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
var cause = exception?.cause
|
var cause = exception?.cause
|
||||||
while (cause != null) {
|
while (cause != null) {
|
||||||
cause.localizedMessage?.let {
|
cause.localizedMessage?.let {
|
||||||
item {
|
|
||||||
Text(
|
Text(
|
||||||
text = "Caused by: $it",
|
text = "Caused by: $it",
|
||||||
color = MaterialTheme.colorScheme.error,
|
color = MaterialTheme.colorScheme.error,
|
||||||
style = MaterialTheme.typography.titleSmall,
|
style = MaterialTheme.typography.titleSmall,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
cause = cause.cause
|
cause = cause.cause
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
package com.github.damontecres.wholphin.ui.detail
|
package com.github.damontecres.wholphin.ui.detail
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.focusable
|
import androidx.compose.foundation.focusable
|
||||||
|
|
@ -34,11 +35,16 @@ import com.github.damontecres.wholphin.data.ServerRepository
|
||||||
import com.github.damontecres.wholphin.data.model.ItemPlayback
|
import com.github.damontecres.wholphin.data.model.ItemPlayback
|
||||||
import com.github.damontecres.wholphin.preferences.UserPreferences
|
import com.github.damontecres.wholphin.preferences.UserPreferences
|
||||||
import com.github.damontecres.wholphin.ui.launchIO
|
import com.github.damontecres.wholphin.ui.launchIO
|
||||||
|
import com.github.damontecres.wholphin.ui.showToast
|
||||||
import com.github.damontecres.wholphin.util.ExceptionHandler
|
import com.github.damontecres.wholphin.util.ExceptionHandler
|
||||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
|
import org.jellyfin.sdk.api.client.ApiClient
|
||||||
|
import org.jellyfin.sdk.api.client.extensions.clientLogApi
|
||||||
|
import org.jellyfin.sdk.model.ClientInfo
|
||||||
|
import org.jellyfin.sdk.model.DeviceInfo
|
||||||
import java.io.BufferedReader
|
import java.io.BufferedReader
|
||||||
import java.io.InputStreamReader
|
import java.io.InputStreamReader
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
@ -110,6 +116,26 @@ class DebugViewModel
|
||||||
}
|
}
|
||||||
return logLines
|
return logLines
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun ViewModel.sendAppLogs(
|
||||||
|
context: Context,
|
||||||
|
api: ApiClient,
|
||||||
|
clientInfo: ClientInfo?,
|
||||||
|
deviceInfo: DeviceInfo?,
|
||||||
|
) {
|
||||||
|
viewModelScope.launchIO(ExceptionHandler(true)) {
|
||||||
|
val logcat = getLogCatLines().joinToString("\n") { it.text }
|
||||||
|
val body =
|
||||||
|
"""
|
||||||
|
Send App Logs
|
||||||
|
clientInfo=$clientInfo
|
||||||
|
deviceInfo=$deviceInfo
|
||||||
|
|
||||||
|
""".trimIndent() + logcat
|
||||||
|
val response by api.clientLogApi.logFile(body)
|
||||||
|
showToast(context, "Sent! Filename=${response.fileName}")
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -215,7 +215,7 @@ class SeriesViewModel
|
||||||
)
|
)
|
||||||
val pager = ApiRequestPager(api, request, GetEpisodesRequestHandler, viewModelScope)
|
val pager = ApiRequestPager(api, request, GetEpisodesRequestHandler, viewModelScope)
|
||||||
pager.init()
|
pager.init()
|
||||||
Timber.Forest.v("Loaded ${pager.size} episodes for season $season")
|
Timber.v("Loaded ${pager.size} episodes for season $season")
|
||||||
return EpisodeList.Success(convertPager(pager))
|
return EpisodeList.Success(convertPager(pager))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,18 +12,16 @@ import com.github.damontecres.wholphin.data.isPinned
|
||||||
import com.github.damontecres.wholphin.data.model.NavDrawerPinnedItem
|
import com.github.damontecres.wholphin.data.model.NavDrawerPinnedItem
|
||||||
import com.github.damontecres.wholphin.data.model.NavPinType
|
import com.github.damontecres.wholphin.data.model.NavPinType
|
||||||
import com.github.damontecres.wholphin.preferences.AppPreferences
|
import com.github.damontecres.wholphin.preferences.AppPreferences
|
||||||
import com.github.damontecres.wholphin.ui.detail.DebugViewModel
|
import com.github.damontecres.wholphin.ui.detail.DebugViewModel.Companion.sendAppLogs
|
||||||
import com.github.damontecres.wholphin.ui.launchIO
|
import com.github.damontecres.wholphin.ui.launchIO
|
||||||
import com.github.damontecres.wholphin.ui.nav.NavDrawerItem
|
import com.github.damontecres.wholphin.ui.nav.NavDrawerItem
|
||||||
import com.github.damontecres.wholphin.ui.nav.NavigationManager
|
import com.github.damontecres.wholphin.ui.nav.NavigationManager
|
||||||
import com.github.damontecres.wholphin.ui.setValueOnMain
|
import com.github.damontecres.wholphin.ui.setValueOnMain
|
||||||
import com.github.damontecres.wholphin.ui.showToast
|
|
||||||
import com.github.damontecres.wholphin.util.ExceptionHandler
|
import com.github.damontecres.wholphin.util.ExceptionHandler
|
||||||
import com.github.damontecres.wholphin.util.RememberTabManager
|
import com.github.damontecres.wholphin.util.RememberTabManager
|
||||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||||
import org.jellyfin.sdk.api.client.ApiClient
|
import org.jellyfin.sdk.api.client.ApiClient
|
||||||
import org.jellyfin.sdk.api.client.extensions.clientLogApi
|
|
||||||
import org.jellyfin.sdk.model.ClientInfo
|
import org.jellyfin.sdk.model.ClientInfo
|
||||||
import org.jellyfin.sdk.model.DeviceInfo
|
import org.jellyfin.sdk.model.DeviceInfo
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
@ -91,17 +89,6 @@ class PreferencesViewModel
|
||||||
}
|
}
|
||||||
|
|
||||||
fun sendAppLogs() {
|
fun sendAppLogs() {
|
||||||
viewModelScope.launchIO(ExceptionHandler(true)) {
|
sendAppLogs(context, api, clientInfo, deviceInfo)
|
||||||
val logcat = DebugViewModel.getLogCatLines().joinToString("\n") { it.text }
|
|
||||||
val body =
|
|
||||||
"""
|
|
||||||
Send App Logs
|
|
||||||
$clientInfo
|
|
||||||
$deviceInfo
|
|
||||||
|
|
||||||
""".trimIndent() + logcat
|
|
||||||
val response by api.clientLogApi.logFile(body)
|
|
||||||
showToast(context, "Sent! Filename=${response.fileName}")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue