migrate watch positions to room

This commit is contained in:
Bnyro 2022-08-13 22:03:11 +02:00
parent 17626419a2
commit 3eadc46780
12 changed files with 108 additions and 130 deletions

View File

@ -4,11 +4,11 @@ import android.view.LayoutInflater
import android.view.ViewGroup import android.view.ViewGroup
import androidx.fragment.app.FragmentManager import androidx.fragment.app.FragmentManager
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import com.github.libretube.database.DatabaseHelper
import com.github.libretube.databinding.WatchHistoryRowBinding import com.github.libretube.databinding.WatchHistoryRowBinding
import com.github.libretube.dialogs.VideoOptionsDialog import com.github.libretube.dialogs.VideoOptionsDialog
import com.github.libretube.extensions.setFormattedDuration import com.github.libretube.extensions.setFormattedDuration
import com.github.libretube.obj.WatchHistoryItem import com.github.libretube.obj.WatchHistoryItem
import com.github.libretube.preferences.PreferenceHelper
import com.github.libretube.util.ConnectionHelper import com.github.libretube.util.ConnectionHelper
import com.github.libretube.util.NavigationHelper import com.github.libretube.util.NavigationHelper
import com.github.libretube.util.setWatchProgressLength import com.github.libretube.util.setWatchProgressLength
@ -21,7 +21,7 @@ class WatchHistoryAdapter(
private val TAG = "WatchHistoryAdapter" private val TAG = "WatchHistoryAdapter"
fun removeFromWatchHistory(position: Int) { fun removeFromWatchHistory(position: Int) {
PreferenceHelper.removeFromWatchHistory(position) DatabaseHelper.removeFromWatchHistory(position)
watchHistory.removeAt(position) watchHistory.removeAt(position)
notifyDataSetChanged() notifyDataSetChanged()
} }
@ -54,12 +54,12 @@ class WatchHistoryAdapter(
NavigationHelper.navigateVideo(root.context, video.videoId) NavigationHelper.navigateVideo(root.context, video.videoId)
} }
root.setOnLongClickListener { root.setOnLongClickListener {
VideoOptionsDialog(video.videoId!!) VideoOptionsDialog(video.videoId)
.show(childFragmentManager, VideoOptionsDialog::class.java.name) .show(childFragmentManager, VideoOptionsDialog::class.java.name)
true true
} }
watchProgress.setWatchProgressLength(video.videoId!!, video.duration) watchProgress.setWatchProgressLength(video.videoId, video.duration)
} }
} }

View File

@ -3,8 +3,23 @@ package com.github.libretube.database
import androidx.room.Database import androidx.room.Database
import androidx.room.RoomDatabase import androidx.room.RoomDatabase
import com.github.libretube.obj.WatchHistoryItem import com.github.libretube.obj.WatchHistoryItem
import com.github.libretube.obj.WatchPosition
@Database(entities = [WatchHistoryItem::class], version = 1) @Database(
entities = [
WatchHistoryItem::class,
WatchPosition::class
],
version = 2
)
abstract class AppDatabase : RoomDatabase() { abstract class AppDatabase : RoomDatabase() {
/**
* Watch History
*/
abstract fun watchHistoryDao(): WatchHistoryDao abstract fun watchHistoryDao(): WatchHistoryDao
/**
* Watch Positions
*/
abstract fun watchPositionDao(): WatchPositionDao
} }

View File

@ -2,6 +2,7 @@ package com.github.libretube.database
import com.github.libretube.obj.Streams import com.github.libretube.obj.Streams
import com.github.libretube.obj.WatchHistoryItem import com.github.libretube.obj.WatchHistoryItem
import com.github.libretube.obj.WatchPosition
import com.github.libretube.util.toID import com.github.libretube.util.toID
object DatabaseHelper { object DatabaseHelper {
@ -20,4 +21,30 @@ object DatabaseHelper {
DatabaseHolder.database.watchHistoryDao().insertAll(watchHistoryItem) DatabaseHolder.database.watchHistoryDao().insertAll(watchHistoryItem)
}.start() }.start()
} }
fun removeFromWatchHistory(index: Int) {
Thread {
DatabaseHolder.database.watchHistoryDao().delete(
DatabaseHolder.database.watchHistoryDao().getAll()[index]
)
}.start()
}
fun saveWatchPosition(videoId: String, position: Long) {
val watchPosition = WatchPosition(
videoId,
position
)
Thread {
DatabaseHolder.database.watchPositionDao().insertAll(watchPosition)
}.start()
}
fun removeWatchPosition(videoId: String) {
Thread {
DatabaseHolder.database.watchPositionDao().delete(
DatabaseHolder.database.watchPositionDao().findById(videoId)
)
}.start()
}
} }

