mirror of
https://github.com/NiciDieNase/chaosflix
synced 2024-11-22 12:23:06 +00:00
fix: handle recordings not yet loaded in event details VM
This commit is contained in:
parent
c0b32e560a
commit
795647c240
7 changed files with 91 additions and 60 deletions
|
@ -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 {
|
||||
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))
|
||||
} else {
|
||||
updateState.postValue(LiveEvent(State.DONE, error = "Error updating Recordings for ${event.title}"))
|
||||
}
|
||||
} 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() }
|
||||
suspend fun updateRecordingsForEvent(event: Event): List<Recording>? {
|
||||
return try {
|
||||
val eventDto = recordingApi.getEventByGUIDSuspending(event.guid)
|
||||
val recordingDtos = eventDto?.recordings
|
||||
if (recordingDtos != null) {
|
||||
saveRecordings(event, recordingDtos)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
null
|
||||
}
|
||||
return updateState
|
||||
}
|
||||
|
||||
suspend fun updateSingleEvent(guid: String): Event? = withContext(Dispatchers.IO) {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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>> {
|
||||
mediaRepository.updateRecordingsForEvent(event)
|
||||
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)
|
||||
val bundle = Bundle()
|
||||
bundle.putParcelable(EVENT, event)
|
||||
bundle.putParcelableArrayList(KEY_SELECT_RECORDINGS, ArrayList(items))
|
||||
state.postValue(LiveEvent(State.SelectRecording, data = bundle))
|
||||
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 {
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
@ -30,11 +30,10 @@ 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 =
|
||||
ArrayObjectAdapter(CardPresenter(R.style.EventGridCardStyle))
|
||||
ArrayObjectAdapter(CardPresenter(R.style.EventGridCardStyle))
|
||||
private lateinit var defaultBackground: Drawable
|
||||
private var metrics: DisplayMetrics? = null
|
||||
private var backgroundTimer: Timer? = null
|
||||
|
@ -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
|
||||
|
@ -91,16 +88,16 @@ class EventsGridBrowseFragment : VerticalGridSupportFragment(), EventsActivity.E
|
|||
options.centerCrop()
|
||||
|
||||
Glide.with(this)
|
||||
.load(url)
|
||||
.apply(options)
|
||||
.into(object : SimpleTarget<Drawable>() {
|
||||
override fun onResourceReady(
|
||||
resource: Drawable,
|
||||
transition: Transition<in Drawable>?
|
||||
) {
|
||||
consumer.invoke(resource)
|
||||
}
|
||||
})
|
||||
.load(url)
|
||||
.apply(options)
|
||||
.into(object : SimpleTarget<Drawable>() {
|
||||
override fun onResourceReady(
|
||||
resource: Drawable,
|
||||
transition: Transition<in Drawable>?
|
||||
) {
|
||||
consumer.invoke(resource)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
protected fun updateBackground(uri: String) {
|
||||
|
@ -120,10 +117,10 @@ class EventsGridBrowseFragment : VerticalGridSupportFragment(), EventsActivity.E
|
|||
|
||||
private inner class ItemViewSelectedListener : OnItemViewSelectedListener {
|
||||
override fun onItemSelected(
|
||||
itemViewHolder: Presenter.ViewHolder,
|
||||
item: Any,
|
||||
rowViewHolder: RowPresenter.ViewHolder,
|
||||
row: Row
|
||||
itemViewHolder: Presenter.ViewHolder,
|
||||
item: Any,
|
||||
rowViewHolder: RowPresenter.ViewHolder,
|
||||
row: Row
|
||||
) {
|
||||
if (item is Event) {
|
||||
try {
|
||||
|
@ -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) }
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue