Skip to content

Commit

Permalink
feat(player): remember playback state
Browse files Browse the repository at this point in the history
  • Loading branch information
abdallahmehiz committed Jun 20, 2024
1 parent 27deffb commit f430cce
Show file tree
Hide file tree
Showing 8 changed files with 119 additions and 12 deletions.
10 changes: 10 additions & 0 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
plugins {
alias(libs.plugins.ksp)
alias(libs.plugins.android.application)
alias(libs.plugins.jetbrains.kotlin.android)
alias(libs.plugins.kotlin.compose.compiler)
alias(libs.plugins.room)
}

android {
Expand Down Expand Up @@ -69,6 +71,10 @@ android {
}
}

room {
schemaDirectory("$projectDir/schemas")
}

dependencies {

implementation(libs.androidx.core.ktx)
Expand Down Expand Up @@ -103,4 +109,8 @@ dependencies {
implementation(libs.bundles.koin)
implementation(libs.bundles.voyager)
implementation(libs.compose.prefs)

implementation(libs.room.runtime)
ksp(libs.room.compiler)
implementation(libs.room.ktx)
}
4 changes: 3 additions & 1 deletion app/src/main/java/live/mehiz/mpvkt/App.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package live.mehiz.mpvkt

import android.app.Application
import live.mehiz.mpvkt.di.DatabaseModule
import live.mehiz.mpvkt.di.PreferencesModule
import org.koin.android.ext.koin.androidContext
import org.koin.core.context.startKoin
Expand All @@ -11,7 +12,8 @@ class App : Application() {
startKoin {
androidContext(this@App)
modules(
PreferencesModule
PreferencesModule,
DatabaseModule
)
}
}
Expand Down
11 changes: 11 additions & 0 deletions app/src/main/java/live/mehiz/mpvkt/database/MpvKtDatabase.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package live.mehiz.mpvkt.database

import androidx.room.Database
import androidx.room.RoomDatabase
import live.mehiz.mpvkt.database.dao.PlaybackStateDao
import live.mehiz.mpvkt.database.entities.PlaybackStateEntity

@Database(entities = [PlaybackStateEntity::class], version = 1)
abstract class MpvKtDatabase: RoomDatabase() {
abstract fun videoDataDao(): PlaybackStateDao
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package live.mehiz.mpvkt.database.dao

import androidx.room.Dao
import androidx.room.Query
import androidx.room.Upsert
import live.mehiz.mpvkt.database.entities.PlaybackStateEntity

@Dao
interface PlaybackStateDao {
@Upsert
suspend fun upsert(playbackStateEntity: PlaybackStateEntity)

@Query("SELECT * FROM PlaybackStateEntity WHERE mediaTitle = :mediaTitle LIMIT 1")
suspend fun getVideoDataByTitle(mediaTitle: String): PlaybackStateEntity?
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package live.mehiz.mpvkt.database.entities

import androidx.room.Entity
import androidx.room.PrimaryKey

@Entity
data class PlaybackStateEntity(
@PrimaryKey val mediaTitle: String,
val lastPosition: Int, // in seconds
val sid: Int,
val secondarySid: Int,
val aid: Int,
)
14 changes: 14 additions & 0 deletions app/src/main/java/live/mehiz/mpvkt/di/DatabaseModule.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package live.mehiz.mpvkt.di

import androidx.room.Room
import live.mehiz.mpvkt.database.MpvKtDatabase
import org.koin.android.ext.koin.androidContext
import org.koin.dsl.module

val DatabaseModule = module {
single<MpvKtDatabase> {
Room
.databaseBuilder(androidContext(), MpvKtDatabase::class.java, "mpvKt.db")
.build()
}
}
57 changes: 46 additions & 11 deletions app/src/main/java/live/mehiz/mpvkt/ui/player/PlayerActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import android.content.Intent
import android.content.pm.ActivityInfo
import android.media.AudioManager
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.os.ParcelFileDescriptor
import android.util.Log
Expand All @@ -16,7 +15,12 @@ import androidx.core.view.WindowCompat
import androidx.documentfile.provider.DocumentFile
import `is`.xyz.mpv.MPVLib
import `is`.xyz.mpv.Utils
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
import live.mehiz.mpvkt.database.MpvKtDatabase
import live.mehiz.mpvkt.database.entities.PlaybackStateEntity
import live.mehiz.mpvkt.databinding.PlayerLayoutBinding
import live.mehiz.mpvkt.preferences.AdvancedPreferences
import live.mehiz.mpvkt.preferences.AudioPreferences
Expand All @@ -32,14 +36,15 @@ class PlayerActivity : AppCompatActivity() {

private val viewModel: PlayerViewModel by lazy { PlayerViewModel(this) }
private val binding by lazy { PlayerLayoutBinding.inflate(this.layoutInflater) }
private val mpvKtDatabase: MpvKtDatabase by inject()
val player by lazy { binding.player }
val windowInsetsController by lazy { WindowCompat.getInsetsController(window, window.decorView) }
val audioManager by lazy { getSystemService(Context.AUDIO_SERVICE) as AudioManager }
private val playerPreferences by inject<PlayerPreferences>()
private val decoderPreferences by inject<DecoderPreferences>()
private val audioPreferences by inject<AudioPreferences>()
private val subtitlesPreferences by inject<SubtitlesPreferences>()
private val advancedPreferences by inject<AdvancedPreferences>()
private val playerPreferences: PlayerPreferences by inject()
private val decoderPreferences: DecoderPreferences by inject()
private val audioPreferences: AudioPreferences by inject()
private val subtitlesPreferences: SubtitlesPreferences by inject()
private val advancedPreferences: AdvancedPreferences by inject()

override fun onCreate(savedInstanceState: Bundle?) {
if (playerPreferences.drawOverDisplayCutout.get()) enableEdgeToEdge()
Expand Down Expand Up @@ -107,8 +112,11 @@ class PlayerActivity : AppCompatActivity() {
Debanding.CPU -> MPVLib.setPropertyString("vf", "gradfun=radius=12")
Debanding.GPU -> MPVLib.setPropertyString("deband", "yes")
}
if (decoderPreferences.useYUV420P.get()) MPVLib.setPropertyString("vf", "format=yuv420p")
MPVLib.setPropertyDouble("speed", playerPreferences.defaultSpeed.get().toDouble())
if (decoderPreferences.useYUV420P.get()) {
MPVLib.setPropertyString("vf", "format=yuv420p")
}
player.playbackSpeed = playerPreferences.defaultSpeed.get().toDouble()
MPVLib.setPropertyString("keep-open", "yes")

player.addObserver(PlayerObserver(this))
}
Expand Down Expand Up @@ -139,8 +147,7 @@ class PlayerActivity : AppCompatActivity() {
}

private fun setupIntents(intent: Intent) {
val title = intent.getStringExtra("title")
if (title?.isNotBlank() == true) viewModel.fileName = intent.getStringExtra("title") ?: ""
viewModel.fileName = intent.getStringExtra("title") ?: ""
player.timePos = intent.getIntExtra("position", 0) / 1000
}

Expand Down Expand Up @@ -229,11 +236,14 @@ class PlayerActivity : AppCompatActivity() {
MPVLib.mpvEventId.MPV_EVENT_FILE_LOADED -> {
setOrientation()
viewModel.changeVideoAspect(playerPreferences.videoAspect.get())
CoroutineScope(Dispatchers.IO).launch {
reuseVideoPlaybackState(MPVLib.getPropertyString("media-title"))
if (intent.hasExtra("position")) setupIntents(intent)
}
viewModel.duration.value = player.duration!!.toFloat()
viewModel.loadChapters()
viewModel.loadTracks()
viewModel.getDecoder()
setupIntents(intent)
}

MPVLib.mpvEventId.MPV_EVENT_SEEK -> {
Expand All @@ -246,11 +256,36 @@ class PlayerActivity : AppCompatActivity() {
}
}

private suspend fun saveVideoPlaybackState() {
mpvKtDatabase.videoDataDao().upsert(
PlaybackStateEntity(
MPVLib.getPropertyString("media-title"),
player.timePos?: 0,
player.sid,
player.secondarySid,
player.aid
)
)
}

private suspend fun reuseVideoPlaybackState(mediaTitle: String) {
val state = mpvKtDatabase.videoDataDao().getVideoDataByTitle(mediaTitle)
state?.let {
player.timePos = it.lastPosition
player.sid = it.sid
player.secondarySid = it.secondarySid
player.aid = it.aid
}
}

override fun finish() {
endPlayback(EndPlaybackReason.ExternalAction)
}

private fun endPlayback(reason: EndPlaybackReason) {
CoroutineScope(Dispatchers.IO).launch {
saveVideoPlaybackState()
}
if (!intent.getBooleanExtra("return_result", false)) {
super.finish()
return
Expand Down
7 changes: 7 additions & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ composeBom = "2024.05.00"
koin = "3.6.0-wasm-alpha2"
voyager = "1.0.0"
material3Android = "1.2.1"
room = "2.6.1"

[libraries]
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
Expand Down Expand Up @@ -49,11 +50,17 @@ voyager-transitions = { module = "cafe.adriel.voyager:voyager-transitions", vers

compose-prefs = { module = "me.zhanghai.compose.preference:library", version = "1.0.0" }

room-runtime = { module = "androidx.room:room-runtime", version.ref = "room" }
room-compiler = { module = "androidx.room:room-compiler", version.ref = "room" }
room-ktx = { module = "androidx.room:room-ktx", version.ref = "room" }

[bundles]
koin = ["koin-core", "koin-android", "koin-compose"]
voyager = ["voyager-navigator", "voyager-transitions"]

[plugins]
ksp = { id = "com.google.devtools.ksp", version = "2.0.0-1.0.22" }
android-application = { id = "com.android.application", version.ref = "agp" }
jetbrains-kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
kotlin-compose-compiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }
room = { id = "androidx.room", version.ref = "room" }

0 comments on commit f430cce

Please sign in to comment.