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
|
||||||
_mediaSources.value = jellyfinRepository.getMediaSources(episodeId)
|
_runTime.value = "${item.runTimeTicks?.div(600000000)} min"
|
||||||
_played.value = _item.value?.userData?.played
|
_dateString.value = getDateString(item)
|
||||||
_favorite.value = _item.value?.userData?.isFavorite
|
_mediaSources.value = jellyfinRepository.getMediaSources(episodeId)
|
||||||
|
_played.value = item.userData?.played
|
||||||
|
_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 {
|
||||||
_items.value = jellyfinRepository.getItems(parentId)
|
try {
|
||||||
|
_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,25 +63,34 @@ 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 {
|
||||||
_item.value = jellyfinRepository.getItem(itemId)
|
try {
|
||||||
_actors.value = getActors(_item.value!!)
|
_item.value = jellyfinRepository.getItem(itemId)
|
||||||
_director.value = getDirector(_item.value!!)
|
_actors.value = getActors(_item.value!!)
|
||||||
_writers.value = getWriters(_item.value!!)
|
_director.value = getDirector(_item.value!!)
|
||||||
_writersString.value =
|
_writers.value = getWriters(_item.value!!)
|
||||||
_writers.value?.joinToString(separator = ", ") { it.name.toString() }
|
_writersString.value =
|
||||||
_genresString.value = _item.value?.genres?.joinToString(separator = ", ")
|
_writers.value?.joinToString(separator = ", ") { it.name.toString() }
|
||||||
_runTime.value = "${_item.value?.runTimeTicks?.div(600000000)} min"
|
_genresString.value = _item.value?.genres?.joinToString(separator = ", ")
|
||||||
_dateString.value = getDateString(_item.value!!)
|
_runTime.value = "${_item.value?.runTimeTicks?.div(600000000)} min"
|
||||||
_played.value = _item.value?.userData?.played
|
_dateString.value = getDateString(_item.value!!)
|
||||||
_favorite.value = _item.value?.userData?.isFavorite
|
_played.value = _item.value?.userData?.played
|
||||||
if (itemType == "Series") {
|
_favorite.value = _item.value?.userData?.isFavorite
|
||||||
_nextUp.value = getNextUp(itemId)
|
if (itemType == "Series") {
|
||||||
_seasons.value = jellyfinRepository.getSeasons(itemId)
|
_nextUp.value = getNextUp(itemId)
|
||||||
}
|
_seasons.value = jellyfinRepository.getSeasons(itemId)
|
||||||
if (itemType == "Movie") {
|
}
|
||||||
_mediaSources.value = jellyfinRepository.getMediaSources(itemId)
|
if (itemType == "Movie") {
|
||||||
|
_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,16 +21,30 @@ 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 {
|
||||||
val items = jellyfinRepository.getItems()
|
try {
|
||||||
_collections.value =
|
val items = jellyfinRepository.getItems()
|
||||||
items.filter {
|
_collections.value =
|
||||||
it.collectionType != "homevideos" &&
|
items.filter {
|
||||||
it.collectionType != "music" &&
|
it.collectionType != "homevideos" &&
|
||||||
it.collectionType != "playlists" &&
|
it.collectionType != "music" &&
|
||||||
it.collectionType != "boxsets"
|
it.collectionType != "playlists" &&
|
||||||
}
|
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 {
|
||||||
_episodes.value = getEpisodes(seriesId, seasonId)
|
try {
|
||||||
|
_episodes.value = getEpisodes(seriesId, seasonId)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Timber.e(e)
|
||||||
|
_error.value = true
|
||||||
|
}
|
||||||
|
_finishedLoading.value = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,34 +2,54 @@
|
||||||
<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.constraintlayout.widget.ConstraintLayout
|
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||||
|
android:id="@+id/main_layout"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent">
|
||||||
tools:context=".fragments.LibraryFragment">
|
|
||||||
|
|
||||||
<androidx.recyclerview.widget.RecyclerView
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
android:id="@+id/items_recycler_view"
|
android:layout_width="match_parent"
|
||||||
android:layout_width="0dp"
|
android:layout_height="match_parent"
|
||||||
android:layout_height="0dp"
|
tools:context=".fragments.LibraryFragment">
|
||||||
android:clipToPadding="false"
|
|
||||||
android:paddingHorizontal="12dp"
|
<com.google.android.material.progressindicator.CircularProgressIndicator
|
||||||
android:paddingTop="16dp"
|
android:id="@+id/loading_indicator"
|
||||||
app:items="@{viewModel.items}"
|
android:layout_width="wrap_content"
|
||||||
app:layoutManager="androidx.recyclerview.widget.GridLayoutManager"
|
android:layout_height="wrap_content"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
android:indeterminate="true"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:spanCount="@integer/library_columns"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
tools:itemCount="6"
|
app:trackCornerRadius="10dp" />
|
||||||
tools:listitem="@layout/base_item" />
|
|
||||||
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:id="@+id/items_recycler_view"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:clipToPadding="false"
|
||||||
|
android:paddingHorizontal="12dp"
|
||||||
|
android:paddingTop="16dp"
|
||||||
|
app:items="@{viewModel.items}"
|
||||||
|
app:layoutManager="androidx.recyclerview.widget.GridLayoutManager"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:spanCount="@integer/library_columns"
|
||||||
|
tools:itemCount="6"
|
||||||
|
tools:listitem="@layout/base_item" />
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
||||||
</layout>
|
</layout>
|
||||||
|
|
||||||
|
|
|
@ -10,39 +10,45 @@
|
||||||
type="dev.jdtech.jellyfin.viewmodels.MediaViewModel" />
|
type="dev.jdtech.jellyfin.viewmodels.MediaViewModel" />
|
||||||
</data>
|
</data>
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||||
|
android:id="@+id/main_layout"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent">
|
||||||
android:animateLayoutChanges="true"
|
|
||||||
tools:context=".fragments.MediaFragment">
|
|
||||||
|
|
||||||
<com.google.android.material.progressindicator.CircularProgressIndicator
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
android:id="@+id/loading_indicator"
|
android:layout_width="match_parent"
|
||||||
android:layout_width="wrap_content"
|
android:layout_height="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:animateLayoutChanges="true"
|
||||||
android:indeterminate="true"
|
tools:context=".fragments.MediaFragment">
|
||||||
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
|
<com.google.android.material.progressindicator.CircularProgressIndicator
|
||||||
android:id="@+id/views_recycler_view"
|
android:id="@+id/loading_indicator"
|
||||||
android:layout_width="0dp"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="0dp"
|
android:layout_height="wrap_content"
|
||||||
android:clipToPadding="false"
|
android:indeterminate="true"
|
||||||
android:paddingHorizontal="12dp"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
android:paddingTop="16dp"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:collections="@{viewModel.collections}"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layoutManager="androidx.recyclerview.widget.GridLayoutManager"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:trackCornerRadius="10dp" />
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
|
||||||
app:spanCount="@integer/collection_columns"
|
|
||||||
tools:itemCount="4"
|
|
||||||
tools:listitem="@layout/collection_item" />
|
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:id="@+id/views_recycler_view"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:clipToPadding="false"
|
||||||
|
android:paddingHorizontal="12dp"
|
||||||
|
android:paddingTop="16dp"
|
||||||
|
app:collections="@{viewModel.collections}"
|
||||||
|
app:layoutManager="androidx.recyclerview.widget.GridLayoutManager"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:spanCount="@integer/collection_columns"
|
||||||
|
tools:itemCount="4"
|
||||||
|
tools:listitem="@layout/collection_item" />
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||||
</layout>
|
</layout>
|
||||||
|
|
|
@ -12,366 +12,373 @@
|
||||||
type="dev.jdtech.jellyfin.viewmodels.MediaInfoViewModel" />
|
type="dev.jdtech.jellyfin.viewmodels.MediaInfoViewModel" />
|
||||||
</data>
|
</data>
|
||||||
|
|
||||||
<ScrollView
|
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||||
|
android:id="@+id/main_layout"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent">
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
<LinearLayout
|
<ScrollView
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="match_parent">
|
||||||
android:orientation="vertical"
|
|
||||||
tools:context=".fragments.MediaInfoFragment">
|
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="200dp"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginBottom="8dp">
|
android:orientation="vertical"
|
||||||
|
tools:context=".fragments.MediaInfoFragment">
|
||||||
|
|
||||||
<ImageView
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
android:id="@+id/item_banner"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="200dp"
|
android:layout_height="200dp"
|
||||||
android:scaleType="centerCrop"
|
android:layout_marginBottom="8dp">
|
||||||
app:itemBackdropImage="@{viewModel.item}"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
|
||||||
tools:ignore="ContentDescription" />
|
|
||||||
|
|
||||||
<FrameLayout
|
<ImageView
|
||||||
android:layout_width="0dp"
|
android:id="@+id/item_banner"
|
||||||
android:layout_height="0dp"
|
android:layout_width="match_parent"
|
||||||
android:background="@drawable/header_gradient"
|
android:layout_height="200dp"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
android:scaleType="centerCrop"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:itemBackdropImage="@{viewModel.item}"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
tools:ignore="ContentDescription" />
|
||||||
|
|
||||||
<TextView
|
<FrameLayout
|
||||||
android:id="@+id/name"
|
android:layout_width="0dp"
|
||||||
android:layout_width="match_parent"
|
android:layout_height="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:background="@drawable/header_gradient"
|
||||||
android:layout_marginHorizontal="24dp"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
android:text="@{viewModel.item.name}"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
android:textAppearance="@style/TextAppearance.MaterialComponents.Headline5"
|
|
||||||
app:layout_constraintBottom_toTopOf="@id/original_title"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
tools:text="Alita: Battle Angel" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/original_title"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginHorizontal="24dp"
|
|
||||||
android:text="@{viewModel.item.originalTitle}"
|
|
||||||
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
|
||||||
app:layout_constraintStart_toStartOf="parent" />
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginHorizontal="24dp"
|
|
||||||
android:layout_marginBottom="16dp">
|
|
||||||
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/year"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginEnd="8dp"
|
|
||||||
android:text="@{viewModel.dateString}"
|
|
||||||
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
|
|
||||||
tools:text="2019" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/playtime"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginEnd="8dp"
|
|
||||||
android:text="@{viewModel.runTime}"
|
|
||||||
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
|
|
||||||
tools:text="122 min" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/official_rating"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginEnd="8dp"
|
|
||||||
android:text="@{viewModel.item.officialRating}"
|
|
||||||
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
|
|
||||||
tools:text="PG-13" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/community_rating"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:drawablePadding="4dp"
|
|
||||||
android:gravity="bottom"
|
|
||||||
android:text="@{viewModel.item.communityRating.toString()}"
|
|
||||||
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
|
|
||||||
app:drawableStartCompat="@drawable/ic_star"
|
|
||||||
app:drawableTint="@color/yellow"
|
|
||||||
tools:text="7.3" />
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginHorizontal="24dp"
|
|
||||||
android:layout_marginBottom="24dp">
|
|
||||||
|
|
||||||
<ImageButton
|
|
||||||
android:id="@+id/play_button"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginEnd="12dp"
|
|
||||||
android:background="@drawable/button_setup_background"
|
|
||||||
android:contentDescription="@string/play_button_description"
|
|
||||||
android:paddingHorizontal="24dp"
|
|
||||||
android:paddingVertical="12dp"
|
|
||||||
android:src="@drawable/ic_play" />
|
|
||||||
|
|
||||||
<ImageButton
|
|
||||||
android:id="@+id/trailer_button"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginEnd="12dp"
|
|
||||||
android:background="@drawable/button_accent_background"
|
|
||||||
android:contentDescription="@string/trailer_button_description"
|
|
||||||
android:padding="12dp"
|
|
||||||
android:src="@drawable/ic_film" />
|
|
||||||
|
|
||||||
<ImageButton
|
|
||||||
android:id="@+id/check_button"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginEnd="12dp"
|
|
||||||
android:background="@drawable/button_accent_background"
|
|
||||||
android:contentDescription="@string/check_button_description"
|
|
||||||
android:padding="12dp"
|
|
||||||
android:src="@drawable/ic_check" />
|
|
||||||
|
|
||||||
<ImageButton
|
|
||||||
android:id="@+id/favorite_button"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:background="@drawable/button_accent_background"
|
|
||||||
android:contentDescription="@string/favorite_button_description"
|
|
||||||
android:padding="12dp"
|
|
||||||
android:src="@drawable/ic_heart" />
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:id="@+id/info"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginHorizontal="24dp"
|
|
||||||
android:layout_marginBottom="12dp"
|
|
||||||
android:orientation="vertical">
|
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
|
||||||
android:id="@+id/genres_layout"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginBottom="12dp"
|
|
||||||
android:visibility="@{viewModel.item.genres.size() < 1 ? View.GONE : View.VISIBLE}">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/genres_title"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="@string/genres"
|
|
||||||
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/genres"
|
android:id="@+id/name"
|
||||||
android:layout_width="0dp"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="64dp"
|
android:layout_marginHorizontal="24dp"
|
||||||
android:text="@{viewModel.genresString}"
|
android:text="@{viewModel.item.name}"
|
||||||
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
|
android:textAppearance="@style/TextAppearance.MaterialComponents.Headline5"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintBottom_toTopOf="@id/original_title"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
tools:text="Alita: Battle Angel" />
|
||||||
tools:text="Action, Science Fiction, Adventure" />
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/original_title"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginHorizontal="24dp"
|
||||||
|
android:text="@{viewModel.item.originalTitle}"
|
||||||
|
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent" />
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
|
||||||
android:id="@+id/director_layout"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginBottom="12dp"
|
|
||||||
android:visibility="@{viewModel.director == null ? View.GONE : View.VISIBLE}">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/director_title"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="@string/director"
|
|
||||||
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/director"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginStart="64dp"
|
|
||||||
android:text="@{viewModel.director.name}"
|
|
||||||
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
|
||||||
tools:text="Robert Rodriguez" />
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
|
||||||
android:id="@+id/writers_layout"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginBottom="12dp"
|
|
||||||
android:visibility="@{viewModel.writers.size() < 1 ? View.GONE : View.VISIBLE}">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/writers_title"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="@string/writers"
|
|
||||||
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/writers"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginStart="64dp"
|
|
||||||
android:text="@{viewModel.writersString}"
|
|
||||||
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
|
||||||
tools:text="James Cameron, Laeta Kalogridis, Yukito Kishiro" />
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/description"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginHorizontal="24dp"
|
|
||||||
android:layout_marginBottom="24dp"
|
|
||||||
android:text="@{viewModel.item.overview}"
|
|
||||||
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
|
|
||||||
tools:text="An angel falls. A warrior rises. When Alita awakens with no memory of who she is in a future world she does not recognize, she is taken in by Ido, a compassionate doctor who realizes that somewhere in this abandoned cyborg shell is the heart and soul of a young woman with an extraordinary past." />
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginBottom="24dp"
|
|
||||||
android:orientation="vertical"
|
|
||||||
android:visibility="@{viewModel.nextUp != null ? View.VISIBLE : View.GONE}">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginHorizontal="24dp"
|
|
||||||
android:layout_marginBottom="12dp"
|
|
||||||
android:text="@string/next_up"
|
|
||||||
android:textAppearance="@style/TextAppearance.MaterialComponents.Subtitle1"
|
|
||||||
android:textSize="18sp" />
|
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:id="@+id/next_up"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginHorizontal="24dp"
|
android:layout_marginHorizontal="24dp"
|
||||||
android:foreground="?attr/selectableItemBackground"
|
android:layout_marginBottom="16dp">
|
||||||
|
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/year"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginEnd="8dp"
|
||||||
|
android:text="@{viewModel.dateString}"
|
||||||
|
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
|
||||||
|
tools:text="2019" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/playtime"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginEnd="8dp"
|
||||||
|
android:text="@{viewModel.runTime}"
|
||||||
|
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
|
||||||
|
tools:text="122 min" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/official_rating"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginEnd="8dp"
|
||||||
|
android:text="@{viewModel.item.officialRating}"
|
||||||
|
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
|
||||||
|
tools:text="PG-13" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/community_rating"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:drawablePadding="4dp"
|
||||||
|
android:gravity="bottom"
|
||||||
|
android:text="@{viewModel.item.communityRating.toString()}"
|
||||||
|
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
|
||||||
|
app:drawableStartCompat="@drawable/ic_star"
|
||||||
|
app:drawableTint="@color/yellow"
|
||||||
|
tools:text="7.3" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginHorizontal="24dp"
|
||||||
|
android:layout_marginBottom="24dp">
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/play_button"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginEnd="12dp"
|
||||||
|
android:background="@drawable/button_setup_background"
|
||||||
|
android:contentDescription="@string/play_button_description"
|
||||||
|
android:paddingHorizontal="24dp"
|
||||||
|
android:paddingVertical="12dp"
|
||||||
|
android:src="@drawable/ic_play" />
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/trailer_button"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginEnd="12dp"
|
||||||
|
android:background="@drawable/button_accent_background"
|
||||||
|
android:contentDescription="@string/trailer_button_description"
|
||||||
|
android:padding="12dp"
|
||||||
|
android:src="@drawable/ic_film" />
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/check_button"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginEnd="12dp"
|
||||||
|
android:background="@drawable/button_accent_background"
|
||||||
|
android:contentDescription="@string/check_button_description"
|
||||||
|
android:padding="12dp"
|
||||||
|
android:src="@drawable/ic_check" />
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/favorite_button"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="@drawable/button_accent_background"
|
||||||
|
android:contentDescription="@string/favorite_button_description"
|
||||||
|
android:padding="12dp"
|
||||||
|
android:src="@drawable/ic_heart" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/info"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginHorizontal="24dp"
|
||||||
|
android:layout_marginBottom="12dp"
|
||||||
android:orientation="vertical">
|
android:orientation="vertical">
|
||||||
|
|
||||||
<com.google.android.material.imageview.ShapeableImageView
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
android:id="@+id/genres_layout"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginBottom="8dp"
|
android:layout_marginBottom="12dp"
|
||||||
android:adjustViewBounds="true"
|
android:visibility="@{viewModel.item.genres.size() < 1 ? View.GONE : View.VISIBLE}">
|
||||||
app:itemPrimaryImage="@{viewModel.nextUp}"
|
|
||||||
app:shapeAppearance="@style/roundedImageView" />
|
<TextView
|
||||||
|
android:id="@+id/genres_title"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/genres"
|
||||||
|
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/genres"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="64dp"
|
||||||
|
android:text="@{viewModel.genresString}"
|
||||||
|
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
tools:text="Action, Science Fiction, Adventure" />
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
android:id="@+id/director_layout"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="12dp"
|
||||||
|
android:visibility="@{viewModel.director == null ? View.GONE : View.VISIBLE}">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/director_title"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/director"
|
||||||
|
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/director"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="64dp"
|
||||||
|
android:text="@{viewModel.director.name}"
|
||||||
|
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
tools:text="Robert Rodriguez" />
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
android:id="@+id/writers_layout"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="12dp"
|
||||||
|
android:visibility="@{viewModel.writers.size() < 1 ? View.GONE : View.VISIBLE}">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/writers_title"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/writers"
|
||||||
|
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/writers"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="64dp"
|
||||||
|
android:text="@{viewModel.writersString}"
|
||||||
|
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
tools:text="James Cameron, Laeta Kalogridis, Yukito Kishiro" />
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/description"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginHorizontal="24dp"
|
||||||
|
android:layout_marginBottom="24dp"
|
||||||
|
android:text="@{viewModel.item.overview}"
|
||||||
|
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
|
||||||
|
tools:text="An angel falls. A warrior rises. When Alita awakens with no memory of who she is in a future world she does not recognize, she is taken in by Ido, a compassionate doctor who realizes that somewhere in this abandoned cyborg shell is the heart and soul of a young woman with an extraordinary past." />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="24dp"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:visibility="@{viewModel.nextUp != null ? View.VISIBLE : View.GONE}">
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="@{String.format(@string/episode_name_extended, viewModel.nextUp.parentIndexNumber, viewModel.nextUp.indexNumber, viewModel.nextUp.name)}"
|
android:layout_marginHorizontal="24dp"
|
||||||
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
|
android:layout_marginBottom="12dp"
|
||||||
tools:text="The Girl Flautist" />
|
android:text="@string/next_up"
|
||||||
|
android:textAppearance="@style/TextAppearance.MaterialComponents.Subtitle1"
|
||||||
|
android:textSize="18sp" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/next_up"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginHorizontal="24dp"
|
||||||
|
android:foreground="?attr/selectableItemBackground"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<com.google.android.material.imageview.ShapeableImageView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="8dp"
|
||||||
|
android:adjustViewBounds="true"
|
||||||
|
app:itemPrimaryImage="@{viewModel.nextUp}"
|
||||||
|
app:shapeAppearance="@style/roundedImageView" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@{String.format(@string/episode_name_extended, viewModel.nextUp.parentIndexNumber, viewModel.nextUp.indexNumber, viewModel.nextUp.name)}"
|
||||||
|
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
|
||||||
|
tools:text="The Girl Flautist" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="24dp"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:visibility="@{viewModel.seasons != null ? View.VISIBLE : View.GONE}">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginHorizontal="24dp"
|
||||||
|
android:layout_marginBottom="12dp"
|
||||||
|
android:text="@string/seasons"
|
||||||
|
android:textAppearance="@style/TextAppearance.MaterialComponents.Subtitle1"
|
||||||
|
android:textSize="18sp" />
|
||||||
|
|
||||||
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:id="@+id/seasons_recycler_view"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:clipToPadding="false"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:paddingHorizontal="12dp"
|
||||||
|
app:items="@{viewModel.seasons}"
|
||||||
|
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||||
|
tools:itemCount="3"
|
||||||
|
tools:listitem="@layout/base_item" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/actors"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginHorizontal="24dp"
|
||||||
|
android:layout_marginBottom="12dp"
|
||||||
|
android:text="@string/cast_amp_crew"
|
||||||
|
android:textAppearance="@style/TextAppearance.MaterialComponents.Subtitle1"
|
||||||
|
android:textSize="18sp" />
|
||||||
|
|
||||||
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:id="@+id/people_recycler_view"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:clipToPadding="false"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:paddingHorizontal="16dp"
|
||||||
|
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||||
|
app:people="@{viewModel.actors}"
|
||||||
|
tools:itemCount="3"
|
||||||
|
tools:listitem="@layout/person_item" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
</ScrollView>
|
||||||
|
|
||||||
<LinearLayout
|
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginBottom="24dp"
|
|
||||||
android:orientation="vertical"
|
|
||||||
android:visibility="@{viewModel.seasons != null ? View.VISIBLE : View.GONE}">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginHorizontal="24dp"
|
|
||||||
android:layout_marginBottom="12dp"
|
|
||||||
android:text="@string/seasons"
|
|
||||||
android:textAppearance="@style/TextAppearance.MaterialComponents.Subtitle1"
|
|
||||||
android:textSize="18sp" />
|
|
||||||
|
|
||||||
<androidx.recyclerview.widget.RecyclerView
|
|
||||||
android:id="@+id/seasons_recycler_view"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:clipToPadding="false"
|
|
||||||
android:orientation="horizontal"
|
|
||||||
android:paddingHorizontal="12dp"
|
|
||||||
app:items="@{viewModel.seasons}"
|
|
||||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
|
||||||
tools:itemCount="3"
|
|
||||||
tools:listitem="@layout/base_item" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:id="@+id/actors"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:orientation="vertical">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginHorizontal="24dp"
|
|
||||||
android:layout_marginBottom="12dp"
|
|
||||||
android:text="@string/cast_amp_crew"
|
|
||||||
android:textAppearance="@style/TextAppearance.MaterialComponents.Subtitle1"
|
|
||||||
android:textSize="18sp" />
|
|
||||||
|
|
||||||
<androidx.recyclerview.widget.RecyclerView
|
|
||||||
android:id="@+id/people_recycler_view"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:clipToPadding="false"
|
|
||||||
android:orientation="horizontal"
|
|
||||||
android:paddingHorizontal="16dp"
|
|
||||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
|
||||||
app:people="@{viewModel.actors}"
|
|
||||||
tools:itemCount="3"
|
|
||||||
tools:listitem="@layout/person_item" />
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
</ScrollView>
|
|
||||||
|
|
||||||
</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