Add error handling to all fragments
This commit is contained in:
parent
11793a423b
commit
fe7775329a
14 changed files with 600 additions and 414 deletions
|
@ -8,7 +8,9 @@ import android.view.ViewGroup
|
||||||
import androidx.fragment.app.viewModels
|
import androidx.fragment.app.viewModels
|
||||||
import androidx.navigation.fragment.findNavController
|
import androidx.navigation.fragment.findNavController
|
||||||
import androidx.navigation.fragment.navArgs
|
import androidx.navigation.fragment.navArgs
|
||||||
|
import com.google.android.material.snackbar.Snackbar
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
|
import dev.jdtech.jellyfin.R
|
||||||
import dev.jdtech.jellyfin.viewmodels.LibraryViewModel
|
import dev.jdtech.jellyfin.viewmodels.LibraryViewModel
|
||||||
import dev.jdtech.jellyfin.adapters.ViewItemListAdapter
|
import dev.jdtech.jellyfin.adapters.ViewItemListAdapter
|
||||||
import dev.jdtech.jellyfin.databinding.FragmentLibraryBinding
|
import dev.jdtech.jellyfin.databinding.FragmentLibraryBinding
|
||||||
|
@ -36,6 +38,27 @@ class LibraryFragment : Fragment() {
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
binding.viewModel = viewModel
|
binding.viewModel = viewModel
|
||||||
|
|
||||||
|
val snackbar =
|
||||||
|
Snackbar.make(
|
||||||
|
binding.mainLayout,
|
||||||
|
getString(R.string.error_loading_data),
|
||||||
|
Snackbar.LENGTH_INDEFINITE
|
||||||
|
)
|
||||||
|
snackbar.setAction(getString(R.string.retry)) {
|
||||||
|
viewModel.loadItems(args.libraryId)
|
||||||
|
}
|
||||||
|
|
||||||
|
viewModel.error.observe(viewLifecycleOwner, { error ->
|
||||||
|
if (error) {
|
||||||
|
snackbar.show()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
viewModel.finishedLoading.observe(viewLifecycleOwner, {
|
||||||
|
binding.loadingIndicator.visibility = if (it) View.GONE else View.VISIBLE
|
||||||
|
})
|
||||||
|
|
||||||
binding.itemsRecyclerView.adapter =
|
binding.itemsRecyclerView.adapter =
|
||||||
ViewItemListAdapter(ViewItemListAdapter.OnClickListener { item ->
|
ViewItemListAdapter(ViewItemListAdapter.OnClickListener { item ->
|
||||||
navigateToMediaInfoFragment(item)
|
navigateToMediaInfoFragment(item)
|
||||||
|
|
|
@ -7,7 +7,9 @@ import android.view.ViewGroup
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.fragment.app.viewModels
|
import androidx.fragment.app.viewModels
|
||||||
import androidx.navigation.fragment.findNavController
|
import androidx.navigation.fragment.findNavController
|
||||||
|
import com.google.android.material.snackbar.Snackbar
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
|
import dev.jdtech.jellyfin.R
|
||||||
import dev.jdtech.jellyfin.adapters.CollectionListAdapter
|
import dev.jdtech.jellyfin.adapters.CollectionListAdapter
|
||||||
import dev.jdtech.jellyfin.databinding.FragmentMediaBinding
|
import dev.jdtech.jellyfin.databinding.FragmentMediaBinding
|
||||||
import dev.jdtech.jellyfin.viewmodels.MediaViewModel
|
import dev.jdtech.jellyfin.viewmodels.MediaViewModel
|
||||||
|
@ -26,6 +28,16 @@ class MediaFragment : Fragment() {
|
||||||
): View {
|
): View {
|
||||||
binding = FragmentMediaBinding.inflate(inflater, container, false)
|
binding = FragmentMediaBinding.inflate(inflater, container, false)
|
||||||
|
|
||||||
|
val snackbar =
|
||||||
|
Snackbar.make(
|
||||||
|
binding.mainLayout,
|
||||||
|
getString(R.string.error_loading_data),
|
||||||
|
Snackbar.LENGTH_INDEFINITE
|
||||||
|
)
|
||||||
|
snackbar.setAction(getString(R.string.retry)) {
|
||||||
|
viewModel.loadData()
|
||||||
|
}
|
||||||
|
|
||||||
binding.lifecycleOwner = this
|
binding.lifecycleOwner = this
|
||||||
binding.viewModel = viewModel
|
binding.viewModel = viewModel
|
||||||
binding.viewsRecyclerView.adapter =
|
binding.viewsRecyclerView.adapter =
|
||||||
|
@ -34,8 +46,12 @@ class MediaFragment : Fragment() {
|
||||||
})
|
})
|
||||||
|
|
||||||
viewModel.finishedLoading.observe(viewLifecycleOwner, {
|
viewModel.finishedLoading.observe(viewLifecycleOwner, {
|
||||||
if (it) {
|
binding.loadingIndicator.visibility = if (it) View.GONE else View.VISIBLE
|
||||||
binding.loadingIndicator.visibility = View.GONE
|
})
|
||||||
|
|
||||||
|
viewModel.error.observe(viewLifecycleOwner, { error ->
|
||||||
|
if (error) {
|
||||||
|
snackbar.show()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,7 @@ import androidx.fragment.app.Fragment
|
||||||
import androidx.fragment.app.viewModels
|
import androidx.fragment.app.viewModels
|
||||||
import androidx.navigation.fragment.findNavController
|
import androidx.navigation.fragment.findNavController
|
||||||
import androidx.navigation.fragment.navArgs
|
import androidx.navigation.fragment.navArgs
|
||||||
|
import com.google.android.material.snackbar.Snackbar
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
import dev.jdtech.jellyfin.R
|
import dev.jdtech.jellyfin.R
|
||||||
import dev.jdtech.jellyfin.adapters.PersonListAdapter
|
import dev.jdtech.jellyfin.adapters.PersonListAdapter
|
||||||
|
@ -42,8 +43,24 @@ class MediaInfoFragment : Fragment() {
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
|
||||||
|
val snackbar =
|
||||||
|
Snackbar.make(
|
||||||
|
binding.mainLayout,
|
||||||
|
getString(R.string.error_loading_data),
|
||||||
|
Snackbar.LENGTH_INDEFINITE
|
||||||
|
)
|
||||||
|
snackbar.setAction(getString(R.string.retry)) {
|
||||||
|
viewModel.loadData(args.itemId, args.itemType)
|
||||||
|
}
|
||||||
|
|
||||||
binding.viewModel = viewModel
|
binding.viewModel = viewModel
|
||||||
|
|
||||||
|
viewModel.error.observe(viewLifecycleOwner, { error ->
|
||||||
|
if (error) {
|
||||||
|
snackbar.show()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
viewModel.item.observe(viewLifecycleOwner, { item ->
|
viewModel.item.observe(viewLifecycleOwner, { item ->
|
||||||
if (item.originalTitle != item.name) {
|
if (item.originalTitle != item.name) {
|
||||||
binding.originalTitle.visibility = View.VISIBLE
|
binding.originalTitle.visibility = View.VISIBLE
|
||||||
|
|
|
@ -8,7 +8,9 @@ import android.view.ViewGroup
|
||||||
import androidx.fragment.app.viewModels
|
import androidx.fragment.app.viewModels
|
||||||
import androidx.navigation.fragment.findNavController
|
import androidx.navigation.fragment.findNavController
|
||||||
import androidx.navigation.fragment.navArgs
|
import androidx.navigation.fragment.navArgs
|
||||||
|
import com.google.android.material.snackbar.Snackbar
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
|
import dev.jdtech.jellyfin.R
|
||||||
import dev.jdtech.jellyfin.adapters.EpisodeListAdapter
|
import dev.jdtech.jellyfin.adapters.EpisodeListAdapter
|
||||||
import dev.jdtech.jellyfin.databinding.FragmentSeasonBinding
|
import dev.jdtech.jellyfin.databinding.FragmentSeasonBinding
|
||||||
import dev.jdtech.jellyfin.viewmodels.SeasonViewModel
|
import dev.jdtech.jellyfin.viewmodels.SeasonViewModel
|
||||||
|
@ -34,6 +36,27 @@ class SeasonFragment : Fragment() {
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
binding.viewModel = viewModel
|
binding.viewModel = viewModel
|
||||||
|
|
||||||
|
val snackbar =
|
||||||
|
Snackbar.make(
|
||||||
|
binding.mainLayout,
|
||||||
|
getString(R.string.error_loading_data),
|
||||||
|
Snackbar.LENGTH_INDEFINITE
|
||||||
|
)
|
||||||
|
snackbar.setAction(getString(R.string.retry)) {
|
||||||
|
viewModel.loadEpisodes(args.seriesId, args.seasonId)
|
||||||
|
}
|
||||||
|
|
||||||
|
viewModel.error.observe(viewLifecycleOwner, { error ->
|
||||||
|
if (error) {
|
||||||
|
snackbar.show()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
viewModel.finishedLoading.observe(viewLifecycleOwner, {
|
||||||
|
binding.loadingIndicator.visibility = if (it) View.GONE else View.VISIBLE
|
||||||
|
})
|
||||||
|
|
||||||
binding.episodesRecyclerView.adapter =
|
binding.episodesRecyclerView.adapter =
|
||||||
EpisodeListAdapter(EpisodeListAdapter.OnClickListener { episode ->
|
EpisodeListAdapter(EpisodeListAdapter.OnClickListener { episode ->
|
||||||
navigateToEpisodeBottomSheetFragment(episode)
|
navigateToEpisodeBottomSheetFragment(episode)
|
||||||
|
|
|
@ -10,6 +10,7 @@ import dev.jdtech.jellyfin.repository.JellyfinRepository
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import org.jellyfin.sdk.model.api.BaseItemDto
|
import org.jellyfin.sdk.model.api.BaseItemDto
|
||||||
import org.jellyfin.sdk.model.api.MediaSourceInfo
|
import org.jellyfin.sdk.model.api.MediaSourceInfo
|
||||||
|
import timber.log.Timber
|
||||||
import java.text.DateFormat
|
import java.text.DateFormat
|
||||||
import java.time.ZoneOffset
|
import java.time.ZoneOffset
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
@ -42,12 +43,17 @@ constructor(
|
||||||
|
|
||||||
fun loadEpisode(episodeId: UUID) {
|
fun loadEpisode(episodeId: UUID) {
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
_item.value = jellyfinRepository.getItem(episodeId)
|
try {
|
||||||
_runTime.value = "${_item.value?.runTimeTicks?.div(600000000)} min"
|
val item = jellyfinRepository.getItem(episodeId)
|
||||||
_dateString.value = getDateString(_item.value!!)
|
_item.value = item
|
||||||
|
_runTime.value = "${item.runTimeTicks?.div(600000000)} min"
|
||||||
|
_dateString.value = getDateString(item)
|
||||||
_mediaSources.value = jellyfinRepository.getMediaSources(episodeId)
|
_mediaSources.value = jellyfinRepository.getMediaSources(episodeId)
|
||||||
_played.value = _item.value?.userData?.played
|
_played.value = item.userData?.played
|
||||||
_favorite.value = _item.value?.userData?.isFavorite
|
_favorite.value = item.userData?.isFavorite
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Timber.e(e)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -85,12 +85,11 @@ constructor(
|
||||||
|
|
||||||
_views.value = items + views.map { HomeItem.ViewItem(it) }
|
_views.value = items + views.map { HomeItem.ViewItem(it) }
|
||||||
|
|
||||||
_finishedLoading.value = true
|
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Timber.e(e)
|
Timber.e(e)
|
||||||
_finishedLoading.value = true
|
|
||||||
_error.value = true
|
_error.value = true
|
||||||
}
|
}
|
||||||
|
_finishedLoading.value = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@ import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
import dev.jdtech.jellyfin.repository.JellyfinRepository
|
import dev.jdtech.jellyfin.repository.JellyfinRepository
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import org.jellyfin.sdk.model.api.BaseItemDto
|
import org.jellyfin.sdk.model.api.BaseItemDto
|
||||||
|
import timber.log.Timber
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
@ -19,9 +20,19 @@ constructor(private val jellyfinRepository: JellyfinRepository) : ViewModel() {
|
||||||
private val _finishedLoading = MutableLiveData<Boolean>()
|
private val _finishedLoading = MutableLiveData<Boolean>()
|
||||||
val finishedLoading: LiveData<Boolean> = _finishedLoading
|
val finishedLoading: LiveData<Boolean> = _finishedLoading
|
||||||
|
|
||||||
|
private val _error = MutableLiveData<Boolean>()
|
||||||
|
val error: LiveData<Boolean> = _error
|
||||||
|
|
||||||
fun loadItems(parentId: UUID) {
|
fun loadItems(parentId: UUID) {
|
||||||
|
_error.value = false
|
||||||
|
_finishedLoading.value = false
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
|
try {
|
||||||
_items.value = jellyfinRepository.getItems(parentId)
|
_items.value = jellyfinRepository.getItems(parentId)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Timber.e(e)
|
||||||
|
_error.value = true
|
||||||
|
}
|
||||||
_finishedLoading.value = true
|
_finishedLoading.value = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@ import kotlinx.coroutines.withContext
|
||||||
import org.jellyfin.sdk.model.api.BaseItemDto
|
import org.jellyfin.sdk.model.api.BaseItemDto
|
||||||
import org.jellyfin.sdk.model.api.BaseItemPerson
|
import org.jellyfin.sdk.model.api.BaseItemPerson
|
||||||
import org.jellyfin.sdk.model.api.MediaSourceInfo
|
import org.jellyfin.sdk.model.api.MediaSourceInfo
|
||||||
|
import timber.log.Timber
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
@ -62,8 +63,13 @@ constructor(private val jellyfinRepository: JellyfinRepository) : ViewModel() {
|
||||||
private val _favorite = MutableLiveData<Boolean>()
|
private val _favorite = MutableLiveData<Boolean>()
|
||||||
val favorite: LiveData<Boolean> = _favorite
|
val favorite: LiveData<Boolean> = _favorite
|
||||||
|
|
||||||
|
private val _error = MutableLiveData<Boolean>()
|
||||||
|
val error: LiveData<Boolean> = _error
|
||||||
|
|
||||||
fun loadData(itemId: UUID, itemType: String) {
|
fun loadData(itemId: UUID, itemType: String) {
|
||||||
|
_error.value = false
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
|
try {
|
||||||
_item.value = jellyfinRepository.getItem(itemId)
|
_item.value = jellyfinRepository.getItem(itemId)
|
||||||
_actors.value = getActors(_item.value!!)
|
_actors.value = getActors(_item.value!!)
|
||||||
_director.value = getDirector(_item.value!!)
|
_director.value = getDirector(_item.value!!)
|
||||||
|
@ -82,6 +88,10 @@ constructor(private val jellyfinRepository: JellyfinRepository) : ViewModel() {
|
||||||
if (itemType == "Movie") {
|
if (itemType == "Movie") {
|
||||||
_mediaSources.value = jellyfinRepository.getMediaSources(itemId)
|
_mediaSources.value = jellyfinRepository.getMediaSources(itemId)
|
||||||
}
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Timber.e(e)
|
||||||
|
_error.value = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@ import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
import dev.jdtech.jellyfin.repository.JellyfinRepository
|
import dev.jdtech.jellyfin.repository.JellyfinRepository
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import org.jellyfin.sdk.model.api.BaseItemDto
|
import org.jellyfin.sdk.model.api.BaseItemDto
|
||||||
|
import timber.log.Timber
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
@HiltViewModel
|
@HiltViewModel
|
||||||
|
@ -20,8 +21,18 @@ constructor(
|
||||||
private val _finishedLoading = MutableLiveData<Boolean>()
|
private val _finishedLoading = MutableLiveData<Boolean>()
|
||||||
val finishedLoading: LiveData<Boolean> = _finishedLoading
|
val finishedLoading: LiveData<Boolean> = _finishedLoading
|
||||||
|
|
||||||
|
private val _error = MutableLiveData<Boolean>()
|
||||||
|
val error: LiveData<Boolean> = _error
|
||||||
|
|
||||||
init {
|
init {
|
||||||
|
loadData()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun loadData() {
|
||||||
|
_finishedLoading.value = false
|
||||||
|
_error.value = false
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
|
try {
|
||||||
val items = jellyfinRepository.getItems()
|
val items = jellyfinRepository.getItems()
|
||||||
_collections.value =
|
_collections.value =
|
||||||
items.filter {
|
items.filter {
|
||||||
|
@ -30,6 +41,10 @@ constructor(
|
||||||
it.collectionType != "playlists" &&
|
it.collectionType != "playlists" &&
|
||||||
it.collectionType != "boxsets"
|
it.collectionType != "boxsets"
|
||||||
}
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Timber.e(e)
|
||||||
|
_error.value = true
|
||||||
|
}
|
||||||
_finishedLoading.value = true
|
_finishedLoading.value = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ import dev.jdtech.jellyfin.adapters.EpisodeItem
|
||||||
import dev.jdtech.jellyfin.repository.JellyfinRepository
|
import dev.jdtech.jellyfin.repository.JellyfinRepository
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import org.jellyfin.sdk.model.api.ItemFields
|
import org.jellyfin.sdk.model.api.ItemFields
|
||||||
|
import timber.log.Timber
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
@ -20,9 +21,23 @@ constructor(private val jellyfinRepository: JellyfinRepository) : ViewModel() {
|
||||||
private val _episodes = MutableLiveData<List<EpisodeItem>>()
|
private val _episodes = MutableLiveData<List<EpisodeItem>>()
|
||||||
val episodes: LiveData<List<EpisodeItem>> = _episodes
|
val episodes: LiveData<List<EpisodeItem>> = _episodes
|
||||||
|
|
||||||
|
private val _finishedLoading = MutableLiveData<Boolean>()
|
||||||
|
val finishedLoading: LiveData<Boolean> = _finishedLoading
|
||||||
|
|
||||||
|
private val _error = MutableLiveData<Boolean>()
|
||||||
|
val error: LiveData<Boolean> = _error
|
||||||
|
|
||||||
fun loadEpisodes(seriesId: UUID, seasonId: UUID) {
|
fun loadEpisodes(seriesId: UUID, seasonId: UUID) {
|
||||||
|
_error.value = false
|
||||||
|
_finishedLoading.value = false
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
|
try {
|
||||||
_episodes.value = getEpisodes(seriesId, seasonId)
|
_episodes.value = getEpisodes(seriesId, seasonId)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Timber.e(e)
|
||||||
|
_error.value = true
|
||||||
|
}
|
||||||
|
_finishedLoading.value = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,17 +2,35 @@
|
||||||
<layout xmlns:android="http://schemas.android.com/apk/res/android"
|
<layout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools">
|
xmlns:tools="http://schemas.android.com/tools">
|
||||||
|
|
||||||
<data>
|
<data>
|
||||||
|
|
||||||
<variable
|
<variable
|
||||||
name="viewModel"
|
name="viewModel"
|
||||||
type="dev.jdtech.jellyfin.viewmodels.LibraryViewModel" />
|
type="dev.jdtech.jellyfin.viewmodels.LibraryViewModel" />
|
||||||
</data>
|
</data>
|
||||||
|
|
||||||
|
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||||
|
android:id="@+id/main_layout"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
tools:context=".fragments.LibraryFragment">
|
tools:context=".fragments.LibraryFragment">
|
||||||
|
|
||||||
|
<com.google.android.material.progressindicator.CircularProgressIndicator
|
||||||
|
android:id="@+id/loading_indicator"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:indeterminate="true"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:trackCornerRadius="10dp" />
|
||||||
|
|
||||||
<androidx.recyclerview.widget.RecyclerView
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
android:id="@+id/items_recycler_view"
|
android:id="@+id/items_recycler_view"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
|
@ -31,5 +49,7 @@
|
||||||
tools:listitem="@layout/base_item" />
|
tools:listitem="@layout/base_item" />
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||||
|
|
||||||
</layout>
|
</layout>
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,11 @@
|
||||||
type="dev.jdtech.jellyfin.viewmodels.MediaViewModel" />
|
type="dev.jdtech.jellyfin.viewmodels.MediaViewModel" />
|
||||||
</data>
|
</data>
|
||||||
|
|
||||||
|
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||||
|
android:id="@+id/main_layout"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
|
@ -45,4 +50,5 @@
|
||||||
tools:listitem="@layout/collection_item" />
|
tools:listitem="@layout/collection_item" />
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||||
</layout>
|
</layout>
|
||||||
|
|
|
@ -12,6 +12,11 @@
|
||||||
type="dev.jdtech.jellyfin.viewmodels.MediaInfoViewModel" />
|
type="dev.jdtech.jellyfin.viewmodels.MediaInfoViewModel" />
|
||||||
</data>
|
</data>
|
||||||
|
|
||||||
|
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||||
|
android:id="@+id/main_layout"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
<ScrollView
|
<ScrollView
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent">
|
android:layout_height="match_parent">
|
||||||
|
@ -374,4 +379,6 @@
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
|
|
||||||
|
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||||
|
|
||||||
</layout>
|
</layout>
|
||||||
|
|
|
@ -12,10 +12,27 @@
|
||||||
|
|
||||||
</data>
|
</data>
|
||||||
|
|
||||||
|
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||||
|
android:id="@+id/main_layout"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent">
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
|
<com.google.android.material.progressindicator.CircularProgressIndicator
|
||||||
|
android:id="@+id/loading_indicator"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:indeterminate="true"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:trackCornerRadius="10dp" />
|
||||||
|
|
||||||
<androidx.recyclerview.widget.RecyclerView
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
android:id="@+id/episodes_recycler_view"
|
android:id="@+id/episodes_recycler_view"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
|
@ -30,5 +47,6 @@
|
||||||
tools:itemCount="4"
|
tools:itemCount="4"
|
||||||
tools:listitem="@layout/episode_item" />
|
tools:listitem="@layout/episode_item" />
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||||
|
|
||||||
</layout>
|
</layout>
|
Loading…
Reference in a new issue