diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 43c0fcda..f0dc572c 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -3,6 +3,7 @@ plugins { id("org.jetbrains.kotlin.android") id("com.google.devtools.ksp") id("com.google.dagger.hilt.android") + kotlin("plugin.serialization") version "2.0.10" } android { @@ -20,11 +21,11 @@ android { } compileOptions { - sourceCompatibility = JavaVersion.VERSION_1_8 - targetCompatibility = JavaVersion.VERSION_1_8 + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 } kotlinOptions { - jvmTarget = "1.8" + jvmTarget = JavaVersion.VERSION_17.toString() } viewBinding { enable = true @@ -79,7 +80,4 @@ dependencies { testImplementation("org.jetbrains.kotlin:kotlin-reflect:1.9.22") testImplementation("junit:junit:4.13.2") - - androidTestImplementation("androidx.test.ext:junit:1.1.5") - androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1") } \ No newline at end of file diff --git a/app/src/main/java/dev/brahmkshatriya/echo/download/DownloadReceiver.kt b/app/src/main/java/dev/brahmkshatriya/echo/download/DownloadReceiver.kt index dbdbef8e..02e3074b 100644 --- a/app/src/main/java/dev/brahmkshatriya/echo/download/DownloadReceiver.kt +++ b/app/src/main/java/dev/brahmkshatriya/echo/download/DownloadReceiver.kt @@ -42,7 +42,7 @@ class DownloadReceiver : BroadcastReceiver() { withContext(Dispatchers.IO) { downloadDao.getDownload(downloadId) } } ?: return val track = - context.getFromCache(download.itemId, Track.creator, "downloads") ?: return + context.getFromCache(download.itemId, "downloads") ?: return val downloadManager = context.getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager diff --git a/app/src/main/java/dev/brahmkshatriya/echo/download/Downloader.kt b/app/src/main/java/dev/brahmkshatriya/echo/download/Downloader.kt index de3be08d..5d7621ce 100644 --- a/app/src/main/java/dev/brahmkshatriya/echo/download/Downloader.kt +++ b/app/src/main/java/dev/brahmkshatriya/echo/download/Downloader.kt @@ -151,7 +151,7 @@ class Downloader( client as TrackClient val info = extension.info val track = - context.getFromCache(download.itemId, Track.creator, "downloads") + context.getFromCache(download.itemId, "downloads") ?: return@withContext context.enqueueDownload(info, client, track) } diff --git a/app/src/main/java/dev/brahmkshatriya/echo/offline/Convertors.kt b/app/src/main/java/dev/brahmkshatriya/echo/offline/Convertors.kt index b67143b5..1ebf76b2 100644 --- a/app/src/main/java/dev/brahmkshatriya/echo/offline/Convertors.kt +++ b/app/src/main/java/dev/brahmkshatriya/echo/offline/Convertors.kt @@ -1,12 +1,11 @@ package dev.brahmkshatriya.echo.offline -import androidx.core.net.toUri import androidx.media3.common.MediaItem import dev.brahmkshatriya.echo.common.helpers.PagedData import dev.brahmkshatriya.echo.common.models.Album import dev.brahmkshatriya.echo.common.models.Artist import dev.brahmkshatriya.echo.common.models.EchoMediaItem.Companion.toMediaItem -import dev.brahmkshatriya.echo.common.models.ImageHolder.Companion.toImageHolder +import dev.brahmkshatriya.echo.common.models.ImageHolder.Companion.toUriImageHolder import dev.brahmkshatriya.echo.common.models.MediaItemsContainer import dev.brahmkshatriya.echo.common.models.Playlist import dev.brahmkshatriya.echo.common.models.Streamable @@ -25,7 +24,7 @@ fun MediaItem.toTrack() = mediaMetadata.run { title.toString(), artists, album, - artworkUri.toString().toUri().toImageHolder(), + artworkUri.toString().toUriImageHolder(), extras?.getLong("Duration"), null, releaseYear.toString(), @@ -39,7 +38,7 @@ fun MediaItem.toTrack() = mediaMetadata.run { fun MediaStoreUtils.MAlbum.toAlbum() = Album( id.toString(), title ?: "Unknown", - cover.toString().toUri().toImageHolder(), + cover.toString().toUriImageHolder(), artists.map { it.toArtist() }, songList.size, albumYear?.toString() diff --git a/app/src/main/java/dev/brahmkshatriya/echo/offline/OfflineExtension.kt b/app/src/main/java/dev/brahmkshatriya/echo/offline/OfflineExtension.kt index fc5dda83..a5853438 100644 --- a/app/src/main/java/dev/brahmkshatriya/echo/offline/OfflineExtension.kt +++ b/app/src/main/java/dev/brahmkshatriya/echo/offline/OfflineExtension.kt @@ -280,21 +280,17 @@ class OfflineExtension(val context: Context) : ExtensionClient, HomeFeedClient, override suspend fun deleteSearchHistory(query: QuickSearchItem.SearchQueryItem) { val history = getHistory().toMutableList() history.remove(query.query) - context.saveToCache("search_history", "offline") { parcel -> - parcel.writeStringList(history) - } + context.saveToCache("search_history", history, "offline") } - private fun getHistory() = context.getFromCache("search_history", "offline") { - it.createStringArrayList()?.distinct()?.take(5) - } ?: emptyList() + private fun getHistory() = context.getFromCache>("search_history", "offline") + ?.distinct()?.take(5) + ?: emptyList() private fun saveInHistory(query: String) { val history = getHistory().toMutableList() history.add(0, query) - context.saveToCache("search_history", "offline") { parcel -> - parcel.writeStringList(history) - } + context.saveToCache("search_history", history, "offline") } override suspend fun searchTabs(query: String?) = @@ -342,7 +338,7 @@ class OfflineExtension(val context: Context) : ExtensionClient, HomeFeedClient, ).map { Tab(it, it) } override fun getLibraryFeed(tab: Tab?): PagedData { - if(refreshLibrary) library = MediaStoreUtils.getAllSongs(context) + if (refreshLibrary) library = MediaStoreUtils.getAllSongs(context) return when (tab?.id) { "Folders" -> library.folderStructure.folderList.entries.first().value.toContainer(null).more!! else -> { diff --git a/app/src/main/java/dev/brahmkshatriya/echo/playback/MediaItemUtils.kt b/app/src/main/java/dev/brahmkshatriya/echo/playback/MediaItemUtils.kt index e53ed846..2ad7ff04 100644 --- a/app/src/main/java/dev/brahmkshatriya/echo/playback/MediaItemUtils.kt +++ b/app/src/main/java/dev/brahmkshatriya/echo/playback/MediaItemUtils.kt @@ -9,7 +9,8 @@ import androidx.media3.common.ThumbRating import dev.brahmkshatriya.echo.common.models.EchoMediaItem import dev.brahmkshatriya.echo.common.models.Track import dev.brahmkshatriya.echo.ui.settings.AudioFragment.AudioPreference.Companion.selectStreamIndex -import dev.brahmkshatriya.echo.utils.getParcel +import dev.brahmkshatriya.echo.utils.getSerialized +import dev.brahmkshatriya.echo.utils.toJson object MediaItemUtils { @@ -49,9 +50,9 @@ object MediaItemUtils { .setIsBrowsable(false) .setExtras( bundleOf( - "track" to this, + "track" to this.toJson(), "clientId" to clientId, - "context" to context, + "context" to context.toJson(), "loaded" to loaded, "audioStream" to selectStream(settings, loaded, audioStreamIndex) ) @@ -71,9 +72,9 @@ object MediaItemUtils { } val MediaMetadata.isLoaded get() = extras?.getBoolean("loaded") ?: false - val MediaMetadata.track get() = requireNotNull(extras?.getParcel("track")) + val MediaMetadata.track get() = requireNotNull(extras?.getSerialized("track")) val MediaMetadata.clientId get() = requireNotNull(extras?.getString("clientId")) - val MediaMetadata.context get() = extras?.getParcel("context") + val MediaMetadata.context get() = extras?.getSerialized("context") val MediaMetadata.audioStreamIndex get() = extras?.getInt("audioStream") ?: -1 val MediaMetadata.isLiked get() = (userRating as? ThumbRating)?.isThumbsUp == true diff --git a/app/src/main/java/dev/brahmkshatriya/echo/playback/PlayerSessionCallback.kt b/app/src/main/java/dev/brahmkshatriya/echo/playback/PlayerSessionCallback.kt index 75a1fe14..2f29f5cf 100644 --- a/app/src/main/java/dev/brahmkshatriya/echo/playback/PlayerSessionCallback.kt +++ b/app/src/main/java/dev/brahmkshatriya/echo/playback/PlayerSessionCallback.kt @@ -31,7 +31,7 @@ import dev.brahmkshatriya.echo.playback.MediaItemUtils.clientId import dev.brahmkshatriya.echo.playback.MediaItemUtils.track import dev.brahmkshatriya.echo.plugger.MusicExtension import dev.brahmkshatriya.echo.plugger.getExtension -import dev.brahmkshatriya.echo.utils.getParcel +import dev.brahmkshatriya.echo.utils.getSerialized import dev.brahmkshatriya.echo.viewmodels.ExtensionViewModel.Companion.noClient import dev.brahmkshatriya.echo.viewmodels.ExtensionViewModel.Companion.searchNotSupported import dev.brahmkshatriya.echo.viewmodels.ExtensionViewModel.Companion.trackNotSupported @@ -91,7 +91,7 @@ class PlayerSessionCallback( private fun radio(player: Player, args: Bundle) = scope.future { val error = SessionResult(SessionResult.RESULT_ERROR_UNKNOWN) val clientId = args.getString("clientId") ?: return@future error - val item = args.getParcel("item") ?: return@future error + val item = args.getSerialized("item") ?: return@future error radioFlow.value = Radio.State.Loading val loaded = Radio.start( context, messageFlow, throwableFlow, extensionList, clientId, item, 0 diff --git a/app/src/main/java/dev/brahmkshatriya/echo/playback/ResumptionUtils.kt b/app/src/main/java/dev/brahmkshatriya/echo/playback/ResumptionUtils.kt index 161973b6..fd9bb484 100644 --- a/app/src/main/java/dev/brahmkshatriya/echo/playback/ResumptionUtils.kt +++ b/app/src/main/java/dev/brahmkshatriya/echo/playback/ResumptionUtils.kt @@ -12,7 +12,6 @@ import dev.brahmkshatriya.echo.playback.MediaItemUtils.clientId import dev.brahmkshatriya.echo.playback.MediaItemUtils.context import dev.brahmkshatriya.echo.playback.MediaItemUtils.track import dev.brahmkshatriya.echo.utils.getFromCache -import dev.brahmkshatriya.echo.utils.getListFromCache import dev.brahmkshatriya.echo.utils.saveToCache object ResumptionUtils { @@ -22,31 +21,19 @@ object ResumptionUtils { val contexts = list.map { it.context } context.saveToCache("queue_tracks", tracks, "queue") context.saveToCache("queue_contexts", contexts, "queue") - context.saveToCache("queue_clients", "queue") { parcel -> - parcel.writeStringList(clients) - } - context.saveToCache("queue_index", "queue") { - it.writeInt(currentIndex) - } + context.saveToCache("queue_clients", clients, "queue") + context.saveToCache("queue_index", currentIndex, "queue") } fun saveCurrentPos(context: Context, position: Long) { - context.saveToCache("position", "queue") { - it.writeLong(position) - } + context.saveToCache("position", position, "queue") } private fun recoverQueue(context: Context): List? { val settings = context.getSharedPreferences("settings", Context.MODE_PRIVATE) - val tracks = context.getListFromCache( - "queue_tracks", Track.creator, "queue" - ) - val clientIds = context.getFromCache("queue_clients", "queue") { - it.createStringArrayList() - } - val contexts = context.getListFromCache( - "queue_contexts", EchoMediaItem.creator, "queue" - ) + val tracks = context.getFromCache>("queue_tracks", "queue") + val clientIds = context.getFromCache>("queue_clients", "queue") + val contexts = context.getFromCache>("queue_contexts", "queue") return tracks?.mapIndexedNotNull { index, track -> val clientId = clientIds?.getOrNull(index) ?: return@mapIndexedNotNull null val item = contexts?.getOrNull(index) @@ -55,10 +42,10 @@ object ResumptionUtils { } private fun recoverIndex(context: Context) = - context.getFromCache("queue_index", "queue") { it.readInt() } + context.getFromCache("queue_index", "queue") private fun recoverPosition(context: Context) = - context.getFromCache("position", "queue") { it.readLong() } + context.getFromCache("position", "queue") @OptIn(UnstableApi::class) fun recoverPlaylist(context: Context): MediaSession.MediaItemsWithStartPosition { diff --git a/app/src/main/java/dev/brahmkshatriya/echo/playback/TrackResolver.kt b/app/src/main/java/dev/brahmkshatriya/echo/playback/TrackResolver.kt index af332a78..3083e01b 100644 --- a/app/src/main/java/dev/brahmkshatriya/echo/playback/TrackResolver.kt +++ b/app/src/main/java/dev/brahmkshatriya/echo/playback/TrackResolver.kt @@ -82,7 +82,7 @@ class TrackResolver( } private fun getTrackFromCache(id: String): Track? { - val track = context.getFromCache(id, Track.creator) ?: return null + val track = context.getFromCache(id) ?: return null return if (!track.isExpired()) track else null } diff --git a/app/src/main/java/dev/brahmkshatriya/echo/plugger/Injector.kt b/app/src/main/java/dev/brahmkshatriya/echo/plugger/Injector.kt index d36c57e2..1e8ea78d 100644 --- a/app/src/main/java/dev/brahmkshatriya/echo/plugger/Injector.kt +++ b/app/src/main/java/dev/brahmkshatriya/echo/plugger/Injector.kt @@ -5,7 +5,6 @@ import android.content.SharedPreferences import androidx.core.content.edit import dev.brahmkshatriya.echo.common.clients.ExtensionClient import dev.brahmkshatriya.echo.common.models.ExtensionType -import dev.brahmkshatriya.echo.common.providers.ContextProvider import dev.brahmkshatriya.echo.common.settings.Settings import dev.brahmkshatriya.echo.utils.mapState import kotlinx.coroutines.flow.StateFlow @@ -26,17 +25,17 @@ inline fun StateFlow StateFlow>>>.injectContext( - context: Context -) = mapState { list -> - list.map { - runCatching { - it.getOrThrow().apply { - (second as? ContextProvider)?.setContext(context) - } - } - } -} +//inline fun StateFlow>>>.injectContext( +// context: Context +//) = mapState { list -> +// list.map { +// runCatching { +// it.getOrThrow().apply { +// (second as? ContextProvider)?.setContext(context) +// } +// } +// } +//} fun toSettings(prefs: SharedPreferences) = object : Settings { override fun getString(key: String) = prefs.getString(key, null) diff --git a/app/src/main/java/dev/brahmkshatriya/echo/plugger/LyricsExtension.kt b/app/src/main/java/dev/brahmkshatriya/echo/plugger/LyricsExtension.kt index 21a06912..d5467bea 100644 --- a/app/src/main/java/dev/brahmkshatriya/echo/plugger/LyricsExtension.kt +++ b/app/src/main/java/dev/brahmkshatriya/echo/plugger/LyricsExtension.kt @@ -22,5 +22,5 @@ class LyricsExtensionRepo( ) : PluginRepo { override fun getAllPlugins() = pluginRepo.getAllPlugins() .injectSettings(ExtensionType.LYRICS, context) - .injectContext(context) +// .injectContext(context) } \ No newline at end of file diff --git a/app/src/main/java/dev/brahmkshatriya/echo/plugger/MusicExtension.kt b/app/src/main/java/dev/brahmkshatriya/echo/plugger/MusicExtension.kt index f5435e0e..a2dfceae 100644 --- a/app/src/main/java/dev/brahmkshatriya/echo/plugger/MusicExtension.kt +++ b/app/src/main/java/dev/brahmkshatriya/echo/plugger/MusicExtension.kt @@ -21,6 +21,6 @@ class MusicExtensionRepo( override fun getAllPlugins() = pluginRepo.getAllPlugins() .injectSettings(ExtensionType.MUSIC, context) - .injectContext(context) +// .injectContext(context) } diff --git a/app/src/main/java/dev/brahmkshatriya/echo/plugger/TrackerExtension.kt b/app/src/main/java/dev/brahmkshatriya/echo/plugger/TrackerExtension.kt index 85d29a0c..47788221 100644 --- a/app/src/main/java/dev/brahmkshatriya/echo/plugger/TrackerExtension.kt +++ b/app/src/main/java/dev/brahmkshatriya/echo/plugger/TrackerExtension.kt @@ -20,5 +20,5 @@ class TrackerExtensionRepo( ) : PluginRepo { override fun getAllPlugins() = pluginRepo.getAllPlugins() .injectSettings(ExtensionType.TRACKER, context) - .injectContext(context) +// .injectContext(context) } \ No newline at end of file diff --git a/app/src/main/java/dev/brahmkshatriya/echo/ui/download/DownloadItem.kt b/app/src/main/java/dev/brahmkshatriya/echo/ui/download/DownloadItem.kt index 7929b86d..30dbe41e 100644 --- a/app/src/main/java/dev/brahmkshatriya/echo/ui/download/DownloadItem.kt +++ b/app/src/main/java/dev/brahmkshatriya/echo/ui/download/DownloadItem.kt @@ -31,7 +31,7 @@ sealed class DownloadItem { context: Context, extensionList: MutableStateFlow?> ): DownloadItem? { val extension = extensionList.getExtension(clientId) ?: return null - val item = context.getFromCache(itemId, Track.creator, "downloads")?.toMediaItem() + val item = context.getFromCache(itemId, "downloads")?.toMediaItem() ?: return null return Single( id = id, diff --git a/app/src/main/java/dev/brahmkshatriya/echo/ui/editplaylist/AddToPlaylistBottomSheet.kt b/app/src/main/java/dev/brahmkshatriya/echo/ui/editplaylist/AddToPlaylistBottomSheet.kt index b90ae896..dd2cde52 100644 --- a/app/src/main/java/dev/brahmkshatriya/echo/ui/editplaylist/AddToPlaylistBottomSheet.kt +++ b/app/src/main/java/dev/brahmkshatriya/echo/ui/editplaylist/AddToPlaylistBottomSheet.kt @@ -16,8 +16,9 @@ import dev.brahmkshatriya.echo.databinding.DialogAddToPlaylistBinding import dev.brahmkshatriya.echo.ui.adapter.MediaItemSelectableAdapter import dev.brahmkshatriya.echo.ui.adapter.MediaItemSelectableAdapter.Companion.mediaItemSpanCount import dev.brahmkshatriya.echo.utils.autoCleared -import dev.brahmkshatriya.echo.utils.getParcel +import dev.brahmkshatriya.echo.utils.getSerialized import dev.brahmkshatriya.echo.utils.observe +import dev.brahmkshatriya.echo.utils.putSerialized @AndroidEntryPoint class AddToPlaylistBottomSheet : BottomSheetDialogFragment() { @@ -26,14 +27,14 @@ class AddToPlaylistBottomSheet : BottomSheetDialogFragment() { fun newInstance(clientId: String, item: EchoMediaItem) = AddToPlaylistBottomSheet().apply { arguments = Bundle().apply { putString("clientId", clientId) - putParcelable("item", item) + putSerialized("item", item) } } } private val args by lazy { requireArguments() } private val clientId by lazy { args.getString("clientId")!! } - private val item: EchoMediaItem by lazy { args.getParcel("item")!! } + private val item: EchoMediaItem by lazy { args.getSerialized("item")!! } var binding by autoCleared() val viewModel by viewModels() diff --git a/app/src/main/java/dev/brahmkshatriya/echo/ui/editplaylist/EditPlaylistFragment.kt b/app/src/main/java/dev/brahmkshatriya/echo/ui/editplaylist/EditPlaylistFragment.kt index 1bc92edb..7399f0b3 100644 --- a/app/src/main/java/dev/brahmkshatriya/echo/ui/editplaylist/EditPlaylistFragment.kt +++ b/app/src/main/java/dev/brahmkshatriya/echo/ui/editplaylist/EditPlaylistFragment.kt @@ -27,10 +27,10 @@ import dev.brahmkshatriya.echo.ui.editplaylist.EditPlaylistViewModel.ListAction. import dev.brahmkshatriya.echo.ui.player.PlaylistAdapter import dev.brahmkshatriya.echo.utils.autoCleared import dev.brahmkshatriya.echo.utils.dpToPx -import dev.brahmkshatriya.echo.utils.getParcel -import dev.brahmkshatriya.echo.utils.getParcelArray +import dev.brahmkshatriya.echo.utils.getSerialized import dev.brahmkshatriya.echo.utils.observe import dev.brahmkshatriya.echo.utils.onAppBarChangeListener +import dev.brahmkshatriya.echo.utils.putSerialized import dev.brahmkshatriya.echo.utils.setupTransition import dev.brahmkshatriya.echo.viewmodels.SnackBar.Companion.createSnack import dev.brahmkshatriya.echo.viewmodels.UiViewModel.Companion.applyBackPressCallback @@ -48,7 +48,7 @@ class EditPlaylistFragment : Fragment() { return EditPlaylistFragment().apply { arguments = Bundle().apply { putString("clientId", client) - putParcelable("playlist", playlist) + putSerialized("playlist", playlist) } } } @@ -56,7 +56,7 @@ class EditPlaylistFragment : Fragment() { private val args by lazy { requireArguments() } private val clientId by lazy { args.getString("clientId")!! } - private val playlist by lazy { args.getParcel("playlist")!! } + private val playlist by lazy { args.getSerialized("playlist")!! } var binding by autoCleared() val viewModel by activityViewModels() @@ -144,7 +144,7 @@ class EditPlaylistFragment : Fragment() { "searchedTracks", viewLifecycleOwner ) { _, bundle -> - val tracks = bundle.getParcelArray("tracks")!!.toMutableList() + val tracks = bundle.getSerialized>("tracks")!!.toMutableList() viewModel.edit(Add(viewModel.currentTracks.value?.size ?: 0, tracks)) backCallback.isEnabled = true } diff --git a/app/src/main/java/dev/brahmkshatriya/echo/ui/editplaylist/SearchForPlaylistFragment.kt b/app/src/main/java/dev/brahmkshatriya/echo/ui/editplaylist/SearchForPlaylistFragment.kt index 3d7828d8..dddd6b01 100644 --- a/app/src/main/java/dev/brahmkshatriya/echo/ui/editplaylist/SearchForPlaylistFragment.kt +++ b/app/src/main/java/dev/brahmkshatriya/echo/ui/editplaylist/SearchForPlaylistFragment.kt @@ -24,6 +24,7 @@ import dev.brahmkshatriya.echo.ui.search.SearchFragment import dev.brahmkshatriya.echo.utils.autoCleared import dev.brahmkshatriya.echo.utils.dpToPx import dev.brahmkshatriya.echo.utils.observe +import dev.brahmkshatriya.echo.utils.putSerialized import dev.brahmkshatriya.echo.utils.setupTransition import dev.brahmkshatriya.echo.viewmodels.UiViewModel.Companion.applyBackPressCallback import dev.brahmkshatriya.echo.viewmodels.UiViewModel.Companion.applyInsets @@ -103,7 +104,7 @@ class SearchForPlaylistFragment : Fragment() { binding.addTracks.setOnClickListener { parentFragmentManager.setFragmentResult("searchedTracks", Bundle().apply { - putParcelableArray("tracks", viewModel.selectedTracks.value.toTypedArray()) + putSerialized("tracks", viewModel.selectedTracks.value) }) viewModel.selectedTracks.value = emptyList() parentFragmentManager.popBackStack() @@ -123,7 +124,6 @@ class SearchForPlaylistFragment : Fragment() { fun newInstance(clientId: String, playlist: Playlist) = SearchForPlaylistFragment().apply { arguments = Bundle().apply { putString("clientId", clientId) - putParcelable("playlist", playlist) } } } diff --git a/app/src/main/java/dev/brahmkshatriya/echo/ui/item/ItemBottomSheet.kt b/app/src/main/java/dev/brahmkshatriya/echo/ui/item/ItemBottomSheet.kt index 268adf4d..166a66ee 100644 --- a/app/src/main/java/dev/brahmkshatriya/echo/ui/item/ItemBottomSheet.kt +++ b/app/src/main/java/dev/brahmkshatriya/echo/ui/item/ItemBottomSheet.kt @@ -30,9 +30,10 @@ import dev.brahmkshatriya.echo.ui.common.openFragment import dev.brahmkshatriya.echo.ui.editplaylist.AddToPlaylistBottomSheet import dev.brahmkshatriya.echo.ui.exception.ExceptionFragment.Companion.copyToClipboard import dev.brahmkshatriya.echo.utils.autoCleared -import dev.brahmkshatriya.echo.utils.getParcel +import dev.brahmkshatriya.echo.utils.getSerialized import dev.brahmkshatriya.echo.utils.loadInto import dev.brahmkshatriya.echo.utils.observe +import dev.brahmkshatriya.echo.utils.putSerialized import dev.brahmkshatriya.echo.viewmodels.DownloadViewModel import dev.brahmkshatriya.echo.viewmodels.PlayerViewModel import dev.brahmkshatriya.echo.viewmodels.SnackBar.Companion.createSnack @@ -46,7 +47,7 @@ class ItemBottomSheet : BottomSheetDialogFragment() { ) = ItemBottomSheet().apply { arguments = Bundle().apply { putString("clientId", clientId) - putParcelable("item", item) + putSerialized("item", item) putBoolean("loaded", loaded) putBoolean("fromPlayer", fromPlayer) } @@ -61,7 +62,7 @@ class ItemBottomSheet : BottomSheetDialogFragment() { private val args by lazy { requireArguments() } private val clientId by lazy { args.getString("clientId")!! } - private val item by lazy { args.getParcel("item")!! } + private val item by lazy { args.getSerialized("item")!! } private val fromPlayer by lazy { args.getBoolean("fromPlayer") } private val loaded by lazy { args.getBoolean("loaded") } private val extension by lazy { playerViewModel.extensionListFlow.getExtension(clientId) } diff --git a/app/src/main/java/dev/brahmkshatriya/echo/ui/item/ItemFragment.kt b/app/src/main/java/dev/brahmkshatriya/echo/ui/item/ItemFragment.kt index 7011d346..13876dbf 100644 --- a/app/src/main/java/dev/brahmkshatriya/echo/ui/item/ItemFragment.kt +++ b/app/src/main/java/dev/brahmkshatriya/echo/ui/item/ItemFragment.kt @@ -45,10 +45,12 @@ import dev.brahmkshatriya.echo.utils.collect import dev.brahmkshatriya.echo.utils.configure import dev.brahmkshatriya.echo.utils.dpToPx import dev.brahmkshatriya.echo.utils.getParcel +import dev.brahmkshatriya.echo.utils.getSerialized import dev.brahmkshatriya.echo.utils.load import dev.brahmkshatriya.echo.utils.loadInto import dev.brahmkshatriya.echo.utils.loadWith import dev.brahmkshatriya.echo.utils.onAppBarChangeListener +import dev.brahmkshatriya.echo.utils.putSerialized import dev.brahmkshatriya.echo.utils.setupTransition import dev.brahmkshatriya.echo.viewmodels.ExtensionViewModel.Companion.applyAdapter import dev.brahmkshatriya.echo.viewmodels.PlayerViewModel @@ -65,14 +67,14 @@ class ItemFragment : Fragment() { fun newInstance(clientId: String, item: EchoMediaItem) = ItemFragment().apply { arguments = Bundle().apply { putString("clientId", clientId) - putParcelable("item", item) + putSerialized("item", item) } } } private val args by lazy { requireArguments() } private val clientId by lazy { args.getString("clientId")!! } - private val item by lazy { args.getParcel("item")!! } + private val item by lazy { args.getSerialized("item")!! } private var binding by autoCleared() private val viewModel by viewModels() diff --git a/app/src/main/java/dev/brahmkshatriya/echo/utils/AndroidCope.kt b/app/src/main/java/dev/brahmkshatriya/echo/utils/AndroidCope.kt index baa6d648..a478143e 100644 --- a/app/src/main/java/dev/brahmkshatriya/echo/utils/AndroidCope.kt +++ b/app/src/main/java/dev/brahmkshatriya/echo/utils/AndroidCope.kt @@ -2,16 +2,17 @@ package dev.brahmkshatriya.echo.utils import android.os.Build import android.os.Bundle +import android.os.Parcelable import java.io.Serializable @Suppress("DEPRECATION") -inline fun Bundle.getParcel(key: String?) = +inline fun Bundle.getParcel(key: String?) = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) getParcelable(key, T::class.java) else getParcelable(key) @Suppress("DEPRECATION") -inline fun Bundle.getParcelArray(key: String?) = +inline fun Bundle.getParcelArray(key: String?) = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) getParcelableArray(key, T::class.java)?.toList() else getParcelableArray(key)?.map { it as T } diff --git a/app/src/main/java/dev/brahmkshatriya/echo/utils/Cache.kt b/app/src/main/java/dev/brahmkshatriya/echo/utils/Cache.kt index 5c9b3688..4075a313 100644 --- a/app/src/main/java/dev/brahmkshatriya/echo/utils/Cache.kt +++ b/app/src/main/java/dev/brahmkshatriya/echo/utils/Cache.kt @@ -1,55 +1,38 @@ package dev.brahmkshatriya.echo.utils import android.content.Context -import android.os.Parcel -import android.os.Parcelable import java.io.File -import java.io.FileInputStream fun cacheDir(context: Context, folderName: String) = File(context.cacheDir, folderName).apply { mkdirs() } -fun Context.getFromCache( - id: String, folderName: String, creator: (Parcel) -> T? -): T? { +const val CACHE_FOLDER_SIZE = 50 * 1024 * 1024 //50MB + + +inline fun Context.saveToCache( + id: String, data: T?, folderName: String = T::class.java.simpleName +) { val fileName = id.hashCode().toString() val cacheDir = cacheDir(this, folderName) val file = File(cacheDir, fileName) - return if (file.exists()) runCatching { - val bytes = FileInputStream(file).use { it.readBytes() } - val parcel = Parcel.obtain() - parcel.unmarshall(bytes, 0, bytes.size) - parcel.setDataPosition(0) - val value = creator(parcel) - parcel.recycle() - value - }.getOrNull() else null + + var size = cacheDir.walk().sumOf { it.length().toInt() } + while (size > CACHE_FOLDER_SIZE) { + val files = cacheDir.listFiles() + files?.sortBy { it.lastModified() } + files?.firstOrNull()?.delete() + size = cacheDir.walk().sumOf { it.length().toInt() } + } + file.writeText(data.toJson()) } -fun Context.saveToCache( - id: String, folderName: String, writer: (Parcel) -> Unit -) { +inline fun Context.getFromCache( + id: String, folderName: String = T::class.java.simpleName +): T? { val fileName = id.hashCode().toString() val cacheDir = cacheDir(this, folderName) - val parcel = Parcel.obtain() - writer(parcel) - val bytes = parcel.marshall() - parcel.recycle() - File(cacheDir, fileName).outputStream().use { it.write(bytes) } -} - -inline fun Context.getFromCache( - id: String, creator: Parcelable.Creator, folderName: String? = null -) = getFromCache(id, folderName ?: T::class.java.simpleName) { creator.createFromParcel(it) } - -inline fun Context.saveToCache( - id: String, value: T?, folderName: String? = null -) = saveToCache(id, folderName ?: T::class.java.simpleName) { value?.writeToParcel(it, 0) } - -inline fun Context.saveToCache( - id: String, value: List, folderName: String? = null -) = saveToCache(id, folderName ?: T::class.java.simpleName) { it.writeTypedList(value) } - -inline fun Context.getListFromCache( - id: String, creator: Parcelable.Creator, folderName: String? = null -) = getFromCache(id, folderName ?: T::class.java.simpleName) { it.createTypedArrayList(creator) } + val file = File(cacheDir, fileName) + return if (file.exists()) runCatching { + file.readText().toData() + }.getOrNull() else null +} \ No newline at end of file diff --git a/app/src/main/java/dev/brahmkshatriya/echo/utils/ImageLoadingUtils.kt b/app/src/main/java/dev/brahmkshatriya/echo/utils/ImageLoadingUtils.kt index 15154207..ef587dfc 100644 --- a/app/src/main/java/dev/brahmkshatriya/echo/utils/ImageLoadingUtils.kt +++ b/app/src/main/java/dev/brahmkshatriya/echo/utils/ImageLoadingUtils.kt @@ -99,7 +99,6 @@ private fun createRequest( requestBuilder: RequestBuilder, ) = imageHolder.run { when (this) { - is ImageHolder.BitmapImageHolder -> requestBuilder.load(bitmap) is ImageHolder.UriImageHolder -> requestBuilder.load(uri) is ImageHolder.UrlRequestImageHolder -> requestBuilder.load(GlideUrl(request.url) { request.headers }) diff --git a/app/src/main/java/dev/brahmkshatriya/echo/utils/Serializer.kt b/app/src/main/java/dev/brahmkshatriya/echo/utils/Serializer.kt new file mode 100644 index 00000000..8a00c34a --- /dev/null +++ b/app/src/main/java/dev/brahmkshatriya/echo/utils/Serializer.kt @@ -0,0 +1,21 @@ +package dev.brahmkshatriya.echo.utils + +import android.os.Bundle +import kotlinx.serialization.encodeToString +import kotlinx.serialization.json.Json + +val json = Json { + ignoreUnknownKeys = true + prettyPrint = true +} + +inline fun String.toData() = json.decodeFromString(this) +inline fun T.toJson() = json.encodeToString(this) + +inline fun Bundle.putSerialized(key: String, value: T) { + putString(key, value.toJson()) +} + +inline fun Bundle.getSerialized(key: String): T? { + return getString(key)?.toData() +} \ No newline at end of file diff --git a/app/src/main/java/dev/brahmkshatriya/echo/viewmodels/PlayerViewModel.kt b/app/src/main/java/dev/brahmkshatriya/echo/viewmodels/PlayerViewModel.kt index 40cfd1b0..e69b9ffa 100644 --- a/app/src/main/java/dev/brahmkshatriya/echo/viewmodels/PlayerViewModel.kt +++ b/app/src/main/java/dev/brahmkshatriya/echo/viewmodels/PlayerViewModel.kt @@ -27,6 +27,7 @@ import dev.brahmkshatriya.echo.ui.player.PlayerUiListener import dev.brahmkshatriya.echo.ui.settings.AudioFragment.AudioPreference.Companion.KEEP_QUEUE import dev.brahmkshatriya.echo.utils.getSerial import dev.brahmkshatriya.echo.utils.listenFuture +import dev.brahmkshatriya.echo.utils.toJson import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableStateFlow @@ -179,7 +180,7 @@ class PlayerViewModel @Inject constructor( fun radio(clientId: String, item: EchoMediaItem) { withBrowser { - it.sendCustomCommand(radioCommand, bundleOf("clientId" to clientId, "item" to item)) + it.sendCustomCommand(radioCommand, bundleOf("clientId" to clientId, "item" to item.toJson())) } } diff --git a/common/build.gradle.kts b/common/build.gradle.kts index cfec1e85..4039adc0 100644 --- a/common/build.gradle.kts +++ b/common/build.gradle.kts @@ -6,12 +6,12 @@ plugins { } java { - sourceCompatibility = JavaVersion.VERSION_21 - targetCompatibility = JavaVersion.VERSION_21 + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 } dependencies { - implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.1") + api("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.1") } publishing { diff --git a/common/src/main/java/dev/brahmkshatriya/echo/common/models/Album.kt b/common/src/main/java/dev/brahmkshatriya/echo/common/models/Album.kt index cdb643d6..38c65412 100644 --- a/common/src/main/java/dev/brahmkshatriya/echo/common/models/Album.kt +++ b/common/src/main/java/dev/brahmkshatriya/echo/common/models/Album.kt @@ -1,7 +1,6 @@ package dev.brahmkshatriya.echo.common.models import kotlinx.serialization.Serializable -import java.io.Serializable as JSerializable @Serializable data class Album( @@ -16,4 +15,4 @@ data class Album( val description: String? = null, val subtitle: String? = null, val extras: Map = mapOf() -) : JSerializable \ No newline at end of file +) \ No newline at end of file diff --git a/common/src/main/java/dev/brahmkshatriya/echo/common/models/Artist.kt b/common/src/main/java/dev/brahmkshatriya/echo/common/models/Artist.kt index 4b5c4683..9de76844 100644 --- a/common/src/main/java/dev/brahmkshatriya/echo/common/models/Artist.kt +++ b/common/src/main/java/dev/brahmkshatriya/echo/common/models/Artist.kt @@ -1,7 +1,6 @@ package dev.brahmkshatriya.echo.common.models import kotlinx.serialization.Serializable -import java.io.Serializable as JSerializable @Serializable data class Artist( @@ -13,4 +12,4 @@ data class Artist( val description: String? = null, val followers: Int? = null, val isFollowing : Boolean = false, -) : JSerializable +) diff --git a/common/src/main/java/dev/brahmkshatriya/echo/common/models/Bitmap.kt b/common/src/main/java/dev/brahmkshatriya/echo/common/models/Bitmap.kt deleted file mode 100644 index 78d56b68..00000000 --- a/common/src/main/java/dev/brahmkshatriya/echo/common/models/Bitmap.kt +++ /dev/null @@ -1,7 +0,0 @@ -package dev.brahmkshatriya.echo.common.models - -import kotlinx.serialization.Serializable -import java.io.Serializable as JSerializable - -@Serializable -class Bitmap: JSerializable diff --git a/common/src/main/java/dev/brahmkshatriya/echo/common/models/EchoMediaItem.kt b/common/src/main/java/dev/brahmkshatriya/echo/common/models/EchoMediaItem.kt index e792a7b2..01597f51 100644 --- a/common/src/main/java/dev/brahmkshatriya/echo/common/models/EchoMediaItem.kt +++ b/common/src/main/java/dev/brahmkshatriya/echo/common/models/EchoMediaItem.kt @@ -1,23 +1,30 @@ package dev.brahmkshatriya.echo.common.models +import kotlinx.serialization.ExperimentalSerializationApi import kotlinx.serialization.Serializable -import java.io.Serializable as JSerializable +import kotlinx.serialization.json.JsonClassDiscriminator - -sealed class EchoMediaItem : JSerializable { +@OptIn(ExperimentalSerializationApi::class) +@JsonClassDiscriminator("type") +@Serializable +sealed class EchoMediaItem { @Serializable data class TrackItem(val track: Track) : EchoMediaItem() @Serializable sealed class Profile : EchoMediaItem() { + @Serializable data class ArtistItem(val artist: Artist) : Profile() + @Serializable data class UserItem(val user: User) : Profile() } @Serializable sealed class Lists : EchoMediaItem() { + @Serializable data class AlbumItem(val album: Album) : Lists() + @Serializable data class PlaylistItem(val playlist: Playlist) : Lists() val size @@ -33,27 +40,6 @@ sealed class EchoMediaItem : JSerializable { fun Artist.toMediaItem() = Profile.ArtistItem(this) fun User.toMediaItem() = Profile.UserItem(this) fun Playlist.toMediaItem() = Lists.PlaylistItem(this) - -// val creator = object : Parcelable.Creator { -// -// inline fun create(source: Parcel?) = runCatching { -// parcelableCreator().createFromParcel(source)!! -// }.getOrNull() -// -// override fun createFromParcel(source: Parcel?): EchoMediaItem { -// return create(source) -// ?: create(source) -// ?: create(source) -// ?: create(source) -// ?: create(source) -// ?: throw IllegalArgumentException("Unknown parcelable type") -// } -// -// override fun newArray(size: Int): Array { -// return arrayOfNulls(size) -// } -// -// } } fun toMediaItemsContainer() = MediaItemsContainer.Item( diff --git a/common/src/main/java/dev/brahmkshatriya/echo/common/models/ImageHolder.kt b/common/src/main/java/dev/brahmkshatriya/echo/common/models/ImageHolder.kt index 5f6b2275..b45de7c7 100644 --- a/common/src/main/java/dev/brahmkshatriya/echo/common/models/ImageHolder.kt +++ b/common/src/main/java/dev/brahmkshatriya/echo/common/models/ImageHolder.kt @@ -2,33 +2,24 @@ package dev.brahmkshatriya.echo.common.models import dev.brahmkshatriya.echo.common.models.Request.Companion.toRequest import kotlinx.serialization.Serializable -import java.io.Serializable as JSerializable @Serializable -sealed class ImageHolder : JSerializable { +sealed class ImageHolder { abstract val crop: Boolean + @Serializable data class UrlRequestImageHolder(val request: Request, override val crop: Boolean) : ImageHolder() + @Serializable data class UriImageHolder(val uri: String, override val crop: Boolean) : ImageHolder() - data class BitmapImageHolder(val bitmap: Bitmap, override val crop: Boolean) : ImageHolder() companion object { -// fun Uri.toImageHolder(crop: Boolean = false): UriImageHolder { -// return UriImageHolder(this, crop) -// } - fun String.toImageHolder( headers: Map = mapOf(), crop: Boolean = false - ): UrlRequestImageHolder { - return UrlRequestImageHolder(this.toRequest(headers), crop) - } + ) = UrlRequestImageHolder(this.toRequest(headers), crop) - fun Bitmap.toImageHolder(crop: Boolean = false): BitmapImageHolder { - return BitmapImageHolder(this, crop) - } + fun String.toUriImageHolder(crop: Boolean = false) = UriImageHolder(this, crop) } -} - +} \ No newline at end of file diff --git a/common/src/main/java/dev/brahmkshatriya/echo/common/models/Playlist.kt b/common/src/main/java/dev/brahmkshatriya/echo/common/models/Playlist.kt index 2ad38337..02edd35a 100644 --- a/common/src/main/java/dev/brahmkshatriya/echo/common/models/Playlist.kt +++ b/common/src/main/java/dev/brahmkshatriya/echo/common/models/Playlist.kt @@ -1,7 +1,6 @@ package dev.brahmkshatriya.echo.common.models import kotlinx.serialization.Serializable -import java.io.Serializable as JSerializable @Serializable data class Playlist( @@ -16,4 +15,4 @@ data class Playlist( val description: String? = null, val subtitle: String? = null, val extras: Map = mapOf() -) : JSerializable \ No newline at end of file +) \ No newline at end of file diff --git a/common/src/main/java/dev/brahmkshatriya/echo/common/models/Request.kt b/common/src/main/java/dev/brahmkshatriya/echo/common/models/Request.kt index cae6aad2..f9fe54e1 100644 --- a/common/src/main/java/dev/brahmkshatriya/echo/common/models/Request.kt +++ b/common/src/main/java/dev/brahmkshatriya/echo/common/models/Request.kt @@ -1,17 +1,15 @@ package dev.brahmkshatriya.echo.common.models import kotlinx.serialization.Serializable -import java.io.Serializable as JSerializable @Serializable data class Request( val url: String, val headers: Map = emptyMap() -) : JSerializable { +) { companion object { fun String.toRequest(headers: Map = emptyMap()): Request { return Request(this, headers) } } - } \ No newline at end of file diff --git a/common/src/main/java/dev/brahmkshatriya/echo/common/models/Streamable.kt b/common/src/main/java/dev/brahmkshatriya/echo/common/models/Streamable.kt index b33b13a9..9092cd6d 100644 --- a/common/src/main/java/dev/brahmkshatriya/echo/common/models/Streamable.kt +++ b/common/src/main/java/dev/brahmkshatriya/echo/common/models/Streamable.kt @@ -1,11 +1,10 @@ package dev.brahmkshatriya.echo.common.models import kotlinx.serialization.Serializable -import java.io.Serializable as JSerializable @Serializable data class Streamable( val id: String, val quality: Int, val extra: Map = mapOf() -) : JSerializable \ No newline at end of file +) \ No newline at end of file diff --git a/common/src/main/java/dev/brahmkshatriya/echo/common/models/StreamableAudio.kt b/common/src/main/java/dev/brahmkshatriya/echo/common/models/StreamableAudio.kt index 0c812490..3224e37f 100644 --- a/common/src/main/java/dev/brahmkshatriya/echo/common/models/StreamableAudio.kt +++ b/common/src/main/java/dev/brahmkshatriya/echo/common/models/StreamableAudio.kt @@ -1,13 +1,11 @@ package dev.brahmkshatriya.echo.common.models import dev.brahmkshatriya.echo.common.models.Request.Companion.toRequest -import java.io.InputStream - import kotlinx.serialization.Serializable -import java.io.Serializable as JSerializable +import java.io.InputStream @Serializable -sealed class StreamableAudio : JSerializable { +sealed class StreamableAudio { data class StreamableRequest(val request: Request) : StreamableAudio() data class ByteStreamAudio(val stream: InputStream, val totalBytes: Long) : StreamableAudio() diff --git a/common/src/main/java/dev/brahmkshatriya/echo/common/models/Track.kt b/common/src/main/java/dev/brahmkshatriya/echo/common/models/Track.kt index ebc25797..9ed1309a 100644 --- a/common/src/main/java/dev/brahmkshatriya/echo/common/models/Track.kt +++ b/common/src/main/java/dev/brahmkshatriya/echo/common/models/Track.kt @@ -1,7 +1,6 @@ package dev.brahmkshatriya.echo.common.models import kotlinx.serialization.Serializable -import java.io.Serializable as JSerializable @Serializable data class Track( @@ -18,9 +17,4 @@ data class Track( val videoStreamable: List = listOf(), val audioStreamables: List = listOf(), val expiresAt: Long = 0, -) : JSerializable { - -// companion object { -// val creator = parcelableCreator() -// } -} \ No newline at end of file +) \ No newline at end of file diff --git a/common/src/main/java/dev/brahmkshatriya/echo/common/models/User.kt b/common/src/main/java/dev/brahmkshatriya/echo/common/models/User.kt index b187cc40..3dcc391d 100644 --- a/common/src/main/java/dev/brahmkshatriya/echo/common/models/User.kt +++ b/common/src/main/java/dev/brahmkshatriya/echo/common/models/User.kt @@ -1,12 +1,11 @@ package dev.brahmkshatriya.echo.common.models import kotlinx.serialization.Serializable -import java.io.Serializable as JSerializable @Serializable -open class User( - open val id: String, - open val name: String, - open val cover: ImageHolder? = null, - open val extras: Map = emptyMap(), -) : JSerializable \ No newline at end of file +data class User( + val id: String, + val name: String, + val cover: ImageHolder? = null, + val extras: Map = emptyMap(), +) \ No newline at end of file