forked from recloudstream/cloudstream
tv layout stuff
This commit is contained in:
parent
33045c9115
commit
fdaeffed0c
25 changed files with 710 additions and 188 deletions
|
@ -260,10 +260,10 @@ object CommonActivity {
|
|||
KeyEvent.KEYCODE_A, KeyEvent.KEYCODE_MEDIA_SKIP_BACKWARD, KeyEvent.KEYCODE_MEDIA_REWIND -> {
|
||||
PlayerEventType.SeekBack
|
||||
}
|
||||
KeyEvent.KEYCODE_MEDIA_NEXT, KeyEvent.KEYCODE_BUTTON_R1 -> {
|
||||
KeyEvent.KEYCODE_MEDIA_NEXT, KeyEvent.KEYCODE_BUTTON_R1, KeyEvent.KEYCODE_N -> {
|
||||
PlayerEventType.NextEpisode
|
||||
}
|
||||
KeyEvent.KEYCODE_MEDIA_PREVIOUS, KeyEvent.KEYCODE_BUTTON_L1 -> {
|
||||
KeyEvent.KEYCODE_MEDIA_PREVIOUS, KeyEvent.KEYCODE_BUTTON_L1, KeyEvent.KEYCODE_B -> {
|
||||
PlayerEventType.PrevEpisode
|
||||
}
|
||||
KeyEvent.KEYCODE_MEDIA_PAUSE -> {
|
||||
|
@ -294,6 +294,9 @@ object CommonActivity {
|
|||
KeyEvent.KEYCODE_R, KeyEvent.KEYCODE_NUMPAD_0 -> {
|
||||
PlayerEventType.Resize
|
||||
}
|
||||
KeyEvent.KEYCODE_C, KeyEvent.KEYCODE_NUMPAD_4 -> {
|
||||
PlayerEventType.SkipOp
|
||||
}
|
||||
KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE, KeyEvent.KEYCODE_P, KeyEvent.KEYCODE_SPACE, KeyEvent.KEYCODE_NUMPAD_ENTER, KeyEvent.KEYCODE_ENTER -> { // space is not captured due to navigation
|
||||
PlayerEventType.PlayPauseToggle
|
||||
}
|
||||
|
|
|
@ -98,7 +98,7 @@ class ParentItemAdapter(
|
|||
recyclerView?.apply {
|
||||
// this loops every viewHolder in the recycle view and checks the position to see if it is within the update range
|
||||
val missingUpdates = (position until (position + count)).toMutableSet()
|
||||
for (i in 0 until mAdapter.itemCount) {
|
||||
for (i in 0 until itemCount) {
|
||||
val viewHolder = getChildViewHolder(getChildAt(i))
|
||||
val absolutePosition = viewHolder.absoluteAdapterPosition
|
||||
if (absolutePosition >= position && absolutePosition < position + count) {
|
||||
|
|
|
@ -1164,6 +1164,9 @@ open class FullScreenPlayer : AbstractPlayerFragment() {
|
|||
openOnlineSubPicker(view.context, null) {}
|
||||
}
|
||||
}
|
||||
PlayerEventType.SkipOp -> {
|
||||
skipOp()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@ enum class PlayerEventType(val value: Int) {
|
|||
ShowMirrors(12),
|
||||
Resize(13),
|
||||
SearchSubtitlesOnline(14),
|
||||
SkipOp(15),
|
||||
}
|
||||
|
||||
enum class CSPlayerEvent(val value: Int) {
|
||||
|
|
|
@ -57,11 +57,11 @@ const val ACTION_DOWNLOAD_EPISODE_SUBTITLE_MIRROR = 14
|
|||
data class EpisodeClickEvent(val action: Int, val data: ResultEpisode)
|
||||
|
||||
class EpisodeAdapter(
|
||||
private var cardList: MutableList<ResultEpisode>,
|
||||
private val hasDownloadSupport: Boolean,
|
||||
private val clickCallback: (EpisodeClickEvent) -> Unit,
|
||||
private val downloadClickCallback: (DownloadClickEvent) -> Unit,
|
||||
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
||||
private var cardList: MutableList<ResultEpisode> = mutableListOf()
|
||||
|
||||
private val mBoundViewHolders: HashSet<DownloadButtonViewHolder> = HashSet()
|
||||
private fun getAllBoundViewHolders(): Set<DownloadButtonViewHolder?>? {
|
||||
|
@ -104,6 +104,8 @@ class EpisodeAdapter(
|
|||
diffResult.dispatchUpdatesTo(this)
|
||||
}
|
||||
|
||||
var layout = R.layout.result_episode_both
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
||||
/*val layout = if (cardList.filter { it.poster != null }.size >= cardList.size / 2)
|
||||
R.layout.result_episode_large
|
||||
|
@ -111,7 +113,7 @@ class EpisodeAdapter(
|
|||
|
||||
return EpisodeCardViewHolder(
|
||||
LayoutInflater.from(parent.context)
|
||||
.inflate(R.layout.result_episode_both, parent, false),
|
||||
.inflate(layout, parent, false),
|
||||
hasDownloadSupport,
|
||||
clickCallback,
|
||||
downloadClickCallback
|
||||
|
@ -149,6 +151,8 @@ class EpisodeAdapter(
|
|||
fun bind(card: ResultEpisode) {
|
||||
localCard = card
|
||||
|
||||
val isTrueTv = itemView.context?.isTrueTvSettings() == true
|
||||
|
||||
val (parentView, otherView) = if (card.poster == null) {
|
||||
itemView.episode_holder to itemView.episode_holder_large
|
||||
} else {
|
||||
|
@ -199,20 +203,22 @@ class EpisodeAdapter(
|
|||
}
|
||||
}
|
||||
|
||||
episodePoster?.setOnClickListener {
|
||||
clickCallback.invoke(EpisodeClickEvent(ACTION_CLICK_DEFAULT, card))
|
||||
}
|
||||
if (!isTrueTv) {
|
||||
episodePoster?.setOnClickListener {
|
||||
clickCallback.invoke(EpisodeClickEvent(ACTION_CLICK_DEFAULT, card))
|
||||
}
|
||||
|
||||
episodePoster?.setOnLongClickListener {
|
||||
clickCallback.invoke(EpisodeClickEvent(ACTION_SHOW_TOAST, card))
|
||||
return@setOnLongClickListener true
|
||||
episodePoster?.setOnLongClickListener {
|
||||
clickCallback.invoke(EpisodeClickEvent(ACTION_SHOW_TOAST, card))
|
||||
return@setOnLongClickListener true
|
||||
}
|
||||
}
|
||||
|
||||
parentView.setOnClickListener {
|
||||
clickCallback.invoke(EpisodeClickEvent(ACTION_CLICK_DEFAULT, card))
|
||||
}
|
||||
|
||||
if (parentView.context.isTrueTvSettings()) {
|
||||
if (isTrueTv) {
|
||||
parentView.isFocusable = true
|
||||
parentView.isFocusableInTouchMode = true
|
||||
parentView.touchscreenBlocksFocus = false
|
||||
|
|
|
@ -328,6 +328,98 @@ open class ResultFragment : ResultTrailerPlayer() {
|
|||
viewModel.reloadEpisodes()
|
||||
}
|
||||
|
||||
open fun updateMovie(data : ResourceSome<Pair<UiText, ResultEpisode>>) {
|
||||
when (data) {
|
||||
is ResourceSome.Success -> {
|
||||
data.value.let { (text, ep) ->
|
||||
result_play_movie.setText(text)
|
||||
result_play_movie?.setOnClickListener {
|
||||
viewModel.handleAction(
|
||||
activity,
|
||||
EpisodeClickEvent(ACTION_CLICK_DEFAULT, ep)
|
||||
)
|
||||
}
|
||||
result_play_movie?.setOnLongClickListener {
|
||||
viewModel.handleAction(
|
||||
activity,
|
||||
EpisodeClickEvent(ACTION_SHOW_OPTIONS, ep)
|
||||
)
|
||||
return@setOnLongClickListener true
|
||||
}
|
||||
|
||||
main {
|
||||
val file =
|
||||
ioWork {
|
||||
context?.let {
|
||||
VideoDownloadManager.getDownloadFileInfoAndUpdateSettings(
|
||||
it,
|
||||
ep.id
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
downloadButton?.dispose()
|
||||
downloadButton = EasyDownloadButton()
|
||||
downloadButton?.setUpMoreButton(
|
||||
file?.fileLength,
|
||||
file?.totalBytes,
|
||||
result_movie_progress_downloaded,
|
||||
result_movie_download_icon,
|
||||
result_movie_download_text,
|
||||
result_movie_download_text_precentage,
|
||||
result_download_movie,
|
||||
true,
|
||||
VideoDownloadHelper.DownloadEpisodeCached(
|
||||
ep.name,
|
||||
ep.poster,
|
||||
0,
|
||||
null,
|
||||
ep.id,
|
||||
ep.id,
|
||||
null,
|
||||
null,
|
||||
System.currentTimeMillis(),
|
||||
)
|
||||
) { click ->
|
||||
when(click.action) {
|
||||
DOWNLOAD_ACTION_DOWNLOAD -> {
|
||||
viewModel.handleAction(
|
||||
activity,
|
||||
EpisodeClickEvent(ACTION_DOWNLOAD_EPISODE, ep)
|
||||
)
|
||||
}
|
||||
else -> handleDownloadClick(activity, click)
|
||||
}
|
||||
}
|
||||
result_movie_progress_downloaded_holder?.isVisible = true
|
||||
}
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
result_movie_progress_downloaded_holder?.isVisible = false
|
||||
result_play_movie?.isVisible = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
open fun updateEpisodes(episodes : ResourceSome<List<ResultEpisode>>) {
|
||||
when (episodes) {
|
||||
is ResourceSome.None -> {
|
||||
result_episode_loading?.isVisible = false
|
||||
result_episodes?.isVisible = false
|
||||
}
|
||||
is ResourceSome.Loading -> {
|
||||
result_episode_loading?.isVisible = true
|
||||
result_episodes?.isVisible = false
|
||||
}
|
||||
is ResourceSome.Success -> {
|
||||
result_episodes?.isVisible = true
|
||||
result_episode_loading?.isVisible = false
|
||||
(result_episodes?.adapter as? EpisodeAdapter?)?.updateList(episodes.value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("SetTextI18n")
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
@ -401,24 +493,8 @@ open class ResultFragment : ResultTrailerPlayer() {
|
|||
}
|
||||
}
|
||||
|
||||
result_scroll.setOnScrollChangeListener(NestedScrollView.OnScrollChangeListener { _, _, scrollY, _, oldScrollY ->
|
||||
val dy = scrollY - oldScrollY
|
||||
if (dy > 0) { //check for scroll down
|
||||
result_bookmark_fab?.shrink()
|
||||
} else if (dy < -5) {
|
||||
result_bookmark_fab?.extend()
|
||||
}
|
||||
if (!isFullScreenPlayer && player.getIsPlaying()) {
|
||||
if (scrollY > (player_background?.height ?: scrollY)) {
|
||||
player.handleEvent(CSPlayerEvent.Pause)
|
||||
}
|
||||
}
|
||||
//result_poster_blur_holder?.translationY = -scrollY.toFloat()
|
||||
})
|
||||
|
||||
result_episodes.adapter =
|
||||
EpisodeAdapter(
|
||||
ArrayList(),
|
||||
api.hasDownloadSupport,
|
||||
{ episodeClick ->
|
||||
viewModel.handleAction(activity, episodeClick)
|
||||
|
@ -456,9 +532,10 @@ open class ResultFragment : ResultTrailerPlayer() {
|
|||
}
|
||||
|
||||
// This is to band-aid FireTV navigation
|
||||
result_season_button?.isFocusableInTouchMode = context?.isTvSettings() == true
|
||||
result_episode_select?.isFocusableInTouchMode = context?.isTvSettings() == true
|
||||
result_dub_select?.isFocusableInTouchMode = context?.isTvSettings() == true
|
||||
val isTv = context?.isTvSettings() == true
|
||||
result_season_button?.isFocusableInTouchMode = isTv
|
||||
result_episode_select?.isFocusableInTouchMode = isTv
|
||||
result_dub_select?.isFocusableInTouchMode = isTv
|
||||
|
||||
context?.let { ctx ->
|
||||
val arrayAdapter = ArrayAdapter<String>(ctx, R.layout.sort_bottom_single_choice)
|
||||
|
@ -653,21 +730,7 @@ open class ResultFragment : ResultTrailerPlayer() {
|
|||
}
|
||||
|
||||
observe(viewModel.episodes) { episodes ->
|
||||
when (episodes) {
|
||||
is ResourceSome.None -> {
|
||||
result_episode_loading?.isVisible = false
|
||||
result_episodes?.isVisible = false
|
||||
}
|
||||
is ResourceSome.Loading -> {
|
||||
result_episode_loading?.isVisible = true
|
||||
result_episodes?.isVisible = false
|
||||
}
|
||||
is ResourceSome.Success -> {
|
||||
result_episodes?.isVisible = true
|
||||
result_episode_loading?.isVisible = false
|
||||
(result_episodes?.adapter as? EpisodeAdapter?)?.updateList(episodes.value)
|
||||
}
|
||||
}
|
||||
updateEpisodes(episodes)
|
||||
}
|
||||
|
||||
result_cast_items?.setOnFocusChangeListener { _, hasFocus ->
|
||||
|
@ -692,77 +755,7 @@ open class ResultFragment : ResultTrailerPlayer() {
|
|||
}
|
||||
|
||||
observe(viewModel.movie) { data ->
|
||||
when (data) {
|
||||
is ResourceSome.Success -> {
|
||||
data.value.let { (text, ep) ->
|
||||
result_play_movie.setText(text)
|
||||
result_play_movie?.setOnClickListener {
|
||||
viewModel.handleAction(
|
||||
activity,
|
||||
EpisodeClickEvent(ACTION_CLICK_DEFAULT, ep)
|
||||
)
|
||||
}
|
||||
result_play_movie?.setOnLongClickListener {
|
||||
viewModel.handleAction(
|
||||
activity,
|
||||
EpisodeClickEvent(ACTION_SHOW_OPTIONS, ep)
|
||||
)
|
||||
return@setOnLongClickListener true
|
||||
}
|
||||
|
||||
main {
|
||||
val file =
|
||||
ioWork {
|
||||
context?.let {
|
||||
VideoDownloadManager.getDownloadFileInfoAndUpdateSettings(
|
||||
it,
|
||||
ep.id
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
downloadButton?.dispose()
|
||||
downloadButton = EasyDownloadButton()
|
||||
downloadButton?.setUpMoreButton(
|
||||
file?.fileLength,
|
||||
file?.totalBytes,
|
||||
result_movie_progress_downloaded,
|
||||
result_movie_download_icon,
|
||||
result_movie_download_text,
|
||||
result_movie_download_text_precentage,
|
||||
result_download_movie,
|
||||
true,
|
||||
VideoDownloadHelper.DownloadEpisodeCached(
|
||||
ep.name,
|
||||
ep.poster,
|
||||
0,
|
||||
null,
|
||||
ep.id,
|
||||
ep.id,
|
||||
null,
|
||||
null,
|
||||
System.currentTimeMillis(),
|
||||
)
|
||||
) { click ->
|
||||
when(click.action) {
|
||||
DOWNLOAD_ACTION_DOWNLOAD -> {
|
||||
viewModel.handleAction(
|
||||
activity,
|
||||
EpisodeClickEvent(ACTION_DOWNLOAD_EPISODE, ep)
|
||||
)
|
||||
}
|
||||
else -> handleDownloadClick(activity, click)
|
||||
}
|
||||
}
|
||||
result_movie_progress_downloaded_holder?.isVisible = true
|
||||
}
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
result_movie_progress_downloaded_holder?.isVisible = false
|
||||
result_play_movie?.isVisible = false
|
||||
}
|
||||
}
|
||||
updateMovie(data)
|
||||
}
|
||||
|
||||
observe(viewModel.page) { data ->
|
||||
|
|
|
@ -7,6 +7,7 @@ import android.view.View
|
|||
import android.view.ViewGroup
|
||||
import androidx.core.view.isGone
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.core.widget.NestedScrollView
|
||||
import com.discord.panels.OverlappingPanelsLayout
|
||||
import com.discord.panels.PanelsChildGestureRegionObserver
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||
|
@ -18,6 +19,7 @@ import com.lagradost.cloudstream3.SearchResponse
|
|||
import com.lagradost.cloudstream3.mvvm.Some
|
||||
import com.lagradost.cloudstream3.mvvm.observe
|
||||
import com.lagradost.cloudstream3.ui.WatchType
|
||||
import com.lagradost.cloudstream3.ui.player.CSPlayerEvent
|
||||
import com.lagradost.cloudstream3.ui.search.SearchAdapter
|
||||
import com.lagradost.cloudstream3.ui.search.SearchHelper
|
||||
import com.lagradost.cloudstream3.utils.AppUtils.openBrowser
|
||||
|
@ -30,6 +32,7 @@ import com.lagradost.cloudstream3.utils.UIHelper.popupMenuNoIcons
|
|||
import com.lagradost.cloudstream3.utils.UIHelper.popupMenuNoIconsAndNoStringRes
|
||||
import kotlinx.android.synthetic.main.fragment_result.*
|
||||
import kotlinx.android.synthetic.main.fragment_result_swipe.*
|
||||
import kotlinx.android.synthetic.main.fragment_trailer.*
|
||||
import kotlinx.android.synthetic.main.result_recommendations.*
|
||||
import kotlinx.android.synthetic.main.trailer_custom_layout.*
|
||||
|
||||
|
@ -129,10 +132,10 @@ class ResultFragmentPhone : ResultFragment() {
|
|||
context?.openBrowser(it.url)
|
||||
}
|
||||
}
|
||||
result_recommendations?.spanCount = 3
|
||||
result_overlapping_panels?.setStartPanelLockState(OverlappingPanelsLayout.LockState.CLOSE)
|
||||
result_overlapping_panels?.setEndPanelLockState(OverlappingPanelsLayout.LockState.CLOSE)
|
||||
|
||||
result_recommendations?.spanCount = 3
|
||||
result_recommendations?.adapter =
|
||||
SearchAdapter(
|
||||
ArrayList(),
|
||||
|
@ -175,6 +178,21 @@ class ResultFragmentPhone : ResultFragment() {
|
|||
})
|
||||
|
||||
|
||||
result_scroll?.setOnScrollChangeListener(NestedScrollView.OnScrollChangeListener { _, _, scrollY, _, oldScrollY ->
|
||||
val dy = scrollY - oldScrollY
|
||||
if (dy > 0) { //check for scroll down
|
||||
result_bookmark_fab?.shrink()
|
||||
} else if (dy < -5) {
|
||||
result_bookmark_fab?.extend()
|
||||
}
|
||||
if (!isFullScreenPlayer && player.getIsPlaying()) {
|
||||
if (scrollY > (player_background?.height ?: scrollY)) {
|
||||
player.handleEvent(CSPlayerEvent.Pause)
|
||||
}
|
||||
}
|
||||
//result_poster_blur_holder?.translationY = -scrollY.toFloat()
|
||||
})
|
||||
|
||||
observe(viewModel.selectPopup) { popup ->
|
||||
when (popup) {
|
||||
is Some.Success -> {
|
||||
|
|
|
@ -1,11 +1,129 @@
|
|||
package com.lagradost.cloudstream3.ui.result
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import androidx.core.view.children
|
||||
import androidx.core.view.isGone
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.discord.panels.OverlappingPanelsLayout
|
||||
import com.lagradost.cloudstream3.DubStatus
|
||||
import com.lagradost.cloudstream3.R
|
||||
import com.lagradost.cloudstream3.SearchResponse
|
||||
import com.lagradost.cloudstream3.mvvm.ResourceSome
|
||||
import com.lagradost.cloudstream3.mvvm.observe
|
||||
import com.lagradost.cloudstream3.ui.search.SearchAdapter
|
||||
import com.lagradost.cloudstream3.ui.search.SearchHelper
|
||||
import com.lagradost.cloudstream3.utils.SingleSelectionHelper.showBottomDialog
|
||||
import kotlinx.android.synthetic.main.fragment_result_swipe.*
|
||||
import kotlinx.android.synthetic.main.fragment_result_tv.*
|
||||
import kotlinx.android.synthetic.main.result_recommendations.*
|
||||
|
||||
class ResultFragmentTv : ResultFragment() {
|
||||
override val resultLayout = R.layout.fragment_result_tv
|
||||
override fun setRecommendations(rec: List<SearchResponse>?, validApiName: String?) {
|
||||
|
||||
private fun handleSelection(data: Any) {
|
||||
when (data) {
|
||||
is EpisodeRange -> {
|
||||
viewModel.changeRange(data)
|
||||
}
|
||||
is Int -> {
|
||||
viewModel.changeSeason(data)
|
||||
}
|
||||
is DubStatus -> {
|
||||
viewModel.changeDubStatus(data)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun RecyclerView?.select(index: Int) {
|
||||
(this?.adapter as? SelectAdaptor?)?.select(index, this)
|
||||
}
|
||||
|
||||
private fun RecyclerView?.update(data: List<SelectData>) {
|
||||
(this?.adapter as? SelectAdaptor?)?.updateSelectionList(data)
|
||||
this?.isVisible = data.size > 1
|
||||
}
|
||||
|
||||
private fun RecyclerView?.setAdapter() {
|
||||
this?.adapter = SelectAdaptor { data ->
|
||||
handleSelection(data)
|
||||
}
|
||||
}
|
||||
|
||||
private fun hasNoFocus(): Boolean {
|
||||
val focus = activity?.currentFocus
|
||||
if (focus == null || !focus.isVisible) return true
|
||||
return focus == this.result_root
|
||||
}
|
||||
|
||||
override fun updateEpisodes(episodes: ResourceSome<List<ResultEpisode>>) {
|
||||
super.updateEpisodes(episodes)
|
||||
if (episodes is ResourceSome.Success && hasNoFocus()) {
|
||||
result_episodes?.requestFocus()
|
||||
}
|
||||
}
|
||||
|
||||
override fun updateMovie(data: ResourceSome<Pair<UiText, ResultEpisode>>) {
|
||||
super.updateMovie(data)
|
||||
if (data is ResourceSome.Success && hasNoFocus()) {
|
||||
result_play_movie?.requestFocus()
|
||||
}
|
||||
}
|
||||
|
||||
override fun setRecommendations(rec: List<SearchResponse>?, validApiName: String?) {
|
||||
val isInvalid = rec.isNullOrEmpty()
|
||||
result_recommendations?.isGone = isInvalid
|
||||
result_recommendations_btt?.isGone = isInvalid
|
||||
val matchAgainst = validApiName ?: rec?.firstOrNull()?.apiName
|
||||
(result_recommendations?.adapter as SearchAdapter?)?.updateList(rec?.filter { it.apiName == matchAgainst } ?: emptyList())
|
||||
|
||||
rec?.map { it.apiName }?.distinct()?.let { apiNames ->
|
||||
// very dirty selection
|
||||
result_recommendations_filter_button?.isVisible = apiNames.size > 1
|
||||
result_recommendations_filter_button?.text = matchAgainst
|
||||
|
||||
} ?: run {
|
||||
result_recommendations_filter_button?.isVisible = false
|
||||
}
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
(result_episodes?.adapter as EpisodeAdapter?)?.apply {
|
||||
layout = R.layout.result_episode_both_tv
|
||||
}
|
||||
|
||||
result_season_selection.setAdapter()
|
||||
result_range_selection.setAdapter()
|
||||
result_dub_selection.setAdapter()
|
||||
|
||||
observe(viewModel.selectedRangeIndex) { selected ->
|
||||
result_range_selection.select(selected)
|
||||
}
|
||||
observe(viewModel.selectedSeasonIndex) { selected ->
|
||||
result_season_selection.select(selected)
|
||||
}
|
||||
observe(viewModel.selectedDubStatusIndex) { selected ->
|
||||
result_dub_selection.select(selected)
|
||||
}
|
||||
observe(viewModel.rangeSelections) {
|
||||
result_range_selection.update(it)
|
||||
}
|
||||
observe(viewModel.dubSubSelections) {
|
||||
result_dub_selection.update(it)
|
||||
}
|
||||
observe(viewModel.seasonSelections) {
|
||||
result_season_selection.update(it)
|
||||
}
|
||||
|
||||
result_recommendations?.spanCount = 8
|
||||
result_recommendations?.adapter =
|
||||
SearchAdapter(
|
||||
ArrayList(),
|
||||
result_recommendations,
|
||||
) { callback ->
|
||||
SearchHelper.handleSearchClickCallback(activity, callback)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -57,6 +57,7 @@ import com.lagradost.cloudstream3.utils.UIHelper.navigate
|
|||
import com.lagradost.cloudstream3.utils.UIHelper.requestRW
|
||||
import kotlinx.coroutines.*
|
||||
import java.io.File
|
||||
import java.lang.Math.abs
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
|
||||
|
@ -311,8 +312,8 @@ class ResultViewModel2 : ViewModel() {
|
|||
/** map<dub, map<season, List<episode>>> */
|
||||
private var currentEpisodes: Map<EpisodeIndexer, List<ResultEpisode>> = mapOf()
|
||||
private var currentRanges: Map<EpisodeIndexer, List<EpisodeRange>> = mapOf()
|
||||
private var currentSeasons: Set<Int> = setOf()
|
||||
private var currentDubStatus: Set<DubStatus> = setOf()
|
||||
private var currentSeasons: List<Int> = listOf()
|
||||
private var currentDubStatus: List<DubStatus> = listOf()
|
||||
private var currentMeta: SyncAPI.SyncResult? = null
|
||||
private var currentSync: Map<String, String>? = null
|
||||
private var currentIndex: EpisodeIndexer? = null
|
||||
|
@ -376,6 +377,18 @@ class ResultViewModel2 : ViewModel() {
|
|||
private val _selectedDubStatus: MutableLiveData<Some<UiText>> = MutableLiveData(Some.None)
|
||||
val selectedDubStatus: LiveData<Some<UiText>> = _selectedDubStatus
|
||||
|
||||
private val _selectedRangeIndex: MutableLiveData<Int> =
|
||||
MutableLiveData(-1)
|
||||
val selectedRangeIndex: LiveData<Int> = _selectedRangeIndex
|
||||
|
||||
private val _selectedSeasonIndex: MutableLiveData<Int> =
|
||||
MutableLiveData(-1)
|
||||
val selectedSeasonIndex: LiveData<Int> = _selectedSeasonIndex
|
||||
|
||||
private val _selectedDubStatusIndex: MutableLiveData<Int> = MutableLiveData(-1)
|
||||
val selectedDubStatusIndex: LiveData<Int> = _selectedDubStatusIndex
|
||||
|
||||
|
||||
private val _loadedLinks: MutableLiveData<Some<LinkProgress>> = MutableLiveData(Some.None)
|
||||
val loadedLinks: LiveData<Some<LinkProgress>> = _loadedLinks
|
||||
|
||||
|
@ -1414,6 +1427,16 @@ class ResultViewModel2 : ViewModel() {
|
|||
|
||||
val episodes = currentEpisodes[indexer]
|
||||
val ranges = currentRanges[indexer]
|
||||
|
||||
if (ranges?.contains(range) != true) {
|
||||
// if the current ranges does not include the range then select the range with the closest matching start episode
|
||||
// this usually happends when dub has less episodes then sub -> the range does not exist
|
||||
ranges?.minByOrNull { abs(it.startEpisode - range.startEpisode) }?.let { r ->
|
||||
postEpisodeRange(indexer, r)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
val size = episodes?.size
|
||||
val isMovie = currentResponse?.isMovie() == true
|
||||
currentIndex = indexer
|
||||
|
@ -1435,6 +1458,10 @@ class ResultViewModel2 : ViewModel() {
|
|||
)
|
||||
)
|
||||
|
||||
_selectedSeasonIndex.postValue(
|
||||
currentSeasons.indexOf(indexer.season)
|
||||
)
|
||||
|
||||
_selectedSeason.postValue(
|
||||
some(
|
||||
if (isMovie || currentSeasons.size <= 1) null else
|
||||
|
@ -1449,6 +1476,10 @@ class ResultViewModel2 : ViewModel() {
|
|||
)
|
||||
)
|
||||
|
||||
_selectedRangeIndex.postValue(
|
||||
ranges?.indexOf(range) ?: -1
|
||||
)
|
||||
|
||||
_selectedRange.postValue(
|
||||
some(
|
||||
if (isMovie) null else if ((currentRanges[indexer]?.size ?: 0) > 1) {
|
||||
|
@ -1458,6 +1489,11 @@ class ResultViewModel2 : ViewModel() {
|
|||
}
|
||||
)
|
||||
)
|
||||
|
||||
_selectedDubStatusIndex.postValue(
|
||||
currentDubStatus.indexOf(indexer.dubStatus)
|
||||
)
|
||||
|
||||
_selectedDubStatus.postValue(
|
||||
some(
|
||||
if (isMovie || currentDubStatus.size <= 1) null else
|
||||
|
@ -1487,6 +1523,12 @@ class ResultViewModel2 : ViewModel() {
|
|||
postMovie()
|
||||
} else {
|
||||
val ret = getEpisodes(indexer, range)
|
||||
/*if (ret.isEmpty()) {
|
||||
val index = ranges?.indexOf(range)
|
||||
if(index != null && index > 0) {
|
||||
|
||||
}
|
||||
}*/
|
||||
_episodes.postValue(ResourceSome.Success(ret))
|
||||
}
|
||||
}
|
||||
|
@ -1675,8 +1717,8 @@ class ResultViewModel2 : ViewModel() {
|
|||
seasonsSelection += key.season
|
||||
dubSelection += key.dubStatus
|
||||
}
|
||||
currentDubStatus = dubSelection
|
||||
currentSeasons = seasonsSelection
|
||||
currentDubStatus = dubSelection.toList()
|
||||
currentSeasons = seasonsSelection.toList()
|
||||
_dubSubSelections.postValue(dubSelection.map { txt(it) to it })
|
||||
if (loadResponse is EpisodeResponse) {
|
||||
_seasonSelections.postValue(seasonsSelection.map { seasonNumber ->
|
||||
|
|
|
@ -0,0 +1,121 @@
|
|||
package com.lagradost.cloudstream3.ui.result
|
||||
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.ImageView
|
||||
import android.widget.TextView
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.recyclerview.widget.DiffUtil
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.google.android.material.button.MaterialButton
|
||||
import com.lagradost.cloudstream3.ActorData
|
||||
import com.lagradost.cloudstream3.ActorRole
|
||||
import com.lagradost.cloudstream3.R
|
||||
import com.lagradost.cloudstream3.ui.home.ParentItemAdapter
|
||||
import com.lagradost.cloudstream3.ui.settings.AccountAdapter
|
||||
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTrueTvSettings
|
||||
import com.lagradost.cloudstream3.utils.UIHelper.setImage
|
||||
import kotlinx.android.synthetic.main.cast_item.view.*
|
||||
import org.schabi.newpipe.extractor.timeago.patterns.it
|
||||
|
||||
typealias SelectData = Pair<UiText?, Any>
|
||||
|
||||
class SelectAdaptor(val callback: (Any) -> Unit) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
||||
private val selection: MutableList<SelectData> = mutableListOf()
|
||||
private var selectedIndex: Int = -1
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
||||
return SelectViewHolder(
|
||||
LayoutInflater.from(parent.context).inflate(R.layout.result_selection, parent, false),
|
||||
)
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
|
||||
when (holder) {
|
||||
is SelectViewHolder -> {
|
||||
holder.bind(selection[position], position == selectedIndex, callback)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int {
|
||||
return selection.size
|
||||
}
|
||||
|
||||
fun select(newIndex: Int, recyclerView: RecyclerView?) {
|
||||
if(recyclerView == null) return
|
||||
if(newIndex == selectedIndex) return
|
||||
val oldIndex = selectedIndex
|
||||
selectedIndex = newIndex
|
||||
recyclerView.apply {
|
||||
for (i in 0 until itemCount) {
|
||||
val viewHolder = getChildViewHolder( getChildAt(i) ?: continue) ?: continue
|
||||
val pos = viewHolder.absoluteAdapterPosition
|
||||
if (viewHolder is SelectViewHolder) {
|
||||
if (pos == oldIndex) {
|
||||
viewHolder.update(false)
|
||||
} else if (pos == newIndex) {
|
||||
viewHolder.update(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun updateSelectionList(newList: List<SelectData>) {
|
||||
val diffResult = DiffUtil.calculateDiff(
|
||||
SelectDataCallback(this.selection, newList)
|
||||
)
|
||||
|
||||
selection.clear()
|
||||
selection.addAll(newList)
|
||||
|
||||
diffResult.dispatchUpdatesTo(this)
|
||||
}
|
||||
|
||||
|
||||
private class SelectViewHolder
|
||||
constructor(
|
||||
itemView: View,
|
||||
) :
|
||||
RecyclerView.ViewHolder(itemView) {
|
||||
private val item: MaterialButton = itemView as MaterialButton
|
||||
|
||||
fun update(isSelected: Boolean) {
|
||||
item.isSelected = isSelected
|
||||
}
|
||||
|
||||
fun bind(
|
||||
data: SelectData, isSelected: Boolean, callback: (Any) -> Unit
|
||||
) {
|
||||
val isTrueTv = itemView.context?.isTrueTvSettings() == true
|
||||
if (isTrueTv) {
|
||||
item.isFocusable = true
|
||||
item.isFocusableInTouchMode = true
|
||||
}
|
||||
|
||||
item.isSelected = isSelected
|
||||
item.setText(data.first)
|
||||
item.setOnClickListener {
|
||||
callback.invoke(data.second)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class SelectDataCallback(
|
||||
private val oldList: List<SelectData>,
|
||||
private val newList: List<SelectData>
|
||||
) :
|
||||
DiffUtil.Callback() {
|
||||
override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int) =
|
||||
oldList[oldItemPosition].second == newList[newItemPosition].second
|
||||
|
||||
override fun getOldListSize() = oldList.size
|
||||
|
||||
override fun getNewListSize() = newList.size
|
||||
|
||||
override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int) =
|
||||
oldList[oldItemPosition] == newList[newItemPosition]
|
||||
}
|
|
@ -44,6 +44,7 @@ import com.lagradost.cloudstream3.isMovieType
|
|||
import com.lagradost.cloudstream3.mapper
|
||||
import com.lagradost.cloudstream3.mvvm.logError
|
||||
import com.lagradost.cloudstream3.ui.result.ResultFragment
|
||||
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTrueTvSettings
|
||||
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTvSettings
|
||||
import com.lagradost.cloudstream3.utils.AppUtils.loadResult
|
||||
import com.lagradost.cloudstream3.utils.Coroutines.ioSafe
|
||||
|
@ -316,12 +317,11 @@ object AppUtils {
|
|||
//private val viewModel: ResultViewModel by activityViewModels()
|
||||
|
||||
private fun getResultsId(context: Context) : Int {
|
||||
return R.id.global_to_navigation_results_phone
|
||||
//return if(context.isTvSettings()) {
|
||||
// R.id.global_to_navigation_results_tv
|
||||
//} else {
|
||||
// R.id.global_to_navigation_results_phone
|
||||
//}
|
||||
return if(context.isTrueTvSettings()) {
|
||||
R.id.global_to_navigation_results_tv
|
||||
} else {
|
||||
R.id.global_to_navigation_results_phone
|
||||
}
|
||||
}
|
||||
|
||||
fun AppCompatActivity.loadResult(
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:color="?attr/textColor"/>
|
||||
<item android:state_focused="true" android:color="?attr/iconGrayBackground"/>
|
||||
<item android:state_selected="true" android:color="?attr/iconGrayBackground" />
|
||||
<item android:color="?attr/textColor" />
|
||||
</selector>
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:state_focused="true" android:color="?attr/textColor"/>
|
||||
<item android:state_selected="true" android:color="?attr/textColor"/>
|
||||
<item android:color="?attr/iconGrayBackground"/>
|
||||
</selector>
|
4
app/src/main/res/drawable/outline_drawable_less.xml
Normal file
4
app/src/main/res/drawable/outline_drawable_less.xml
Normal file
|
@ -0,0 +1,4 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:state_focused="true" android:drawable="@drawable/outline_less" /> <!-- focused -->
|
||||
</selector>
|
10
app/src/main/res/drawable/outline_less.xml
Normal file
10
app/src/main/res/drawable/outline_less.xml
Normal file
|
@ -0,0 +1,10 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android" >
|
||||
<stroke android:width="2dp"
|
||||
android:color="?attr/white"/>
|
||||
<corners
|
||||
android:bottomLeftRadius="@dimen/rounded_button_radius"
|
||||
android:bottomRightRadius="@dimen/rounded_button_radius"
|
||||
android:topLeftRadius="@dimen/rounded_button_radius"
|
||||
android:topRightRadius="@dimen/rounded_button_radius" />
|
||||
</shape>
|
|
@ -6,9 +6,7 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
style="@style/DarkFragment"
|
||||
android:background="?attr/primaryBlackBackground"
|
||||
android:clickable="true"
|
||||
android:focusable="true">
|
||||
android:background="?attr/primaryBlackBackground">
|
||||
|
||||
<com.facebook.shimmer.ShimmerFrameLayout
|
||||
android:id="@+id/result_loading"
|
||||
|
@ -271,7 +269,7 @@
|
|||
tools:text="Cast: Joe Ligma" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
tools:visibility="gone"
|
||||
tools:visibility="visible"
|
||||
android:nextFocusUp="@id/result_bookmark_button"
|
||||
android:nextFocusDown="@id/result_play_movie"
|
||||
|
||||
|
@ -305,6 +303,7 @@
|
|||
android:textColor="?attr/grayTextColor"
|
||||
android:textSize="15sp"
|
||||
tools:text="@string/provider_info_meta" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/result_no_episodes"
|
||||
android:layout_width="match_parent"
|
||||
|
@ -373,6 +372,10 @@
|
|||
tools:visibility="visible">
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:nextFocusRight="@id/result_download_movie"
|
||||
android:nextFocusUp="@id/result_cast_items"
|
||||
android:nextFocusDown="@id/result_resume_series_button_play"
|
||||
|
||||
android:id="@+id/result_play_movie"
|
||||
style="@style/WhiteButton"
|
||||
android:layout_width="0dp"
|
||||
|
@ -381,14 +384,10 @@
|
|||
android:layout_marginStart="0dp"
|
||||
android:layout_marginEnd="5dp"
|
||||
android:layout_marginBottom="10dp"
|
||||
android:nextFocusUp="@id/result_bookmark_button"
|
||||
android:nextFocusDown="@id/result_download_movie"
|
||||
android:text="@string/play_movie_button"
|
||||
android:visibility="visible"
|
||||
app:icon="@drawable/ic_baseline_play_arrow_24">
|
||||
|
||||
<requestFocus />
|
||||
|
||||
</com.google.android.material.button.MaterialButton>
|
||||
|
||||
|
||||
|
@ -400,6 +399,10 @@
|
|||
android:layout_height="wrap_content">
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:nextFocusLeft="@id/result_play_movie"
|
||||
android:nextFocusUp="@id/result_cast_items"
|
||||
android:nextFocusDown="@id/result_resume_series_button_play"
|
||||
|
||||
android:id="@+id/result_download_movie"
|
||||
style="@style/BlackButton"
|
||||
|
||||
|
@ -410,8 +413,6 @@
|
|||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
|
||||
android:nextFocusUp="@id/result_play_movie"
|
||||
android:nextFocusDown="@id/result_season_button"
|
||||
android:visibility="visible" />
|
||||
|
||||
<LinearLayout
|
||||
|
@ -508,8 +509,10 @@
|
|||
android:layout_height="wrap_content">
|
||||
|
||||
<ImageView
|
||||
android:layout_marginEnd="10dp"
|
||||
android:id="@+id/result_resume_series_button_play"
|
||||
android:nextFocusUp="@id/result_play_movie"
|
||||
android:nextFocusDown="@id/result_season_selection"
|
||||
|
||||
android:layout_width="30dp"
|
||||
android:layout_height="30dp"
|
||||
android:layout_gravity="center"
|
||||
|
@ -522,6 +525,8 @@
|
|||
|
||||
|
||||
<TextView
|
||||
android:paddingStart="10dp"
|
||||
android:paddingEnd="10dp"
|
||||
android:layout_gravity="center"
|
||||
android:gravity="center"
|
||||
android:id="@+id/result_resume_series_title"
|
||||
|
@ -540,7 +545,6 @@
|
|||
android:layout_gravity="center"
|
||||
android:layout_weight="0"
|
||||
android:gravity="center"
|
||||
android:paddingStart="10dp"
|
||||
android:textColor="?attr/grayTextColor"
|
||||
tools:ignore="RtlSymmetry"
|
||||
tools:text="69m remaining" />
|
||||
|
@ -574,42 +578,46 @@
|
|||
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/result_episodes_tab"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:paddingBottom="10dp"
|
||||
android:nextFocusUp="@id/result_resume_series_button_play"
|
||||
android:nextFocusDown="@id/result_range_selection"
|
||||
android:id="@+id/result_season_selection"
|
||||
|
||||
android:paddingBottom="10dp"
|
||||
tools:listitem="@layout/result_selection"
|
||||
android:orientation="horizontal"
|
||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content">
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
</androidx.recyclerview.widget.RecyclerView>
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:paddingBottom="10dp"
|
||||
android:nextFocusUp="@id/result_season_selection"
|
||||
android:nextFocusDown="@id/result_dub_selection"
|
||||
android:id="@+id/result_range_selection"
|
||||
tools:listitem="@layout/result_selection"
|
||||
android:orientation="horizontal"
|
||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content">
|
||||
</androidx.recyclerview.widget.RecyclerView>
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:paddingBottom="10dp"
|
||||
android:id="@+id/result_dub_selection"
|
||||
tools:listitem="@layout/result_selection"
|
||||
android:orientation="horizontal"
|
||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
</androidx.recyclerview.widget.RecyclerView>
|
||||
android:paddingBottom="10dp"
|
||||
tools:listitem="@layout/result_selection"
|
||||
android:orientation="horizontal"
|
||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:nextFocusUp="@id/result_range_selection"
|
||||
android:nextFocusDown="@id/result_episodes"
|
||||
android:id="@+id/result_dub_selection"
|
||||
|
||||
android:paddingBottom="10dp"
|
||||
tools:listitem="@layout/result_selection"
|
||||
android:orientation="horizontal"
|
||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/result_next_airing_holder"
|
||||
|
@ -643,6 +651,7 @@
|
|||
</LinearLayout>
|
||||
|
||||
<com.facebook.shimmer.ShimmerFrameLayout
|
||||
tools:visibility="gone"
|
||||
android:id="@+id/result_episode_loading"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
|
@ -652,8 +661,7 @@
|
|||
app:shimmer_auto_start="true"
|
||||
app:shimmer_base_alpha="0.2"
|
||||
app:shimmer_duration="@integer/loading_time"
|
||||
app:shimmer_highlight_alpha="0.3"
|
||||
tools:visibility="visible">
|
||||
app:shimmer_highlight_alpha="0.3">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
|
@ -678,22 +686,21 @@
|
|||
android:layout_height="50dp" />-->
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:nextFocusUp="@id/result_dub_selection"
|
||||
android:id="@+id/result_episodes"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="0dp"
|
||||
android:clipToPadding="false"
|
||||
android:orientation="horizontal"
|
||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||
android:descendantFocusability="afterDescendants"
|
||||
android:paddingBottom="100dp"
|
||||
tools:listitem="@layout/result_episode" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
<include layout="@layout/result_recommendations" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
</androidx.core.widget.NestedScrollView>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</FrameLayout>
|
|
@ -2,8 +2,6 @@
|
|||
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
|
||||
android:nextFocusLeft="@id/result_episode_download"
|
||||
android:nextFocusRight="@id/result_episode_download"
|
||||
|
||||
android:id="@+id/episode_holder"
|
||||
|
@ -15,6 +13,10 @@
|
|||
app:cardElevation="0dp"
|
||||
android:foreground="@drawable/outline_drawable"
|
||||
android:layout_marginBottom="5dp">
|
||||
<!--
|
||||
android:nextFocusLeft="@id/result_episode_download"
|
||||
-->
|
||||
|
||||
<!-- IDK BUT THIS DOES NOT SEAM LIKE A GOOD WAY OF DOING IT -->
|
||||
<!--<LinearLayout
|
||||
android:layout_width="fill_parent"
|
||||
|
@ -110,9 +112,10 @@
|
|||
android:progress="0"
|
||||
android:visibility="visible" />
|
||||
|
||||
<!--
|
||||
android:nextFocusRight="@id/episode_holder"-->
|
||||
<ImageView
|
||||
android:nextFocusLeft="@id/episode_holder"
|
||||
android:nextFocusRight="@id/episode_holder"
|
||||
app:tint="?attr/white"
|
||||
android:id="@+id/result_episode_download"
|
||||
android:visibility="visible"
|
||||
|
|
|
@ -4,5 +4,5 @@
|
|||
android:layout_height="wrap_content">
|
||||
|
||||
<include android:visibility="gone" layout="@layout/result_episode" />
|
||||
<include android:visibility="gone" layout="@layout/result_episode_large" />
|
||||
<include android:visibility="visible" layout="@layout/result_episode_large" />
|
||||
</FrameLayout>
|
20
app/src/main/res/layout/result_episode_both_tv.xml
Normal file
20
app/src/main/res/layout/result_episode_both_tv.xml
Normal file
|
@ -0,0 +1,20 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
|
||||
<include
|
||||
tools:visibility="visible"
|
||||
android:visibility="gone"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="50dp"
|
||||
layout="@layout/result_episode_tv" />
|
||||
|
||||
<include
|
||||
tools:visibility="gone"
|
||||
android:visibility="gone"
|
||||
android:layout_width="450dp"
|
||||
android:layout_height="wrap_content"
|
||||
layout="@layout/result_episode_large_tv" />
|
||||
</FrameLayout>
|
|
@ -3,11 +3,10 @@
|
|||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
|
||||
android:nextFocusLeft="@id/episode_poster"
|
||||
android:nextFocusRight="@id/result_episode_download"
|
||||
android:id="@+id/episode_holder_large"
|
||||
|
||||
android:layout_width="match_parent"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:cardCornerRadius="@dimen/rounded_image_radius"
|
||||
app:cardBackgroundColor="?attr/boxItemBackground"
|
||||
|
@ -19,7 +18,7 @@
|
|||
android:foreground="?android:attr/selectableItemBackgroundBorderless"
|
||||
android:padding="10dp"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<LinearLayout
|
||||
|
@ -33,8 +32,7 @@
|
|||
android:foreground="@drawable/outline_drawable">
|
||||
|
||||
<ImageView
|
||||
android:nextFocusLeft="@id/result_episode_download"
|
||||
android:nextFocusRight="@id/episode_holder"
|
||||
android:nextFocusRight="@id/result_episode_download"
|
||||
|
||||
android:id="@+id/episode_poster"
|
||||
tools:src="@drawable/example_poster"
|
||||
|
@ -126,7 +124,6 @@
|
|||
|
||||
<ImageView
|
||||
android:nextFocusLeft="@id/episode_poster"
|
||||
android:nextFocusRight="@id/episode_holder"
|
||||
android:id="@+id/result_episode_download"
|
||||
|
||||
android:visibility="visible"
|
||||
|
|
113
app/src/main/res/layout/result_episode_large_tv.xml
Normal file
113
app/src/main/res/layout/result_episode_large_tv.xml
Normal file
|
@ -0,0 +1,113 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
|
||||
android:nextFocusRight="@id/result_episode_download"
|
||||
android:id="@+id/episode_holder_large"
|
||||
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:cardCornerRadius="@dimen/rounded_image_radius"
|
||||
app:cardBackgroundColor="?attr/boxItemBackground"
|
||||
|
||||
android:foreground="@drawable/outline_drawable"
|
||||
android:layout_marginBottom="10dp">
|
||||
|
||||
<LinearLayout
|
||||
android:foreground="?android:attr/selectableItemBackgroundBorderless"
|
||||
android:padding="10dp"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:orientation="horizontal"
|
||||
android:layout_height="wrap_content">
|
||||
<!--app:cardCornerRadius="@dimen/roundedImageRadius"-->
|
||||
<androidx.cardview.widget.CardView
|
||||
android:layout_width="126dp"
|
||||
android:layout_height="72dp"
|
||||
android:foreground="@drawable/outline_drawable">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/episode_poster"
|
||||
tools:src="@drawable/example_poster"
|
||||
android:foreground="?android:attr/selectableItemBackgroundBorderless"
|
||||
|
||||
android:scaleType="centerCrop"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:contentDescription="@string/episode_poster_img_des" />
|
||||
|
||||
<ImageView
|
||||
android:src="@drawable/play_button"
|
||||
android:layout_gravity="center"
|
||||
android:layout_width="36dp"
|
||||
android:layout_height="36dp"
|
||||
android:contentDescription="@string/play_episode" />
|
||||
|
||||
<androidx.core.widget.ContentLoadingProgressBar
|
||||
android:layout_marginBottom="-1.5dp"
|
||||
android:id="@+id/episode_progress"
|
||||
android:progressTint="?attr/colorPrimary"
|
||||
android:progressBackgroundTint="?attr/colorPrimary"
|
||||
style="@android:style/Widget.Material.ProgressBar.Horizontal"
|
||||
android:layout_width="match_parent"
|
||||
tools:progress="50"
|
||||
android:layout_gravity="bottom"
|
||||
android:layout_height="5dp" />
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_marginStart="15dp"
|
||||
android:orientation="vertical"
|
||||
android:layout_gravity="center"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_marginEnd="50dp"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<LinearLayout
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:layout_gravity="start"
|
||||
style="@style/SmallBlackButton"
|
||||
android:layout_marginEnd="10dp"
|
||||
android:text="@string/filler"
|
||||
android:id="@+id/episode_filler" />
|
||||
|
||||
<TextView
|
||||
android:layout_gravity="center_vertical"
|
||||
android:id="@+id/episode_text"
|
||||
tools:text="1. Jobless"
|
||||
android:textStyle="bold"
|
||||
android:textColor="?attr/textColor"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
</LinearLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/episode_rating"
|
||||
tools:text="Rated: 8.8"
|
||||
android:textColor="?attr/grayTextColor"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
<TextView
|
||||
android:maxLines="4"
|
||||
android:ellipsize="end"
|
||||
android:paddingTop="10dp"
|
||||
android:paddingBottom="10dp"
|
||||
android:id="@+id/episode_descript"
|
||||
android:textColor="?attr/grayTextColor"
|
||||
tools:text="Jon and Daenerys arrive in Winterfell and are met with skepticism. Sam learns about the fate of his family. Cersei gives Euron the reward he aims for. Theon follows his heart. Jon and Daenerys arrive in Winterfell and are met with skepticism. Sam learns about the fate of his family. Cersei gives Euron the reward he aims for. Theon follows his heart."
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
</LinearLayout>
|
||||
</androidx.cardview.widget.CardView>
|
62
app/src/main/res/layout/result_episode_tv.xml
Normal file
62
app/src/main/res/layout/result_episode_tv.xml
Normal file
|
@ -0,0 +1,62 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:nextFocusRight="@id/result_episode_download"
|
||||
|
||||
android:id="@+id/episode_holder"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="50dp"
|
||||
|
||||
app:cardCornerRadius="@dimen/rounded_image_radius"
|
||||
app:cardBackgroundColor="@color/transparent"
|
||||
app:cardElevation="0dp"
|
||||
android:foreground="@drawable/outline_drawable"
|
||||
android:layout_marginBottom="5dp">
|
||||
|
||||
<androidx.core.widget.ContentLoadingProgressBar
|
||||
android:layout_marginBottom="-1.5dp"
|
||||
android:id="@+id/episode_progress"
|
||||
android:progressTint="?attr/colorPrimary"
|
||||
android:progressBackgroundTint="?attr/colorPrimary"
|
||||
style="@android:style/Widget.Material.ProgressBar.Horizontal"
|
||||
android:layout_width="match_parent"
|
||||
tools:progress="50"
|
||||
android:layout_gravity="bottom"
|
||||
android:layout_height="5dp" />
|
||||
|
||||
<LinearLayout
|
||||
android:paddingStart="20dp"
|
||||
android:paddingEnd="20dp"
|
||||
android:gravity="center"
|
||||
android:foreground="?android:attr/selectableItemBackgroundBorderless"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<!--marquee_forever-->
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:layout_marginEnd="10dp"
|
||||
tools:visibility="visible"
|
||||
android:gravity="center"
|
||||
android:layout_gravity="center"
|
||||
style="@style/SmallBlackButton"
|
||||
android:text="@string/filler"
|
||||
android:id="@+id/episode_filler" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/episode_text"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:gravity="center"
|
||||
tools:text="Episode 1"
|
||||
android:textColor="?attr/textColor"
|
||||
|
||||
android:scrollHorizontally="true"
|
||||
android:ellipsize="marquee"
|
||||
|
||||
android:marqueeRepeatLimit="0"
|
||||
android:singleLine="true"
|
||||
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent" />
|
||||
</LinearLayout>
|
||||
</androidx.cardview.widget.CardView>
|
|
@ -1,8 +1,7 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<com.google.android.material.button.MaterialButton android:id="@+id/result_season_button"
|
||||
<com.google.android.material.button.MaterialButton xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
style="@style/SelectableButton"
|
||||
android:layout_marginStart="0dp"
|
||||
android:layout_marginEnd="10dp"
|
||||
tools:text="Season 1"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools" />
|
||||
tools:text="Season 1" />
|
|
@ -3,6 +3,8 @@
|
|||
<dimen name="activity_horizontal_margin">16dp</dimen>
|
||||
<dimen name="activity_vertical_margin">16dp</dimen>
|
||||
<dimen name="rounded_image_radius">10dp</dimen>
|
||||
<dimen name="rounded_button_radius">4dp</dimen>
|
||||
|
||||
<dimen name="navbar_height">0dp</dimen>
|
||||
<dimen name="card_corner_radius">2dp</dimen>
|
||||
<dimen name="result_padding">15dp</dimen>
|
||||
|
|
|
@ -432,12 +432,12 @@
|
|||
<item name="android:textAllCaps">false</item>
|
||||
<item name="iconGravity">textStart</item>
|
||||
<item name="iconSize">20dp</item>
|
||||
<item name="cornerRadius">4dp</item>
|
||||
<item name="cornerRadius">@dimen/rounded_button_radius</item>
|
||||
<item name="android:textSize">15sp</item>
|
||||
|
||||
<item name="android:insetTop">0dp</item>
|
||||
<item name="android:insetBottom">0dp</item>
|
||||
<item name="android:foreground">@drawable/outline_drawable</item>
|
||||
<item name="android:foreground">@drawable/outline_drawable_less</item>
|
||||
</style>
|
||||
|
||||
<style name="WhiteButton" parent="NiceButton">
|
||||
|
|
Loading…
Reference in a new issue