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
|
||||||
|
@ -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…
Reference in a new issue