forked from recloudstream/cloudstream
		
	store data stuff
This commit is contained in:
		
							parent
							
								
									1e01abf929
								
							
						
					
					
						commit
						881ee223c2
					
				
					 17 changed files with 201 additions and 37 deletions
				
			
		|  | @ -1,6 +1,7 @@ | ||||||
| package com.lagradost.cloudstream3 | package com.lagradost.cloudstream3 | ||||||
| 
 | 
 | ||||||
| import android.Manifest | import android.Manifest | ||||||
|  | import android.annotation.SuppressLint | ||||||
| import android.app.Activity | import android.app.Activity | ||||||
| import android.app.AppOpsManager | import android.app.AppOpsManager | ||||||
| import android.content.Context | import android.content.Context | ||||||
|  | @ -11,13 +12,19 @@ import android.media.AudioAttributes | ||||||
| import android.media.AudioFocusRequest | import android.media.AudioFocusRequest | ||||||
| import android.media.AudioManager | import android.media.AudioManager | ||||||
| import android.os.Build | import android.os.Build | ||||||
|  | import android.view.Gravity | ||||||
|  | import android.view.MenuItem | ||||||
| import android.view.View | import android.view.View | ||||||
| import android.view.WindowManager | import android.view.WindowManager | ||||||
| import android.view.inputmethod.InputMethodManager | import android.view.inputmethod.InputMethodManager | ||||||
| import androidx.annotation.ColorInt | import androidx.annotation.ColorInt | ||||||
| import androidx.appcompat.app.AppCompatActivity | import androidx.appcompat.app.AppCompatActivity | ||||||
|  | import androidx.appcompat.view.ContextThemeWrapper | ||||||
|  | import androidx.appcompat.view.menu.MenuBuilder | ||||||
|  | import androidx.appcompat.widget.PopupMenu | ||||||
| import androidx.core.app.ActivityCompat | import androidx.core.app.ActivityCompat | ||||||
| import androidx.core.content.ContextCompat | import androidx.core.content.ContextCompat | ||||||
|  | import androidx.core.view.forEach | ||||||
| import androidx.fragment.app.FragmentActivity | import androidx.fragment.app.FragmentActivity | ||||||
| import androidx.preference.PreferenceManager | import androidx.preference.PreferenceManager | ||||||
| import com.google.android.gms.cast.framework.CastContext | import com.google.android.gms.cast.framework.CastContext | ||||||
|  | @ -112,12 +119,11 @@ object UIHelper { | ||||||
|             ) |             ) | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 |  | ||||||
|     private var _AudioFocusRequest: AudioFocusRequest? = null |     private var _AudioFocusRequest: AudioFocusRequest? = null | ||||||
|     private var _OnAudioFocusChangeListener: AudioManager.OnAudioFocusChangeListener? = null |     private var _OnAudioFocusChangeListener: AudioManager.OnAudioFocusChangeListener? = null | ||||||
|     var onAudioFocusEvent = Event<Boolean>() |     var onAudioFocusEvent = Event<Boolean>() | ||||||
| 
 | 
 | ||||||
