From e539cc26dd6c3857836a11d73f1e43a0fd7dd84b Mon Sep 17 00:00:00 2001 From: Antoine POPINEAU Date: Sat, 20 Jun 2020 15:42:10 +0200 Subject: [PATCH] Manage cached and downloaded tracks separately. Downloaded track are not automatically evicted and do not count towards cache storage limit. Contributes to #37. Fixed an issue where the event bus on main would be duplicated. --- .../java/com/github/apognu/otter/Otter.kt | 18 +++++++++++---- .../apognu/otter/activities/MainActivity.kt | 23 +++++++++++++++---- .../apognu/otter/adapters/FavoritesAdapter.kt | 16 ++++++++++++- .../apognu/otter/adapters/TracksAdapter.kt | 17 +++++++++++--- .../apognu/otter/playback/QueueManager.kt | 13 ++++++++++- .../otter/repositories/FavoritesRepository.kt | 8 +++++++ .../otter/repositories/TracksRepository.kt | 8 +++++++ .../com/github/apognu/otter/utils/Models.kt | 1 + app/src/main/res/values-night/colors.xml | 3 +++ app/src/main/res/values/colors.xml | 3 +++ 10 files changed, 95 insertions(+), 15 deletions(-) diff --git a/app/src/main/java/com/github/apognu/otter/Otter.kt b/app/src/main/java/com/github/apognu/otter/Otter.kt index d094f3b..7b7604e 100644 --- a/app/src/main/java/com/github/apognu/otter/Otter.kt +++ b/app/src/main/java/com/github/apognu/otter/Otter.kt @@ -3,16 +3,14 @@ package com.github.apognu.otter import android.app.Application import androidx.appcompat.app.AppCompatDelegate import com.github.apognu.otter.playback.QueueManager -import com.github.apognu.otter.utils.Cache -import com.github.apognu.otter.utils.Command -import com.github.apognu.otter.utils.Event -import com.github.apognu.otter.utils.Request +import com.github.apognu.otter.utils.* import com.google.android.exoplayer2.database.ExoDatabaseProvider import com.google.android.exoplayer2.offline.DefaultDownloadIndex import com.google.android.exoplayer2.offline.DefaultDownloaderFactory import com.google.android.exoplayer2.offline.DownloadManager import com.google.android.exoplayer2.offline.DownloaderConstructorHelper import com.google.android.exoplayer2.upstream.cache.LeastRecentlyUsedCacheEvictor +import com.google.android.exoplayer2.upstream.cache.NoOpCacheEvictor import com.google.android.exoplayer2.upstream.cache.SimpleCache import com.preference.PowerPreference import kotlinx.coroutines.channels.BroadcastChannel @@ -36,6 +34,7 @@ class Otter : Application() { val progressBus: BroadcastChannel> = ConflatedBroadcastChannel() private val exoDatabase: ExoDatabaseProvider by lazy { ExoDatabaseProvider(this) } + val exoCache: SimpleCache by lazy { PowerPreference.getDefaultFile().getInt("media_cache_size", 1).toLong().let { SimpleCache( @@ -45,8 +44,17 @@ class Otter : Application() { ) } } + + val exoDownloadCache: SimpleCache by lazy { + SimpleCache( + cacheDir.resolve("downloads"), + NoOpCacheEvictor(), + exoDatabase + ) + } + val exoDownloadManager: DownloadManager by lazy { - DownloaderConstructorHelper(exoCache, QueueManager.factory(this)).run { + DownloaderConstructorHelper(exoDownloadCache, QueueManager.factory(this)).run { DownloadManager(this@Otter, DefaultDownloadIndex(exoDatabase), DefaultDownloaderFactory(this)) } } diff --git a/app/src/main/java/com/github/apognu/otter/activities/MainActivity.kt b/app/src/main/java/com/github/apognu/otter/activities/MainActivity.kt index 01f6f8a..4f0b441 100644 --- a/app/src/main/java/com/github/apognu/otter/activities/MainActivity.kt +++ b/app/src/main/java/com/github/apognu/otter/activities/MainActivity.kt @@ -41,9 +41,11 @@ import kotlinx.android.synthetic.main.partial_now_playing.* import kotlinx.coroutines.Dispatchers.IO import kotlinx.coroutines.Dispatchers.Main import kotlinx.coroutines.GlobalScope +import kotlinx.coroutines.Job import kotlinx.coroutines.flow.collect import kotlinx.coroutines.launch import kotlinx.coroutines.withContext +import kotlin.random.Random class MainActivity : AppCompatActivity() { enum class ResultCode(val code: Int) { @@ -53,6 +55,8 @@ class MainActivity : AppCompatActivity() { private val favoriteRepository = FavoritesRepository(this) private val favoriteCheckRepository = FavoritedRepository(this) + private var bus: Job? = null + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -69,10 +73,6 @@ class MainActivity : AppCompatActivity() { .beginTransaction() .replace(R.id.container, BrowseFragment()) .commit() - - watchEventBus() - - CommandBus.send(Command.RefreshService) } override fun onResume() { @@ -116,6 +116,19 @@ class MainActivity : AppCompatActivity() { landscape_queue?.let { supportFragmentManager.beginTransaction().replace(R.id.landscape_queue, LandscapeQueueFragment()).commit() } + + if (bus == null) { + watchEventBus() + } + + CommandBus.send(Command.RefreshService) + } + + override fun onPause() { + super.onPause() + + bus?.cancel() + bus = null } override fun onBackPressed() { @@ -212,7 +225,7 @@ class MainActivity : AppCompatActivity() { @SuppressLint("NewApi") private fun watchEventBus() { - GlobalScope.launch(Main) { + bus = GlobalScope.launch(Main) { EventBus.get().collect { message -> when (message) { is Event.LogOut -> { diff --git a/app/src/main/java/com/github/apognu/otter/adapters/FavoritesAdapter.kt b/app/src/main/java/com/github/apognu/otter/adapters/FavoritesAdapter.kt index 4b82f9f..a73fd31 100644 --- a/app/src/main/java/com/github/apognu/otter/adapters/FavoritesAdapter.kt +++ b/app/src/main/java/com/github/apognu/otter/adapters/FavoritesAdapter.kt @@ -2,6 +2,8 @@ package com.github.apognu.otter.adapters import android.annotation.SuppressLint import android.content.Context +import android.graphics.PorterDuff +import android.graphics.PorterDuffColorFilter import android.graphics.Typeface import android.os.Build import android.view.Gravity @@ -74,11 +76,23 @@ class FavoritesAdapter(private val context: Context?, private val favoriteListen false -> holder.favorite.setColorFilter(context.getColor(R.color.colorSelected)) } - when (favorite.downloaded) { + when (favorite.cached || favorite.downloaded) { true -> holder.title.setCompoundDrawablesWithIntrinsicBounds(R.drawable.downloaded, 0, 0, 0) false -> holder.title.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0) } + if (favorite.cached && !favorite.downloaded) { + holder.title.compoundDrawables.forEach { + it?.colorFilter = PorterDuffColorFilter(context.getColor(R.color.cached), PorterDuff.Mode.SRC_IN) + } + } + + if (favorite.downloaded) { + holder.title.compoundDrawables.forEach { + it?.colorFilter = PorterDuffColorFilter(context.getColor(R.color.downloaded), PorterDuff.Mode.SRC_IN) + } + } + holder.favorite.setOnClickListener { favoriteListener.onToggleFavorite(favorite.id, !favorite.favorite) diff --git a/app/src/main/java/com/github/apognu/otter/adapters/TracksAdapter.kt b/app/src/main/java/com/github/apognu/otter/adapters/TracksAdapter.kt index 03eb570..f8e4de1 100644 --- a/app/src/main/java/com/github/apognu/otter/adapters/TracksAdapter.kt +++ b/app/src/main/java/com/github/apognu/otter/adapters/TracksAdapter.kt @@ -2,8 +2,7 @@ package com.github.apognu.otter.adapters import android.annotation.SuppressLint import android.content.Context -import android.graphics.Color -import android.graphics.Typeface +import android.graphics.* import android.graphics.drawable.ColorDrawable import android.os.Build import android.view.* @@ -95,10 +94,22 @@ class TracksAdapter(private val context: Context?, private val favoriteListener: } } - when (track.downloaded) { + when (track.cached || track.downloaded) { true -> holder.title.setCompoundDrawablesWithIntrinsicBounds(R.drawable.downloaded, 0, 0, 0) false -> holder.title.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0) } + + if (track.cached && !track.downloaded) { + holder.title.compoundDrawables.forEach { + it?.colorFilter = PorterDuffColorFilter(context.getColor(R.color.cached), PorterDuff.Mode.SRC_IN) + } + } + + if (track.downloaded) { + holder.title.compoundDrawables.forEach { + it?.colorFilter = PorterDuffColorFilter(context.getColor(R.color.downloaded), PorterDuff.Mode.SRC_IN) + } + } } holder.actions.setOnClickListener { diff --git a/app/src/main/java/com/github/apognu/otter/playback/QueueManager.kt b/app/src/main/java/com/github/apognu/otter/playback/QueueManager.kt index dbd6cd8..cf7c47c 100644 --- a/app/src/main/java/com/github/apognu/otter/playback/QueueManager.kt +++ b/app/src/main/java/com/github/apognu/otter/playback/QueueManager.kt @@ -9,6 +9,8 @@ import com.github.kittinunf.fuel.gson.gsonDeserializerOf import com.google.android.exoplayer2.source.ConcatenatingMediaSource import com.google.android.exoplayer2.source.ProgressiveMediaSource import com.google.android.exoplayer2.upstream.DefaultHttpDataSourceFactory +import com.google.android.exoplayer2.upstream.FileDataSource +import com.google.android.exoplayer2.upstream.cache.CacheDataSource import com.google.android.exoplayer2.upstream.cache.CacheDataSourceFactory import com.google.android.exoplayer2.util.Util import com.google.gson.Gson @@ -28,7 +30,16 @@ class QueueManager(val context: Context) { } } - return CacheDataSourceFactory(Otter.get().exoCache, http) + val playbackCache = CacheDataSourceFactory(Otter.get().exoCache, http) + + return CacheDataSourceFactory( + Otter.get().exoDownloadCache, + playbackCache, + FileDataSource.Factory(), + null, + CacheDataSource.FLAG_IGNORE_CACHE_ON_ERROR, + null + ) } } diff --git a/app/src/main/java/com/github/apognu/otter/repositories/FavoritesRepository.kt b/app/src/main/java/com/github/apognu/otter/repositories/FavoritesRepository.kt index b2db91e..039f388 100644 --- a/app/src/main/java/com/github/apognu/otter/repositories/FavoritesRepository.kt +++ b/app/src/main/java/com/github/apognu/otter/repositories/FavoritesRepository.kt @@ -1,6 +1,7 @@ package com.github.apognu.otter.repositories import android.content.Context +import com.github.apognu.otter.Otter import com.github.apognu.otter.utils.* import com.github.kittinunf.fuel.Fuel import com.github.kittinunf.fuel.coroutines.awaitByteArrayResponseResult @@ -26,6 +27,13 @@ class FavoritesRepository(override val context: Context?) : Repository track.favorite = true track.downloaded = downloaded.contains(track.id) + + track.bestUpload()?.let { upload -> + val url = mustNormalizeUrl(upload.listen_url) + + track.cached = Otter.get().exoCache.isCached(url, 0, upload.duration * 1000L) + } + track } } diff --git a/app/src/main/java/com/github/apognu/otter/repositories/TracksRepository.kt b/app/src/main/java/com/github/apognu/otter/repositories/TracksRepository.kt index f4b1818..1f58878 100644 --- a/app/src/main/java/com/github/apognu/otter/repositories/TracksRepository.kt +++ b/app/src/main/java/com/github/apognu/otter/repositories/TracksRepository.kt @@ -1,6 +1,7 @@ package com.github.apognu.otter.repositories import android.content.Context +import com.github.apognu.otter.Otter import com.github.apognu.otter.utils.* import com.github.kittinunf.fuel.gson.gsonDeserializerOf import com.google.android.exoplayer2.offline.Download @@ -48,6 +49,13 @@ class TracksRepository(override val context: Context?, albumId: Int) : Repositor data.map { track -> track.favorite = favorites.contains(track.id) track.downloaded = downloaded.contains(track.id) + + track.bestUpload()?.let { upload -> + val url = mustNormalizeUrl(upload.listen_url) + + track.cached = Otter.get().exoCache.isCached(url, 0, upload.duration * 1000L) + } + track }.sortedBy { it.position } } diff --git a/app/src/main/java/com/github/apognu/otter/utils/Models.kt b/app/src/main/java/com/github/apognu/otter/utils/Models.kt index a148a43..73b2846 100644 --- a/app/src/main/java/com/github/apognu/otter/utils/Models.kt +++ b/app/src/main/java/com/github/apognu/otter/utils/Models.kt @@ -100,6 +100,7 @@ data class Track( ) : SearchResult { var current: Boolean = false var favorite: Boolean = false + var cached: Boolean = false var downloaded: Boolean = false data class Upload( diff --git a/app/src/main/res/values-night/colors.xml b/app/src/main/res/values-night/colors.xml index 90ecf33..24bf72e 100644 --- a/app/src/main/res/values-night/colors.xml +++ b/app/src/main/res/values-night/colors.xml @@ -16,4 +16,7 @@ #000000 #ffffff + + @color/controlColor + #aeaeae \ No newline at end of file diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index 76d77b6..4ae8547 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -18,4 +18,7 @@ #ffffff #000000 + + @color/colorPrimary + #999999