mirror of
				https://github.com/recloudstream/cloudstream.git
				synced 2024-08-15 01:53:11 +00:00 
			
		
		
		
	ui stuff
This commit is contained in:
		
							parent
							
								
									41d81a0c40
								
							
						
					
					
						commit
						2c312cd9b4
					
				
					 9 changed files with 155 additions and 39 deletions
				
			
		|  | @ -354,4 +354,26 @@ object UIHelper { | |||
|         popup.show() | ||||
|         return popup | ||||
|     } | ||||
| 
 | ||||
|     inline fun View.popupMenuNoIconsAndNoStringres( | ||||
|         items: List<Pair<Int, String>>, | ||||
|         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 | ||||
|     } | ||||
| } | ||||
|  | @ -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? { | ||||
|  |  | |||
|  | @ -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 = "" | ||||
|             } | ||||
|  |  | |||
|  | @ -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 | ||||
|  |  | |||
|  | @ -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<Resource<Any?>> = MutableLiveData() | ||||
|     private val _episodes: MutableLiveData<List<ResultEpisode>> = MutableLiveData() | ||||
|     private val _publicEpisodes: MutableLiveData<List<ResultEpisode>> = MutableLiveData() | ||||
|     val resultResponse: LiveData<Resource<Any?>> get() = _resultResponse | ||||
|     val episodes: LiveData<List<ResultEpisode>> get() = _episodes | ||||
|     val publicEpisodes: LiveData<List<ResultEpisode>> get() = _publicEpisodes | ||||
| 
 | ||||
|     private val dubStatus: MutableLiveData<DubStatus> = MutableLiveData() | ||||
| 
 | ||||
|     private val page: MutableLiveData<LoadResponse> = MutableLiveData() | ||||
|     private val id: MutableLiveData<Int> = MutableLiveData() | ||||
|     val selectedSeason: MutableLiveData<Int> = MutableLiveData(-2) | ||||
|     val seasonSelections: MutableLiveData<List<Int?>> = MutableLiveData() | ||||
| 
 | ||||
|     private val _watchStatus: MutableLiveData<WatchType> = MutableLiveData() | ||||
|     val watchStatus: LiveData<WatchType> get() = _watchStatus | ||||
|  | @ -41,13 +45,43 @@ class ResultViewModel : ViewModel() { | |||
|         _watchStatus.postValue(currentWatch) | ||||
|     } | ||||
| 
 | ||||
|     private fun filterEpisodes(context: Context, list: List<ResultEpisode>?, selection: Int?) { | ||||
|         if (list == null) return | ||||
|         val seasonTypes = HashMap<Int?, Boolean>() | ||||
|         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<ResultEpisode>, 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<ResultEpisode>() | ||||
|                             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) | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|  |  | |||
|  | @ -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<Int>("$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) | ||||
|     } | ||||
| } | ||||
|  | @ -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"> | ||||
|                     </com.google.android.material.button.MaterialButton> | ||||
| 
 | ||||
| 
 | ||||
|  | @ -294,19 +294,40 @@ | |||
|                         android:layout_height="45dp"> | ||||
|                 </com.google.android.material.button.MaterialButton> | ||||
| 
 | ||||
|                 <TextView | ||||
|                         android:layout_width="wrap_content" | ||||
|                         android:layout_height="wrap_content" | ||||
|                         android:id="@+id/result_episodes_text" | ||||
|                         tools:text="8 Episodes" | ||||
|                         android:textSize="17sp" | ||||
|                         android:layout_marginTop="10dp" | ||||
|                         android:layout_marginBottom="10dp" | ||||
|                         android:textStyle="normal" | ||||
|                         android:textColor="?attr/textColor" | ||||
|                 /> | ||||
|                 <LinearLayout android:orientation="horizontal" android:gravity="center_vertical" android:layout_width="match_parent" android:layout_height="wrap_content"> | ||||
|                     <com.google.android.material.button.MaterialButton | ||||
|                             android:visibility="visible" | ||||
|                             android:layout_gravity="center_vertical" | ||||
|                             app:cornerRadius="4dp" | ||||
|                             android:id="@+id/result_season_button" | ||||
|                             tools:text="Bookmark" | ||||
| 
 | ||||
|                             app:rippleColor="?attr/bitDarkerGrayBackground" | ||||
|                             android:textColor="?attr/textColor" | ||||
|                             app:iconTint="?attr/textColor" | ||||
|                             android:textAllCaps="false" | ||||
| 
 | ||||