|     fun getAudioListener(): AudioManager.OnAudioFocusChangeListener? { |     private fun getAudioListener(): AudioManager.OnAudioFocusChangeListener? { | ||||||
|         if (_OnAudioFocusChangeListener != null) return _OnAudioFocusChangeListener |         if (_OnAudioFocusChangeListener != null) return _OnAudioFocusChangeListener | ||||||
|         _OnAudioFocusChangeListener = AudioManager.OnAudioFocusChangeListener { |         _OnAudioFocusChangeListener = AudioManager.OnAudioFocusChangeListener { | ||||||
|             onAudioFocusEvent.invoke( |             onAudioFocusEvent.invoke( | ||||||
|  | @ -302,4 +308,50 @@ object UIHelper { | ||||||
|         val inputMethodManager = getSystemService(Activity.INPUT_METHOD_SERVICE) as InputMethodManager |         val inputMethodManager = getSystemService(Activity.INPUT_METHOD_SERVICE) as InputMethodManager | ||||||
|         inputMethodManager.hideSoftInputFromWindow(view.windowToken, 0) |         inputMethodManager.hideSoftInputFromWindow(view.windowToken, 0) | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |     @SuppressLint("RestrictedApi") | ||||||
|  |     inline fun View.popupMenu( | ||||||
|  |         items: List<Triple<Int, Int, Int>>, | ||||||
|  |         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, icon, stringRes) -> | ||||||
|  |             popup.menu.add(0, id, 0, stringRes).setIcon(icon) | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         (popup.menu as? MenuBuilder)?.setOptionalIconsVisible(true) | ||||||
|  | 
 | ||||||
|  |         popup.setOnMenuItemClickListener { | ||||||
|  |             it.onMenuItemClick() | ||||||
|  |             true | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         popup.show() | ||||||
|  |         return popup | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     inline fun View.popupMenuNoIcons( | ||||||
|  |         items: List<Pair<Int, Int>>, | ||||||
|  |         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 | ||||||
|  |     } | ||||||
| } | } | ||||||
							
								
								
									
										19
									
								
								app/src/main/java/com/lagradost/cloudstream3/ui/WatchType.kt
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								app/src/main/java/com/lagradost/cloudstream3/ui/WatchType.kt
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,19 @@ | ||||||
|  | package com.lagradost.cloudstream3.ui | ||||||
|  | 
 | ||||||
|  | import androidx.annotation.DrawableRes | ||||||
|  | import androidx.annotation.StringRes | ||||||
|  | import com.lagradost.cloudstream3.R | ||||||
|  | 
 | ||||||
|  | enum class WatchType(val internalId: Int, @StringRes val stringRes: Int, @DrawableRes val iconRes: Int) { | ||||||
|  |     // FIX ICONS | ||||||
|  |     WATCHING(0, R.string.type_watching, R.drawable.ic_baseline_remove_red_eye_24), | ||||||
|  |     COMPLETED(1, R.string.type_completed, R.drawable.ic_baseline_check_24), | ||||||
|  |     ONHOLD(2, R.string.type_on_hold, R.drawable.ic_baseline_pause_24), | ||||||
|  |     DROPPED(3, R.string.type_dropped, R.drawable.ic_baseline_close_24), | ||||||
|  |     PLANTOWATCH(4, R.string.type_plan_to_watch, R.drawable.ic_baseline_close_24), | ||||||
|  |     NONE(5, R.string.type_none, R.drawable.ic_baseline_remove_red_eye_24); | ||||||
|  | 
 | ||||||
|  |     companion object { | ||||||
|  |         fun fromInternalId(id: Int?) = values().find { value -> value.internalId == id } ?: NONE | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | @ -30,7 +30,6 @@ import android.widget.Toast | ||||||
| import android.widget.Toast.LENGTH_SHORT | import android.widget.Toast.LENGTH_SHORT | ||||||
| import androidx.appcompat.app.AlertDialog | import androidx.appcompat.app.AlertDialog | ||||||
| import androidx.core.content.ContextCompat | import androidx.core.content.ContextCompat | ||||||
| import androidx.core.view.isVisible |  | ||||||
| import androidx.fragment.app.Fragment | import androidx.fragment.app.Fragment | ||||||
| import androidx.lifecycle.ViewModelProvider | import androidx.lifecycle.ViewModelProvider | ||||||
| import androidx.preference.PreferenceManager | import androidx.preference.PreferenceManager | ||||||
|  | @ -42,7 +41,6 @@ import com.fasterxml.jackson.databind.json.JsonMapper | ||||||
| import com.fasterxml.jackson.module.kotlin.KotlinModule | import com.fasterxml.jackson.module.kotlin.KotlinModule | ||||||
| import com.google.android.exoplayer2.* | import com.google.android.exoplayer2.* | ||||||
| import com.google.android.exoplayer2.C.TIME_UNSET | import com.google.android.exoplayer2.C.TIME_UNSET | ||||||
| import com.google.android.exoplayer2.ext.cast.CastPlayer |  | ||||||
| import com.google.android.exoplayer2.source.DefaultMediaSourceFactory | import com.google.android.exoplayer2.source.DefaultMediaSourceFactory | ||||||
| import com.google.android.exoplayer2.trackselection.DefaultTrackSelector | import com.google.android.exoplayer2.trackselection.DefaultTrackSelector | ||||||
| import com.google.android.exoplayer2.ui.AspectRatioFrameLayout | import com.google.android.exoplayer2.ui.AspectRatioFrameLayout | ||||||
|  | @ -51,14 +49,9 @@ import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory | ||||||
| import com.google.android.exoplayer2.upstream.DefaultHttpDataSourceFactory | import com.google.android.exoplayer2.upstream.DefaultHttpDataSourceFactory | ||||||
| import com.google.android.exoplayer2.util.MimeTypes | import com.google.android.exoplayer2.util.MimeTypes | ||||||
| import com.google.android.exoplayer2.util.Util | import com.google.android.exoplayer2.util.Util | ||||||
| import com.google.android.gms.cast.MediaInfo |  | ||||||
| import com.google.android.gms.cast.MediaMetadata |  | ||||||
| import com.google.android.gms.cast.MediaQueueItem |  | ||||||
| import com.google.android.gms.cast.MediaStatus |  | ||||||
| import com.google.android.gms.cast.framework.CastButtonFactory | import com.google.android.gms.cast.framework.CastButtonFactory | ||||||
| import com.google.android.gms.cast.framework.CastContext | import com.google.android.gms.cast.framework.CastContext | ||||||
| import com.google.android.gms.cast.framework.CastState | import com.google.android.gms.cast.framework.CastState | ||||||
| import com.google.android.gms.common.images.WebImage |  | ||||||
| import com.lagradost.cloudstream3.* | import com.lagradost.cloudstream3.* | ||||||
| import com.lagradost.cloudstream3.MainActivity.Companion.isInPIPMode | import com.lagradost.cloudstream3.MainActivity.Companion.isInPIPMode | ||||||
| import com.lagradost.cloudstream3.MainActivity.Companion.isInPlayer | import com.lagradost.cloudstream3.MainActivity.Companion.isInPlayer | ||||||
|  | @ -81,20 +74,16 @@ import com.lagradost.cloudstream3.ui.result.ResultViewModel | ||||||
| import com.lagradost.cloudstream3.utils.CastHelper.startCast | import com.lagradost.cloudstream3.utils.CastHelper.startCast | ||||||
| import com.lagradost.cloudstream3.utils.DataStore.getKey | import com.lagradost.cloudstream3.utils.DataStore.getKey | ||||||
| import com.lagradost.cloudstream3.utils.DataStore.setKey | import com.lagradost.cloudstream3.utils.DataStore.setKey | ||||||
| import com.lagradost.cloudstream3.utils.DataStoreHelper | import com.lagradost.cloudstream3.utils.DataStoreHelper.setViewPos | ||||||
| import com.lagradost.cloudstream3.utils.DataStoreHelper.saveViewPos |  | ||||||
| import com.lagradost.cloudstream3.utils.ExtractorLink | import com.lagradost.cloudstream3.utils.ExtractorLink | ||||||
| import com.lagradost.cloudstream3.utils.getId | import com.lagradost.cloudstream3.utils.getId | ||||||
| import kotlinx.android.synthetic.main.fragment_player.* | import kotlinx.android.synthetic.main.fragment_player.* | ||||||
| import kotlinx.android.synthetic.main.player_custom_layout.* | import kotlinx.android.synthetic.main.player_custom_layout.* | ||||||
| import kotlinx.coroutines.* | import kotlinx.coroutines.* | ||||||
| import org.json.JSONArray |  | ||||||
| import org.json.JSONObject |  | ||||||
| import java.io.File | import java.io.File | ||||||
| import javax.net.ssl.HttpsURLConnection | import javax.net.ssl.HttpsURLConnection | ||||||
| import javax.net.ssl.SSLContext | import javax.net.ssl.SSLContext | ||||||
| import javax.net.ssl.SSLSession | import javax.net.ssl.SSLSession | ||||||
| import kotlin.concurrent.thread |  | ||||||
| import kotlin.math.abs | import kotlin.math.abs | ||||||
| import kotlin.math.ceil | import kotlin.math.ceil | ||||||
| import kotlin.properties.Delegates | import kotlin.properties.Delegates | ||||||
|  | @ -562,7 +551,7 @@ class PlayerFragment : Fragment() { | ||||||
|     private fun savePos() { |     private fun savePos() { | ||||||
|         if (this::exoPlayer.isInitialized) { |         if (this::exoPlayer.isInitialized) { | ||||||
|             if (exoPlayer.duration > 0 && exoPlayer.currentPosition > 0) { |             if (exoPlayer.duration > 0 && exoPlayer.currentPosition > 0) { | ||||||
|                 context?.saveViewPos(getEpisode()?.id, exoPlayer.currentPosition, exoPlayer.duration) |                 context?.setViewPos(getEpisode()?.id, exoPlayer.currentPosition, exoPlayer.duration) | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  | @ -28,8 +28,11 @@ import com.google.android.material.button.MaterialButton | ||||||
| import com.lagradost.cloudstream3.* | import com.lagradost.cloudstream3.* | ||||||
| import com.lagradost.cloudstream3.UIHelper.fixPaddingStatusbar | import com.lagradost.cloudstream3.UIHelper.fixPaddingStatusbar | ||||||
| import com.lagradost.cloudstream3.UIHelper.isCastApiAvailable | import com.lagradost.cloudstream3.UIHelper.isCastApiAvailable | ||||||
|  | import com.lagradost.cloudstream3.UIHelper.popupMenu | ||||||
|  | import com.lagradost.cloudstream3.UIHelper.popupMenuNoIcons | ||||||
| import com.lagradost.cloudstream3.mvvm.Resource | import com.lagradost.cloudstream3.mvvm.Resource | ||||||
| import com.lagradost.cloudstream3.mvvm.observe | import com.lagradost.cloudstream3.mvvm.observe | ||||||
|  | import com.lagradost.cloudstream3.ui.WatchType | ||||||
| import com.lagradost.cloudstream3.ui.player.PlayerData | import com.lagradost.cloudstream3.ui.player.PlayerData | ||||||
| import com.lagradost.cloudstream3.ui.player.PlayerFragment | import com.lagradost.cloudstream3.ui.player.PlayerFragment | ||||||
| import com.lagradost.cloudstream3.utils.CastHelper.startCast | import com.lagradost.cloudstream3.utils.CastHelper.startCast | ||||||
|  | @ -187,7 +190,7 @@ class ResultFragment : Fragment() { | ||||||
|                         // Toast.makeText(activity, "Loading links", Toast.LENGTH_SHORT).show() |                         // Toast.makeText(activity, "Loading links", Toast.LENGTH_SHORT).show() | ||||||
| 
 | 
 | ||||||
|                         viewModel.loadEpisode(episodeClick.data, true) { data -> |                         viewModel.loadEpisode(episodeClick.data, true) { data -> | ||||||
|                             if(currentLoadingCount != currentLoad) return@loadEpisode |                             if (currentLoadingCount != currentLoad) return@loadEpisode | ||||||
|                             dialog.dismiss() |                             dialog.dismiss() | ||||||
|                             when (data) { |                             when (data) { | ||||||
|                                 is Resource.Failure -> { |                                 is Resource.Failure -> { | ||||||
|  | @ -238,6 +241,23 @@ class ResultFragment : Fragment() { | ||||||
|         result_episodes.adapter = adapter |         result_episodes.adapter = adapter | ||||||
|         result_episodes.layoutManager = GridLayoutManager(context, 1) |         result_episodes.layoutManager = GridLayoutManager(context, 1) | ||||||
| 
 | 
 | ||||||
|  |         result_bookmark_button.setOnClickListener { | ||||||
|  |             it.popupMenuNoIcons( | ||||||
|  |                 items = WatchType.values() | ||||||
|  |                     .map { watchType -> Pair(watchType.internalId, watchType.stringRes) }, | ||||||
|  |                     //.map { watchType -> Triple(watchType.internalId, watchType.iconRes, watchType.stringRes) }, | ||||||
|  |             ) { | ||||||
|  |                 context?.let { localContext -> | ||||||
|  |                     viewModel.updateWatchStatus(localContext, WatchType.fromInternalId(this.itemId)) | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         observe(viewModel.watchStatus) { | ||||||
|  |             //result_bookmark_button.setIconResource(it.iconRes) | ||||||
|  |             result_bookmark_button.text = getString(it.stringRes) | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|         observe(viewModel.allEpisodes) { |         observe(viewModel.allEpisodes) { | ||||||
|             allEpisodes = it |             allEpisodes = it | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  | @ -9,7 +9,10 @@ import com.lagradost.cloudstream3.* | ||||||
| import com.lagradost.cloudstream3.APIHolder.getApiFromName | import com.lagradost.cloudstream3.APIHolder.getApiFromName | ||||||
| import com.lagradost.cloudstream3.mvvm.Resource | import com.lagradost.cloudstream3.mvvm.Resource | ||||||
| import com.lagradost.cloudstream3.mvvm.safeApiCall | import com.lagradost.cloudstream3.mvvm.safeApiCall | ||||||
|  | import com.lagradost.cloudstream3.ui.WatchType | ||||||
|  | import com.lagradost.cloudstream3.utils.DataStoreHelper.getResultWatchState | ||||||
| import com.lagradost.cloudstream3.utils.DataStoreHelper.getViewPos | import com.lagradost.cloudstream3.utils.DataStoreHelper.getViewPos | ||||||
|  | import com.lagradost.cloudstream3.utils.DataStoreHelper.setResultWatchState | ||||||
| import com.lagradost.cloudstream3.utils.ExtractorLink | import com.lagradost.cloudstream3.utils.ExtractorLink | ||||||
| import kotlinx.coroutines.launch | import kotlinx.coroutines.launch | ||||||
| 
 | 
 | ||||||
|  | @ -20,6 +23,24 @@ class ResultViewModel : ViewModel() { | ||||||
|     val episodes: LiveData<List<ResultEpisode>> get() = _episodes |     val episodes: LiveData<List<ResultEpisode>> get() = _episodes | ||||||
|     private val dubStatus: MutableLiveData<DubStatus> = MutableLiveData() |     private val dubStatus: MutableLiveData<DubStatus> = MutableLiveData() | ||||||
| 
 | 
 | ||||||
|  |     private val page: MutableLiveData<LoadResponse> = MutableLiveData() | ||||||
|  |     private val id: MutableLiveData<Int> = MutableLiveData() | ||||||
|  | 
 | ||||||
|  |     private val _watchStatus: MutableLiveData<WatchType> = MutableLiveData() | ||||||
|  |     val watchStatus: LiveData<WatchType> get() = _watchStatus | ||||||
|  | 
 | ||||||
|  |     fun updateWatchStatus(context: Context, status: WatchType) { | ||||||
|  |         val currentId = id.value ?: return | ||||||
|  |         _watchStatus.postValue(status) | ||||||
|  |         context.setResultWatchState(currentId, status.internalId) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private fun loadWatchStatus(context: Context, localId: Int? = null) { | ||||||
|  |         val currentId = localId ?: id.value ?: return | ||||||
|  |         val currentWatch = context.getResultWatchState(currentId) | ||||||
|  |         _watchStatus.postValue(currentWatch) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     fun reloadEpisodes(context: Context) { |     fun reloadEpisodes(context: Context) { | ||||||
|         val current = _episodes.value ?: return |         val current = _episodes.value ?: return | ||||||
|         val copy = current.map { |         val copy = current.map { | ||||||
|  | @ -29,10 +50,16 @@ class ResultViewModel : ViewModel() { | ||||||
|         _episodes.postValue(copy) |         _episodes.postValue(copy) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     // THIS SHOULD AT LEAST CLEAN IT UP, SO APIS CAN SWITCH DOMAIN | ||||||
|  |     private fun getId(url: String, api: MainAPI): Int { | ||||||
|  |         return url.replace(api.mainUrl, "").hashCode() | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     fun load(context: Context, url: String, apiName: String) = viewModelScope.launch { |     fun load(context: Context, url: String, apiName: String) = viewModelScope.launch { | ||||||
|         _apiName.postValue(apiName) |         _apiName.postValue(apiName) | ||||||
|  |         val api = getApiFromName(apiName) | ||||||
|         val data = safeApiCall { |         val data = safeApiCall { | ||||||
|             getApiFromName(apiName).load(url) |             api.load(url) | ||||||
|         } |         } | ||||||
|         _resultResponse.postValue(data) |         _resultResponse.postValue(data) | ||||||
| 
 | 
 | ||||||
|  | @ -40,6 +67,11 @@ class ResultViewModel : ViewModel() { | ||||||
|             is Resource.Success -> { |             is Resource.Success -> { | ||||||
|                 val d = data.value |                 val d = data.value | ||||||
|                 if (d is LoadResponse) { |                 if (d is LoadResponse) { | ||||||
|  |                     page.postValue(d) | ||||||
|  |                     val mainId = getId(d.url, api) | ||||||
|  |                     id.postValue(mainId) | ||||||
|  |                     loadWatchStatus(context, mainId) | ||||||
|  | 
 | ||||||
|                     when (d) { |                     when (d) { | ||||||
|                         is AnimeLoadResponse -> { |                         is AnimeLoadResponse -> { | ||||||
|                             val isDub = d.dubEpisodes != null && d.dubEpisodes.size > 0 |                             val isDub = d.dubEpisodes != null && d.dubEpisodes.size > 0 | ||||||
|  | @ -57,14 +89,14 @@ class ResultViewModel : ViewModel() { | ||||||
|                                         null, // TODO FIX SEASON |                                         null, // TODO FIX SEASON | ||||||
|                                         i, |                                         i, | ||||||
|                                         apiName, |                                         apiName, | ||||||
|                                         (d.url + index).hashCode(), |                                         (mainId + index + 1), | ||||||
|                                         index, |                                         index, | ||||||
|                                     )) |                                     )) | ||||||
|                                 } |                                 } | ||||||
|                                 _episodes.postValue(episodes) |                                 _episodes.postValue(episodes) | ||||||
|                             } |                             } | ||||||
| 
 |  | ||||||
|                         } |                         } | ||||||
|  | 
 | ||||||
|                         is TvSeriesLoadResponse -> { |                         is TvSeriesLoadResponse -> { | ||||||
|                             val episodes = ArrayList<ResultEpisode>() |                             val episodes = ArrayList<ResultEpisode>() | ||||||
|                             for ((index, i) in d.episodes.withIndex()) { |                             for ((index, i) in d.episodes.withIndex()) { | ||||||
|  | @ -75,7 +107,7 @@ class ResultViewModel : ViewModel() { | ||||||
|                                     null, // TODO FIX SEASON |                                     null, // TODO FIX SEASON | ||||||
|                                     i, |                                     i, | ||||||
|                                     apiName, |                                     apiName, | ||||||
|                                     (d.url + index).hashCode(), |                                     (mainId + index + 1).hashCode(), | ||||||
|                                     index, |                                     index, | ||||||
|                                 )) |                                 )) | ||||||
|                             } |                             } | ||||||
|  | @ -88,7 +120,7 @@ class ResultViewModel : ViewModel() { | ||||||
|                                 0, null, |                                 0, null, | ||||||
|                                 d.movieUrl, |                                 d.movieUrl, | ||||||
|                                 d.apiName, |                                 d.apiName, | ||||||
|                                 (d.url).hashCode(), |                                 (mainId + 1), | ||||||
|                                 0, |                                 0, | ||||||
|                             ))) |                             ))) | ||||||
|                         } |                         } | ||||||
|  |  | ||||||
|  | @ -1,6 +1,5 @@ | ||||||
| package com.lagradost.cloudstream3.utils | package com.lagradost.cloudstream3.utils | ||||||
| 
 | 
 | ||||||
| import android.app.Activity |  | ||||||
| import android.content.Context | import android.content.Context | ||||||
| import android.net.Uri | import android.net.Uri | ||||||
| import com.fasterxml.jackson.databind.DeserializationFeature | import com.fasterxml.jackson.databind.DeserializationFeature | ||||||
|  | @ -21,10 +20,8 @@ import com.lagradost.cloudstream3.ui.MetadataHolder | ||||||
| import com.lagradost.cloudstream3.ui.result.ResultEpisode | import com.lagradost.cloudstream3.ui.result.ResultEpisode | ||||||
| import com.lagradost.cloudstream3.utils.Coroutines.main | import com.lagradost.cloudstream3.utils.Coroutines.main | ||||||
| import kotlinx.coroutines.Dispatchers | import kotlinx.coroutines.Dispatchers | ||||||
| import kotlinx.coroutines.awaitAll |  | ||||||
| import kotlinx.coroutines.withContext | import kotlinx.coroutines.withContext | ||||||
| import org.json.JSONObject | import org.json.JSONObject | ||||||
| import kotlin.concurrent.thread |  | ||||||
| 
 | 
 | ||||||
| object CastHelper { | object CastHelper { | ||||||
|     private val mapper: JsonMapper = JsonMapper.builder().addModule(KotlinModule()) |     private val mapper: JsonMapper = JsonMapper.builder().addModule(KotlinModule()) | ||||||
|  |  | ||||||
|  | @ -1,22 +1,33 @@ | ||||||
| package com.lagradost.cloudstream3.utils | package com.lagradost.cloudstream3.utils | ||||||
| 
 | 
 | ||||||
| import android.content.Context | import android.content.Context | ||||||
|  | import com.lagradost.cloudstream3.ui.WatchType | ||||||
| import com.lagradost.cloudstream3.utils.DataStore.getKey | import com.lagradost.cloudstream3.utils.DataStore.getKey | ||||||
| import com.lagradost.cloudstream3.utils.DataStore.setKey | import com.lagradost.cloudstream3.utils.DataStore.setKey | ||||||
| 
 | 
 | ||||||
| const val VIDEO_POS_DUR = "video_pos_dur" | const val VIDEO_POS_DUR = "video_pos_dur" | ||||||
|  | const val RESULT_WATCH_STATE = "result_watch_state" | ||||||
| 
 | 
 | ||||||
| data class PosDur(val position: Long, val duration: Long) | data class PosDur(val position: Long, val duration: Long) | ||||||
| 
 | 
 | ||||||
| object DataStoreHelper { | object DataStoreHelper { | ||||||
|     var currentAccount: String = "0" //TODO ACCOUNT IMPLEMENTATION |     var currentAccount: String = "0" //TODO ACCOUNT IMPLEMENTATION | ||||||
| 
 | 
 | ||||||
|     fun Context.saveViewPos(id: Int?, pos: Long, dur: Long) { |     fun Context.setViewPos(id: Int?, pos: Long, dur: Long) { | ||||||
|         if(id == null) return |         if (id == null) return | ||||||
|         setKey("$currentAccount/$VIDEO_POS_DUR", id.toString(), PosDur(pos, dur)) |         setKey("$currentAccount/$VIDEO_POS_DUR", id.toString(), PosDur(pos, dur)) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fun Context.getViewPos(id: Int): PosDur? { |     fun Context.getViewPos(id: Int): PosDur? { | ||||||
|         return getKey<PosDur>("$currentAccount/$VIDEO_POS_DUR", id.toString(), null) |         return getKey("$currentAccount/$VIDEO_POS_DUR", id.toString(), null) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     fun Context.setResultWatchState(id: Int?, status: Int) { | ||||||
|  |         if (id == null) return | ||||||
|  |         setKey("$currentAccount/$RESULT_WATCH_STATE", id.toString(), status) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     fun Context.getResultWatchState(id: Int): WatchType { | ||||||
|  |         return WatchType.fromInternalId(getKey<Int>("$currentAccount/$RESULT_WATCH_STATE", id.toString(), null)) | ||||||
|     } |     } | ||||||
| } | } | ||||||
							
								
								
									
										5
									
								
								app/src/main/res/drawable/ic_baseline_check_24.xml
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								app/src/main/res/drawable/ic_baseline_check_24.xml
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,5 @@ | ||||||
|  | <vector android:height="24dp" android:tint="#FFFFFF" | ||||||
|  |     android:viewportHeight="24" android:viewportWidth="24" | ||||||
|  |     android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android"> | ||||||
|  |     <path android:fillColor="@android:color/white" android:pathData="M9,16.17L4.83,12l-1.42,1.41L9,19 21,7l-1.41,-1.41z"/> | ||||||
|  | </vector> | ||||||
							
								
								
									
										5
									
								
								app/src/main/res/drawable/ic_baseline_close_24.xml
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								app/src/main/res/drawable/ic_baseline_close_24.xml
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,5 @@ | ||||||
|  | <vector android:height="24dp" android:tint="#FFFFFF" | ||||||
|  |     android:viewportHeight="24" android:viewportWidth="24" | ||||||
|  |     android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android"> | ||||||
|  |     <path android:fillColor="@android:color/white" android:pathData="M19,6.41L17.59,5 12,10.59 6.41,5 5,6.41 10.59,12 5,17.59 6.41,19 12,13.41 17.59,19 19,17.59 13.41,12z"/> | ||||||
|  | </vector> | ||||||
							
								
								
									
										5
									
								
								app/src/main/res/drawable/ic_baseline_pause_24.xml
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								app/src/main/res/drawable/ic_baseline_pause_24.xml
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,5 @@ | ||||||
|  | <vector android:height="24dp" android:tint="#FFFFFF" | ||||||
|  |     android:viewportHeight="24" android:viewportWidth="24" | ||||||
|  |     android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android"> | ||||||
|  |     <path android:fillColor="@android:color/white" android:pathData="M6,19h4L10,5L6,5v14zM14,5v14h4L18,5h-4z"/> | ||||||
|  | </vector> | ||||||
|  | @ -0,0 +1,5 @@ | ||||||
|  | <vector android:height="24dp" android:tint="#FFFFFF" | ||||||
|  |     android:viewportHeight="24" android:viewportWidth="24" | ||||||
|  |     android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android"> | ||||||
|  |     <path android:fillColor="@android:color/white" android:pathData="M12,7c2.76,0 5,2.24 5,5 0,0.65 -0.13,1.26 -0.36,1.83l2.92,2.92c1.51,-1.26 2.7,-2.89 3.43,-4.75 -1.73,-4.39 -6,-7.5 -11,-7.5 -1.4,0 -2.74,0.25 -3.98,0.7l2.16,2.16C10.74,7.13 11.35,7 12,7zM2,4.27l2.28,2.28 0.46,0.46C3.08,8.3 1.78,10.02 1,12c1.73,4.39 6,7.5 11,7.5 1.55,0 3.03,-0.3 4.38,-0.84l0.42,0.42L19.73,22 21,20.73 3.27,3 2,4.27zM7.53,9.8l1.55,1.55c-0.05,0.21 -0.08,0.43 -0.08,0.65 0,1.66 1.34,3 3,3 0.22,0 0.44,-0.03 0.65,-0.08l1.55,1.55c-0.67,0.33 -1.41,0.53 -2.2,0.53 -2.76,0 -5,-2.24 -5,-5 0,-0.79 0.2,-1.53 0.53,-2.2zM11.84,9.02l3.15,3.15 0.02,-0.16c0,-1.66 -1.34,-3 -3,-3l-0.17,0.01z"/> | ||||||
|  | </vector> | ||||||
|  | @ -0,0 +1,5 @@ | ||||||
|  | <?xml version="1.0" encoding="utf-8"?> | ||||||
|  | <shape xmlns:android="http://schemas.android.com/apk/res/android"> | ||||||
|  |     <solid android:color="?attr/bitDarkerGrayBackground"/> | ||||||
|  |     <stroke android:width="@dimen/mtrl_btn_stroke_size" android:color="@color/mtrl_btn_stroke_color_selector"/> | ||||||
|  | </shape> | ||||||
|  | @ -61,14 +61,22 @@ | ||||||
|                         </LinearLayout>--> |                         </LinearLayout>--> | ||||||
|             <LinearLayout |             <LinearLayout | ||||||
|                     android:layout_marginTop="10dp" |                     android:layout_marginTop="10dp" | ||||||
| 
 |  | ||||||
|                     android:orientation="horizontal" android:layout_width="match_parent" |                     android:orientation="horizontal" android:layout_width="match_parent" | ||||||
|                     android:layout_height="wrap_content"> |                     android:layout_height="wrap_content"> | ||||||
|  | 
 | ||||||
|  |                 <androidx.cardview.widget.CardView | ||||||
|  |                         app:cardCornerRadius="@dimen/roundedImageRadius" | ||||||
|  |                         android:layout_width="100dp" | ||||||
|  |                         android:layout_height="140dp"> | ||||||
|                     <ImageView |                     <ImageView | ||||||
|                             android:id="@+id/result_poster" |                             android:id="@+id/result_poster" | ||||||
|                         android:layout_width="100dp" android:layout_height="150dp" |                             android:scaleType="centerCrop" | ||||||
|  |                             android:layout_width="match_parent" | ||||||
|  |                             android:layout_height="match_parent" | ||||||
|                             tools:src="@drawable/example_poster" |                             tools:src="@drawable/example_poster" | ||||||
|                             android:contentDescription="@string/result_poster"/> |                             android:contentDescription="@string/result_poster"/> | ||||||
|  |                 </androidx.cardview.widget.CardView> | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
|                 <LinearLayout android:layout_marginLeft="10dp" |                 <LinearLayout android:layout_marginLeft="10dp" | ||||||
|                               android:gravity="center_vertical" |                               android:gravity="center_vertical" | ||||||
|  |  | ||||||
|  | @ -23,7 +23,7 @@ | ||||||
|             android:id="@+id/backgroundCard" |             android:id="@+id/backgroundCard" | ||||||
|             app:cardBackgroundColor="@color/darkBackground" |             app:cardBackgroundColor="@color/darkBackground" | ||||||
|     > |     > | ||||||
|         <!-- USING CROP RATIO (182/268), centerCrop for fill --> | 
 | ||||||
|         <ImageView |         <ImageView | ||||||
|                 android:duplicateParentState="true" |                 android:duplicateParentState="true" | ||||||
|                 android:id="@+id/imageView" |                 android:id="@+id/imageView" | ||||||
|  |  | ||||||
|  | @ -2,7 +2,7 @@ | ||||||
|     <!-- Default screen margins, per the Android Design guidelines. --> |     <!-- Default screen margins, per the Android Design guidelines. --> | ||||||
|     <dimen name="activity_horizontal_margin">16dp</dimen> |     <dimen name="activity_horizontal_margin">16dp</dimen> | ||||||
|     <dimen name="activity_vertical_margin">16dp</dimen> |     <dimen name="activity_vertical_margin">16dp</dimen> | ||||||
|     <dimen name="roundedImageRadius">4dp</dimen> |     <dimen name="roundedImageRadius">1dp</dimen> | ||||||
|     <dimen name="navbarHeight">0dp</dimen> |     <dimen name="navbarHeight">0dp</dimen> | ||||||
|     <dimen name="card_corner_radius">2dp</dimen> |     <dimen name="card_corner_radius">2dp</dimen> | ||||||
| </resources> | </resources> | ||||||
|  | @ -22,5 +22,12 @@ | ||||||
|     <string name="result_share">Share</string> |     <string name="result_share">Share</string> | ||||||
|     <string name="result_open_in_browser">Open In Browser</string> |     <string name="result_open_in_browser">Open In Browser</string> | ||||||
|     <string name="skip_loading">Skip Loading</string> |     <string name="skip_loading">Skip Loading</string> | ||||||
|     <string name="loading_chromecast">Loading...</string> |     <string name="loading_chromecast">Loading…</string> | ||||||
|  | 
 | ||||||
|  |     <string name="type_watching">Watching</string> | ||||||
|  |     <string name="type_on_hold">On-Hold</string> | ||||||
|  |     <string name="type_completed">Completed</string> | ||||||
|  |     <string name="type_dropped">Dropped</string> | ||||||
|  |     <string name="type_plan_to_watch">Plan to Watch</string> | ||||||
|  |     <string name="type_none">None</string> | ||||||
| </resources> | </resources> | ||||||
|  | @ -32,6 +32,7 @@ | ||||||
|             @style/CustomCastExpandedController |             @style/CustomCastExpandedController | ||||||
|         </item> |         </item> | ||||||
|         <item name="castMiniControllerStyle">@style/CustomCastMiniController</item> |         <item name="castMiniControllerStyle">@style/CustomCastMiniController</item> | ||||||
|  |         <!--<item name="mediaRouteButtonTint">?attr/colorPrimary</item>--> | ||||||
| 
 | 
 | ||||||
|         <!-- DEF STYLE --> |         <!-- DEF STYLE --> | ||||||
|         <item name="textColor">@color/textColor</item> |         <item name="textColor">@color/textColor</item> | ||||||
|  | @ -118,6 +119,9 @@ | ||||||
|         <item name="android:windowBackground">@color/transparent</item> |         <item name="android:windowBackground">@color/transparent</item> | ||||||
|     </style> |     </style> | ||||||
| 
 | 
 | ||||||
|  |     <style name="PopupMenu" parent="@android:style/Widget.PopupMenu"> | ||||||
|  |         <item name="android:backgroundTint">?attr/bitDarkerGrayBackground</item> | ||||||
|  |     </style> | ||||||
| 
 | 
 | ||||||
|     <!-- CHROMECAST --> |     <!-- CHROMECAST --> | ||||||
|     <style name="CustomCastExpandedController" parent="CastExpandedController"> |     <style name="CustomCastExpandedController" parent="CastExpandedController"> | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue