diff --git a/app/src/main/java/com/github/libretube/adapters/WatchHistoryAdapter.kt b/app/src/main/java/com/github/libretube/adapters/WatchHistoryAdapter.kt index f6a63f981..c864eff29 100644 --- a/app/src/main/java/com/github/libretube/adapters/WatchHistoryAdapter.kt +++ b/app/src/main/java/com/github/libretube/adapters/WatchHistoryAdapter.kt @@ -4,11 +4,11 @@ import android.view.LayoutInflater import android.view.ViewGroup import androidx.fragment.app.FragmentManager import androidx.recyclerview.widget.RecyclerView +import com.github.libretube.database.DatabaseHelper import com.github.libretube.databinding.WatchHistoryRowBinding import com.github.libretube.dialogs.VideoOptionsDialog import com.github.libretube.extensions.setFormattedDuration import com.github.libretube.obj.WatchHistoryItem -import com.github.libretube.preferences.PreferenceHelper import com.github.libretube.util.ConnectionHelper import com.github.libretube.util.NavigationHelper import com.github.libretube.util.setWatchProgressLength @@ -21,7 +21,7 @@ class WatchHistoryAdapter( private val TAG = "WatchHistoryAdapter" fun removeFromWatchHistory(position: Int) { - PreferenceHelper.removeFromWatchHistory(position) + DatabaseHelper.removeFromWatchHistory(position) watchHistory.removeAt(position) notifyDataSetChanged() } @@ -54,12 +54,12 @@ class WatchHistoryAdapter( NavigationHelper.navigateVideo(root.context, video.videoId) } root.setOnLongClickListener { - VideoOptionsDialog(video.videoId!!) + VideoOptionsDialog(video.videoId) .show(childFragmentManager, VideoOptionsDialog::class.java.name) true } - watchProgress.setWatchProgressLength(video.videoId!!, video.duration) + watchProgress.setWatchProgressLength(video.videoId, video.duration) } } diff --git a/app/src/main/java/com/github/libretube/database/AppDatabase.kt b/app/src/main/java/com/github/libretube/database/AppDatabase.kt index e60631dd5..9ad08b99b 100644 --- a/app/src/main/java/com/github/libretube/database/AppDatabase.kt +++ b/app/src/main/java/com/github/libretube/database/AppDatabase.kt @@ -3,8 +3,23 @@ package com.github.libretube.database import androidx.room.Database import androidx.room.RoomDatabase 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() { + /** + * Watch History + */ abstract fun watchHistoryDao(): WatchHistoryDao + + /** + * Watch Positions + */ + abstract fun watchPositionDao(): WatchPositionDao } diff --git a/app/src/main/java/com/github/libretube/database/DatabaseHelper.kt b/app/src/main/java/com/github/libretube/database/DatabaseHelper.kt index 1585f3797..8e927d8d3 100644 --- a/app/src/main/java/com/github/libretube/database/DatabaseHelper.kt +++ b/app/src/main/java/com/github/libretube/database/DatabaseHelper.kt @@ -2,6 +2,7 @@ package com.github.libretube.database 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 DatabaseHelper { @@ -20,4 +21,30 @@ object DatabaseHelper { DatabaseHolder.database.watchHistoryDao().insertAll(watchHistoryItem) }.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() + } } diff --git a/app/src/main/java/com/github/libretube/database/DatabaseHolder.kt b/app/src/main/java/com/github/libretube/database/DatabaseHolder.kt index 09ce329a8..401f95260 100644 --- a/app/src/main/java/com/github/libretube/database/DatabaseHolder.kt +++ b/app/src/main/java/com/github/libretube/database/DatabaseHolder.kt @@ -12,6 +12,8 @@ object DatabaseHolder { context, AppDatabase::class.java, DATABASE_NAME - ).build() + ) + .fallbackToDestructiveMigration() + .build() } } diff --git a/app/src/main/java/com/github/libretube/database/WatchHistoryDao.kt b/app/src/main/java/com/github/libretube/database/WatchHistoryDao.kt index 23957f518..5ff9f9c2d 100644 --- a/app/src/main/java/com/github/libretube/database/WatchHistoryDao.kt +++ b/app/src/main/java/com/github/libretube/database/WatchHistoryDao.kt @@ -3,6 +3,7 @@ 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.WatchHistoryItem @@ -14,7 +15,7 @@ interface WatchHistoryDao { @Query("SELECT * FROM watchHistoryItem WHERE videoId LIKE :videoId LIMIT 1") fun findById(videoId: String): WatchHistoryItem - @Insert + @Insert(onConflict = OnConflictStrategy.REPLACE) fun insertAll(vararg watchHistoryItems: WatchHistoryItem) @Delete diff --git a/app/src/main/java/com/github/libretube/database/WatchPositionDao.kt b/app/src/main/java/com/github/libretube/database/WatchPositionDao.kt new file mode 100644 index 000000000..999d89e43 --- /dev/null +++ b/app/src/main/java/com/github/libretube/database/WatchPositionDao.kt @@ -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 + + @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) +} diff --git a/app/src/main/java/com/github/libretube/extensions/SetWatchProgressLength.kt b/app/src/main/java/com/github/libretube/extensions/SetWatchProgressLength.kt index 22780a71e..543a8fe26 100644 --- a/app/src/main/java/com/github/libretube/extensions/SetWatchProgressLength.kt +++ b/app/src/main/java/com/github/libretube/extensions/SetWatchProgressLength.kt @@ -3,15 +3,23 @@ package com.github.libretube.util import android.view.View import android.view.ViewTreeObserver 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 */ fun View?.setWatchProgressLength(videoId: String, duration: Long) { val view = this!! - val positions = PreferenceHelper.getWatchPositions() + var positions = listOf() var newWidth: Long? = null + + val thread = Thread { + positions = DatabaseHolder.database.watchPositionDao().getAll() + } + thread.start() + thread.join() + view.getViewTreeObserver() .addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener { override fun onGlobalLayout() { diff --git a/app/src/main/java/com/github/libretube/fragments/PlayerFragment.kt b/app/src/main/java/com/github/libretube/fragments/PlayerFragment.kt index 34af17ea6..0e5aee8d9 100644 --- a/app/src/main/java/com/github/libretube/fragments/PlayerFragment.kt +++ b/app/src/main/java/com/github/libretube/fragments/PlayerFragment.kt @@ -38,6 +38,7 @@ import com.github.libretube.adapters.ChaptersAdapter import com.github.libretube.adapters.CommentsAdapter import com.github.libretube.adapters.TrendingAdapter import com.github.libretube.database.DatabaseHelper +import com.github.libretube.database.DatabaseHolder import com.github.libretube.databinding.DoubleTapOverlayBinding import com.github.libretube.databinding.ExoStyledPlayerControlViewBinding 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.Segments import com.github.libretube.obj.Streams +import com.github.libretube.obj.WatchPosition import com.github.libretube.preferences.PreferenceHelper import com.github.libretube.preferences.PreferenceKeys import com.github.libretube.services.BackgroundMode @@ -444,8 +446,7 @@ class PlayerFragment : BaseFragment() { val newParams = if (index != 0) { // caption selected - // get the caption name and language - val captionLanguage = subtitlesNamesList[index] + // get the caption language code val captionLanguageCode = subtitleCodesList[index] // select the new caption preference @@ -814,13 +815,13 @@ class PlayerFragment : BaseFragment() { // save the watch position if video isn't finished and option enabled private fun saveWatchPosition() { if (watchPositionsEnabled && exoPlayer.currentPosition != exoPlayer.duration) { - PreferenceHelper.saveWatchPosition( + DatabaseHelper.saveWatchPosition( videoId!!, exoPlayer.currentPosition ) } else if (watchPositionsEnabled) { // delete watch position if video has ended - PreferenceHelper.removeWatchPosition(videoId!!) + DatabaseHelper.removeWatchPosition(videoId!!) } } @@ -934,7 +935,12 @@ class PlayerFragment : BaseFragment() { private fun seekToWatchPosition() { // seek to saved watch position if available - val watchPositions = PreferenceHelper.getWatchPositions() + var watchPositions = listOf() + val thread = Thread { + watchPositions = DatabaseHolder.database.watchPositionDao().getAll() + } + thread.start() + thread.join() var position: Long? = null watchPositions.forEach { if (it.videoId == videoId && diff --git a/app/src/main/java/com/github/libretube/fragments/WatchHistoryFragment.kt b/app/src/main/java/com/github/libretube/fragments/WatchHistoryFragment.kt index a3471392f..b5a6f64f3 100644 --- a/app/src/main/java/com/github/libretube/fragments/WatchHistoryFragment.kt +++ b/app/src/main/java/com/github/libretube/fragments/WatchHistoryFragment.kt @@ -12,7 +12,6 @@ import com.github.libretube.database.DatabaseHolder import com.github.libretube.databinding.FragmentWatchHistoryBinding import com.github.libretube.extensions.BaseFragment import com.github.libretube.obj.WatchHistoryItem -import kotlinx.coroutines.runBlocking class WatchHistoryFragment : BaseFragment() { private val TAG = "WatchHistoryFragment" diff --git a/app/src/main/java/com/github/libretube/obj/CustomInstance.kt b/app/src/main/java/com/github/libretube/obj/CustomInstance.kt index 880044448..c6d601171 100644 --- a/app/src/main/java/com/github/libretube/obj/CustomInstance.kt +++ b/app/src/main/java/com/github/libretube/obj/CustomInstance.kt @@ -1,7 +1,11 @@ package com.github.libretube.obj +import androidx.room.ColumnInfo +import androidx.room.Entity + +@Entity class CustomInstance( - var name: String = "", + @ColumnInfo var name: String = "", var apiUrl: String = "", var frontendUrl: String = "" ) diff --git a/app/src/main/java/com/github/libretube/obj/WatchPosition.kt b/app/src/main/java/com/github/libretube/obj/WatchPosition.kt index e98b4e812..73b56e51e 100644 --- a/app/src/main/java/com/github/libretube/obj/WatchPosition.kt +++ b/app/src/main/java/com/github/libretube/obj/WatchPosition.kt @@ -1,6 +1,11 @@ package com.github.libretube.obj +import androidx.room.ColumnInfo +import androidx.room.Entity +import androidx.room.PrimaryKey + +@Entity(tableName = "watchPosition") data class WatchPosition( - val videoId: String = "", - val position: Long = 0L + @PrimaryKey val videoId: String = "", + @ColumnInfo val position: Long = 0L ) diff --git a/app/src/main/java/com/github/libretube/preferences/PreferenceHelper.kt b/app/src/main/java/com/github/libretube/preferences/PreferenceHelper.kt index 52beac2e3..0f8f68f2c 100644 --- a/app/src/main/java/com/github/libretube/preferences/PreferenceHelper.kt +++ b/app/src/main/java/com/github/libretube/preferences/PreferenceHelper.kt @@ -6,10 +6,6 @@ import androidx.preference.PreferenceManager import com.fasterxml.jackson.core.type.TypeReference import com.fasterxml.jackson.databind.ObjectMapper 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 { private val TAG = "PreferenceHelper" @@ -135,114 +131,6 @@ object PreferenceHelper { 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 { - 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 { - 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) { editor.putString(PreferenceKeys.LAST_STREAM_VIDEO_ID, videoId) }