mirror of
				https://github.com/recloudstream/cloudstream.git
				synced 2024-08-15 01:53:11 +00:00 
			
		
		
		
	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…
	
	Add table
		Add a link
		
	
		Reference in a new issue