From 2c312cd9b410dc5ff8ae80df1c2cab918531cd00 Mon Sep 17 00:00:00 2001 From: LagradOst Date: Sun, 27 Jun 2021 00:15:19 +0200 Subject: [PATCH] ui stuff --- .../com/lagradost/cloudstream3/UIHelper.kt | 22 ++++++++ .../cloudstream3/ui/player/PlayerFragment.kt | 3 +- .../cloudstream3/ui/result/EpisodeAdapter.kt | 5 +- .../cloudstream3/ui/result/ResultFragment.kt | 32 ++++++++++- .../cloudstream3/ui/result/ResultViewModel.kt | 56 +++++++++++++++---- .../cloudstream3/utils/DataStoreHelper.kt | 8 +++ app/src/main/res/layout/fragment_result.xml | 53 ++++++++++++------ .../main/res/layout/result_episode_large.xml | 11 +++- app/src/main/res/values/colors.xml | 4 +- 9 files changed, 155 insertions(+), 39 deletions(-) diff --git a/app/src/main/java/com/lagradost/cloudstream3/UIHelper.kt b/app/src/main/java/com/lagradost/cloudstream3/UIHelper.kt index 8c06f093..dfc8b5e6 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/UIHelper.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/UIHelper.kt @@ -354,4 +354,26 @@ object UIHelper { popup.show() return popup } + + inline fun View.popupMenuNoIconsAndNoStringres( + items: List>, + noinline onMenuItemClick: MenuItem.() -> Unit, + ): PopupMenu { + val ctw = ContextThemeWrapper(context, R.style.PopupMenu) + val popup = PopupMenu(ctw, this, Gravity.NO_GRAVITY, R.attr.actionOverflowMenuStyle, 0) + + items.forEach { (id, stringRes) -> + popup.menu.add(0, id, 0, stringRes) + } + + (popup.menu as? MenuBuilder)?.setOptionalIconsVisible(true) + + popup.setOnMenuItemClickListener { + it.onMenuItemClick() + true + } + + popup.show() + return popup + } } \ No newline at end of file diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/player/PlayerFragment.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/player/PlayerFragment.kt index 45e3245c..25d02f25 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/player/PlayerFragment.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/player/PlayerFragment.kt @@ -873,7 +873,6 @@ class PlayerFragment : Fragment() { viewModel = ViewModelProvider(requireActivity()).get(ResultViewModel::class.java) - observeDirectly(viewModel.episodes) { _episodes -> episodes = _episodes if (isLoading) { @@ -1129,7 +1128,7 @@ class PlayerFragment : Fragment() { changeSkip() - // initPlayer() + // initPlayer() } private fun getCurrentUrl(): ExtractorLink? { diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/result/EpisodeAdapter.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/result/EpisodeAdapter.kt index dbd3a977..b2e7d4a0 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/result/EpisodeAdapter.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/result/EpisodeAdapter.kt @@ -89,7 +89,8 @@ class EpisodeAdapter( @SuppressLint("SetTextI18n") fun bind(card: ResultEpisode) { - episodeText.text = card.name ?: "Episode ${card.episode}" + val name = if (card.name == null) "Episode ${card.episode}" else "${card.episode}. ${card.name}" + episodeText.text = name fun setWidth(v: View, procentage: Float) { val param = LinearLayout.LayoutParams( @@ -125,7 +126,7 @@ class EpisodeAdapter( } if (card.rating != null) { - episodeRating?.text = "%.1f".format(card.rating.toFloat() / 10f).replace(",", ".") + episodeRating?.text = "Rated: %.1f".format(card.rating.toFloat() / 10f).replace(",", ".") } else { episodeRating?.text = "" } diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultFragment.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultFragment.kt index 7a2bf721..675f985e 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultFragment.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultFragment.kt @@ -5,8 +5,6 @@ import android.content.Context import android.content.Intent import android.net.Uri import android.os.Bundle -import android.text.Spannable -import android.text.SpannableString import android.text.SpannableStringBuilder import android.view.LayoutInflater import android.view.View @@ -39,6 +37,7 @@ import com.lagradost.cloudstream3.UIHelper.getStatusBarHeight import com.lagradost.cloudstream3.UIHelper.isCastApiAvailable import com.lagradost.cloudstream3.UIHelper.popCurrentPage import com.lagradost.cloudstream3.UIHelper.popupMenuNoIcons +import com.lagradost.cloudstream3.UIHelper.popupMenuNoIconsAndNoStringres import com.lagradost.cloudstream3.mvvm.Resource import com.lagradost.cloudstream3.mvvm.observe import com.lagradost.cloudstream3.ui.WatchType @@ -191,6 +190,14 @@ class ResultFragment : Fragment() { var url: String? = null + private fun fromIndexToSeasonText(selection: Int?): String { + return when (selection) { + null -> "No Season" + -2 -> "No Season" + else -> "Season $selection" + } + } + @SuppressLint("SetTextI18n") override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) @@ -358,7 +365,26 @@ class ResultFragment : Fragment() { allEpisodes = it } - observe(viewModel.episodes) { episodes -> + observe(viewModel.selectedSeason) { season -> + result_season_button?.text = fromIndexToSeasonText(season) + } + + observe(viewModel.seasonSelections) { seasonList -> + result_season_button?.visibility = if (seasonList.size <= 1) GONE else VISIBLE + result_season_button?.setOnClickListener { + result_season_button?.popupMenuNoIconsAndNoStringres( + items = seasonList + .map { Pair(it ?: -2, fromIndexToSeasonText(it)) }, + ) { + val id = this.itemId + context?.let { + viewModel.changeSeason(it, if (id == -2) null else id) + } + } + } + } + + observe(viewModel.publicEpisodes) { episodes -> if (result_episodes == null || result_episodes.adapter == null) return@observe result_episodes_text.text = "${episodes.size} Episode${if (episodes.size == 1) "" else "s"}" currentEpisodes = episodes diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultViewModel.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultViewModel.kt index 3f2f8c2c..3d843a3d 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultViewModel.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultViewModel.kt @@ -1,17 +1,16 @@ package com.lagradost.cloudstream3.ui.result import android.content.Context -import androidx.lifecycle.LiveData -import androidx.lifecycle.MutableLiveData -import androidx.lifecycle.ViewModel -import androidx.lifecycle.viewModelScope +import androidx.lifecycle.* import com.lagradost.cloudstream3.* import com.lagradost.cloudstream3.APIHolder.getApiFromName import com.lagradost.cloudstream3.mvvm.Resource import com.lagradost.cloudstream3.mvvm.safeApiCall import com.lagradost.cloudstream3.ui.WatchType +import com.lagradost.cloudstream3.utils.DataStoreHelper.getResultSeason import com.lagradost.cloudstream3.utils.DataStoreHelper.getResultWatchState import com.lagradost.cloudstream3.utils.DataStoreHelper.getViewPos +import com.lagradost.cloudstream3.utils.DataStoreHelper.setResultSeason import com.lagradost.cloudstream3.utils.DataStoreHelper.setResultWatchState import com.lagradost.cloudstream3.utils.ExtractorLink import kotlinx.coroutines.launch @@ -19,12 +18,17 @@ import kotlinx.coroutines.launch class ResultViewModel : ViewModel() { private val _resultResponse: MutableLiveData> = MutableLiveData() private val _episodes: MutableLiveData> = MutableLiveData() + private val _publicEpisodes: MutableLiveData> = MutableLiveData() val resultResponse: LiveData> get() = _resultResponse val episodes: LiveData> get() = _episodes + val publicEpisodes: LiveData> get() = _publicEpisodes + private val dubStatus: MutableLiveData = MutableLiveData() private val page: MutableLiveData = MutableLiveData() private val id: MutableLiveData = MutableLiveData() + val selectedSeason: MutableLiveData = MutableLiveData(-2) + val seasonSelections: MutableLiveData> = MutableLiveData() private val _watchStatus: MutableLiveData = MutableLiveData() val watchStatus: LiveData get() = _watchStatus @@ -41,13 +45,43 @@ class ResultViewModel : ViewModel() { _watchStatus.postValue(currentWatch) } + private fun filterEpisodes(context: Context, list: List?, selection: Int?) { + if (list == null) return + val seasonTypes = HashMap() + for (i in list) { + if (!seasonTypes.containsKey(i.season)) { + seasonTypes[i.season] = true + } + } + val seasons = seasonTypes.toList().map { it.first } + seasonSelections.postValue(seasons) + val realSelection = if (!seasonTypes.containsKey(selection)) seasons[0] else selection + val internalId = id.value + + if (internalId != null) context.setResultSeason(internalId, realSelection) + + selectedSeason.postValue(realSelection ?: -2) + _publicEpisodes.postValue(list.filter { it.season == realSelection }) + } + + fun changeSeason(context: Context, selection: Int?) { + filterEpisodes(context, _episodes.value, selection) + } + + private fun updateEpisodes(context: Context, localId: Int?, list: List, selection: Int?) { + _episodes.postValue(list) + filterEpisodes(context, + list, + if (selection == -1) context.getResultSeason(localId ?: id.value ?: return) else selection) + } + fun reloadEpisodes(context: Context) { val current = _episodes.value ?: return val copy = current.map { val posDur = context.getViewPos(it.id) it.copy(position = posDur?.position ?: 0, duration = posDur?.duration ?: 0) } - _episodes.postValue(copy) + updateEpisodes(context, null, copy, selectedSeason.value) } // THIS SHOULD AT LEAST CLEAN IT UP, SO APIS CAN SWITCH DOMAIN @@ -98,7 +132,7 @@ class ResultViewModel : ViewModel() { i.descript, )) } - _episodes.postValue(episodes) + updateEpisodes(context, mainId, episodes, -1) } } @@ -106,8 +140,8 @@ class ResultViewModel : ViewModel() { val episodes = ArrayList() for ((index, i) in d.episodes.withIndex()) { episodes.add(context.buildResultEpisode( - (i.name - ?: (if (i.season != null && i.episode != null) "S${i.season}:E${i.episode}" else null)), // TODO ADD NAMES + i.name, + //?: (if (i.season != null && i.episode != null) "S${i.season}:E${i.episode}" else null)), // TODO ADD NAMES i.posterUrl, i.episode ?: (index + 1), i.season, @@ -119,10 +153,10 @@ class ResultViewModel : ViewModel() { i.descript )) } - _episodes.postValue(episodes) + updateEpisodes(context, mainId, episodes, -1) } is MovieLoadResponse -> { - _episodes.postValue(arrayListOf(context.buildResultEpisode( + updateEpisodes(context, mainId, arrayListOf(context.buildResultEpisode( null, null, 0, null, @@ -132,7 +166,7 @@ class ResultViewModel : ViewModel() { 0, null, null, - ))) + )), -1) } } } diff --git a/app/src/main/java/com/lagradost/cloudstream3/utils/DataStoreHelper.kt b/app/src/main/java/com/lagradost/cloudstream3/utils/DataStoreHelper.kt index 8bd1a23c..f13d0806 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/utils/DataStoreHelper.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/utils/DataStoreHelper.kt @@ -7,6 +7,7 @@ import com.lagradost.cloudstream3.utils.DataStore.setKey const val VIDEO_POS_DUR = "video_pos_dur" const val RESULT_WATCH_STATE = "result_watch_state" +const val RESULT_SEASON = "result_season" data class PosDur(val position: Long, val duration: Long) @@ -30,4 +31,11 @@ object DataStoreHelper { fun Context.getResultWatchState(id: Int): WatchType { return WatchType.fromInternalId(getKey("$currentAccount/$RESULT_WATCH_STATE", id.toString(), null)) } + + fun Context.getResultSeason(id: Int): Int { + return getKey("$currentAccount/$RESULT_SEASON", id.toString(), -1)!! + } + fun Context.setResultSeason(id: Int, value : Int?) { + return setKey("$currentAccount/$RESULT_SEASON", id.toString(), value) + } } \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_result.xml b/app/src/main/res/layout/fragment_result.xml index de709564..ef4b8039 100644 --- a/app/src/main/res/layout/fragment_result.xml +++ b/app/src/main/res/layout/fragment_result.xml @@ -183,15 +183,15 @@ android:id="@+id/result_bookmark_button" tools:text="Bookmark" - app:rippleColor="?attr/colorPrimary" + app:rippleColor="?attr/bitDarkerGrayBackground" android:textColor="?attr/textColor" app:iconTint="?attr/textColor" android:textAllCaps="false" app:icon="@drawable/ic_outline_remove_red_eye_24" - android:backgroundTint="@color/transparent" - style="@style/Widget.MaterialComponents.Button.OutlinedButton" + android:backgroundTint="@color/itemBackground" + style="@style/Widget.MaterialComponents.Button" android:layout_width="wrap_content" - android:layout_height="45dp"> + android:layout_height="50dp"> @@ -294,19 +294,40 @@ android:layout_height="45dp"> - + + + + + + + @@ -41,7 +42,10 @@ android:contentDescription="@string/play_episode"> diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index 7927bef6..359f91be 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -10,9 +10,9 @@ #3b65f5 #2B2C30 - #1C1C20 + #111111 #1C1C20 - #17171B + #161616 #e9eaee #9ba0a4