vfsfitvnm 3 роки тому
батько
коміт
625fbb0247

+ 1 - 0
app/src/main/kotlin/it/vfsfitvnm/vimusic/MainActivity.kt

@@ -42,6 +42,7 @@ import it.vfsfitvnm.vimusic.ui.components.rememberBottomSheetState
 import it.vfsfitvnm.vimusic.ui.components.rememberMenuState
 import it.vfsfitvnm.vimusic.ui.screens.HomeScreen
 import it.vfsfitvnm.vimusic.ui.screens.IntentUriScreen
+import it.vfsfitvnm.vimusic.ui.screens.settings.OtherScreen
 import it.vfsfitvnm.vimusic.ui.styling.*
 import it.vfsfitvnm.vimusic.ui.views.PlayerView
 import it.vfsfitvnm.vimusic.utils.*

+ 9 - 14
app/src/main/kotlin/it/vfsfitvnm/vimusic/MainApplication.kt

@@ -1,7 +1,6 @@
 package it.vfsfitvnm.vimusic
 
 import android.app.Application
-import android.content.Context
 import coil.ImageLoader
 import coil.ImageLoaderFactory
 import coil.disk.DiskCache
@@ -15,18 +14,14 @@ class MainApplication : Application(), ImageLoaderFactory {
     }
 
     override fun newImageLoader(): ImageLoader {
-        return defaultCoilImageLoader(preferences.coilDiskCacheMaxSizeBytes)
+        return ImageLoader.Builder(this)
+            .crossfade(true)
+            .diskCache(
+                DiskCache.Builder()
+                    .directory(filesDir.resolve("coil"))
+                    .maxSizeBytes(preferences.coilDiskCacheMaxSizeBytes)
+                    .build()
+            )
+            .build()
     }
 }
-
-fun Context.defaultCoilImageLoader(diskCacheMaxSize: Long): ImageLoader {
-    return ImageLoader.Builder(this)
-        .crossfade(true)
-        .diskCache(
-            DiskCache.Builder()
-                .directory(filesDir.resolve("coil"))
-                .maxSizeBytes(diskCacheMaxSize)
-                .build()
-        )
-        .build()
-}

+ 12 - 5
app/src/main/kotlin/it/vfsfitvnm/vimusic/services/PlayerService.kt

@@ -18,6 +18,7 @@ import androidx.core.app.NotificationCompat
 import androidx.core.graphics.drawable.IconCompat
 import androidx.core.graphics.drawable.toBitmap
 import androidx.core.net.toUri
+import androidx.core.os.bundleOf
 import androidx.media3.common.*
 import androidx.media3.common.util.Util
 import androidx.media3.database.StandaloneDatabaseProvider
@@ -25,7 +26,7 @@ import androidx.media3.datasource.DataSource
 import androidx.media3.datasource.DefaultHttpDataSource
 import androidx.media3.datasource.ResolvingDataSource
 import androidx.media3.datasource.cache.CacheDataSource
-import androidx.media3.datasource.cache.NoOpCacheEvictor
+import androidx.media3.datasource.cache.LeastRecentlyUsedCacheEvictor
 import androidx.media3.datasource.cache.SimpleCache
 import androidx.media3.exoplayer.ExoPlayer
 import androidx.media3.exoplayer.analytics.AnalyticsListener
@@ -36,11 +37,10 @@ import androidx.media3.session.*
 import androidx.media3.session.MediaNotification.ActionFactory
 import coil.ImageLoader
 import coil.request.ImageRequest
+import com.google.common.util.concurrent.Futures
 import com.google.common.util.concurrent.ListenableFuture
-import it.vfsfitvnm.vimusic.Database
-import it.vfsfitvnm.vimusic.MainActivity
+import it.vfsfitvnm.vimusic.*
 import it.vfsfitvnm.vimusic.R
-import it.vfsfitvnm.vimusic.internal
 import it.vfsfitvnm.vimusic.models.QueuedMediaItem
 import it.vfsfitvnm.vimusic.utils.*
 import it.vfsfitvnm.youtubemusic.Outcome