View File

@ -12,6 +12,8 @@ object DatabaseHolder {
context, context,
AppDatabase::class.java, AppDatabase::class.java,
DATABASE_NAME DATABASE_NAME
).build() )
.fallbackToDestructiveMigration()
.build()
} }
} }

View File

@ -3,6 +3,7 @@ package com.github.libretube.database
import androidx.room.Dao import androidx.room.Dao
import androidx.room.Delete import androidx.room.Delete
import androidx.room.Insert import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query import androidx.room.Query
import com.github.libretube.obj.WatchHistoryItem import com.github.libretube.obj.WatchHistoryItem
@ -14,7 +15,7 @@ interface WatchHistoryDao {
@Query("SELECT * FROM watchHistoryItem WHERE videoId LIKE :videoId LIMIT 1") @Query("SELECT * FROM watchHistoryItem WHERE videoId LIKE :videoId LIMIT 1")
fun findById(videoId: String): WatchHistoryItem fun findById(videoId: String): WatchHistoryItem
@Insert @Insert(onConflict = OnConflictStrategy.REPLACE)
fun insertAll(vararg watchHistoryItems: WatchHistoryItem) fun insertAll(vararg watchHistoryItems: WatchHistoryItem)
@Delete @Delete

View File

@ -0,0 +1,23 @@
package com.github.libretube.database
import androidx.room.Dao
import androidx.room.Delete
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
import com.github.libretube.obj.WatchPosition
@Dao
interface WatchPositionDao {
@Query("SELECT * FROM watchPosition")
fun getAll(): List<WatchPosition>
@Query("SELECT * FROM watchPosition WHERE videoId LIKE :videoId LIMIT 1")
fun findById(videoId: String): WatchPosition
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insertAll(vararg watchPositions: WatchPosition)
@Delete
fun delete(watchPosition: WatchPosition)
}

View File

@ -3,15 +3,23 @@ package com.github.libretube.util
import android.view.View import android.view.View
import android.view.ViewTreeObserver import android.view.ViewTreeObserver
import android.widget.LinearLayout import android.widget.LinearLayout
import com.github.libretube.preferences.PreferenceHelper import com.github.libretube.database.DatabaseHolder
import com.github.libretube.obj.WatchPosition
/** /**
* shows the already watched time under the video * shows the already watched time under the video
*/ */
fun View?.setWatchProgressLength(videoId: String, duration: Long) { fun View?.setWatchProgressLength(videoId: String, duration: Long) {
val view = this!! val view = this!!
val positions = PreferenceHelper.getWatchPositions() var positions = listOf<WatchPosition>()
var newWidth: Long? = null var newWidth: Long? = null
val thread = Thread {
positions = DatabaseHolder.database.watchPositionDao().getAll()
}
thread.start()
thread.join()
view.getViewTreeObserver() view.getViewTreeObserver()
.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener { .addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener {
override fun onGlobalLayout() { override fun onGlobalLayout() {

View File

@ -38,6 +38,7 @@ import com.github.libretube.adapters.ChaptersAdapter
import com.github.libretube.adapters.CommentsAdapter import com.github.libretube.adapters.CommentsAdapter
import com.github.libretube.adapters.TrendingAdapter import com.github.libretube.adapters.TrendingAdapter
import com.github.libretube.database.DatabaseHelper import com.github.libretube.database.DatabaseHelper
import com.github.libretube.database.DatabaseHolder
import com.github.libretube.databinding.DoubleTapOverlayBinding import com.github.libretube.databinding.DoubleTapOverlayBinding
import com.github.libretube.databinding.ExoStyledPlayerControlViewBinding import com.github.libretube.databinding.ExoStyledPlayerControlViewBinding
import com.github.libretube.databinding.FragmentPlayerBinding import com.github.libretube.databinding.FragmentPlayerBinding
@ -51,6 +52,7 @@ import com.github.libretube.obj.ChapterSegment
import com.github.libretube.obj.Segment import com.github.libretube.obj.Segment
import com.github.libretube.obj.Segments import com.github.libretube.obj.Segments
import com.github.libretube.obj.Streams import com.github.libretube.obj.Streams
import com.github.libretube.obj.WatchPosition
import com.github.libretube.preferences.PreferenceHelper import com.github.libretube.preferences.PreferenceHelper
import com.github.libretube.preferences.PreferenceKeys import com.github.libretube.preferences.PreferenceKeys
import com.github.libretube.services.BackgroundMode import com.github.libretube.services.BackgroundMode
@ -444,8 +446,7 @@ class PlayerFragment : BaseFragment() {
val newParams = if (index != 0) { val newParams = if (index != 0) {
// caption selected // caption selected
// get the caption name and language // get the caption language code
val captionLanguage = subtitlesNamesList[index]
val captionLanguageCode = subtitleCodesList[index] val captionLanguageCode = subtitleCodesList[index]
// select the new caption preference // select the new caption preference
@ -814,13 +815,13 @@ class PlayerFragment : BaseFragment() {
// save the watch position if video isn't finished and option enabled // save the watch position if video isn't finished and option enabled
private fun saveWatchPosition() { private fun saveWatchPosition() {
if (watchPositionsEnabled && exoPlayer.currentPosition != exoPlayer.duration) { if (watchPositionsEnabled && exoPlayer.currentPosition != exoPlayer.duration) {
PreferenceHelper.saveWatchPosition( DatabaseHelper.saveWatchPosition(
videoId!!, videoId!!,
exoPlayer.currentPosition exoPlayer.currentPosition
) )
} else if (watchPositionsEnabled) { } else if (watchPositionsEnabled) {
// delete watch position if video has ended // delete watch position if video has ended
PreferenceHelper.removeWatchPosition(videoId!!) DatabaseHelper.removeWatchPosition(videoId!!)
} }
} }
@ -934,7 +935,12 @@ class PlayerFragment : BaseFragment() {
private fun seekToWatchPosition() { private fun seekToWatchPosition() {
// seek to saved watch position if available // seek to saved watch position if available
val watchPositions = PreferenceHelper.getWatchPositions() var watchPositions = listOf<WatchPosition>()
val thread = Thread {
watchPositions = DatabaseHolder.database.watchPositionDao().getAll()
}
thread.start()
thread.join()
var position: Long? = null var position: Long? = null
watchPositions.forEach { watchPositions.forEach {
if (it.videoId == videoId && if (it.videoId == videoId &&

View File

@ -12,7 +12,6 @@ import com.github.libretube.database.DatabaseHolder
import com.github.libretube.databinding.FragmentWatchHistoryBinding import com.github.libretube.databinding.FragmentWatchHistoryBinding
import com.github.libretube.extensions.BaseFragment import com.github.libretube.extensions.BaseFragment
import com.github.libretube.obj.WatchHistoryItem import com.github.libretube.obj.WatchHistoryItem
import kotlinx.coroutines.runBlocking
class WatchHistoryFragment : BaseFragment() { class WatchHistoryFragment : BaseFragment() {
private val TAG = "WatchHistoryFragment" private val TAG = "WatchHistoryFragment"

View File

@ -1,7 +1,11 @@
package com.github.libretube.obj package com.github.libretube.obj
import androidx.room.ColumnInfo
import androidx.room.Entity
@Entity
class CustomInstance( class CustomInstance(
var name: String = "", @ColumnInfo var name: String = "",
var apiUrl: String = "", var apiUrl: String = "",
var frontendUrl: String = "" var frontendUrl: String = ""
) )

View File

@ -1,6 +1,11 @@
package com.github.libretube.obj package com.github.libretube.obj
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
@Entity(tableName = "watchPosition")
data class WatchPosition( data class WatchPosition(
val videoId: String = "", @PrimaryKey val videoId: String = "",
val position: Long = 0L @ColumnInfo val position: Long = 0L
) )

View File

@ -6,10 +6,6 @@ import androidx.preference.PreferenceManager
import com.fasterxml.jackson.core.type.TypeReference import com.fasterxml.jackson.core.type.TypeReference
import com.fasterxml.jackson.databind.ObjectMapper import com.fasterxml.jackson.databind.ObjectMapper
import com.github.libretube.obj.CustomInstance import com.github.libretube.obj.CustomInstance
import com.github.libretube.obj.Streams
import com.github.libretube.obj.WatchHistoryItem
import com.github.libretube.obj.WatchPosition
import com.github.libretube.util.toID
object PreferenceHelper { object PreferenceHelper {
private val TAG = "PreferenceHelper" private val TAG = "PreferenceHelper"
@ -135,114 +131,6 @@ object PreferenceHelper {
editor.putString("search_history", json).apply() editor.putString("search_history", json).apply()
} }
fun addToWatchHistory(videoId: String, streams: Streams) {
removeFromWatchHistory(videoId)
val watchHistoryItem = WatchHistoryItem(
videoId,
streams.title,
streams.uploadDate,
streams.uploader,
streams.uploaderUrl.toID(),
streams.uploaderAvatar,
streams.thumbnailUrl,
streams.duration
)
val watchHistory = getWatchHistory()
watchHistory += watchHistoryItem
// remove oldest item when the watch history is longer than the pref
val maxWatchHistorySize = getString(PreferenceKeys.WATCH_HISTORY_SIZE, "unlimited")
if (maxWatchHistorySize != "unlimited" && watchHistory.size > maxWatchHistorySize.toInt()) {
watchHistory.removeAt(0)
}
val json = mapper.writeValueAsString(watchHistory)
editor.putString("watch_history", json).apply()
}
fun removeFromWatchHistory(videoId: String) {
val watchHistory = getWatchHistory()
var indexToRemove: Int? = null
watchHistory.forEachIndexed { index, item ->
if (item.videoId == videoId) indexToRemove = index
}
if (indexToRemove == null) return
watchHistory.removeAt(indexToRemove!!)
val json = mapper.writeValueAsString(watchHistory)
editor.putString("watch_history", json).commit()
}
fun removeFromWatchHistory(position: Int) {
val watchHistory = getWatchHistory()
watchHistory.removeAt(position)
val json = mapper.writeValueAsString(watchHistory)
editor.putString("watch_history", json).commit()
}
fun getWatchHistory(): ArrayList<WatchHistoryItem> {
val json: String = settings.getString("watch_history", "")!!
val type = mapper.typeFactory.constructCollectionType(
List::class.java,
WatchHistoryItem::class.java
)
return try {
mapper.readValue(json, type)
} catch (e: Exception) {
arrayListOf()
}
}
fun saveWatchPosition(videoId: String, position: Long) {
val watchPositions = getWatchPositions()
val watchPositionItem = WatchPosition(videoId, position)
var indexToRemove: Int? = null
watchPositions.forEachIndexed { index, item ->
if (item.videoId == videoId) indexToRemove = index
}
if (indexToRemove != null) watchPositions.removeAt(indexToRemove!!)
watchPositions += watchPositionItem
val json = mapper.writeValueAsString(watchPositions)
editor.putString("watch_positions", json).commit()
}
fun removeWatchPosition(videoId: String) {
val watchPositions = getWatchPositions()
var indexToRemove: Int? = null
watchPositions.forEachIndexed { index, item ->
if (item.videoId == videoId) indexToRemove = index
}
if (indexToRemove != null) watchPositions.removeAt(indexToRemove!!)
val json = mapper.writeValueAsString(watchPositions)
editor.putString("watch_positions", json).commit()
}
fun getWatchPositions(): ArrayList<WatchPosition> {
val json: String = settings.getString("watch_positions", "")!!
val type = mapper.typeFactory.constructCollectionType(
List::class.java,
WatchPosition::class.java
)
return try {
mapper.readValue(json, type)
} catch (e: Exception) {
arrayListOf()
}
}
fun setLatestVideoId(videoId: String) { fun setLatestVideoId(videoId: String) {
editor.putString(PreferenceKeys.LAST_STREAM_VIDEO_ID, videoId) editor.putString(PreferenceKeys.LAST_STREAM_VIDEO_ID, videoId)
} }