Merge pull request #1055 from Bnyro/master

Migrate all stored data to Room database
This commit is contained in:
Bnyro 2022-08-13 23:19:25 +02:00 committed by GitHub
commit ed51cf91a2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
31 changed files with 478 additions and 332 deletions

View File

@ -4,6 +4,7 @@ plugins {
id 'com.android.application' id 'com.android.application'
id 'kotlin-android' id 'kotlin-android'
id 'kotlin-android-extensions' id 'kotlin-android-extensions'
id 'kotlin-kapt'
} }
android { android {
@ -74,6 +75,8 @@ android {
dependencies { dependencies {
//debugImplementation libs.square.leakcanary //debugImplementation libs.square.leakcanary
kapt libs.room.compiler
implementation libs.androidx.appcompat implementation libs.androidx.appcompat
implementation libs.androidx.constraintlayout implementation libs.androidx.constraintlayout
implementation libs.androidx.legacySupport implementation libs.androidx.legacySupport
@ -106,6 +109,8 @@ dependencies {
implementation libs.lifecycle.viewmodel implementation libs.lifecycle.viewmodel
implementation libs.lifecycle.runtime implementation libs.lifecycle.runtime
implementation libs.lifecycle.livedata implementation libs.lifecycle.livedata
implementation libs.room
} }
static def getUnixTime() { static def getUnixTime() {

View File

@ -49,3 +49,8 @@ const val DOWNLOAD_SUCCESS_NOTIFICATION_ID = 5
const val DOWNLOAD_CHANNEL_ID = "download_service" const val DOWNLOAD_CHANNEL_ID = "download_service"
const val BACKGROUND_CHANNEL_ID = "background_mode" const val BACKGROUND_CHANNEL_ID = "background_mode"
const val PUSH_CHANNEL_ID = "notification_worker" const val PUSH_CHANNEL_ID = "notification_worker"
/**
* Database
*/
const val DATABASE_NAME = "LibreTubeDatabase"

View File

@ -8,6 +8,7 @@ import android.os.Build
import android.os.StrictMode import android.os.StrictMode
import android.os.StrictMode.VmPolicy import android.os.StrictMode.VmPolicy
import androidx.work.ExistingPeriodicWorkPolicy import androidx.work.ExistingPeriodicWorkPolicy
import com.github.libretube.database.DatabaseHolder
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.util.ExceptionHandler import com.github.libretube.util.ExceptionHandler
@ -19,15 +20,20 @@ class MyApp : Application() {
super.onCreate() super.onCreate()
/** /**
* initialize the needed [NotificationChannel]s for DownloadService and BackgroundMode * Initialize the needed [NotificationChannel]s for DownloadService and BackgroundMode
*/ */
initializeNotificationChannels() initializeNotificationChannels()
/** /**
* set the applicationContext as context for the [PreferenceHelper] * Set the applicationContext as context for the [PreferenceHelper]
*/ */
PreferenceHelper.setContext(applicationContext) PreferenceHelper.setContext(applicationContext)
/**
* Initialize the [DatabaseHolder]
*/
DatabaseHolder.initializeDatabase(this)
/** /**
* bypassing fileUriExposedException, see https://stackoverflow.com/questions/38200282/android-os-fileuriexposedexception-file-storage-emulated-0-test-txt-exposed * bypassing fileUriExposedException, see https://stackoverflow.com/questions/38200282/android-os-fileuriexposedexception-file-storage-emulated-0-test-txt-exposed
*/ */
@ -35,12 +41,12 @@ class MyApp : Application() {
StrictMode.setVmPolicy(builder.build()) StrictMode.setVmPolicy(builder.build())
/** /**
* set the api and the auth api url * Set the api and the auth api url
*/ */
setRetrofitApiUrls() setRetrofitApiUrls()
/** /**
* initialize the notification listener in the background * Initialize the notification listener in the background
*/ */
NotificationHelper.enqueueWork(this, ExistingPeriodicWorkPolicy.KEEP) NotificationHelper.enqueueWork(this, ExistingPeriodicWorkPolicy.KEEP)
@ -52,13 +58,13 @@ class MyApp : Application() {
Thread.setDefaultUncaughtExceptionHandler(exceptionHandler) Thread.setDefaultUncaughtExceptionHandler(exceptionHandler)
/** /**
* legacy preference file migration * Legacy preference file migration
*/ */
prefFileMigration() prefFileMigration()
} }
/** /**
* set the api urls needed for the [RetrofitInstance] * Set the api urls needed for the [RetrofitInstance]
*/ */
private fun setRetrofitApiUrls() { private fun setRetrofitApiUrls() {
RetrofitInstance.url = RetrofitInstance.url =

View File

@ -89,77 +89,79 @@ class MainActivity : BaseActivity() {
if (!ConnectionHelper.isNetworkAvailable(this)) { if (!ConnectionHelper.isNetworkAvailable(this)) {
val noInternetIntent = Intent(this, NoInternetActivity::class.java) val noInternetIntent = Intent(this, NoInternetActivity::class.java)
startActivity(noInternetIntent) startActivity(noInternetIntent)
} else { finish()
binding = ActivityMainBinding.inflate(layoutInflater) return
setContentView(binding.root)
// set the action bar for the activity
setSupportActionBar(binding.toolbar)
navController = findNavController(R.id.fragment)
binding.bottomNav.setupWithNavController(navController)
// gets the surface color of the bottom navigation view
val color = SurfaceColors.getColorForElevation(this, 10F)
// sets the navigation bar color to the previously calculated color
window.navigationBarColor = color
// hide the trending page if enabled
val hideTrendingPage =
PreferenceHelper.getBoolean(PreferenceKeys.HIDE_TRENDING_PAGE, false)
if (hideTrendingPage) binding.bottomNav.menu.findItem(R.id.homeFragment).isVisible =
false
// save start tab fragment id
startFragmentId =
when (PreferenceHelper.getString(PreferenceKeys.DEFAULT_TAB, "home")) {
"home" -> R.id.homeFragment
"subscriptions" -> R.id.subscriptionsFragment
"library" -> R.id.libraryFragment
else -> R.id.homeFragment
}
// set default tab as start fragment
navController.graph.setStartDestination(startFragmentId)
// navigate to the default fragment
navController.navigate(startFragmentId)
val labelVisibilityMode = when (
PreferenceHelper.getString(PreferenceKeys.LABEL_VISIBILITY, "always")
) {
"always" -> NavigationBarView.LABEL_VISIBILITY_LABELED
"selected" -> NavigationBarView.LABEL_VISIBILITY_SELECTED
"never" -> NavigationBarView.LABEL_VISIBILITY_UNLABELED
else -> NavigationBarView.LABEL_VISIBILITY_AUTO
}
binding.bottomNav.labelVisibilityMode = labelVisibilityMode
binding.bottomNav.setOnApplyWindowInsetsListener(null)
binding.bottomNav.setOnItemSelectedListener {
// clear backstack if it's the start fragment
if (startFragmentId == it.itemId) navController.backQueue.clear()
// set menu item on click listeners
removeSearchFocus()
when (it.itemId) {
R.id.homeFragment -> {
navController.navigate(R.id.homeFragment)
}
R.id.subscriptionsFragment -> {
navController.navigate(R.id.subscriptionsFragment)
}
R.id.libraryFragment -> {
navController.navigate(R.id.libraryFragment)
}
}
false
}
binding.toolbar.title = ThemeHelper.getStyledAppName(this)
} }
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
// set the action bar for the activity
setSupportActionBar(binding.toolbar)
navController = findNavController(R.id.fragment)
binding.bottomNav.setupWithNavController(navController)
// gets the surface color of the bottom navigation view
val color = SurfaceColors.getColorForElevation(this, 10F)
// sets the navigation bar color to the previously calculated color
window.navigationBarColor = color
// hide the trending page if enabled
val hideTrendingPage =
PreferenceHelper.getBoolean(PreferenceKeys.HIDE_TRENDING_PAGE, false)
if (hideTrendingPage) binding.bottomNav.menu.findItem(R.id.homeFragment).isVisible =
false
// save start tab fragment id
startFragmentId =
when (PreferenceHelper.getString(PreferenceKeys.DEFAULT_TAB, "home")) {
"home" -> R.id.homeFragment
"subscriptions" -> R.id.subscriptionsFragment
"library" -> R.id.libraryFragment
else -> R.id.homeFragment
}
// set default tab as start fragment
navController.graph.setStartDestination(startFragmentId)
// navigate to the default fragment
navController.navigate(startFragmentId)
val labelVisibilityMode = when (
PreferenceHelper.getString(PreferenceKeys.LABEL_VISIBILITY, "always")
) {
"always" -> NavigationBarView.LABEL_VISIBILITY_LABELED
"selected" -> NavigationBarView.LABEL_VISIBILITY_SELECTED
"never" -> NavigationBarView.LABEL_VISIBILITY_UNLABELED
else -> NavigationBarView.LABEL_VISIBILITY_AUTO
}
binding.bottomNav.labelVisibilityMode = labelVisibilityMode
binding.bottomNav.setOnApplyWindowInsetsListener(null)
binding.bottomNav.setOnItemSelectedListener {
// clear backstack if it's the start fragment
if (startFragmentId == it.itemId) navController.backQueue.clear()
// set menu item on click listeners
removeSearchFocus()
when (it.itemId) {
R.id.homeFragment -> {
navController.navigate(R.id.homeFragment)
}
R.id.subscriptionsFragment -> {
navController.navigate(R.id.subscriptionsFragment)
}
R.id.libraryFragment -> {
navController.navigate(R.id.libraryFragment)
}
}
false
}
binding.toolbar.title = ThemeHelper.getStyledAppName(this)
/** /**
* handle error logs * handle error logs
*/ */

View File

@ -4,8 +4,9 @@ import android.view.LayoutInflater
import android.view.ViewGroup import android.view.ViewGroup
import androidx.appcompat.widget.SearchView import androidx.appcompat.widget.SearchView
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import com.github.libretube.database.DatabaseHolder
import com.github.libretube.databinding.SearchhistoryRowBinding import com.github.libretube.databinding.SearchhistoryRowBinding
import com.github.libretube.preferences.PreferenceHelper import com.github.libretube.obj.SearchHistoryItem
class SearchHistoryAdapter( class SearchHistoryAdapter(
private var historyList: List<String>, private var historyList: List<String>,
@ -29,8 +30,12 @@ class SearchHistoryAdapter(
historyText.text = historyQuery historyText.text = historyQuery
deleteHistory.setOnClickListener { deleteHistory.setOnClickListener {
historyList = historyList - historyQuery historyList -= historyQuery
PreferenceHelper.removeFromSearchHistory(historyQuery) Thread {
DatabaseHolder.database.searchHistoryDao().delete(
SearchHistoryItem(query = historyQuery)
)
}.start()
notifyDataSetChanged() notifyDataSetChanged()
} }

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

@ -0,0 +1,39 @@
package com.github.libretube.database
import androidx.room.Database
import androidx.room.RoomDatabase
import com.github.libretube.obj.CustomInstance
import com.github.libretube.obj.SearchHistoryItem
import com.github.libretube.obj.WatchHistoryItem
import com.github.libretube.obj.WatchPosition
@Database(
entities = [
WatchHistoryItem::class,
WatchPosition::class,
SearchHistoryItem::class,
CustomInstance::class
],
version = 6
)
abstract class AppDatabase : RoomDatabase() {
/**
* Watch History
*/
abstract fun watchHistoryDao(): WatchHistoryDao
/**
* Watch Positions
*/
abstract fun watchPositionDao(): WatchPositionDao
/**
* Search History
*/
abstract fun searchHistoryDao(): SearchHistoryDao
/**
* Custom Instances
*/
abstract fun customInstanceDao(): CustomInstanceDao
}

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.CustomInstance
@Dao
interface CustomInstanceDao {
@Query("SELECT * FROM customInstance")
fun getAll(): List<CustomInstance>
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insertAll(vararg customInstances: CustomInstance)
@Delete
fun delete(customInstance: CustomInstance)
@Query("DELETE FROM customInstance")
fun deleteAll()
}

View File

@ -0,0 +1,61 @@
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.preferences.PreferenceHelper
import com.github.libretube.preferences.PreferenceKeys
import com.github.libretube.util.toID
object DatabaseHelper {
fun addToWatchHistory(videoId: String, streams: Streams) {
val watchHistoryItem = WatchHistoryItem(
videoId,
streams.title,
streams.uploadDate,
streams.uploader,
streams.uploaderUrl.toID(),
streams.uploaderAvatar,
streams.thumbnailUrl,
streams.duration
)
Thread {
DatabaseHolder.database.watchHistoryDao().insertAll(watchHistoryItem)
val maxHistorySize = PreferenceHelper.getString(PreferenceKeys.WATCH_HISTORY_SIZE, "unlimited")
if (maxHistorySize == "unlimited") return@Thread
// delete the first watch history entry if the limit is reached
val watchHistory = DatabaseHolder.database.watchHistoryDao().getAll()
if (watchHistory.size > maxHistorySize.toInt()) {
DatabaseHolder.database.watchHistoryDao()
.delete(watchHistory.first())
}
}.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

@ -0,0 +1,19 @@
package com.github.libretube.database
import android.content.Context
import androidx.room.Room
import com.github.libretube.DATABASE_NAME
object DatabaseHolder {
lateinit var database: AppDatabase
fun initializeDatabase(context: Context) {
database = Room.databaseBuilder(
context,
AppDatabase::class.java,
DATABASE_NAME
)
.fallbackToDestructiveMigration()
.build()
}
}

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.SearchHistoryItem
@Dao
interface SearchHistoryDao {
@Query("SELECT * FROM searchHistoryItem")
fun getAll(): List<SearchHistoryItem>
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insertAll(vararg searchHistoryItem: SearchHistoryItem)
@Delete
fun delete(searchHistoryItem: SearchHistoryItem)
@Query("DELETE FROM searchHistoryItem")
fun deleteAll()
}

View File

@ -0,0 +1,26 @@
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
@Dao
interface WatchHistoryDao {
@Query("SELECT * FROM watchHistoryItem")
fun getAll(): List<WatchHistoryItem>
@Query("SELECT * FROM watchHistoryItem WHERE videoId LIKE :videoId LIMIT 1")
fun findById(videoId: String): WatchHistoryItem
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insertAll(vararg watchHistoryItems: WatchHistoryItem)
@Delete
fun delete(watchHistoryItem: WatchHistoryItem)
@Query("DELETE FROM watchHistoryItem")
fun deleteAll()
}

View File

@ -0,0 +1,26 @@
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)
@Query("DELETE FROM watchPosition")
fun deleteAll()
}

View File

@ -5,9 +5,9 @@ import android.os.Bundle
import android.widget.Toast import android.widget.Toast
import androidx.fragment.app.DialogFragment import androidx.fragment.app.DialogFragment
import com.github.libretube.R import com.github.libretube.R
import com.github.libretube.database.DatabaseHolder
import com.github.libretube.databinding.DialogCustomInstanceBinding import com.github.libretube.databinding.DialogCustomInstanceBinding
import com.github.libretube.obj.CustomInstance import com.github.libretube.obj.CustomInstance
import com.github.libretube.preferences.PreferenceHelper
import com.github.libretube.util.ThemeHelper import com.github.libretube.util.ThemeHelper
import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.dialog.MaterialAlertDialogBuilder
import java.net.URL import java.net.URL
@ -26,10 +26,11 @@ class CustomInstanceDialog : DialogFragment() {
} }
binding.addInstance.setOnClickListener { binding.addInstance.setOnClickListener {
val customInstance = CustomInstance() val customInstance = CustomInstance(
customInstance.name = binding.instanceName.text.toString() name = binding.instanceName.text.toString(),
customInstance.apiUrl = binding.instanceApiUrl.text.toString() apiUrl = binding.instanceApiUrl.text.toString(),
customInstance.frontendUrl = binding.instanceFrontendUrl.text.toString() frontendUrl = binding.instanceFrontendUrl.text.toString()
)
if ( if (
customInstance.name != "" && customInstance.name != "" &&
@ -41,7 +42,10 @@ class CustomInstanceDialog : DialogFragment() {
URL(customInstance.apiUrl).toURI() URL(customInstance.apiUrl).toURI()
URL(customInstance.frontendUrl).toURI() URL(customInstance.frontendUrl).toURI()
PreferenceHelper.saveCustomInstance(customInstance) Thread {
DatabaseHolder.database.customInstanceDao().insertAll(customInstance)
}.start()
activity?.recreate() activity?.recreate()
dismiss() dismiss()
} catch (e: Exception) { } catch (e: Exception) {

View File

@ -7,6 +7,9 @@ import androidx.fragment.app.DialogFragment
import com.github.libretube.PIPED_FRONTEND_URL import com.github.libretube.PIPED_FRONTEND_URL
import com.github.libretube.R import com.github.libretube.R
import com.github.libretube.YOUTUBE_FRONTEND_URL import com.github.libretube.YOUTUBE_FRONTEND_URL
import com.github.libretube.database.DatabaseHolder
import com.github.libretube.extensions.await
import com.github.libretube.obj.CustomInstance
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.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.dialog.MaterialAlertDialogBuilder
@ -71,7 +74,10 @@ class ShareDialog(
) )
// get the api urls of the other custom instances // get the api urls of the other custom instances
val customInstances = PreferenceHelper.getCustomInstances() var customInstances = listOf<CustomInstance>()
Thread {
customInstances = DatabaseHolder.database.customInstanceDao().getAll()
}.await()
// return the custom instance frontend url if available // return the custom instance frontend url if available
customInstances.forEach { instance -> customInstances.forEach { instance ->

View File

@ -0,0 +1,8 @@
package com.github.libretube.extensions
fun Thread.await() {
this.apply {
start()
join()
}
}

View File

@ -3,37 +3,38 @@ 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.extensions.await
/** /**
* 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 progress: Long? = null
var newWidth: Long? = null
Thread {
try {
progress = DatabaseHolder.database.watchPositionDao().findById(videoId).position
} catch (e: Exception) {
progress = null
}
}.await()
view.getViewTreeObserver() view.getViewTreeObserver()
.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener { .addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener {
override fun onGlobalLayout() { override fun onGlobalLayout() {
this@setWatchProgressLength.getViewTreeObserver().removeOnGlobalLayoutListener(this) this@setWatchProgressLength.getViewTreeObserver().removeOnGlobalLayoutListener(this)
positions.forEach { if (progress == null) {
if (it.videoId == videoId) {
val fullWidth = (parent as LinearLayout).width
if (duration != 0L) newWidth =
(fullWidth * (it.position / (duration))) / 1000
return@forEach
}
}
if (newWidth != null) {
val lp = view.layoutParams
lp.apply {
width = newWidth!!.toInt()
}
view.layoutParams = lp
view.visibility = View.VISIBLE
} else {
view.visibility = View.GONE view.visibility = View.GONE
return
} }
val fullWidth = (parent as LinearLayout).width
val newWidth = (fullWidth * (progress!! / (duration))) / 1000
val lp = view.layoutParams
lp.width = newWidth.toInt()
view.layoutParams = lp
view.visibility = View.VISIBLE
} }
}) })
} }

View File

@ -37,6 +37,8 @@ import com.github.libretube.activities.MainActivity
import com.github.libretube.adapters.ChaptersAdapter 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.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
@ -44,6 +46,7 @@ import com.github.libretube.dialogs.AddToPlaylistDialog
import com.github.libretube.dialogs.DownloadDialog import com.github.libretube.dialogs.DownloadDialog
import com.github.libretube.dialogs.ShareDialog import com.github.libretube.dialogs.ShareDialog
import com.github.libretube.extensions.BaseFragment import com.github.libretube.extensions.BaseFragment
import com.github.libretube.extensions.await
import com.github.libretube.interfaces.DoubleTapInterface import com.github.libretube.interfaces.DoubleTapInterface
import com.github.libretube.interfaces.PlayerOptionsInterface import com.github.libretube.interfaces.PlayerOptionsInterface
import com.github.libretube.obj.ChapterSegment import com.github.libretube.obj.ChapterSegment
@ -88,7 +91,6 @@ import com.google.android.exoplayer2.upstream.DefaultHttpDataSource
import com.google.android.exoplayer2.util.RepeatModeUtil import com.google.android.exoplayer2.util.RepeatModeUtil
import com.google.android.exoplayer2.video.VideoSize import com.google.android.exoplayer2.video.VideoSize
import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.dialog.MaterialAlertDialogBuilder
import kotlinx.android.synthetic.main.bottom_sheet.repeatMode
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@ -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!!)
} }
} }
@ -878,7 +879,7 @@ class PlayerFragment : BaseFragment() {
if (!relatedStreamsEnabled) toggleComments() if (!relatedStreamsEnabled) toggleComments()
// prepare for autoplay // prepare for autoplay
if (autoplayEnabled) setNextStream() if (autoplayEnabled) setNextStream()
if (watchHistoryEnabled) PreferenceHelper.addToWatchHistory(videoId!!, streams) if (watchHistoryEnabled) DatabaseHelper.addToWatchHistory(videoId!!, streams)
} }
} }
} }
@ -934,14 +935,14 @@ 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 position: Long? = null var position: Long? = null
watchPositions.forEach { Thread {
if (it.videoId == videoId && try {
// don't seek to the position if it's the end, autoplay would skip it immediately position = DatabaseHolder.database.watchPositionDao().findById(videoId!!).position
streams.duration!! - it.position / 1000 > 2 } catch (e: Exception) {
) position = it.position position = null
} }
}.await()
// support for time stamped links // support for time stamped links
val timeStamp: Long? = arguments?.getLong("timeStamp") val timeStamp: Long? = arguments?.getLong("timeStamp")
if (timeStamp != null && timeStamp != 0L) { if (timeStamp != null && timeStamp != 0L) {

View File

@ -11,10 +11,11 @@ import androidx.recyclerview.widget.LinearLayoutManager
import com.github.libretube.activities.MainActivity import com.github.libretube.activities.MainActivity
import com.github.libretube.adapters.SearchHistoryAdapter import com.github.libretube.adapters.SearchHistoryAdapter
import com.github.libretube.adapters.SearchSuggestionsAdapter import com.github.libretube.adapters.SearchSuggestionsAdapter
import com.github.libretube.database.DatabaseHolder
import com.github.libretube.databinding.FragmentSearchBinding import com.github.libretube.databinding.FragmentSearchBinding
import com.github.libretube.extensions.BaseFragment import com.github.libretube.extensions.BaseFragment
import com.github.libretube.extensions.await
import com.github.libretube.models.SearchViewModel import com.github.libretube.models.SearchViewModel
import com.github.libretube.preferences.PreferenceHelper
import com.github.libretube.util.RetrofitInstance import com.github.libretube.util.RetrofitInstance
import retrofit2.HttpException import retrofit2.HttpException
import java.io.IOException import java.io.IOException
@ -89,7 +90,11 @@ class SearchFragment() : BaseFragment() {
} }
private fun showHistory() { private fun showHistory() {
val historyList = PreferenceHelper.getSearchHistory() var historyList = listOf<String>()
Thread {
val history = DatabaseHolder.database.searchHistoryDao().getAll()
historyList = history.map { it.query!! }
}.await()
if (historyList.isNotEmpty()) { if (historyList.isNotEmpty()) {
binding.suggestionsRecycler.adapter = binding.suggestionsRecycler.adapter =
SearchHistoryAdapter( SearchHistoryAdapter(

View File

@ -9,8 +9,11 @@ import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import com.github.libretube.R import com.github.libretube.R
import com.github.libretube.adapters.SearchAdapter import com.github.libretube.adapters.SearchAdapter
import com.github.libretube.database.DatabaseHolder
import com.github.libretube.databinding.FragmentSearchResultBinding import com.github.libretube.databinding.FragmentSearchResultBinding
import com.github.libretube.extensions.BaseFragment import com.github.libretube.extensions.BaseFragment
import com.github.libretube.extensions.await
import com.github.libretube.obj.SearchHistoryItem
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.util.RetrofitInstance import com.github.libretube.util.RetrofitInstance
@ -132,7 +135,13 @@ class SearchResultFragment : BaseFragment() {
val searchHistoryEnabled = val searchHistoryEnabled =
PreferenceHelper.getBoolean(PreferenceKeys.SEARCH_HISTORY_TOGGLE, true) PreferenceHelper.getBoolean(PreferenceKeys.SEARCH_HISTORY_TOGGLE, true)
if (searchHistoryEnabled && query != "") { if (searchHistoryEnabled && query != "") {
PreferenceHelper.saveToSearchHistory(query) Thread {
DatabaseHolder.database.searchHistoryDao().insertAll(
SearchHistoryItem(
query = query
)
)
}.await()
} }
} }
} }

View File

@ -8,9 +8,11 @@ import androidx.recyclerview.widget.ItemTouchHelper
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import com.github.libretube.adapters.WatchHistoryAdapter import com.github.libretube.adapters.WatchHistoryAdapter
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.preferences.PreferenceHelper import com.github.libretube.extensions.await
import com.github.libretube.obj.WatchHistoryItem
class WatchHistoryFragment : BaseFragment() { class WatchHistoryFragment : BaseFragment() {
private val TAG = "WatchHistoryFragment" private val TAG = "WatchHistoryFragment"
@ -28,7 +30,11 @@ class WatchHistoryFragment : BaseFragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
val watchHistory = PreferenceHelper.getWatchHistory() var watchHistory = listOf<WatchHistoryItem>()
Thread {
watchHistory = DatabaseHolder.database.watchHistoryDao().getAll()
}.await()
if (watchHistory.isEmpty()) return if (watchHistory.isEmpty()) return
@ -39,7 +45,7 @@ class WatchHistoryFragment : BaseFragment() {
} }
val watchHistoryAdapter = WatchHistoryAdapter( val watchHistoryAdapter = WatchHistoryAdapter(
watchHistory, watchHistory.toMutableList(),
childFragmentManager childFragmentManager
) )

View File

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

View File

@ -0,0 +1,9 @@
package com.github.libretube.obj
import androidx.room.Entity
import androidx.room.PrimaryKey
@Entity(tableName = "searchHistoryItem")
data class SearchHistoryItem(
@PrimaryKey val query: String = ""
)

View File

@ -1,12 +1,17 @@
package com.github.libretube.obj package com.github.libretube.obj
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
@Entity(tableName = "watchHistoryItem")
data class WatchHistoryItem( data class WatchHistoryItem(
val videoId: String? = null, @PrimaryKey val videoId: String = "",
val title: String? = null, @ColumnInfo val title: String? = null,
val uploadDate: String? = null, @ColumnInfo val uploadDate: String? = null,
val uploader: String? = null, @ColumnInfo val uploader: String? = null,
val uploaderUrl: String? = null, @ColumnInfo val uploaderUrl: String? = null,
val uploaderAvatar: String? = null, @ColumnInfo val uploaderAvatar: String? = null,
val thumbnailUrl: String? = null, @ColumnInfo val thumbnailUrl: String? = null,
val duration: Long? = null @ColumnInfo val duration: Long? = null
) )

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

@ -4,6 +4,7 @@ import android.os.Bundle
import androidx.preference.Preference import androidx.preference.Preference
import com.github.libretube.R import com.github.libretube.R
import com.github.libretube.activities.SettingsActivity import com.github.libretube.activities.SettingsActivity
import com.github.libretube.database.DatabaseHolder
import com.github.libretube.views.MaterialPreferenceFragment import com.github.libretube.views.MaterialPreferenceFragment
import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.dialog.MaterialAlertDialogBuilder
@ -18,33 +19,41 @@ class HistorySettings : MaterialPreferenceFragment() {
// clear search history // clear search history
val clearHistory = findPreference<Preference>(PreferenceKeys.CLEAR_SEARCH_HISTORY) val clearHistory = findPreference<Preference>(PreferenceKeys.CLEAR_SEARCH_HISTORY)
clearHistory?.setOnPreferenceClickListener { clearHistory?.setOnPreferenceClickListener {
showClearDialog(R.string.clear_history, "search_history") showClearDialog(R.string.clear_history) {
DatabaseHolder.database.searchHistoryDao().deleteAll()
}
true true
} }
// clear watch history and positions // clear watch history and positions
val clearWatchHistory = findPreference<Preference>(PreferenceKeys.CLEAR_WATCH_HISTORY) val clearWatchHistory = findPreference<Preference>(PreferenceKeys.CLEAR_WATCH_HISTORY)
clearWatchHistory?.setOnPreferenceClickListener { clearWatchHistory?.setOnPreferenceClickListener {
showClearDialog(R.string.clear_history, "watch_history") showClearDialog(R.string.clear_history) {
DatabaseHolder.database.watchHistoryDao().deleteAll()
}
true true
} }
// clear watch positions // clear watch positions
val clearWatchPositions = findPreference<Preference>(PreferenceKeys.CLEAR_WATCH_POSITIONS) val clearWatchPositions = findPreference<Preference>(PreferenceKeys.CLEAR_WATCH_POSITIONS)
clearWatchPositions?.setOnPreferenceClickListener { clearWatchPositions?.setOnPreferenceClickListener {
showClearDialog(R.string.reset_watch_positions, "watch_positions") showClearDialog(R.string.reset_watch_positions) {
DatabaseHolder.database.watchPositionDao().deleteAll()
}
true true
} }
} }
private fun showClearDialog(title: Int, preferenceKey: String) { private fun showClearDialog(title: Int, action: () -> Unit) {
MaterialAlertDialogBuilder(requireContext()) MaterialAlertDialogBuilder(requireContext())
.setTitle(title) .setTitle(title)
.setMessage(R.string.irreversible) .setMessage(R.string.irreversible)
.setNegativeButton(R.string.cancel, null) .setNegativeButton(R.string.cancel, null)
.setPositiveButton(R.string.okay) { _, _ -> .setPositiveButton(R.string.okay) { _, _ ->
// clear the selected preference preferences // clear the selected preference preferences
PreferenceHelper.removePreference(preferenceKey) Thread {
action()
}.start()
} }
.show() .show()
} }

View File

@ -1,6 +1,5 @@
package com.github.libretube.preferences package com.github.libretube.preferences
import android.content.Intent
import android.net.Uri import android.net.Uri
import android.os.Bundle import android.os.Bundle
import android.widget.Toast import android.widget.Toast
@ -13,10 +12,13 @@ import androidx.preference.Preference
import androidx.preference.SwitchPreferenceCompat import androidx.preference.SwitchPreferenceCompat
import com.github.libretube.R import com.github.libretube.R
import com.github.libretube.activities.SettingsActivity import com.github.libretube.activities.SettingsActivity
import com.github.libretube.database.DatabaseHolder
import com.github.libretube.dialogs.CustomInstanceDialog import com.github.libretube.dialogs.CustomInstanceDialog
import com.github.libretube.dialogs.DeleteAccountDialog import com.github.libretube.dialogs.DeleteAccountDialog
import com.github.libretube.dialogs.LoginDialog import com.github.libretube.dialogs.LoginDialog
import com.github.libretube.dialogs.LogoutDialog import com.github.libretube.dialogs.LogoutDialog
import com.github.libretube.extensions.await
import com.github.libretube.obj.CustomInstance
import com.github.libretube.util.ImportHelper import com.github.libretube.util.ImportHelper
import com.github.libretube.util.PermissionHelper import com.github.libretube.util.PermissionHelper
import com.github.libretube.util.RetrofitInstance import com.github.libretube.util.RetrofitInstance
@ -104,9 +106,10 @@ class InstanceSettings : MaterialPreferenceFragment() {
val clearCustomInstances = findPreference<Preference>(PreferenceKeys.CLEAR_CUSTOM_INSTANCES) val clearCustomInstances = findPreference<Preference>(PreferenceKeys.CLEAR_CUSTOM_INSTANCES)
clearCustomInstances?.setOnPreferenceClickListener { clearCustomInstances?.setOnPreferenceClickListener {
PreferenceHelper.removePreference("customInstances") Thread {
val intent = Intent(context, SettingsActivity::class.java) DatabaseHolder.database.customInstanceDao().deleteAll()
startActivity(intent) }.await()
activity?.recreate()
true true
} }
@ -157,7 +160,10 @@ class InstanceSettings : MaterialPreferenceFragment() {
private fun initCustomInstances(instancePref: ListPreference) { private fun initCustomInstances(instancePref: ListPreference) {
lifecycleScope.launchWhenCreated { lifecycleScope.launchWhenCreated {
val customInstances = PreferenceHelper.getCustomInstances() var customInstances = listOf<CustomInstance>()
Thread {
customInstances = DatabaseHolder.database.customInstanceDao().getAll()
}.await()
val instanceNames = arrayListOf<String>() val instanceNames = arrayListOf<String>()
val instanceValues = arrayListOf<String>() val instanceValues = arrayListOf<String>()

View File

@ -5,11 +5,6 @@ import android.content.SharedPreferences
import androidx.preference.PreferenceManager 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.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"
@ -75,174 +70,6 @@ object PreferenceHelper {
authEditor.putString(PreferenceKeys.USERNAME, newValue).apply() authEditor.putString(PreferenceKeys.USERNAME, newValue).apply()
} }
fun saveCustomInstance(customInstance: CustomInstance) {
val customInstancesList = getCustomInstances()
customInstancesList += customInstance
val json = mapper.writeValueAsString(customInstancesList)
editor.putString("customInstances", json).apply()
}
fun getCustomInstances(): ArrayList<CustomInstance> {
val json: String = settings.getString("customInstances", "")!!
val type = mapper.typeFactory.constructCollectionType(
List::class.java,
CustomInstance::class.java
)
return try {
mapper.readValue(json, type)
} catch (e: Exception) {
arrayListOf()
}
}
fun getSearchHistory(): List<String> {
return try {
val json = settings.getString("search_history", "")!!
val type = object : TypeReference<List<String>>() {}
return mapper.readValue(json, type)
} catch (e: Exception) {
emptyList()
}
}
fun saveToSearchHistory(query: String) {
val historyList = getSearchHistory().toMutableList()
if ((historyList.contains(query))) {
// remove from history list if already contained
historyList -= query
}
// append new query to history
historyList.add(0, query)
if (historyList.size > 10) {
historyList.removeAt(historyList.size - 1)
}
updateSearchHistory(historyList)
}
fun removeFromSearchHistory(query: String) {
val historyList = getSearchHistory().toMutableList()
historyList -= query
updateSearchHistory(historyList)
}
private fun updateSearchHistory(historyList: List<String>) {
val json = mapper.writeValueAsString(historyList)
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)
} }

View File

@ -2,6 +2,7 @@ package com.github.libretube.update
import com.fasterxml.jackson.databind.ObjectMapper import com.fasterxml.jackson.databind.ObjectMapper
import com.github.libretube.GITHUB_API_URL import com.github.libretube.GITHUB_API_URL
import com.github.libretube.extensions.await
import java.net.URL import java.net.URL
object UpdateChecker { object UpdateChecker {
@ -15,10 +16,7 @@ object UpdateChecker {
versionInfo = getUpdateInfo() versionInfo = getUpdateInfo()
} catch (e: Exception) { } catch (e: Exception) {
} }
} }.await()
thread.start()
// wait for the thread to finish
thread.join()
// return the information about the latest version // return the information about the latest version
return versionInfo return versionInfo

View File

@ -10,6 +10,7 @@ import android.support.v4.media.session.MediaSessionCompat
import com.github.libretube.BACKGROUND_CHANNEL_ID import com.github.libretube.BACKGROUND_CHANNEL_ID
import com.github.libretube.PLAYER_NOTIFICATION_ID import com.github.libretube.PLAYER_NOTIFICATION_ID
import com.github.libretube.activities.MainActivity import com.github.libretube.activities.MainActivity
import com.github.libretube.extensions.await
import com.github.libretube.obj.Streams import com.github.libretube.obj.Streams
import com.google.android.exoplayer2.ExoPlayer import com.google.android.exoplayer2.ExoPlayer
import com.google.android.exoplayer2.Player import com.google.android.exoplayer2.Player
@ -87,7 +88,7 @@ class NowPlayingNotification(
/** /**
* running on a new thread to prevent a NetworkMainThreadException * running on a new thread to prevent a NetworkMainThreadException
*/ */
val thread = Thread { Thread {
try { try {
/** /**
* try to GET the thumbnail from the URL * try to GET the thumbnail from the URL
@ -97,9 +98,7 @@ class NowPlayingNotification(
} catch (ex: java.lang.Exception) { } catch (ex: java.lang.Exception) {
ex.printStackTrace() ex.printStackTrace()
} }
} }.await()
thread.start()
thread.join()
/** /**
* returns the scaled bitmap if it got fetched successfully * returns the scaled bitmap if it got fetched successfully
*/ */

View File

@ -20,6 +20,7 @@ cronetEmbedded = "101.4951.41"
cronetOkHttp = "0.1.0" cronetOkHttp = "0.1.0"
coil = "2.1.0" coil = "2.1.0"
leakcanary = "2.8.1" leakcanary = "2.8.1"
room = "2.4.3"
[libraries] [libraries]
androidx-appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "appcompat" } androidx-appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "appcompat" }
@ -48,4 +49,6 @@ coil = { group = "io.coil-kt", name = "coil", version.ref="coil" }
square-leakcanary = { group = "com.squareup.leakcanary", name = "leakcanary-android", version.ref = "leakcanary" } square-leakcanary = { group = "com.squareup.leakcanary", name = "leakcanary-android", version.ref = "leakcanary" }
lifecycle-viewmodel = { group = "androidx.lifecycle", name = "lifecycle-viewmodel-ktx", version.ref = "lifecycle" } lifecycle-viewmodel = { group = "androidx.lifecycle", name = "lifecycle-viewmodel-ktx", version.ref = "lifecycle" }
lifecycle-runtime = { group = "androidx.lifecycle", name = "lifecycle-runtime-ktx", version.ref = "lifecycle" } lifecycle-runtime = { group = "androidx.lifecycle", name = "lifecycle-runtime-ktx", version.ref = "lifecycle" }
lifecycle-livedata = { group = "androidx.lifecycle", name = "lifecycle-livedata-ktx", version.ref = "lifecycle" } lifecycle-livedata = { group = "androidx.lifecycle", name = "lifecycle-livedata-ktx", version.ref = "lifecycle" }
room = { group = "androidx.room", name="room-runtime", version.ref = "room" }
room-compiler = { group = "androidx.room", name = "room-compiler", version.ref = "room" }