@@ -52,6 +52,8 @@ val StartRadioCommand = SessionCommand("StartRadioCommand", Bundle.EMPTY)
 val StartArtistRadioCommand = SessionCommand("StartArtistRadioCommand", Bundle.EMPTY)
 val StopRadioCommand = SessionCommand("StopRadioCommand", Bundle.EMPTY)
 
+val GetCacheSizeCommand = SessionCommand("GetCacheSizeCommand", Bundle.EMPTY)
+
 @ExperimentalAnimationApi
 @ExperimentalFoundationApi
 class PlayerService : MediaSessionService(), MediaSession.MediaItemFiller,
@@ -83,7 +85,8 @@ class PlayerService : MediaSessionService(), MediaSession.MediaItemFiller,
         createNotificationChannel()
         setMediaNotificationProvider(this)
 
-        cache = SimpleCache(cacheDir, NoOpCacheEvictor(), StandaloneDatabaseProvider(this))
+        val cacheEvictor = LeastRecentlyUsedCacheEvictor(preferences.exoPlayerDiskCacheMaxSizeBytes)
+        cache = SimpleCache(cacheDir, cacheEvictor, StandaloneDatabaseProvider(this))
 
         val player = ExoPlayer.Builder(this)
             .setHandleAudioBecomingNoisy(true)
@@ -176,6 +179,7 @@ class PlayerService : MediaSessionService(), MediaSession.MediaItemFiller,
             .add(StartRadioCommand)
             .add(StartArtistRadioCommand)
             .add(StopRadioCommand)
+            .add(GetCacheSizeCommand)
             .build()
         val playerCommands = Player.Commands.Builder().addAllCommands().build()
         return MediaSession.ConnectionResult.accept(sessionCommands, playerCommands)
@@ -206,6 +210,9 @@ class PlayerService : MediaSessionService(), MediaSession.MediaItemFiller,
                 }
             }
             StopRadioCommand -> radio = null
+            GetCacheSizeCommand -> {
+                return Futures.immediateFuture(SessionResult(SessionResult.RESULT_SUCCESS, bundleOf("cacheSize" to cache.cacheSpace)))
+            }
         }
 
         return super.onCustomCommand(session, controller, customCommand, args)

+ 64 - 5
app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/settings/OtherScreen.kt

@@ -1,5 +1,6 @@
 package it.vfsfitvnm.vimusic.ui.screens.settings
 
+import android.os.Bundle
 import android.text.format.Formatter
 import androidx.compose.animation.ExperimentalAnimationApi
 import androidx.compose.foundation.*
@@ -16,15 +17,18 @@ import coil.Coil
 import coil.annotation.ExperimentalCoilApi
 import it.vfsfitvnm.route.RouteHandler
 import it.vfsfitvnm.vimusic.R
+import it.vfsfitvnm.vimusic.services.GetCacheSizeCommand
 import it.vfsfitvnm.vimusic.ui.components.SeekBar
 import it.vfsfitvnm.vimusic.ui.components.TopAppBar
 import it.vfsfitvnm.vimusic.ui.screens.*
 import it.vfsfitvnm.vimusic.ui.styling.LocalColorPalette
 import it.vfsfitvnm.vimusic.ui.styling.LocalTypography
 import it.vfsfitvnm.vimusic.utils.LocalPreferences
+import it.vfsfitvnm.vimusic.utils.LocalYoutubePlayer
 import it.vfsfitvnm.vimusic.utils.secondary
 import it.vfsfitvnm.vimusic.utils.semiBold
 import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.guava.await
 import kotlinx.coroutines.launch
 
 @OptIn(ExperimentalCoilApi::class)
@@ -54,10 +58,9 @@ fun OtherScreen() {
             val colorPalette = LocalColorPalette.current
             val typography = LocalTypography.current
             val preferences = LocalPreferences.current
+            val mediaController = LocalYoutubePlayer.current?.mediaController
 
-            var coilDiskCache by remember {
-                mutableStateOf(Coil.imageLoader(context).diskCache)
-            }
+            val coilDiskCache = Coil.imageLoader(context).diskCache
 
             val coroutineScope = rememberCoroutineScope()
 
@@ -94,7 +97,6 @@ fun OtherScreen() {
                     )
                 }
 