|                             android:backgroundTint="@color/itemBackground" | ||||
|                             style="@style/Widget.MaterialComponents.Button" | ||||
|                             android:layout_width="wrap_content" | ||||
|                             android:layout_marginEnd="10dp" | ||||
|                             android:layout_height="50dp"> | ||||
|                     </com.google.android.material.button.MaterialButton> | ||||
|                     <TextView | ||||
|                             android:layout_width="wrap_content" | ||||
|                             android:layout_height="wrap_content" | ||||
|                             android:id="@+id/result_episodes_text" | ||||
|                             tools:text="8 Episodes" | ||||
|                             android:textSize="17sp" | ||||
|                             android:layout_marginTop="10dp" | ||||
|                             android:layout_marginBottom="10dp" | ||||
|                             android:textStyle="normal" | ||||
|                             android:textColor="?attr/textColor" | ||||
|                     /> | ||||
|                 </LinearLayout> | ||||
| 
 | ||||
|                 <androidx.recyclerview.widget.RecyclerView | ||||
|                         android:layout_marginTop="10dp" | ||||
|                         android:layout_marginTop="0dp" | ||||
|                         android:paddingBottom="100dp" | ||||
|                         tools:listitem="@layout/result_episode" | ||||
|                         android:layout_width="match_parent" | ||||
|  |  | |||
|  | @ -9,7 +9,7 @@ | |||
|         app:cardBackgroundColor="@color/itemBackground" | ||||
|         android:id="@+id/episode_holder" | ||||
|         android:foreground="?android:attr/selectableItemBackgroundBorderless" | ||||
|         android:layout_marginBottom="5dp" | ||||
|         android:layout_marginBottom="10dp" | ||||
| > | ||||
|     <LinearLayout | ||||
|             android:padding="10dp" | ||||
|  | @ -20,8 +20,9 @@ | |||
|                 android:layout_width="match_parent" | ||||
|                 android:orientation="horizontal" | ||||
|                 android:layout_height="wrap_content"> | ||||
|             <!--app:cardCornerRadius="@dimen/roundedImageRadius"--> | ||||
|             <androidx.cardview.widget.CardView | ||||
|                     app:cardCornerRadius="@dimen/roundedImageRadius" | ||||
| 
 | ||||
|                     android:layout_width="126dp" | ||||
|                     android:layout_height="72dp" | ||||
|             > | ||||
|  | @ -41,7 +42,10 @@ | |||
|                         android:contentDescription="@string/play_episode"> | ||||
|                 </ImageView> | ||||
|                 <androidx.core.widget.ContentLoadingProgressBar | ||||
|                         android:layout_marginBottom="-1.5dp" | ||||
|                         android:id="@+id/episode_progress" | ||||
|                         android:progressTint="@color/colorPrimary" | ||||
|                         android:progressBackgroundTint="@color/colorPrimary" | ||||
|                         style="@android:style/Widget.Material.ProgressBar.Horizontal" | ||||
|                         android:layout_width="match_parent" | ||||
|                         tools:progress="50" | ||||
|  | @ -58,13 +62,14 @@ | |||
|                 <TextView | ||||
|                         android:id="@+id/episode_text" | ||||
|                         tools:text="1. Jobless" | ||||
|                         android:textStyle="bold" | ||||
|                         android:textColor="@color/textColor" | ||||
|                         android:layout_width="wrap_content" | ||||
|                         android:layout_height="wrap_content"> | ||||
|                 </TextView> | ||||
|                 <TextView | ||||
|                         android:id="@+id/episode_rating" | ||||
|                         tools:text="8.8" | ||||
|                         tools:text="Rated: 8.8" | ||||
|                         android:textColor="@color/grayTextColor" | ||||
|                         android:layout_width="wrap_content" | ||||
|                         android:layout_height="wrap_content"> | ||||
|  |  | |||
|  | @ -10,9 +10,9 @@ | |||
|     <color name="colorAccent">#3b65f5</color> <!-- 818fff--> | ||||
| 
 | ||||
|     <color name="darkBackground">#2B2C30</color> <!--0f0f10 0E0E10 303135 2B2C30--> | ||||
|     <color name="bitDarkerGrayBackground">#1C1C20</color> <!--191a1f 19181E 202125 1C1C20--> | ||||
|     <color name="bitDarkerGrayBackground">#111111</color> <!--1C1C20 191a1f 19181E 202125 1C1C20--> | ||||
|     <color name="grayBackground">#1C1C20</color> <!--141419 202125--> | ||||
|     <color name="itemBackground">#17171B</color> <!-- 17171B 1B1B20--> | ||||
|     <color name="itemBackground">#161616</color> <!-- 17171B 1B1B20--> | ||||
| 
 | ||||
|     <color name="textColor">#e9eaee</color> <!--FFF--> | ||||
|     <color name="grayTextColor">#9ba0a4</color> <!-- 5e5f62--> | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue