mirror of
https://github.com/recloudstream/cloudstream.git
synced 2024-08-15 01:53:11 +00:00
Added Mark as watched and fixed clicking episode synopsis
This commit is contained in:
parent
89c5cb8a46
commit
b8248d1053
5 changed files with 100 additions and 8 deletions
|
@ -218,10 +218,18 @@ class EpisodeAdapter(
|
|||
name//if(card.isFiller == true) episodeText.context.getString(R.string.filler).format(name) else name
|
||||
episodeText.isSelected = true // is needed for text repeating
|
||||
|
||||
val displayPos = card.getDisplayPosition()
|
||||
episodeProgress?.max = (card.duration / 1000).toInt()
|
||||
episodeProgress?.progress = (displayPos / 1000).toInt()
|
||||
episodeProgress?.isVisible = displayPos > 0L
|
||||
if (card.videoWatchState == VideoWatchState.Watched) {
|
||||
// This cannot be done in getDisplayPosition() as when you have not watched something
|
||||
// the duration and position is 0
|
||||
episodeProgress?.max = 1
|
||||
episodeProgress?.progress = 1
|
||||
episodeProgress?.isVisible = true
|
||||
} else {
|
||||
val displayPos = card.getDisplayPosition()
|
||||
episodeProgress?.max = (card.duration / 1000).toInt()
|
||||
episodeProgress?.progress = (displayPos / 1000).toInt()
|
||||
episodeProgress?.isVisible = displayPos > 0L
|
||||
}
|
||||
|
||||
episodePoster?.isVisible = episodePoster?.setImage(card.poster) == true
|
||||
|
||||
|
|
|
@ -49,6 +49,7 @@ import com.lagradost.cloudstream3.utils.AppUtils.loadCache
|
|||
import com.lagradost.cloudstream3.utils.AppUtils.openBrowser
|
||||
import com.lagradost.cloudstream3.utils.Coroutines.ioWorkSafe
|
||||
import com.lagradost.cloudstream3.utils.Coroutines.main
|
||||
import com.lagradost.cloudstream3.utils.DataStoreHelper.getVideoWatchState
|
||||
import com.lagradost.cloudstream3.utils.DataStoreHelper.getViewPos
|
||||
import com.lagradost.cloudstream3.utils.SingleSelectionHelper.showBottomDialog
|
||||
import com.lagradost.cloudstream3.utils.UIHelper.colorFromAttribute
|
||||
|
@ -106,6 +107,15 @@ import kotlinx.coroutines.runBlocking
|
|||
const val START_ACTION_RESUME_LATEST = 1
|
||||
const val START_ACTION_LOAD_EP = 2
|
||||
|
||||
/**
|
||||
* Future proofed way to mark episodes as watched
|
||||
**/
|
||||
enum class VideoWatchState {
|
||||
/** Default value when no key is set */
|
||||
None,
|
||||
Watched
|
||||
}
|
||||
|
||||
data class ResultEpisode(
|
||||
val headerName: String,
|
||||
val name: String?,
|
||||
|
@ -124,6 +134,10 @@ data class ResultEpisode(
|
|||
val isFiller: Boolean?,
|
||||
val tvType: TvType,
|
||||
val parentId: Int,
|
||||
/**
|
||||
* Conveys if the episode itself is marked as watched
|
||||
**/
|
||||
val videoWatchState: VideoWatchState
|
||||
)
|
||||
|
||||
fun ResultEpisode.getRealPosition(): Long {
|
||||
|
@ -160,6 +174,7 @@ fun buildResultEpisode(
|
|||
parentId: Int,
|
||||
): ResultEpisode {
|
||||
val posDur = getViewPos(id)
|
||||
val videoWatchState = getVideoWatchState(id) ?: VideoWatchState.None
|
||||
return ResultEpisode(
|
||||
headerName,
|
||||
name,
|
||||
|
@ -178,6 +193,7 @@ fun buildResultEpisode(
|
|||
isFiller,
|
||||
tvType,
|
||||
parentId,
|
||||
videoWatchState
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -559,6 +575,19 @@ open class ResultFragment : ResultTrailerPlayer() {
|
|||
)
|
||||
|
||||
|
||||
observe(viewModel.episodeSynopsis) { description ->
|
||||
view.context?.let { ctx ->
|
||||
val builder: AlertDialog.Builder =
|
||||
AlertDialog.Builder(ctx, R.style.AlertDialogCustom)
|
||||
builder.setMessage(description.html())
|
||||
.setTitle(R.string.synopsis)
|
||||
.setOnDismissListener {
|
||||
viewModel.releaseEpisodeSynopsis()
|
||||
}
|
||||
.show()
|
||||
}
|
||||
}
|
||||
|
||||
observe(viewModel.watchStatus) { watchType ->
|
||||
result_bookmark_button?.text = getString(watchType.stringRes)
|
||||
result_bookmark_fab?.text = getString(watchType.stringRes)
|
||||
|
|
|
@ -406,6 +406,9 @@ class ResultViewModel2 : ViewModel() {
|
|||
MutableLiveData(Some.None)
|
||||
val resumeWatching: LiveData<Some<ResumeWatchingStatus>> = _resumeWatching
|
||||
|
||||
private val _episodeSynopsis: MutableLiveData<String?> = MutableLiveData(null)
|
||||
val episodeSynopsis: LiveData<String?> = _episodeSynopsis
|
||||
|
||||
companion object {
|
||||
const val TAG = "RVM2"
|
||||
private const val EPISODE_RANGE_SIZE = 20
|
||||
|
@ -1113,6 +1116,10 @@ class ResultViewModel2 : ViewModel() {
|
|||
)
|
||||
)
|
||||
|
||||
fun releaseEpisodeSynopsis() {
|
||||
_episodeSynopsis.postValue(null)
|
||||
}
|
||||
|
||||
private suspend fun handleEpisodeClickEvent(activity: Activity?, click: EpisodeClickEvent) {
|
||||
when (click.action) {
|
||||
ACTION_SHOW_OPTIONS -> {
|
||||
|
@ -1146,10 +1153,20 @@ class ResultViewModel2 : ViewModel() {
|
|||
txt(R.string.episode_action_download_mirror) to ACTION_DOWNLOAD_MIRROR,
|
||||
txt(R.string.episode_action_download_subtitle) to ACTION_DOWNLOAD_EPISODE_SUBTITLE_MIRROR,
|
||||
txt(R.string.episode_action_reload_links) to ACTION_RELOAD_EPISODE,
|
||||
// txt(R.string.action_mark_as_watched) to ACTION_MARK_AS_WATCHED,
|
||||
)
|
||||
)
|
||||
|
||||
// Do not add mark as watched on movies
|
||||
if (!listOf(TvType.Movie, TvType.AnimeMovie).contains(click.data.tvType)) {
|
||||
val isWatched =
|
||||
DataStoreHelper.getVideoWatchState(click.data.id) == VideoWatchState.Watched
|
||||
|
||||
val watchedText = if (isWatched) R.string.action_remove_from_watched
|
||||
else R.string.action_mark_as_watched
|
||||
|
||||
options.add(txt(watchedText) to ACTION_MARK_AS_WATCHED)
|
||||
}
|
||||
|
||||
postPopup(
|
||||
txt(
|
||||
activity?.getNameFull(
|
||||
|
@ -1182,6 +1199,10 @@ class ResultViewModel2 : ViewModel() {
|
|||
}
|
||||
}
|
||||
}
|
||||
ACTION_SHOW_DESCRIPTION -> {
|
||||
_episodeSynopsis.postValue(click.data.description)
|
||||
}
|
||||
|
||||
/* not implemented, not used
|
||||
ACTION_DOWNLOAD_EPISODE_SUBTITLE -> {
|
||||
loadLinks(click.data, isVisible = false, isCasting = false) { links ->
|
||||
|
@ -1378,8 +1399,17 @@ class ResultViewModel2 : ViewModel() {
|
|||
)
|
||||
}
|
||||
ACTION_MARK_AS_WATCHED -> {
|
||||
// TODO FIX
|
||||
// DataStoreHelper.setViewPos(click.data.id, 1, 1)
|
||||
val isWatched =
|
||||
DataStoreHelper.getVideoWatchState(click.data.id) == VideoWatchState.Watched
|
||||
|
||||
if (isWatched) {
|
||||
DataStoreHelper.setVideoWatchState(click.data.id, VideoWatchState.None)
|
||||
} else {
|
||||
DataStoreHelper.setVideoWatchState(click.data.id, VideoWatchState.Watched)
|
||||
}
|
||||
|
||||
// Kinda dirty to reload all episodes :(
|
||||
reloadEpisodes()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1529,7 +1559,13 @@ class ResultViewModel2 : ViewModel() {
|
|||
val end = minOf(list.size, start + length)
|
||||
list.subList(start, end).map {
|
||||
val posDur = getViewPos(it.id)
|
||||
it.copy(position = posDur?.position ?: 0, duration = posDur?.duration ?: 0)
|
||||
val watchState =
|
||||
DataStoreHelper.getVideoWatchState(it.id) ?: VideoWatchState.None
|
||||
it.copy(
|
||||
position = posDur?.position ?: 0,
|
||||
duration = posDur?.duration ?: 0,
|
||||
videoWatchState = watchState
|
||||
)
|
||||
}
|
||||
}
|
||||
?: emptyList()
|
||||
|
|
|
@ -11,8 +11,10 @@ import com.lagradost.cloudstream3.SearchQuality
|
|||
import com.lagradost.cloudstream3.SearchResponse
|
||||
import com.lagradost.cloudstream3.TvType
|
||||
import com.lagradost.cloudstream3.ui.WatchType
|
||||
import com.lagradost.cloudstream3.ui.result.VideoWatchState
|
||||
|
||||
const val VIDEO_POS_DUR = "video_pos_dur"
|
||||
const val VIDEO_WATCH_STATE = "video_watch_state"
|
||||
const val RESULT_WATCH_STATE = "result_watch_state"
|
||||
const val RESULT_WATCH_STATE_DATA = "result_watch_state_data"
|
||||
const val RESULT_RESUME_WATCHING = "result_resume_watching_2" // changed due to id changes
|
||||
|
@ -193,6 +195,22 @@ object DataStoreHelper {
|
|||
return getKey("$currentAccount/$VIDEO_POS_DUR", id.toString(), null)
|
||||
}
|
||||
|
||||
fun getVideoWatchState(id: Int?): VideoWatchState? {
|
||||
if (id == null) return null
|
||||
return getKey("$currentAccount/$VIDEO_WATCH_STATE", id.toString(), null)
|
||||
}
|
||||
|
||||
fun setVideoWatchState(id: Int?, watchState: VideoWatchState) {
|
||||
if (id == null) return
|
||||
|
||||
// None == No key
|
||||
if (watchState == VideoWatchState.None) {
|
||||
removeKey("$currentAccount/$VIDEO_WATCH_STATE", id.toString())
|
||||
} else {
|
||||
setKey("$currentAccount/$VIDEO_WATCH_STATE", id.toString(), watchState)
|
||||
}
|
||||
}
|
||||
|
||||
fun getDub(id: Int): DubStatus? {
|
||||
return DubStatus.values()
|
||||
.getOrNull(getKey("$currentAccount/$RESULT_DUB", id.toString(), -1) ?: -1)
|
||||
|
|
|
@ -605,6 +605,7 @@
|
|||
<string name="enable_skip_op_from_database_des">Show skip popups for opening/ending</string>
|
||||
<string name="clipboard_too_large">Too much text. Unable to save to clipboard.</string>
|
||||
<string name="action_mark_as_watched">Mark as watched</string>
|
||||
<string name="action_remove_from_watched">Remove from watched</string>
|
||||
<string name="confirm_exit_dialog">Are you sure you want to exit\?</string>
|
||||
<string name="yes">Yes</string>
|
||||
<string name="no">No</string>
|
||||
|
|
Loading…
Reference in a new issue