-
                 coilDiskCache?.let { diskCache ->
                     var diskCacheSize by remember(diskCache) {
                         mutableStateOf(diskCache.size)
@@ -133,7 +135,6 @@ fun OtherScreen() {
                             },
                             onDrag = { delta ->
                                 scrubbingDiskCacheMaxSize = scrubbingDiskCacheMaxSize?.plus(delta)?.coerceIn(250L * 1024 * 1024, 2048L * 1024 * 1024)
-                                println("new = $scrubbingDiskCacheMaxSize")
                             },
                             onDragEnd = {
                                 preferences.coilDiskCacheMaxSizeBytes = scrubbingDiskCacheMaxSize ?: preferences.coilDiskCacheMaxSizeBytes
@@ -164,6 +165,64 @@ fun OtherScreen() {
                         }
                     )
                 }
+
+                mediaController?.let { mediaController ->
+                    val diskCacheSize by produceState(initialValue = 0L) {
+                        value = mediaController.sendCustomCommand(GetCacheSizeCommand, Bundle.EMPTY).await().extras.getLong("cacheSize")
+                    }
+
+                    var scrubbingDiskCacheMaxSize by remember {
+                        mutableStateOf<Long?>(null)
+                    }
+
+                    SettingsEntryGroupText(
+                        title = "SONG CACHE",
+                    )
+
+                    Column(
+                        modifier = Modifier
+                            .padding(start = 24.dp)
+                            .padding(horizontal = 32.dp, vertical = 16.dp)
+                            .fillMaxWidth()
+                    ) {
+                        BasicText(
+                            text = "Max size",
+                            style = typography.xs.semiBold,
+                        )
+
+                        BasicText(
+                            text = Formatter.formatShortFileSize(context, scrubbingDiskCacheMaxSize ?: preferences.exoPlayerDiskCacheMaxSizeBytes),
+                            style = typography.xs.semiBold.secondary
+                        )
+
+                        SeekBar(
+                            value = (scrubbingDiskCacheMaxSize ?: preferences.exoPlayerDiskCacheMaxSizeBytes).coerceIn(250L * 1024 * 1024, 4096L * 1024 * 1024),
+                            minimumValue = 250L * 1024 * 1024,
+                            maximumValue = 4096L * 1024 * 1024,
+                            onDragStart = {
+                                scrubbingDiskCacheMaxSize = it
+                            },
+                            onDrag = { delta ->
+                                scrubbingDiskCacheMaxSize = scrubbingDiskCacheMaxSize?.plus(delta)?.coerceIn(250L * 1024 * 1024, 4096L * 1024 * 1024)
+                            },
+                            onDragEnd = {
+                                preferences.exoPlayerDiskCacheMaxSizeBytes = scrubbingDiskCacheMaxSize ?: preferences.exoPlayerDiskCacheMaxSizeBytes
+                                scrubbingDiskCacheMaxSize = null
+                            },
+                            color = colorPalette.text,
+                            backgroundColor = colorPalette.textDisabled,
+                            shape = RoundedCornerShape(8.dp),
+                            modifier = Modifier
+                                .padding(top = 8.dp)
+                                .fillMaxWidth()
+                        )
+                    }
+
+                    DisabledSettingsEntry(
+                        title = "Space used",
+                        text = "${Formatter.formatShortFileSize(context, diskCacheSize)} (${diskCacheSize * 100 / preferences.exoPlayerDiskCacheMaxSizeBytes.coerceAtLeast(1)}%)",
+                    )
+                }
             }
         }
     }

+ 1 - 0
app/src/main/kotlin/it/vfsfitvnm/vimusic/utils/Preferences.kt

@@ -23,6 +23,7 @@ class Preferences(holder: SharedPreferences) : SharedPreferences by holder {
     var homePageSongCollection by preference("homePageSongCollection", SongCollection.MostPlayed)
     var thumbnailRoundness by preference("thumbnailRoundness", ThumbnailRoundness.Light)
     var coilDiskCacheMaxSizeBytes by preference("coilDiskCacheMaxSizeBytes", 512L * 1024 * 1024)
+    var exoPlayerDiskCacheMaxSizeBytes by preference("exoPlayerDiskCacheMaxSizeBytes", 512L * 1024 * 1024)
     var displayLikeButtonInNotification by preference("displayLikeButtonInNotification", false)
     var persistentQueue by preference("persistentQueue", false)
 }