Provide better error messages with stacktrace (#119)
* Provide better error messages with stacktrace + clean up + fix error details popup in MediaInfoFragment * Simplify exception passing by sending complete exception to the dialog * Use viewLifecycleOwner with repeatOnLifecycle
This commit is contained in:
parent
741083da40
commit
751ee75c3e
31 changed files with 74 additions and 99 deletions
|
@ -8,18 +8,21 @@ import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
|||
import dev.jdtech.jellyfin.R
|
||||
import java.lang.IllegalStateException
|
||||
|
||||
class ErrorDialogFragment(private val errorMessage: String) : DialogFragment() {
|
||||
class ErrorDialogFragment(
|
||||
private val error: Exception
|
||||
) : DialogFragment() {
|
||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||
return activity?.let {
|
||||
val builder = MaterialAlertDialogBuilder(it, R.style.ErrorDialogStyle)
|
||||
builder
|
||||
.setMessage(errorMessage)
|
||||
.setTitle(error.message ?: getString(R.string.unknown_error))
|
||||
.setMessage(error.stackTraceToString())
|
||||
.setPositiveButton(getString(R.string.close)) { _, _ ->
|
||||
}
|
||||
.setNeutralButton(getString(R.string.share)) { _, _ ->
|
||||
val sendIntent: Intent = Intent().apply {
|
||||
action = Intent.ACTION_SEND
|
||||
putExtra(Intent.EXTRA_TEXT, errorMessage)
|
||||
putExtra(Intent.EXTRA_TEXT, "${error.message}\n ${error.stackTraceToString()}")
|
||||
type = "text/plain"
|
||||
}
|
||||
|
||||
|
|
|
@ -12,7 +12,6 @@ import androidx.lifecycle.lifecycleScope
|
|||
import androidx.lifecycle.repeatOnLifecycle
|
||||
import androidx.navigation.fragment.findNavController
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import dev.jdtech.jellyfin.R
|
||||
import dev.jdtech.jellyfin.adapters.*
|
||||
import dev.jdtech.jellyfin.databinding.FragmentDownloadBinding
|
||||
import dev.jdtech.jellyfin.dialogs.ErrorDialogFragment
|
||||
|
@ -86,12 +85,11 @@ class DownloadFragment : Fragment() {
|
|||
}
|
||||
|
||||
private fun bindUiStateError(uiState: DownloadViewModel.UiState.Error) {
|
||||
val error = uiState.message ?: resources.getString(R.string.unknown_error)
|
||||
errorDialog = ErrorDialogFragment(error)
|
||||
errorDialog = ErrorDialogFragment(uiState.error)
|
||||
binding.loadingIndicator.isVisible = false
|
||||
binding.downloadsRecyclerView.isVisible = false
|
||||
binding.errorLayout.errorPanel.isVisible = true
|
||||
checkIfLoginRequired(error)
|
||||
checkIfLoginRequired(uiState.error.message)
|
||||
}
|
||||
|
||||
private fun navigateToMediaInfoFragment(item: PlayerItem) {
|
||||
|
|
|
@ -207,7 +207,7 @@ class EpisodeBottomSheetFragment : BottomSheetDialogFragment() {
|
|||
|
||||
private fun bindUiStateError(uiState: EpisodeBottomSheetViewModel.UiState.Error) {
|
||||
binding.loadingIndicator.isVisible = false
|
||||
binding.overview.text = uiState.message
|
||||
binding.overview.text = uiState.error.message
|
||||
}
|
||||
|
||||
private fun bindPlayerItems(items: PlayerViewModel.PlayerItems) {
|
||||
|
@ -222,7 +222,7 @@ class EpisodeBottomSheetFragment : BottomSheetDialogFragment() {
|
|||
}
|
||||
|
||||
private fun bindPlayerItemsError(error: PlayerViewModel.PlayerItemError) {
|
||||
Timber.e(error.message)
|
||||
Timber.e(error.error.message)
|
||||
|
||||
binding.playerItemsError.isVisible = true
|
||||
binding.playButton.setImageDrawable(
|
||||
|
@ -233,7 +233,7 @@ class EpisodeBottomSheetFragment : BottomSheetDialogFragment() {
|
|||
)
|
||||
binding.progressCircular.visibility = View.INVISIBLE
|
||||
binding.playerItemsErrorDetails.setOnClickListener {
|
||||
ErrorDialogFragment(error.message).show(parentFragmentManager, "errordialog")
|
||||
ErrorDialogFragment(error.error).show(parentFragmentManager, "errordialog")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -12,7 +12,6 @@ import androidx.lifecycle.lifecycleScope
|
|||
import androidx.lifecycle.repeatOnLifecycle
|
||||
import androidx.navigation.fragment.findNavController
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import dev.jdtech.jellyfin.R
|
||||
import dev.jdtech.jellyfin.adapters.FavoritesListAdapter
|
||||
import dev.jdtech.jellyfin.adapters.HomeEpisodeListAdapter
|
||||
import dev.jdtech.jellyfin.adapters.ViewItemListAdapter
|
||||
|
@ -87,12 +86,11 @@ class FavoriteFragment : Fragment() {
|
|||
}
|
||||
|
||||
private fun bindUiStateError(uiState: FavoriteViewModel.UiState.Error) {
|
||||
val error = uiState.message ?: resources.getString(R.string.unknown_error)
|
||||
errorDialog = ErrorDialogFragment(error)
|
||||
errorDialog = ErrorDialogFragment(uiState.error)
|
||||
binding.loadingIndicator.isVisible = false
|
||||
binding.favoritesRecyclerView.isVisible = false
|
||||
binding.errorLayout.errorPanel.isVisible = true
|
||||
checkIfLoginRequired(error)
|
||||
checkIfLoginRequired(uiState.error.message)
|
||||
}
|
||||
|
||||
private fun navigateToMediaInfoFragment(item: BaseItemDto) {
|
||||
|
|
|
@ -139,13 +139,12 @@ class HomeFragment : Fragment() {
|
|||
}
|
||||
|
||||
private fun bindUiStateError(uiState: HomeViewModel.UiState.Error) {
|
||||
val error = uiState.message ?: getString(R.string.unknown_error)
|
||||
errorDialog = ErrorDialogFragment(error)
|
||||
errorDialog = ErrorDialogFragment(uiState.error)
|
||||
binding.loadingIndicator.isVisible = false
|
||||
binding.refreshLayout.isRefreshing = false
|
||||
binding.viewsRecyclerView.isVisible = false
|
||||
binding.errorLayout.errorPanel.isVisible = true
|
||||
checkIfLoginRequired(error)
|
||||
checkIfLoginRequired(uiState.error.message)
|
||||
}
|
||||
|
||||
private fun navigateToLibraryFragment(view: dev.jdtech.jellyfin.models.View) {
|
||||
|
|
|
@ -132,12 +132,11 @@ class LibraryFragment : Fragment() {
|
|||
}
|
||||
|
||||
private fun bindUiStateError(uiState: LibraryViewModel.UiState.Error) {
|
||||
val error = uiState.message ?: getString(R.string.unknown_error)
|
||||
errorDialog = ErrorDialogFragment(error)
|
||||
errorDialog = ErrorDialogFragment(uiState.error)
|
||||
binding.loadingIndicator.isVisible = false
|
||||
binding.itemsRecyclerView.isVisible = false
|
||||
binding.errorLayout.errorPanel.isVisible = true
|
||||
checkIfLoginRequired(error)
|
||||
checkIfLoginRequired(uiState.error.message)
|
||||
}
|
||||
|
||||
private fun navigateToMediaInfoFragment(item: BaseItemDto) {
|
||||
|
|
|
@ -45,7 +45,7 @@ class LoginFragment : Fragment() {
|
|||
}
|
||||
|
||||
viewLifecycleOwner.lifecycleScope.launch {
|
||||
repeatOnLifecycle(Lifecycle.State.STARTED) {
|
||||
viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
|
||||
viewModel.onUiState(viewLifecycleOwner.lifecycleScope) { uiState ->
|
||||
Timber.d("$uiState")
|
||||
when(uiState) {
|
||||
|
|
|
@ -120,12 +120,11 @@ class MediaFragment : Fragment() {
|
|||
}
|
||||
|
||||
private fun bindUiStateError(uiState: MediaViewModel.UiState.Error) {
|
||||
val error = uiState.message ?: resources.getString(R.string.unknown_error)
|
||||
errorDialog = ErrorDialogFragment(error)
|
||||
errorDialog = ErrorDialogFragment(uiState.error)
|
||||
binding.loadingIndicator.isVisible = false
|
||||
binding.viewsRecyclerView.isVisible = false
|
||||
binding.errorLayout.errorPanel.isVisible = true
|
||||
checkIfLoginRequired(error)
|
||||
checkIfLoginRequired(uiState.error.message)
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -145,6 +145,10 @@ class MediaInfoFragment : Fragment() {
|
|||
viewModel.loadData(args.itemId, args.itemType)
|
||||
}
|
||||
|
||||
binding.errorLayout.errorDetailsButton.setOnClickListener {
|
||||
errorDialog.show(parentFragmentManager, "errordialog")
|
||||
}
|
||||
|
||||
binding.checkButton.setOnClickListener {
|
||||
when (viewModel.played) {
|
||||
true -> {
|
||||
|
@ -286,11 +290,11 @@ class MediaInfoFragment : Fragment() {
|
|||
}
|
||||
|
||||
private fun bindUiStateError(uiState: MediaInfoViewModel.UiState.Error) {
|
||||
val error = uiState.message ?: getString(R.string.unknown_error)
|
||||
errorDialog = ErrorDialogFragment(uiState.error)
|
||||
binding.loadingIndicator.isVisible = false
|
||||
binding.mediaInfoScrollview.isVisible = false
|
||||
binding.errorLayout.errorPanel.isVisible = true
|
||||
checkIfLoginRequired(error)
|
||||
checkIfLoginRequired(uiState.error.message)
|
||||
}
|
||||
|
||||
private fun bindPlayerItems(items: PlayerViewModel.PlayerItems) {
|
||||
|
@ -305,7 +309,7 @@ class MediaInfoFragment : Fragment() {
|
|||
}
|
||||
|
||||
private fun bindPlayerItemsError(error: PlayerViewModel.PlayerItemError) {
|
||||
Timber.e(error.message)
|
||||
Timber.e(error.error.message)
|
||||
binding.playerItemsError.visibility = View.VISIBLE
|
||||
binding.playButton.setImageDrawable(
|
||||
ContextCompat.getDrawable(
|
||||
|
@ -315,7 +319,7 @@ class MediaInfoFragment : Fragment() {
|
|||
)
|
||||
binding.progressCircular.visibility = View.INVISIBLE
|
||||
binding.playerItemsErrorDetails.setOnClickListener {
|
||||
ErrorDialogFragment(error.message).show(parentFragmentManager, "errordialog")
|
||||
ErrorDialogFragment(error.error).show(parentFragmentManager, "errordialog")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -104,12 +104,11 @@ internal class PersonDetailFragment : Fragment() {
|
|||
}
|
||||
|
||||
private fun bindUiStateError(uiState: PersonDetailViewModel.UiState.Error) {
|
||||
val error = uiState.message ?: resources.getString(R.string.unknown_error)
|
||||
errorDialog = ErrorDialogFragment(error)
|
||||
errorDialog = ErrorDialogFragment(uiState.error)
|
||||
binding.loadingIndicator.isVisible = false
|
||||
binding.fragmentContent.isVisible = false
|
||||
binding.errorLayout.errorPanel.isVisible = true
|
||||
checkIfLoginRequired(error)
|
||||
checkIfLoginRequired(uiState.error.message)
|
||||
}
|
||||
|
||||
private fun adapter() = ViewItemListAdapter(
|
||||
|
|
|
@ -13,7 +13,6 @@ import androidx.lifecycle.repeatOnLifecycle
|
|||
import androidx.navigation.fragment.findNavController
|
||||
import androidx.navigation.fragment.navArgs
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import dev.jdtech.jellyfin.R
|
||||
import dev.jdtech.jellyfin.adapters.FavoritesListAdapter
|
||||
import dev.jdtech.jellyfin.adapters.HomeEpisodeListAdapter
|
||||
import dev.jdtech.jellyfin.adapters.ViewItemListAdapter
|
||||
|
@ -91,12 +90,11 @@ class SearchResultFragment : Fragment() {
|
|||
}
|
||||
|
||||
private fun bindUiStateError(uiState: SearchResultViewModel.UiState.Error) {
|
||||
val error = uiState.message ?: getString(R.string.unknown_error)
|
||||
errorDialog = ErrorDialogFragment(error)
|
||||
errorDialog = ErrorDialogFragment(uiState.error)
|
||||
binding.loadingIndicator.isVisible = false
|
||||
binding.searchResultsRecyclerView.isVisible = false
|
||||
binding.errorLayout.errorPanel.isVisible = true
|
||||
checkIfLoginRequired(error)
|
||||
checkIfLoginRequired(uiState.error.message)
|
||||
}
|
||||
|
||||
private fun navigateToMediaInfoFragment(item: BaseItemDto) {
|
||||
|
|
|
@ -13,7 +13,6 @@ import androidx.lifecycle.repeatOnLifecycle
|
|||
import androidx.navigation.fragment.findNavController
|
||||
import androidx.navigation.fragment.navArgs
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import dev.jdtech.jellyfin.R
|
||||
import dev.jdtech.jellyfin.adapters.EpisodeListAdapter
|
||||
import dev.jdtech.jellyfin.databinding.FragmentSeasonBinding
|
||||
import dev.jdtech.jellyfin.dialogs.ErrorDialogFragment
|
||||
|
@ -88,12 +87,11 @@ class SeasonFragment : Fragment() {
|
|||
}
|
||||
|
||||
private fun bindUiStateError(uiState: SeasonViewModel.UiState.Error) {
|
||||
val error = uiState.message ?: getString(R.string.unknown_error)
|
||||
errorDialog = ErrorDialogFragment(error)
|
||||
errorDialog = ErrorDialogFragment(uiState.error)
|
||||
binding.loadingIndicator.isVisible = false
|
||||
binding.episodesRecyclerView.isVisible = false
|
||||
binding.errorLayout.errorPanel.isVisible = true
|
||||
checkIfLoginRequired(error)
|
||||
checkIfLoginRequired(uiState.error.message)
|
||||
}
|
||||
|
||||
private fun navigateToEpisodeBottomSheetFragment(episode: BaseItemDto) {
|
||||
|
|
|
@ -49,7 +49,7 @@ class ServerSelectFragment : Fragment() {
|
|||
}
|
||||
|
||||
viewLifecycleOwner.lifecycleScope.launch {
|
||||
repeatOnLifecycle(Lifecycle.State.STARTED) {
|
||||
viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
|
||||
viewModel.onNavigateToMain(viewLifecycleOwner.lifecycleScope) {
|
||||
if (it) {
|
||||
navigateToMainActivity()
|
||||
|
|
|
@ -248,7 +248,7 @@ internal class MediaDetailFragment : Fragment() {
|
|||
}
|
||||
|
||||
private fun bindPlayerItemsError(error: PlayerItemError) {
|
||||
Timber.e(error.message)
|
||||
Timber.e(error.error.message)
|
||||
|
||||
binding.errorLayout.errorPanel.isVisible = true
|
||||
binding.playButton.setImageDrawable(
|
||||
|
|
|
@ -40,7 +40,7 @@ class TvLoginFragment : Fragment() {
|
|||
}
|
||||
|
||||
viewLifecycleOwner.lifecycleScope.launch {
|
||||
repeatOnLifecycle(Lifecycle.State.STARTED) {
|
||||
viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
|
||||
viewModel.onUiState(viewLifecycleOwner.lifecycleScope) { uiState ->
|
||||
Timber.d("$uiState")
|
||||
when(uiState) {
|
||||
|
|
|
@ -32,10 +32,12 @@ fun BaseItemDto.contentType() = when (type) {
|
|||
else -> ContentType.UNKNOWN
|
||||
}
|
||||
|
||||
fun Fragment.checkIfLoginRequired(error: String) {
|
||||
if (error.contains("401")) {
|
||||
Timber.d("Login required!")
|
||||
findNavController().navigate(AppNavigationDirections.actionGlobalLoginFragment())
|
||||
fun Fragment.checkIfLoginRequired(error: String?) {
|
||||
if (error != null) {
|
||||
if (error.contains("401")) {
|
||||
Timber.d("Login required!")
|
||||
findNavController().navigate(AppNavigationDirections.actionGlobalLoginFragment())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -95,8 +95,7 @@ constructor(
|
|||
}
|
||||
okServers.isNotEmpty() -> {
|
||||
val okServer = okServers.first()
|
||||
val issuesString = createIssuesString(okServer)
|
||||
throw Exception(issuesString)
|
||||
throw Exception(createIssuesString(okServer))
|
||||
}
|
||||
else -> {
|
||||
throw Exception(resources.getString(R.string.add_server_error_not_found))
|
||||
|
|
|
@ -8,7 +8,6 @@ import dev.jdtech.jellyfin.models.DownloadSection
|
|||
import dev.jdtech.jellyfin.utils.loadDownloadedEpisodes
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.collect
|
||||
import kotlinx.coroutines.launch
|
||||
import java.util.*
|
||||
import javax.inject.Inject
|
||||
|
@ -24,7 +23,7 @@ constructor(
|
|||
sealed class UiState {
|
||||
data class Normal(val downloadSections: List<DownloadSection>) : UiState()
|
||||
object Loading : UiState()
|
||||
data class Error(val message: String?) : UiState()
|
||||
data class Error(val error: Exception) : UiState()
|
||||
}
|
||||
|
||||
fun onUiState(scope: LifecycleCoroutineScope, collector: (UiState) -> Unit) {
|
||||
|
@ -40,10 +39,6 @@ constructor(
|
|||
uiState.emit(UiState.Loading)
|
||||
try {
|
||||
val items = loadDownloadedEpisodes(downloadDatabase)
|
||||
if (items.isEmpty()) {
|
||||
uiState.emit(UiState.Normal(emptyList()))
|
||||
//return@launch
|
||||
}
|
||||
val downloadSections = mutableListOf<DownloadSection>()
|
||||
withContext(Dispatchers.Default) {
|
||||
DownloadSection(
|
||||
|
@ -65,7 +60,7 @@ constructor(
|
|||
}
|
||||
uiState.emit(UiState.Normal(downloadSections))
|
||||
} catch (e: Exception) {
|
||||
uiState.emit(UiState.Error(e.message))
|
||||
uiState.emit(UiState.Error(e))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -45,7 +45,7 @@ constructor(
|
|||
) : UiState()
|
||||
|
||||
object Loading : UiState()
|
||||
data class Error(val message: String?) : UiState()
|
||||
data class Error(val error: Exception) : UiState()
|
||||
}
|
||||
|
||||
fun onUiState(scope: LifecycleCoroutineScope, collector: (UiState) -> Unit) {
|
||||
|
@ -91,7 +91,7 @@ constructor(
|
|||
)
|
||||
)
|
||||
} catch (e: Exception) {
|
||||
uiState.emit(UiState.Error(e.message))
|
||||
uiState.emit(UiState.Error(e))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -170,7 +170,12 @@ constructor(
|
|||
val metadata = baseItemDtoToDownloadMetadata(episode)
|
||||
downloadRequestItem = DownloadRequestItem(uri, itemId, metadata)
|
||||
downloadEpisode = true
|
||||
requestDownload(downloadDatabase, Uri.parse(downloadRequestItem.uri), downloadRequestItem, application)
|
||||
requestDownload(
|
||||
downloadDatabase,
|
||||
Uri.parse(downloadRequestItem.uri),
|
||||
downloadRequestItem,
|
||||
application
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -8,7 +8,6 @@ import dev.jdtech.jellyfin.models.FavoriteSection
|
|||
import dev.jdtech.jellyfin.repository.JellyfinRepository
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.collect
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.util.*
|
||||
|
@ -25,7 +24,7 @@ constructor(
|
|||
sealed class UiState {
|
||||
data class Normal(val favoriteSections: List<FavoriteSection>) : UiState()
|
||||
object Loading : UiState()
|
||||
data class Error(val message: String?) : UiState()
|
||||
data class Error(val error: Exception) : UiState()
|
||||
}
|
||||
|
||||
fun onUiState(scope: LifecycleCoroutineScope, collector: (UiState) -> Unit) {
|
||||
|
@ -78,7 +77,7 @@ constructor(
|
|||
|
||||
uiState.emit(UiState.Normal(favoriteSections))
|
||||
} catch (e: Exception) {
|
||||
uiState.emit(UiState.Error(e.message))
|
||||
uiState.emit(UiState.Error(e))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,7 +17,6 @@ import dev.jdtech.jellyfin.utils.syncPlaybackProgress
|
|||
import dev.jdtech.jellyfin.utils.toView
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.collect
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.util.*
|
||||
|
@ -34,7 +33,7 @@ class HomeViewModel @Inject internal constructor(
|
|||
sealed class UiState {
|
||||
data class Normal(val homeItems: List<HomeItem>) : UiState()
|
||||
object Loading : UiState()
|
||||
data class Error(val message: String?) : UiState()
|
||||
data class Error(val error: Exception) : UiState()
|
||||
}
|
||||
|
||||
fun onUiState(scope: LifecycleCoroutineScope, collector: (UiState) -> Unit) {
|
||||
|
@ -60,7 +59,7 @@ class HomeViewModel @Inject internal constructor(
|
|||
}
|
||||
uiState.emit(UiState.Normal(updated))
|
||||
} catch (e: Exception) {
|
||||
uiState.emit(UiState.Error(e.message))
|
||||
uiState.emit(UiState.Error(e))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,6 @@ import dagger.hilt.android.lifecycle.HiltViewModel
|
|||
import dev.jdtech.jellyfin.repository.JellyfinRepository
|
||||
import dev.jdtech.jellyfin.utils.SortBy
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.collect
|
||||
import kotlinx.coroutines.launch
|
||||
import org.jellyfin.sdk.model.api.BaseItemDto
|
||||
import org.jellyfin.sdk.model.api.SortOrder
|
||||
|
@ -24,7 +23,7 @@ constructor(
|
|||
sealed class UiState {
|
||||
data class Normal(val items: List<BaseItemDto>) : UiState()
|
||||
object Loading : UiState()
|
||||
data class Error(val message: String?) : UiState()
|
||||
data class Error(val error: Exception) : UiState()
|
||||
}
|
||||
|
||||
fun onUiState(scope: LifecycleCoroutineScope, collector: (UiState) -> Unit) {
|
||||
|
@ -55,7 +54,7 @@ constructor(
|
|||
)
|
||||
uiState.emit(UiState.Normal(items))
|
||||
} catch (e: Exception) {
|
||||
uiState.emit(UiState.Error(e.message))
|
||||
uiState.emit(UiState.Error(e))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,7 +12,6 @@ import dev.jdtech.jellyfin.database.ServerDatabaseDao
|
|||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.collect
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.jellyfin.sdk.model.api.AuthenticateUserByName
|
||||
|
|
|
@ -19,10 +19,6 @@ class MainViewModel
|
|||
constructor(
|
||||
private val database: ServerDatabaseDao,
|
||||
) : ViewModel() {
|
||||
|
||||
private val _doneLoading = MutableLiveData<Boolean>()
|
||||
val doneLoading: LiveData<Boolean> = _doneLoading
|
||||
|
||||
private val _navigateToAddServer = MutableLiveData<Boolean>()
|
||||
val navigateToAddServer: LiveData<Boolean> = _navigateToAddServer
|
||||
|
||||
|
@ -36,9 +32,7 @@ constructor(
|
|||
if (servers.isEmpty()) {
|
||||
_navigateToAddServer.value = true
|
||||
}
|
||||
_doneLoading.value = true
|
||||
}
|
||||
_doneLoading.value = true
|
||||
}
|
||||
|
||||
fun doneNavigateToAddServer() {
|
||||
|
|
|
@ -52,7 +52,7 @@ constructor(
|
|||
) : UiState()
|
||||
|
||||
object Loading : UiState()
|
||||
data class Error(val message: String?) : UiState()
|
||||
data class Error(val error: Exception) : UiState()
|
||||
}
|
||||
|
||||
fun onUiState(scope: LifecycleCoroutineScope, collector: (UiState) -> Unit) {
|
||||
|
@ -121,9 +121,7 @@ constructor(
|
|||
)
|
||||
)
|
||||
} catch (e: Exception) {
|
||||
Timber.d(e)
|
||||
Timber.d(itemId.toString())
|
||||
uiState.emit(UiState.Error(e.message))
|
||||
uiState.emit(UiState.Error(e))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,6 @@ import dagger.hilt.android.lifecycle.HiltViewModel
|
|||
import dev.jdtech.jellyfin.models.CollectionType
|
||||
import dev.jdtech.jellyfin.repository.JellyfinRepository
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.collect
|
||||
import kotlinx.coroutines.launch
|
||||
import org.jellyfin.sdk.model.api.BaseItemDto
|
||||
import javax.inject.Inject
|
||||
|
@ -22,7 +21,7 @@ constructor(
|
|||
sealed class UiState {
|
||||
data class Normal(val collections: List<BaseItemDto>) : UiState()
|
||||
object Loading : UiState()
|
||||
data class Error(val message: String?) : UiState()
|
||||
data class Error(val error: Exception) : UiState()
|
||||
}
|
||||
|
||||
fun onUiState(scope: LifecycleCoroutineScope, collector: (UiState) -> Unit) {
|
||||
|
@ -43,7 +42,7 @@ constructor(
|
|||
uiState.emit(UiState.Normal(collections))
|
||||
} catch (e: Exception) {
|
||||
uiState.emit(
|
||||
UiState.Error(e.message)
|
||||
UiState.Error(e)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,10 +9,8 @@ import dev.jdtech.jellyfin.models.ContentType.TVSHOW
|
|||
import dev.jdtech.jellyfin.repository.JellyfinRepository
|
||||
import dev.jdtech.jellyfin.utils.contentType
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.collect
|
||||
import kotlinx.coroutines.launch
|
||||
import org.jellyfin.sdk.model.api.BaseItemDto
|
||||
import java.lang.Exception
|
||||
import java.util.UUID
|
||||
import javax.inject.Inject
|
||||
|
||||
|
@ -26,7 +24,7 @@ internal class PersonDetailViewModel @Inject internal constructor(
|
|||
sealed class UiState {
|
||||
data class Normal(val data: PersonOverview, val starredIn: StarredIn) : UiState()
|
||||
object Loading : UiState()
|
||||
data class Error(val message: String?) : UiState()
|
||||
data class Error(val error: Exception) : UiState()
|
||||
}
|
||||
|
||||
fun onUiState(scope: LifecycleCoroutineScope, collector: (UiState) -> Unit) {
|
||||
|
@ -58,7 +56,7 @@ internal class PersonDetailViewModel @Inject internal constructor(
|
|||
|
||||
uiState.emit(UiState.Normal(data, starredIn))
|
||||
} catch (e: Exception) {
|
||||
uiState.emit(UiState.Error(e.message))
|
||||
uiState.emit(UiState.Error(e))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -59,7 +59,7 @@ class PlayerViewModel @Inject internal constructor(
|
|||
createItems(item, playbackPosition, mediaSourceIndex).let(::PlayerItems)
|
||||
} catch (e: Exception) {
|
||||
Timber.d(e)
|
||||
PlayerItemError(e.toString())
|
||||
PlayerItemError(e)
|
||||
}
|
||||
|
||||
playerItems.tryEmit(items)
|
||||
|
@ -195,6 +195,6 @@ class PlayerViewModel @Inject internal constructor(
|
|||
|
||||
sealed class PlayerItemState
|
||||
|
||||
data class PlayerItemError(val message: String) : PlayerItemState()
|
||||
data class PlayerItemError(val error: Exception) : PlayerItemState()
|
||||
data class PlayerItems(val items: List<PlayerItem>) : PlayerItemState()
|
||||
}
|
|
@ -8,7 +8,6 @@ import dev.jdtech.jellyfin.models.FavoriteSection
|
|||
import dev.jdtech.jellyfin.repository.JellyfinRepository
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.collect
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.util.*
|
||||
|
@ -25,7 +24,7 @@ constructor(
|
|||
sealed class UiState {
|
||||
data class Normal(val sections: List<FavoriteSection>) : UiState()
|
||||
object Loading : UiState()
|
||||
data class Error(val message: String?) : UiState()
|
||||
data class Error(val error: Exception) : UiState()
|
||||
}
|
||||
|
||||
fun onUiState(scope: LifecycleCoroutineScope, collector: (UiState) -> Unit) {
|
||||
|
@ -74,7 +73,7 @@ constructor(
|
|||
|
||||
uiState.emit(UiState.Normal(sections))
|
||||
} catch (e: Exception) {
|
||||
uiState.emit(UiState.Error(e.message))
|
||||
uiState.emit(UiState.Error(e))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,6 @@ import dagger.hilt.android.lifecycle.HiltViewModel
|
|||
import dev.jdtech.jellyfin.adapters.EpisodeItem
|
||||
import dev.jdtech.jellyfin.repository.JellyfinRepository
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.collect
|
||||
import kotlinx.coroutines.launch
|
||||
import org.jellyfin.sdk.model.api.ItemFields
|
||||
import java.util.*
|
||||
|
@ -22,7 +21,7 @@ constructor(
|
|||
sealed class UiState {
|
||||
data class Normal(val episodes: List<EpisodeItem>) : UiState()
|
||||
object Loading : UiState()
|
||||
data class Error(val message: String?) : UiState()
|
||||
data class Error(val error: Exception) : UiState()
|
||||
}
|
||||
|
||||
fun onUiState(scope: LifecycleCoroutineScope, collector: (UiState) -> Unit) {
|
||||
|
@ -36,7 +35,7 @@ constructor(
|
|||
val episodes = getEpisodes(seriesId, seasonId)
|
||||
uiState.emit(UiState.Normal(episodes))
|
||||
} catch (e: Exception) {
|
||||
uiState.emit(UiState.Error(e.message))
|
||||
uiState.emit(UiState.Error(e))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,9 +11,7 @@ import dev.jdtech.jellyfin.database.ServerDatabaseDao
|
|||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.channels.BufferOverflow
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import kotlinx.coroutines.flow.collect
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.util.*
|
||||
import javax.inject.Inject
|
||||
|
||||
|
@ -43,10 +41,8 @@ constructor(
|
|||
* @param server The server
|
||||
*/
|
||||
fun deleteServer(server: Server) {
|
||||
viewModelScope.launch {
|
||||
withContext(Dispatchers.IO) {
|
||||
database.delete(server.id)
|
||||
}
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
database.delete(server.id)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue