fix: handle recordings not yet loaded in event details VM

This commit is contained in:
Felix 2020-04-08 19:44:26 +02:00
parent c0b32e560a
commit 795647c240
7 changed files with 91 additions and 60 deletions

View file

@ -23,13 +23,13 @@ import de.nicidienase.chaosflix.common.userdata.entities.watchlist.WatchlistItem
import de.nicidienase.chaosflix.common.util.ConferenceUtil
import de.nicidienase.chaosflix.common.util.LiveEvent
import de.nicidienase.chaosflix.common.util.SingleLiveEvent
import java.io.IOException
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import retrofit2.Response
import java.io.IOException
class MediaRepository(
private val recordingApi: RecordingService,
@ -101,25 +101,19 @@ class MediaRepository(
}
}
fun updateRecordingsForEvent(event: Event): LiveData<LiveEvent<State, List<Recording>, String>> {
val updateState = SingleLiveEvent<LiveEvent<State, List<Recording>, String>>()
coroutineScope.launch(Dispatchers.IO) {
try {
suspend fun updateRecordingsForEvent(event: Event): List<Recording>? {
return try {
val eventDto = recordingApi.getEventByGUIDSuspending(event.guid)
val recordingDtos = eventDto?.recordings
if (recordingDtos != null) {
val recordings: List<Recording> = saveRecordings(event, recordingDtos)
updateState.postValue(LiveEvent(State.DONE, data = recordings))
saveRecordings(event, recordingDtos)
} else {
updateState.postValue(LiveEvent(State.DONE, error = "Error updating Recordings for ${event.title}"))
null
}
} catch (e: IOException) {
updateState.postValue(LiveEvent(State.DONE, error = e.message))
} catch (e: Exception) {
updateState.postValue(LiveEvent(State.DONE, error = "Error updating Recordings for ${event.title} (${e.cause})"))
e.printStackTrace() }
e.printStackTrace()
null
}
return updateState
}
suspend fun updateSingleEvent(guid: String): Event? = withContext(Dispatchers.IO) {

View file

@ -77,7 +77,8 @@ abstract class EventDao : BaseDao<Event>() {
@Query("""SELECT event.*, conference.acronym as conference
FROM event JOIN conference ON event.conferenceId=conference.id
WHERE conference.id = :confernceId""")
WHERE conference.id = :confernceId
ORDER BY event.title""")
abstract fun getEventsWithConferenceForConfernce(confernceId: Long): LiveData<List<Event>>
override suspend fun updateOrInsertInternal(item: Event) {

View file

@ -5,14 +5,14 @@ import android.util.Log
import com.google.gson.Gson
import de.nicidienase.chaosflix.BuildConfig
import de.nicidienase.chaosflix.common.SingletonHolder2
import java.io.File
import java.net.SocketTimeoutException
import java.util.concurrent.TimeUnit
import okhttp3.Cache
import okhttp3.Interceptor
import okhttp3.OkHttpClient
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import java.io.File
import java.net.SocketTimeoutException
import java.util.concurrent.TimeUnit
class ApiFactory private constructor(private val recordingUrl: String, cache: File? = null) {
@ -52,6 +52,7 @@ class ApiFactory private constructor(private val recordingUrl: String, cache: Fi
return@Interceptor chain.proceed(requestWithUseragent)
} catch (ex: SocketTimeoutException) {
Log.e("UserAgentIntercepor", ex.message, ex)
return@Interceptor null
}
}

View file

@ -15,10 +15,10 @@ import de.nicidienase.chaosflix.common.mediadata.entities.recording.persistence.
import de.nicidienase.chaosflix.common.userdata.entities.watchlist.WatchlistItem
import de.nicidienase.chaosflix.common.util.LiveEvent
import de.nicidienase.chaosflix.common.util.SingleLiveEvent
import java.io.File
import java.util.ArrayList
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import java.io.File
import java.util.*
class DetailsViewModel(
private val database: ChaosflixDatabase,
@ -30,16 +30,33 @@ class DetailsViewModel(
val state: SingleLiveEvent<LiveEvent<State, Bundle, String>> =
SingleLiveEvent()
private var waitingForRecordings = false
val autoselectRecording: Boolean
get() = preferencesManager.getAutoselectRecording()
fun setEvent(event: Event): LiveData<Event?> {
mediaRepository.updateRecordingsForEvent(event)
viewModelScope.launch {
val recordings = mediaRepository.updateRecordingsForEvent(event)
if(waitingForRecordings){
if(recordings != null){
waitingForRecordings = false
val bundle = Bundle()
bundle.putParcelable(EVENT, event)
bundle.putParcelableArrayList(KEY_SELECT_RECORDINGS, ArrayList(recordings))
state.postValue(LiveEvent(State.SelectRecording, data = bundle))
} else {
state.postValue(LiveEvent(State.Error, error = "Could not load recordings."))
}
}
}
return database.eventDao().findEventByGuid(event.guid)
}
fun getRecordingForEvent(event: Event): LiveData<List<Recording>> {
viewModelScope.launch {
mediaRepository.updateRecordingsForEvent(event)
}
return database.recordingDao().findRecordingByEvent(event.id)
}
@ -104,10 +121,15 @@ class DetailsViewModel(
} else {
// select quality then playEvent
val items: List<Recording> = database.recordingDao().findRecordingByEventSync(event.id)
if(items.isNotEmpty()){
val bundle = Bundle()
bundle.putParcelable(EVENT, event)
bundle.putParcelableArrayList(KEY_SELECT_RECORDINGS, ArrayList(items))
state.postValue(LiveEvent(State.SelectRecording, data = bundle))
} else {
state.postValue(LiveEvent(State.Loading))
waitingForRecordings = true
}
}
}
}
@ -164,7 +186,8 @@ class DetailsViewModel(
DownloadRecording,
DisplayEvent,
PlayExternal,
Error
Error,
Loading
}
companion object {

View file

@ -72,6 +72,7 @@ import kotlinx.coroutines.launch
class EventDetailsFragment : DetailsSupportFragment() {
private var selectDialog: AlertDialog? = null
private var loadingDialog: AlertDialog? = null
private val uiScope = CoroutineScope(Dispatchers.Main)
@ -81,8 +82,6 @@ class EventDetailsFragment : DetailsSupportFragment() {
private var event: Event? = null
private var room: Room? = null
private var currentRecordings: List<Recording>? = null
private lateinit var rowsAdapter: ArrayObjectAdapter
private var relatedEventsAdapter: ArrayObjectAdapter? = null
@ -169,6 +168,8 @@ class EventDetailsFragment : DetailsSupportFragment() {
}
}
DetailsViewModel.State.SelectRecording -> {
loadingDialog?.dismiss()
loadingDialog = null
val event: Event? = state.data?.getParcelable(DetailsViewModel.EVENT)
val recordings: List<Recording>? = state.data?.getParcelableArrayList(DetailsViewModel.KEY_SELECT_RECORDINGS)
if (event != null && recordings != null && recordings.isNotEmpty()) {
@ -184,14 +185,26 @@ class EventDetailsFragment : DetailsSupportFragment() {
DetailsViewModel.State.Error -> {
showError(state.error)
}
else -> {
// Download
Log.e(TAG, "Case not relevant for leanback UI, this should not happen")
DetailsViewModel.State.Loading -> {
showLoadingDialog()
}
DetailsViewModel.State.PlayOfflineItem -> irrelevantCase()
DetailsViewModel.State.DownloadRecording -> irrelevantCase()
DetailsViewModel.State.PlayExternal -> irrelevantCase()
}
})
}
fun showLoadingDialog() {
loadingDialog = AlertDialog.Builder(requireContext())
.setTitle("Loading Recordings")
.create().apply { show() }
}
private fun irrelevantCase() {
Log.e(TAG, "Case not relevant for leanback UI, this should not happen")
}
private fun showError(errorMessage: String?) {
if (errorMessage != null && errorMessage.isNotBlank()) {
view?.let {
@ -315,7 +328,7 @@ class EventDetailsFragment : DetailsSupportFragment() {
}
override fun onLoadFailed(errorDrawable: Drawable?) {
detailsOverview.setImageDrawable(ContextCompat.getDrawable(requireContext(), DEFAULT_DRAWABLE))
detailsOverview.imageDrawable = ContextCompat.getDrawable(requireContext(), DEFAULT_DRAWABLE)
}
})
}

View file

@ -30,7 +30,6 @@ import java.util.Timer
import java.util.TimerTask
class EventsGridBrowseFragment : VerticalGridSupportFragment(), EventsActivity.EventsFragment {
private val NUM_COLUMNS = 4
private val handler = Handler()
private val rowsAdapter: ArrayObjectAdapter =
@ -49,10 +48,8 @@ class EventsGridBrowseFragment : VerticalGridSupportFragment(), EventsActivity.E
defaultBackground = this
}
val conference: Conference? = arguments?.getParcelable(EventsRowsBrowseFragment.CONFERENCE)
if (conference == null) {
throw IllegalStateException("No conference passed")
}
val conference: Conference = arguments?.getParcelable(EventsRowsBrowseFragment.CONFERENCE)
?: throw IllegalStateException("No conference passed")
loadImage(conference.logoUrl, this::setBadgeDrawable)
title = conference.title
@ -157,6 +154,8 @@ class EventsGridBrowseFragment : VerticalGridSupportFragment(), EventsActivity.E
private const val BACKGROUND_UPDATE_DELAY = 300
private const val CONFERENCE = "conference"
private const val NUM_COLUMNS = 4
fun create(conference: Conference): EventsGridBrowseFragment {
return EventsGridBrowseFragment().apply {
arguments = Bundle().apply { putParcelable(CONFERENCE, conference) }

View file

@ -34,7 +34,7 @@ class ConferenceGroupFragment : BrowseFragment() {
StaggeredGridLayoutManager(columnCount, StaggeredGridLayoutManager.VERTICAL)
}
view.layoutManager = layoutManager
val conferencesAdapter: ConferenceRecyclerViewAdapter = ConferenceRecyclerViewAdapter(listener)
val conferencesAdapter = ConferenceRecyclerViewAdapter(listener)
conferencesAdapter.setHasStableIds(true)
view.adapter = conferencesAdapter
val groupId = conferenceGroup?.id
@ -45,7 +45,7 @@ class ConferenceGroupFragment : BrowseFragment() {
setLoadingOverlayVisibility(false)
}
conferencesAdapter.conferences = conferenceList
val layoutState = arguments?.getParcelable<Parcelable>(LAYOUTMANAGER_STATE)?.let {
arguments?.getParcelable<Parcelable>(LAYOUTMANAGER_STATE)?.let {
layoutManager?.onRestoreInstanceState(it)
}
}