player language settings [Part 2]
* move player object to PlayerViewModel * minor code clean up
This commit is contained in:
parent
8a43567737
commit
94da8c6cee
|
@ -315,7 +315,6 @@ object AoDParser {
|
||||||
description = ep.description,
|
description = ep.description,
|
||||||
number = getNumberFromTitle(ep.title, media.type)
|
number = getNumberFromTitle(ep.title, media.type)
|
||||||
))
|
))
|
||||||
println(getNumberFromTitle(ep.title, media.type))
|
|
||||||
}
|
}
|
||||||
} catch (ex: Exception) {
|
} catch (ex: Exception) {
|
||||||
Log.w(javaClass.name, "Could not parse episode information.", ex)
|
Log.w(javaClass.name, "Could not parse episode information.", ex)
|
||||||
|
|
|
@ -3,7 +3,6 @@ package org.mosad.teapod.player
|
||||||
import android.animation.Animator
|
import android.animation.Animator
|
||||||
import android.animation.AnimatorListenerAdapter
|
import android.animation.AnimatorListenerAdapter
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.net.Uri
|
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
|
@ -13,13 +12,8 @@ import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.core.view.GestureDetectorCompat
|
import androidx.core.view.GestureDetectorCompat
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import com.google.android.exoplayer2.ExoPlayer
|
import com.google.android.exoplayer2.ExoPlayer
|
||||||
import com.google.android.exoplayer2.MediaItem
|
|
||||||
import com.google.android.exoplayer2.Player
|
import com.google.android.exoplayer2.Player
|
||||||
import com.google.android.exoplayer2.SimpleExoPlayer
|
|
||||||
import com.google.android.exoplayer2.source.hls.HlsMediaSource
|
|
||||||
import com.google.android.exoplayer2.ui.StyledPlayerControlView
|
import com.google.android.exoplayer2.ui.StyledPlayerControlView
|
||||||
import com.google.android.exoplayer2.upstream.DataSource
|
|
||||||
import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory
|
|
||||||
import com.google.android.exoplayer2.util.Util
|
import com.google.android.exoplayer2.util.Util
|
||||||
import kotlinx.android.synthetic.main.activity_player.*
|
import kotlinx.android.synthetic.main.activity_player.*
|
||||||
import kotlinx.android.synthetic.main.player_controls.*
|
import kotlinx.android.synthetic.main.player_controls.*
|
||||||
|
@ -40,8 +34,6 @@ class PlayerActivity : AppCompatActivity() {
|
||||||
|
|
||||||
private val model: PlayerViewModel by viewModels()
|
private val model: PlayerViewModel by viewModels()
|
||||||
|
|
||||||
private lateinit var player: SimpleExoPlayer
|
|
||||||
private lateinit var dataSourceFactory: DataSource.Factory
|
|
||||||
private lateinit var controller: StyledPlayerControlView
|
private lateinit var controller: StyledPlayerControlView
|
||||||
private lateinit var gestureDetector: GestureDetectorCompat
|
private lateinit var gestureDetector: GestureDetectorCompat
|
||||||
private lateinit var timerUpdates: TimerTask
|
private lateinit var timerUpdates: TimerTask
|
||||||
|
@ -52,8 +44,8 @@ class PlayerActivity : AppCompatActivity() {
|
||||||
private var playbackPosition: Long = 0
|
private var playbackPosition: Long = 0
|
||||||
private var remainingTime: Long = 0
|
private var remainingTime: Long = 0
|
||||||
|
|
||||||
private val rwdTime = 10000
|
private val rwdTime: Long = 10000.unaryMinus()
|
||||||
private val fwdTime = 10000
|
private val fwdTime: Long = 10000
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
@ -117,8 +109,8 @@ class PlayerActivity : AppCompatActivity() {
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun initPlayer() {
|
private fun initPlayer() {
|
||||||
if (model.mediaId <= 0) {
|
if (model.media.id < 0) {
|
||||||
Log.e(javaClass.name, "No media id was set.")
|
Log.e(javaClass.name, "No media was set.")
|
||||||
this.finish()
|
this.finish()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -134,14 +126,12 @@ class PlayerActivity : AppCompatActivity() {
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun initExoPlayer() {
|
private fun initExoPlayer() {
|
||||||
player = SimpleExoPlayer.Builder(this).build()
|
|
||||||
dataSourceFactory = DefaultDataSourceFactory(this, Util.getUserAgent(this, "Teapod"))
|
|
||||||
controller = video_view.findViewById(R.id.exo_controller)
|
controller = video_view.findViewById(R.id.exo_controller)
|
||||||
|
|
||||||
controller.isAnimationEnabled = false // disable controls (time-bar) animation
|
controller.isAnimationEnabled = false // disable controls (time-bar) animation
|
||||||
|
|
||||||
player.playWhenReady = playWhenReady
|
model.player.playWhenReady = playWhenReady
|
||||||
player.addListener(object : Player.EventListener {
|
model.player.addListener(object : Player.EventListener {
|
||||||
override fun onPlaybackStateChanged(state: Int) {
|
override fun onPlaybackStateChanged(state: Int) {
|
||||||
super.onPlaybackStateChanged(state)
|
super.onPlaybackStateChanged(state)
|
||||||
|
|
||||||
|
@ -172,7 +162,7 @@ class PlayerActivity : AppCompatActivity() {
|
||||||
|
|
||||||
@SuppressLint("ClickableViewAccessibility")
|
@SuppressLint("ClickableViewAccessibility")
|
||||||
private fun initVideoView() {
|
private fun initVideoView() {
|
||||||
video_view.player = player
|
video_view.player = model.player
|
||||||
|
|
||||||
// when the player controls get hidden, hide the bars too
|
// when the player controls get hidden, hide the bars too
|
||||||
video_view.setControllerVisibilityListener {
|
video_view.setControllerVisibilityListener {
|
||||||
|
@ -208,10 +198,10 @@ class PlayerActivity : AppCompatActivity() {
|
||||||
var btnNextEpIsVisible: Boolean
|
var btnNextEpIsVisible: Boolean
|
||||||
var controlsVisible: Boolean
|
var controlsVisible: Boolean
|
||||||
|
|
||||||
withContext(Dispatchers.Main) {
|
remainingTime = model.player.duration - model.player.currentPosition
|
||||||
remainingTime = player.duration - player.currentPosition
|
remainingTime = if (remainingTime < 0) 0 else remainingTime
|
||||||
remainingTime = if (remainingTime < 0) 0 else remainingTime
|
|
||||||
|
|
||||||
|
withContext(Dispatchers.Main) {
|
||||||
btnNextEpIsVisible = button_next_ep.isVisible
|
btnNextEpIsVisible = button_next_ep.isVisible
|
||||||
controlsVisible = controller.isVisible
|
controlsVisible = controller.isVisible
|
||||||
}
|
}
|
||||||
|
@ -234,10 +224,10 @@ class PlayerActivity : AppCompatActivity() {
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun releasePlayer(){
|
private fun releasePlayer(){
|
||||||
playbackPosition = player.currentPosition
|
playbackPosition = model.player.currentPosition
|
||||||
currentWindow = player.currentWindowIndex
|
currentWindow = model.player.currentWindowIndex
|
||||||
playWhenReady = player.playWhenReady
|
playWhenReady = model.player.playWhenReady
|
||||||
player.release()
|
model.player.release()
|
||||||
timerUpdates.cancel()
|
timerUpdates.cancel()
|
||||||
|
|
||||||
Log.d(javaClass.name, "Released player")
|
Log.d(javaClass.name, "Released player")
|
||||||
|
@ -265,7 +255,7 @@ class PlayerActivity : AppCompatActivity() {
|
||||||
*/
|
*/
|
||||||
|
|
||||||
private fun rewind() {
|
private fun rewind() {
|
||||||
player.seekTo(player.currentPosition - rwdTime)
|
model.seekToOffset(rwdTime)
|
||||||
|
|
||||||
// hide/show needed components
|
// hide/show needed components
|
||||||
exo_double_tap_indicator.visibility = View.VISIBLE
|
exo_double_tap_indicator.visibility = View.VISIBLE
|
||||||
|
@ -283,7 +273,7 @@ class PlayerActivity : AppCompatActivity() {
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun fastForward() {
|
private fun fastForward() {
|
||||||
player.seekTo(player.currentPosition + fwdTime)
|
model.seekToOffset(fwdTime)
|
||||||
|
|
||||||
// hide/show needed components
|
// hide/show needed components
|
||||||
exo_double_tap_indicator.visibility = View.VISIBLE
|
exo_double_tap_indicator.visibility = View.VISIBLE
|
||||||
|
@ -300,10 +290,6 @@ class PlayerActivity : AppCompatActivity() {
|
||||||
ffwd_10_indicator.runOnClickAnimation()
|
ffwd_10_indicator.runOnClickAnimation()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun togglePausePlay() {
|
|
||||||
if (player.isPlaying) player.pause() else player.play()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun playNextEpisode() = model.nextEpisode?.let {
|
private fun playNextEpisode() = model.nextEpisode?.let {
|
||||||
model.nextEpisode() // current = next, next = new or null
|
model.nextEpisode() // current = next, next = new or null
|
||||||
hideButtonNextEp()
|
hideButtonNextEp()
|
||||||
|
@ -330,15 +316,8 @@ class PlayerActivity : AppCompatActivity() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// update player/media item
|
// update player/media item
|
||||||
player.playWhenReady = true
|
val seekPosition = if (seekToPosition) playbackPosition else 0
|
||||||
player.clearMediaItems() //remove previous item
|
model.playMedia(model.currentEpisode, true, seekPosition)
|
||||||
val mediaSource = HlsMediaSource.Factory(dataSourceFactory).createMediaSource(
|
|
||||||
MediaItem.fromUri(Uri.parse(model.autoSelectStream(model.currentEpisode)))
|
|
||||||
)
|
|
||||||
if (seekToPosition) player.seekTo(playbackPosition)
|
|
||||||
player.setMediaSource(mediaSource)
|
|
||||||
player.prepare()
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -393,23 +372,23 @@ class PlayerActivity : AppCompatActivity() {
|
||||||
|
|
||||||
private fun showEpisodesList() {
|
private fun showEpisodesList() {
|
||||||
val episodesList = EpisodesListPlayer(this, model = model).apply {
|
val episodesList = EpisodesListPlayer(this, model = model).apply {
|
||||||
onViewRemovedAction = { player.play() }
|
onViewRemovedAction = { model.player.play() }
|
||||||
}
|
}
|
||||||
player_layout.addView(episodesList)
|
player_layout.addView(episodesList)
|
||||||
|
|
||||||
// hide player controls and pause playback
|
// hide player controls and pause playback
|
||||||
player.pause()
|
model.player.pause()
|
||||||
controller.hide()
|
controller.hide()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun showLanguageSettings() {
|
private fun showLanguageSettings() {
|
||||||
val languageSettings = LanguageSettingsPlayer(this, model = model).apply {
|
val languageSettings = LanguageSettingsPlayer(this, model = model).apply {
|
||||||
onViewRemovedAction = { player.play() }
|
onViewRemovedAction = { model.player.play() }
|
||||||
}
|
}
|
||||||
player_layout.addView(languageSettings)
|
player_layout.addView(languageSettings)
|
||||||
|
|
||||||
// hide player controls and pause playback
|
// hide player controls and pause playback
|
||||||
player.pause()
|
model.player.pause()
|
||||||
controller.hideImmediately()
|
controller.hideImmediately()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -447,7 +426,7 @@ class PlayerActivity : AppCompatActivity() {
|
||||||
* on long press toggle pause/play
|
* on long press toggle pause/play
|
||||||
*/
|
*/
|
||||||
override fun onLongPress(e: MotionEvent?) {
|
override fun onLongPress(e: MotionEvent?) {
|
||||||
togglePausePlay()
|
model.togglePausePlay()
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,15 @@
|
||||||
package org.mosad.teapod.player
|
package org.mosad.teapod.player
|
||||||
|
|
||||||
import android.util.Log
|
import android.app.Application
|
||||||
import androidx.lifecycle.ViewModel
|
import android.net.Uri
|
||||||
|
import androidx.lifecycle.AndroidViewModel
|
||||||
|
import com.google.android.exoplayer2.C
|
||||||
|
import com.google.android.exoplayer2.MediaItem
|
||||||
|
import com.google.android.exoplayer2.SimpleExoPlayer
|
||||||
|
import com.google.android.exoplayer2.source.MediaSource
|
||||||
|
import com.google.android.exoplayer2.source.hls.HlsMediaSource
|
||||||
|
import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory
|
||||||
|
import com.google.android.exoplayer2.util.Util
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
import org.mosad.teapod.parser.AoDParser
|
import org.mosad.teapod.parser.AoDParser
|
||||||
import org.mosad.teapod.preferences.Preferences
|
import org.mosad.teapod.preferences.Preferences
|
||||||
|
@ -18,63 +26,82 @@ import kotlin.properties.Delegates
|
||||||
* When currentEpisode is changed the player will start playing it (not initial media),
|
* When currentEpisode is changed the player will start playing it (not initial media),
|
||||||
* the next episode will be update and the callback is handled.
|
* the next episode will be update and the callback is handled.
|
||||||
*/
|
*/
|
||||||
class PlayerViewModel : ViewModel() {
|
class PlayerViewModel(application: Application) : AndroidViewModel(application) {
|
||||||
|
|
||||||
|
val player = SimpleExoPlayer.Builder(application).build()
|
||||||
|
val dataSourceFactory = DefaultDataSourceFactory(application, Util.getUserAgent(application, "Teapod"))
|
||||||
|
|
||||||
val currentEpisodeChangedListener = ArrayList<() -> Unit>()
|
val currentEpisodeChangedListener = ArrayList<() -> Unit>()
|
||||||
|
|
||||||
var mediaId = 0
|
var media: Media = Media(-1, "", DataTypes.MediaType.OTHER)
|
||||||
internal set
|
|
||||||
var episodeId = 0
|
|
||||||
internal set
|
internal set
|
||||||
|
|
||||||
var media: Media = Media(0, "", DataTypes.MediaType.OTHER)
|
// TODO rework
|
||||||
internal set
|
|
||||||
var currentEpisode: Episode by Delegates.observable(Episode()) { _, _, _ ->
|
var currentEpisode: Episode by Delegates.observable(Episode()) { _, _, _ ->
|
||||||
currentEpisodeChangedListener.forEach { it() }
|
currentEpisodeChangedListener.forEach { it() }
|
||||||
MediaFragment.instance.updateWatchedState(currentEpisode) // watchedCallback for the new episode
|
MediaFragment.instance.updateWatchedState(currentEpisode) // watchedCallback for the new episode
|
||||||
|
currentStreamUrl = autoSelectStream(currentEpisode)
|
||||||
nextEpisode = selectNextEpisode() // update next ep
|
nextEpisode = selectNextEpisode() // update next ep
|
||||||
}
|
}
|
||||||
|
var currentStreamUrl = "" // TODO don't save selected stream for language, instead save selected language
|
||||||
|
internal set
|
||||||
var nextEpisode: Episode? = null
|
var nextEpisode: Episode? = null
|
||||||
internal set
|
internal set
|
||||||
|
|
||||||
fun loadMedia(iMediaId: Int, iEpisodeId: Int) {
|
fun loadMedia(mediaId: Int, episodeId: Int) {
|
||||||
mediaId = iMediaId
|
|
||||||
episodeId = iEpisodeId
|
|
||||||
|
|
||||||
runBlocking {
|
runBlocking {
|
||||||
media = AoDParser.getMediaById(mediaId)
|
media = AoDParser.getMediaById(mediaId)
|
||||||
}
|
}
|
||||||
|
|
||||||
currentEpisode = media.episodes.first { it.id == episodeId }
|
currentEpisode = media.getEpisodeById(episodeId)
|
||||||
|
currentStreamUrl = autoSelectStream(currentEpisode)
|
||||||
nextEpisode = selectNextEpisode()
|
nextEpisode = selectNextEpisode()
|
||||||
|
}
|
||||||
|
|
||||||
currentEpisode
|
fun changeLanguage(url: String) {
|
||||||
|
println("new stream is: $url")
|
||||||
|
|
||||||
|
val seekTime = player.currentPosition
|
||||||
|
val mediaSource = HlsMediaSource.Factory(dataSourceFactory).createMediaSource(
|
||||||
|
MediaItem.fromUri(Uri.parse(url))
|
||||||
|
)
|
||||||
|
currentStreamUrl = url
|
||||||
|
|
||||||
|
playMedia(mediaSource, true, seekTime)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If preferSecondary or priStreamUrl is empty and secondary is present (secStreamOmU),
|
* update currentEpisode
|
||||||
* use the secondary stream. Else, if the primary stream is set use the primary stream.
|
|
||||||
* If no stream is present, return empty string.
|
|
||||||
*/
|
|
||||||
fun autoSelectStream(episode: Episode): String {
|
|
||||||
return if (Preferences.preferSecondary) {
|
|
||||||
episode.getPreferredStream(Locale.JAPANESE).url
|
|
||||||
} else {
|
|
||||||
episode.getPreferredStream(Locale.GERMAN).url
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun changeLanguage(id: Int) {
|
|
||||||
println("new Language is ABC with id $id")
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* update currentEpisode, episodeId, nextEpisode to new episode
|
|
||||||
* updateWatchedState for the next (now current) episode
|
* updateWatchedState for the next (now current) episode
|
||||||
*/
|
*/
|
||||||
fun nextEpisode() = nextEpisode?.let { nextEp ->
|
fun nextEpisode() = nextEpisode?.let { nextEp ->
|
||||||
currentEpisode = nextEp // set current ep to next ep
|
currentEpisode = nextEp // set current ep to next ep
|
||||||
episodeId = nextEp.id
|
}
|
||||||
|
|
||||||
|
// player actions
|
||||||
|
fun seekToOffset(offset: Long) {
|
||||||
|
player.seekTo(player.currentPosition + offset)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun togglePausePlay() {
|
||||||
|
if (player.isPlaying) player.pause() else player.play()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun playMedia(episode: Episode, replace: Boolean = false, seekPosition: Long = 0) {
|
||||||
|
val mediaSource = HlsMediaSource.Factory(dataSourceFactory).createMediaSource(
|
||||||
|
MediaItem.fromUri(Uri.parse(autoSelectStream(episode)))
|
||||||
|
)
|
||||||
|
|
||||||
|
playMedia(mediaSource, replace, seekPosition)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun playMedia(source: MediaSource, replace: Boolean = false, seekPosition: Long = 0) {
|
||||||
|
if (replace || player.contentDuration == C.TIME_UNSET) {
|
||||||
|
player.setMediaSource(source)
|
||||||
|
player.prepare()
|
||||||
|
if (seekPosition > 0) player.seekTo(seekPosition)
|
||||||
|
player.playWhenReady = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -90,4 +117,18 @@ class PlayerViewModel : ViewModel() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If preferSecondary use the japanese stream, if present.
|
||||||
|
* If the preferred stream is not present the default (first)
|
||||||
|
* stream will be used
|
||||||
|
*/
|
||||||
|
private fun autoSelectStream(episode: Episode): String {
|
||||||
|
return if (Preferences.preferSecondary) {
|
||||||
|
episode.getPreferredStream(Locale.JAPANESE).url
|
||||||
|
} else {
|
||||||
|
episode.getPreferredStream(Locale.GERMAN).url
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
|
@ -28,15 +28,15 @@ class EpisodesListPlayer @JvmOverloads constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
model?.let {
|
model?.let {
|
||||||
adapterRecEpisodes = PlayerEpisodeItemAdapter(it.media.episodes)
|
adapterRecEpisodes = PlayerEpisodeItemAdapter(model.media.episodes)
|
||||||
|
|
||||||
adapterRecEpisodes.onImageClick = { _, position ->
|
adapterRecEpisodes.onImageClick = { _, position ->
|
||||||
(this.parent as ViewGroup).removeView(this)
|
(this.parent as ViewGroup).removeView(this)
|
||||||
it.currentEpisode = it.media.episodes[position]
|
model.currentEpisode = model.media.episodes[position]
|
||||||
}
|
}
|
||||||
|
|
||||||
binding.recyclerEpisodesPlayer.adapter = adapterRecEpisodes
|
binding.recyclerEpisodesPlayer.adapter = adapterRecEpisodes
|
||||||
binding.recyclerEpisodesPlayer.scrollToPosition(it.currentEpisode.number - 1) // number != index
|
binding.recyclerEpisodesPlayer.scrollToPosition(model.currentEpisode.number - 1) // number != index
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,7 @@ import android.view.LayoutInflater
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.widget.LinearLayout
|
import android.widget.LinearLayout
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
|
import androidx.core.view.children
|
||||||
import org.mosad.teapod.R
|
import org.mosad.teapod.R
|
||||||
import org.mosad.teapod.databinding.PlayerLanguageSettingsBinding
|
import org.mosad.teapod.databinding.PlayerLanguageSettingsBinding
|
||||||
import org.mosad.teapod.player.PlayerViewModel
|
import org.mosad.teapod.player.PlayerViewModel
|
||||||
|
@ -24,12 +25,24 @@ class LanguageSettingsPlayer @JvmOverloads constructor(
|
||||||
private val binding = PlayerLanguageSettingsBinding.inflate(LayoutInflater.from(context), this, true)
|
private val binding = PlayerLanguageSettingsBinding.inflate(LayoutInflater.from(context), this, true)
|
||||||
var onViewRemovedAction: (() -> Unit)? = null // TODO find a better solution for this
|
var onViewRemovedAction: (() -> Unit)? = null // TODO find a better solution for this
|
||||||
|
|
||||||
|
private var currentStreamUrl = model?.currentStreamUrl ?: ""
|
||||||
|
|
||||||
init {
|
init {
|
||||||
addLanguage("primary", true) { model?.changeLanguage(0) }
|
model?.let {
|
||||||
addLanguage("secondary", false ) { model?.changeLanguage(1) }
|
model.currentEpisode.streams.forEach { stream ->
|
||||||
|
addLanguage(stream.language.displayName, stream.url == currentStreamUrl) {
|
||||||
|
currentStreamUrl = stream.url
|
||||||
|
updateSelectedLanguage(it as TextView)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
binding.buttonCloseLanguageSettings.setOnClickListener { close() }
|
binding.buttonCloseLanguageSettings.setOnClickListener { close() }
|
||||||
binding.buttonCancel.setOnClickListener { close() }
|
binding.buttonCancel.setOnClickListener { close() }
|
||||||
|
binding.buttonSelect.setOnClickListener {
|
||||||
|
model?.changeLanguage(currentStreamUrl)
|
||||||
|
close()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun addLanguage(str: String, isSelected: Boolean, onClick: OnClickListener) {
|
private fun addLanguage(str: String, isSelected: Boolean, onClick: OnClickListener) {
|
||||||
|
@ -56,6 +69,31 @@ class LanguageSettingsPlayer @JvmOverloads constructor(
|
||||||
binding.linearLanguages.addView(text)
|
binding.linearLanguages.addView(text)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun updateSelectedLanguage(selected: TextView) {
|
||||||
|
// rest all tf to not selected style
|
||||||
|
binding.linearLanguages.children.forEach { child ->
|
||||||
|
if (child is TextView) {
|
||||||
|
child.apply {
|
||||||
|
setTextColor(context.resources.getColor(R.color.textPrimaryDark, context.theme))
|
||||||
|
setTypeface(null, Typeface.NORMAL)
|
||||||
|
setCompoundDrawablesRelativeWithIntrinsicBounds(0, 0, 0, 0)
|
||||||
|
setPadding(75, 0, 0, 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// set selected to selected style
|
||||||
|
selected.apply {
|
||||||
|
setTextColor(context.resources.getColor(R.color.exo_white, context.theme))
|
||||||
|
setTypeface(null, Typeface.BOLD)
|
||||||
|
setCompoundDrawablesRelativeWithIntrinsicBounds(R.drawable.ic_baseline_check_24, 0, 0, 0)
|
||||||
|
setPadding(0, 0, 0, 0)
|
||||||
|
compoundDrawablesRelative.getOrNull(0)?.setTint(Color.WHITE)
|
||||||
|
compoundDrawablePadding = 12
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun close() {
|
private fun close() {
|
||||||
(this.parent as ViewGroup).removeView(this)
|
(this.parent as ViewGroup).removeView(this)
|
||||||
onViewRemovedAction?.invoke()
|
onViewRemovedAction?.invoke()
|
||||||
|
|
|
@ -171,8 +171,12 @@ class MediaFragment(private val mediaId: Int) : Fragment() {
|
||||||
|
|
||||||
fun updateWatchedState(ep: Episode) {
|
fun updateWatchedState(ep: Episode) {
|
||||||
AoDParser.sendCallback(ep.watchedCallback)
|
AoDParser.sendCallback(ep.watchedCallback)
|
||||||
adapterRecEpisodes.updateWatchedState(true, media.episodes.indexOf(ep))
|
|
||||||
adapterRecEpisodes.notifyDataSetChanged()
|
// only notify adapter, if initialized
|
||||||
|
if (this::adapterRecEpisodes.isInitialized) {
|
||||||
|
adapterRecEpisodes.updateWatchedState(true, media.episodes.indexOf(ep))
|
||||||
|
adapterRecEpisodes.notifyDataSetChanged()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -49,7 +49,7 @@ data class Media(
|
||||||
val link: String,
|
val link: String,
|
||||||
val type: DataTypes.MediaType,
|
val type: DataTypes.MediaType,
|
||||||
val info: Info = Info(),
|
val info: Info = Info(),
|
||||||
var episodes: ArrayList<Episode> = arrayListOf()
|
val episodes: ArrayList<Episode> = arrayListOf()
|
||||||
) {
|
) {
|
||||||
fun hasEpisode(id: Int) = episodes.any { it.id == id }
|
fun hasEpisode(id: Int) = episodes.any { it.id == id }
|
||||||
fun getEpisodeById(id: Int) = episodes.first { it.id == id }
|
fun getEpisodeById(id: Int) = episodes.first { it.id == id }
|
||||||
|
@ -71,11 +71,11 @@ data class Info(
|
||||||
data class Episode(
|
data class Episode(
|
||||||
val id: Int = 0,
|
val id: Int = 0,
|
||||||
val streams: MutableList<Stream> = mutableListOf(),
|
val streams: MutableList<Stream> = mutableListOf(),
|
||||||
var title: String = "",
|
val title: String = "",
|
||||||
var posterUrl: String = "",
|
val posterUrl: String = "",
|
||||||
var description: String = "",
|
val description: String = "",
|
||||||
var shortDesc: String = "",
|
var shortDesc: String = "",
|
||||||
var number: Int = 0,
|
val number: Int = 0,
|
||||||
var watched: Boolean = false,
|
var watched: Boolean = false,
|
||||||
var watchedCallback: String = ""
|
var watchedCallback: String = ""
|
||||||
) {
|
) {
|
||||||
|
|
Loading…
Reference in New Issue