|
@@ -6,15 +6,11 @@ import androidx.lifecycle.MutableLiveData
|
|
import androidx.lifecycle.ViewModel
|
|
import androidx.lifecycle.ViewModel
|
|
import androidx.lifecycle.ViewModelProvider
|
|
import androidx.lifecycle.ViewModelProvider
|
|
import androidx.lifecycle.viewModelScope
|
|
import androidx.lifecycle.viewModelScope
|
|
-import com.tencent.liteav.demo.player.util.PlayerTimerUtil
|
|
|
|
-import com.tencent.liteav.demo.superplayer.SuperPlayerModel
|
|
|
|
import com.tencent.liteav.demo.superplayer.database.entity.CountDown
|
|
import com.tencent.liteav.demo.superplayer.database.entity.CountDown
|
|
import com.tencent.liteav.demo.superplayer.database.entity.History
|
|
import com.tencent.liteav.demo.superplayer.database.entity.History
|
|
import com.tencent.liteav.demo.superplayer.database.repo.PlayerRepository
|
|
import com.tencent.liteav.demo.superplayer.database.repo.PlayerRepository
|
|
-import com.tencent.liteav.demo.superplayer.util.CountDownUtil
|
|
|
|
|
|
+import com.tencent.liteav.demo.superplayer.util.*
|
|
import kotlinx.coroutines.Dispatchers
|
|
import kotlinx.coroutines.Dispatchers
|
|
-import kotlinx.coroutines.async
|
|
|
|
-import kotlinx.coroutines.flow.first
|
|
|
|
import kotlinx.coroutines.launch
|
|
import kotlinx.coroutines.launch
|
|
import kotlinx.coroutines.withContext
|
|
import kotlinx.coroutines.withContext
|
|
import java.text.SimpleDateFormat
|
|
import java.text.SimpleDateFormat
|
|
@@ -22,34 +18,52 @@ import java.util.*
|
|
|
|
|
|
class PlayerViewModel(
|
|
class PlayerViewModel(
|
|
private val courseId: String,
|
|
private val courseId: String,
|
|
- private val repository: PlayerRepository
|
|
|
|
-) : ViewModel(), PlayerTimerUtil.Listener, CountDownUtil.OnTickListener {
|
|
|
|
|
|
+ private val repository: PlayerRepository,
|
|
|
|
+) : ViewModel(),
|
|
|
|
+ TimersUtil.Listener,
|
|
|
|
+ CountDownUtil.OnTickListener,
|
|
|
|
+ HistoryUtil.Listener,
|
|
|
|
+ PlayerUtil.Listener {
|
|
|
|
+ companion object {
|
|
|
|
+ val TAG = PlayerViewModel::class.java.simpleName.toString()
|
|
|
|
+ }
|
|
|
|
|
|
init {
|
|
init {
|
|
- PlayerTimerUtil.addListener(this)
|
|
|
|
|
|
+ TimersUtil.addListener(this)
|
|
|
|
+ HistoryUtil.addListener(this)
|
|
|
|
+ PlayerUtil.addListener(this)
|
|
|
|
+ CountDownUtil.addListener(this)
|
|
}
|
|
}
|
|
|
|
|
|
- private lateinit var countDown: CountDown
|
|
|
|
|
|
+ override fun onCleared() {
|
|
|
|
+ super.onCleared()
|
|
|
|
|
|
- private var countDownUtil: CountDownUtil? = null
|
|
|
|
|
|
+ HistoryUtil.removeListener(this)
|
|
|
|
+ TimersUtil.removeListener(this)
|
|
|
|
+ PlayerUtil.removeListener(this)
|
|
|
|
+ CountDownUtil.removeListener(this)
|
|
|
|
+ }
|
|
|
|
|
|
- val toastStr: MutableLiveData<String> = MutableLiveData()
|
|
|
|
|
|
+ private var isPlaying: Boolean = false
|
|
|
|
|
|
- val timeout: MutableLiveData<Boolean> = MutableLiveData()
|
|
|
|
|
|
+ private lateinit var countDown: CountDown
|
|
|
|
+
|
|
|
|
+ val toastStr: MutableLiveData<String> = MutableLiveData()
|
|
|
|
|
|
- fun loadConfig(context: Context) = viewModelScope.launch {
|
|
|
|
|
|
+ fun loadConfig(context: Context) = viewModelScope.launch(Dispatchers.IO) {
|
|
val common = context.getSharedPreferences("player_timer", Context.MODE_PRIVATE)
|
|
val common = context.getSharedPreferences("player_timer", Context.MODE_PRIVATE)
|
|
val defaultType = common.getInt("type", 0)
|
|
val defaultType = common.getInt("type", 0)
|
|
val defaultValue = common.getInt("value", 0)
|
|
val defaultValue = common.getInt("value", 0)
|
|
val defaultDate = common.getString("datetime", "20220831000000")!!
|
|
val defaultDate = common.getString("datetime", "20220831000000")!!
|
|
|
|
|
|
val default = CountDown(
|
|
val default = CountDown(
|
|
- courseId = courseId,
|
|
|
|
|
|
+ id = "global",
|
|
type = defaultType,
|
|
type = defaultType,
|
|
value = defaultValue,
|
|
value = defaultValue,
|
|
|
|
+ rest = defaultValue,
|
|
datetime = defaultDate,
|
|
datetime = defaultDate,
|
|
)
|
|
)
|
|
- val special = repository.findHasCountDown(courseId).first()
|
|
|
|
|
|
+ val special = repository.findHasCountDown(courseId)
|
|
|
|
|
|
if (special == null) {
|
|
if (special == null) {
|
|
countDown = default
|
|
countDown = default
|
|
@@ -57,39 +71,42 @@ class PlayerViewModel(
|
|
countDown = special
|
|
countDown = special
|
|
}
|
|
}
|
|
|
|
|
|
- setCountDown(countDown)
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /* 保存对该门课程单独设置的定时 */
|
|
|
|
- private fun saveCountDown(countDown: CountDown) = viewModelScope.launch(Dispatchers.IO) {
|
|
|
|
- repository.deleteCountDown(courseId)
|
|
|
|
- repository.insertCountDown(countDown)
|
|
|
|
|
|
+ setCountDown(countDown, false)
|
|
}
|
|
}
|
|
|
|
|
|
/* 开启定时器 */
|
|
/* 开启定时器 */
|
|
- private fun setCountDown(countDown: CountDown) {
|
|
|
|
- countDownUtil?.cancel()
|
|
|
|
- countDownUtil = null
|
|
|
|
-
|
|
|
|
- checkTimeout(countDown)
|
|
|
|
- }
|
|
|
|
|
|
+ private fun setCountDown(countDown: CountDown, forceSend: Boolean) {
|
|
|
|
+ if (countDown.type == CountDown.TYPE_DURATION) {
|
|
|
|
+ CountDownUtil.getInstance().reset(countDown.rest.toLong(), isPlaying)
|
|
|
|
+ } else {
|
|
|
|
+ CountDownUtil.getInstance().pause()
|
|
|
|
+ }
|
|
|
|
|
|
- fun resumeTimer() {
|
|
|
|
- countDownUtil?.startOrResume()
|
|
|
|
|
|
+ // 如果定时器已经到时间了 则直接进入锁定状态
|
|
|
|
+ if (!forceSend && countDown.type != 0 && countDown.rest <= 0) {
|
|
|
|
+ sendTimeout(true)
|
|
|
|
+ } else {
|
|
|
|
+ sendTimeout(false)
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
- fun pauseTimer() {
|
|
|
|
- countDownUtil?.pause()
|
|
|
|
|
|
+ fun checkCanPlay(): Boolean {
|
|
|
|
+ return if (checkTimeout(countDown)) {
|
|
|
|
+ sendTimeout(false)
|
|
|
|
+ true
|
|
|
|
+ } else {
|
|
|
|
+ sendTimeout(true)
|
|
|
|
+ false
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
- /* 保存一条观看时间段的记录 */
|
|
|
|
- fun saveHistory(start: Long, end: Long, sectionId: String) {
|
|
|
|
|
|
+ override fun onHistory(start: Long, end: Long, sectionId: String) {
|
|
val history = History(
|
|
val history = History(
|
|
start = start,
|
|
start = start,
|
|
end = end,
|
|
end = end,
|
|
courseId = courseId,
|
|
courseId = courseId,
|
|
sectionId = sectionId,
|
|
sectionId = sectionId,
|
|
- date = SimpleDateFormat("yyyy-MM-dd").format(Date()),
|
|
|
|
|
|
+ date = SimpleDateFormat("yyyy-MM-dd hh:mm:ss").format(Date()),
|
|
countDown = countDown.datetime,
|
|
countDown = countDown.datetime,
|
|
)
|
|
)
|
|
|
|
|
|
@@ -98,91 +115,125 @@ class PlayerViewModel(
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
- suspend fun checkCanPlay(whenCan: () -> Unit) = viewModelScope.launch(Dispatchers.IO) {
|
|
|
|
- checkTimeout(countDown)
|
|
|
|
|
|
+ override fun onNewTimer(type: Int, value: Int) {
|
|
|
|
+ Log.d("PVM", "onListen: $type , $value")
|
|
|
|
|
|
- withContext(Dispatchers.Main) {
|
|
|
|
- whenCan.invoke()
|
|
|
|
|
|
+ var rest = value
|
|
|
|
+ if (type == CountDown.TYPE_EPISODE) {
|
|
|
|
+ rest = value - 1
|
|
}
|
|
}
|
|
- }
|
|
|
|
-
|
|
|
|
- override fun onListen(type: Int, value: Int) {
|
|
|
|
- Log.d("PVM", "onListen: $type , $value")
|
|
|
|
|
|
|
|
countDown = CountDown(
|
|
countDown = CountDown(
|
|
- courseId = courseId,
|
|
|
|
|
|
+ id = courseId,
|
|
type = type,
|
|
type = type,
|
|
value = value,
|
|
value = value,
|
|
- datetime = SimpleDateFormat("yyyyMMddhhmmss").format(Date())
|
|
|
|
|
|
+ rest = rest,
|
|
|
|
+ datetime = SimpleDateFormat("yyyy-MM-dd").format(Date())
|
|
)
|
|
)
|
|
|
|
|
|
countDown.let {
|
|
countDown.let {
|
|
- setCountDown(it)
|
|
|
|
|
|
+ setCountDown(it, true)
|
|
saveCountDown(it)
|
|
saveCountDown(it)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
- override fun onCleared() {
|
|
|
|
- super.onCleared()
|
|
|
|
- PlayerTimerUtil.removeListener(this)
|
|
|
|
- }
|
|
|
|
|
|
|
|
override fun onTimeout(util: CountDownUtil?) {
|
|
override fun onTimeout(util: CountDownUtil?) {
|
|
- util?.cancel()
|
|
|
|
|
|
+ util?.pause()
|
|
sendTimeout(true)
|
|
sendTimeout(true)
|
|
}
|
|
}
|
|
|
|
|
|
- private fun checkTimeout(countDown: CountDown) {
|
|
|
|
|
|
+
|
|
|
|
+ private fun checkTimeout(countDown: CountDown): Boolean {
|
|
countDown.also {
|
|
countDown.also {
|
|
- viewModelScope.launch {
|
|
|
|
- if (it.type == CountDown.TYPE_DURATION) {
|
|
|
|
- checkDurationTimeout()
|
|
|
|
- } else if (it.type == CountDown.TYPE_EPISODE) {
|
|
|
|
- checkEpisodeTimeout()
|
|
|
|
- } else {
|
|
|
|
- sendTimeout(false)
|
|
|
|
- }
|
|
|
|
|
|
+ if (it.type == CountDown.TYPE_DURATION) {
|
|
|
|
+ return checkDurationTimeout()
|
|
|
|
+ } else if (it.type == CountDown.TYPE_EPISODE) {
|
|
|
|
+ return checkEpisodeTimeout()
|
|
|
|
+ } else {
|
|
|
|
+ return true
|
|
}
|
|
}
|
|
|
|
+
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
- private suspend fun checkEpisodeTimeout() = viewModelScope.launch(Dispatchers.IO) {
|
|
|
|
- val history = repository.queryTodayEpisodeHistory(courseId, countDown.datetime!!)
|
|
|
|
-
|
|
|
|
- if (history >= countDown.value) {
|
|
|
|
- sendTimeout(true)
|
|
|
|
- } else {
|
|
|
|
- sendTimeout(false)
|
|
|
|
- }
|
|
|
|
|
|
+ private fun checkEpisodeTimeout(): Boolean {
|
|
|
|
+ val rest = countDown.rest - 1
|
|
|
|
+ countDown = countDown.copyWith(rest = rest)
|
|
|
|
+ saveCountDown(countDown)
|
|
|
|
+ return countDown.rest >= 0
|
|
}
|
|
}
|
|
|
|
|
|
- private suspend fun checkDurationTimeout() = viewModelScope.launch(Dispatchers.IO) {
|
|
|
|
- val history = repository.queryTodayDurationHistory(courseId, countDown.datetime!!)
|
|
|
|
|
|
|
|
- val result = history.fold(0L) { r, h ->
|
|
|
|
- r + (h.end - h.start)
|
|
|
|
- }
|
|
|
|
|
|
+ private fun checkDurationTimeout(): Boolean {
|
|
|
|
+ val rest = countDown.rest - CountDownUtil.getInstance().count
|
|
|
|
+ countDown = countDown.copyWith(rest = rest.toInt())
|
|
|
|
+ setupTimer(countDown.rest.toLong())
|
|
|
|
+ saveCountDown(countDown)
|
|
|
|
+ return countDown.rest > 0
|
|
|
|
+ }
|
|
|
|
|
|
- if (result >= countDown.value) {
|
|
|
|
- sendTimeout(true)
|
|
|
|
- } else {
|
|
|
|
- sendTimeout(false)
|
|
|
|
- setupTimer(countDown.value - result)
|
|
|
|
|
|
+ fun onStop() {
|
|
|
|
+ Log.d(TAG, "onExit")
|
|
|
|
+
|
|
|
|
+ if(countDown.type == CountDown.TYPE_DURATION) {
|
|
|
|
+ val rest = countDown.rest - CountDownUtil.getInstance().count
|
|
|
|
+ countDown = countDown.copyWith(rest = rest.toInt())
|
|
|
|
+ saveCountDown(countDown)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
private fun setupTimer(count: Long) {
|
|
private fun setupTimer(count: Long) {
|
|
if (countDown.type == CountDown.TYPE_DURATION) {
|
|
if (countDown.type == CountDown.TYPE_DURATION) {
|
|
- countDownUtil = CountDownUtil.build(1000, count, this)
|
|
|
|
|
|
+ CountDownUtil.getInstance().reset(count, isPlaying)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ /* 保存对该门课程单独设置的定时 */
|
|
|
|
+ private fun saveCountDown(countDown: CountDown) = viewModelScope.launch(Dispatchers.IO) {
|
|
|
|
+ repository.insertCountDown(countDown)
|
|
|
|
+ }
|
|
|
|
+
|
|
private fun sendTimeout(state: Boolean) {
|
|
private fun sendTimeout(state: Boolean) {
|
|
viewModelScope.launch(Dispatchers.Main) {
|
|
viewModelScope.launch(Dispatchers.Main) {
|
|
- timeout.value = state
|
|
|
|
|
|
+ TimeoutUtil.sendTimeout(state)
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ override fun onStatePlay() {
|
|
|
|
+ isPlaying = true
|
|
|
|
+
|
|
|
|
+ if (countDown.type == CountDown.TYPE_DURATION) {
|
|
|
|
+ CountDownUtil.getInstance().startOrResume()
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ override fun onStateResume() {
|
|
|
|
+ isPlaying = true
|
|
|
|
+
|
|
|
|
+ if (countDown.type == CountDown.TYPE_DURATION) {
|
|
|
|
+ CountDownUtil.getInstance().startOrResume()
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ override fun onStatePause() {
|
|
|
|
+ isPlaying = false
|
|
|
|
+
|
|
|
|
+ if (countDown.type == CountDown.TYPE_DURATION) {
|
|
|
|
+ (CountDownUtil.getInstance()).pause()
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ override fun onStateStop() {
|
|
|
|
+ isPlaying = false
|
|
|
|
+
|
|
|
|
+ if (countDown.type == CountDown.TYPE_DURATION) {
|
|
|
|
+ (CountDownUtil.getInstance()).pause()
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ override fun onStateLoading() {
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
class PlayerViewModelFactory(
|
|
class PlayerViewModelFactory(
|