From b52baf362da99b476bc91378bad25f14cd8f756e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Font=C3=A1n?= Date: Fri, 20 Dec 2024 18:19:12 +0100 Subject: [PATCH] feat: Refactor states, move Song model This commit includes several key changes:- Refactored `ScreenState` to be a sealed interface instead of a sealed class. - Refactored `ResourceState` to use data classes and include loading/error messages instead of generic messages. - Moved `Song` model to `com.bobbyesp.utilities.mediastore.model` package. - Updated usages of `Song`, `ResourceState`, and `ScreenState` across the codebase to reflect the above changes. - Added documentation to the states sealed classes/interfaces - Added `toString` to `ResourceState` for easier debugging - Improved `NavType` creation functions with more documentation. --- .../metadator/domain/model/ParcelableSong.kt | 2 +- .../com/bobbyesp/metadator/ext/MediaItem.kt | 2 +- .../java/com/bobbyesp/metadator/ext/Song.kt | 2 +- .../cards/songs/HorizontalSongCard.kt | 3 +- .../cards/songs/VerticalSongCard.kt | 3 +- .../presentation/pages/MediaStorePage.kt | 2 +- .../pages/MediaStorePageViewModel.kt | 2 +- .../presentation/pages/home/HomePage.kt | 3 +- .../pages/mediaplayer/MediaplayerViewModel.kt | 2 +- .../utilities/tageditor/MetadataEditorVM.kt | 4 +- .../tageditor/spotify/MetadataBsVM.kt | 2 +- .../mediastore/MediaStoreReceiver.kt | 2 +- .../utilities/{ => mediastore}/model/Song.kt | 2 +- .../navigation/CustomNavigationArguments.kt | 68 +++++++++++++++++++ .../utilities/states/ResourceState.kt | 55 +++++++++++++-- .../bobbyesp/utilities/states/ScreenState.kt | 29 ++++++-- 16 files changed, 158 insertions(+), 25 deletions(-) rename app/utilities/src/main/java/com/bobbyesp/utilities/{ => mediastore}/model/Song.kt (96%) diff --git a/app/src/main/java/com/bobbyesp/metadator/domain/model/ParcelableSong.kt b/app/src/main/java/com/bobbyesp/metadator/domain/model/ParcelableSong.kt index 6489346..a21dd38 100644 --- a/app/src/main/java/com/bobbyesp/metadator/domain/model/ParcelableSong.kt +++ b/app/src/main/java/com/bobbyesp/metadator/domain/model/ParcelableSong.kt @@ -3,7 +3,7 @@ package com.bobbyesp.metadator.domain.model import android.net.Uri import android.os.Parcelable import androidx.compose.runtime.Immutable -import com.bobbyesp.utilities.model.UriSerializer +import com.bobbyesp.utilities.mediastore.model.UriSerializer import kotlinx.parcelize.Parcelize import kotlinx.serialization.Serializable diff --git a/app/src/main/java/com/bobbyesp/metadator/ext/MediaItem.kt b/app/src/main/java/com/bobbyesp/metadator/ext/MediaItem.kt index 98e596b..f7b59a7 100644 --- a/app/src/main/java/com/bobbyesp/metadator/ext/MediaItem.kt +++ b/app/src/main/java/com/bobbyesp/metadator/ext/MediaItem.kt @@ -1,7 +1,7 @@ package com.bobbyesp.metadator.ext import androidx.media3.common.MediaItem -import com.bobbyesp.utilities.model.Song +import com.bobbyesp.utilities.mediastore.model.Song fun MediaItem.toSong(): Song { val mediaMetadata = diff --git a/app/src/main/java/com/bobbyesp/metadator/ext/Song.kt b/app/src/main/java/com/bobbyesp/metadator/ext/Song.kt index 2fb46e6..3edf042 100644 --- a/app/src/main/java/com/bobbyesp/metadator/ext/Song.kt +++ b/app/src/main/java/com/bobbyesp/metadator/ext/Song.kt @@ -1,7 +1,7 @@ package com.bobbyesp.metadator.ext import com.bobbyesp.metadator.domain.model.ParcelableSong -import com.bobbyesp.utilities.model.Song +import com.bobbyesp.utilities.mediastore.model.Song fun Song.toParcelableSong(): ParcelableSong { return ParcelableSong( diff --git a/app/src/main/java/com/bobbyesp/metadator/presentation/components/cards/songs/HorizontalSongCard.kt b/app/src/main/java/com/bobbyesp/metadator/presentation/components/cards/songs/HorizontalSongCard.kt index 7ac2bf9..4905527 100644 --- a/app/src/main/java/com/bobbyesp/metadator/presentation/components/cards/songs/HorizontalSongCard.kt +++ b/app/src/main/java/com/bobbyesp/metadator/presentation/components/cards/songs/HorizontalSongCard.kt @@ -21,9 +21,8 @@ import androidx.compose.ui.unit.sp import com.bobbyesp.metadator.presentation.components.image.AsyncImage import com.bobbyesp.metadator.presentation.components.text.ConditionedMarqueeText import com.bobbyesp.metadator.presentation.theme.MetadatorTheme -import com.bobbyesp.ui.components.text.MarqueeText import com.bobbyesp.utilities.Time -import com.bobbyesp.utilities.model.Song +import com.bobbyesp.utilities.mediastore.model.Song @Composable fun HorizontalSongCard( diff --git a/app/src/main/java/com/bobbyesp/metadator/presentation/components/cards/songs/VerticalSongCard.kt b/app/src/main/java/com/bobbyesp/metadator/presentation/components/cards/songs/VerticalSongCard.kt index 3fef5f5..0302f68 100644 --- a/app/src/main/java/com/bobbyesp/metadator/presentation/components/cards/songs/VerticalSongCard.kt +++ b/app/src/main/java/com/bobbyesp/metadator/presentation/components/cards/songs/VerticalSongCard.kt @@ -18,8 +18,7 @@ import androidx.compose.ui.unit.sp import com.bobbyesp.metadator.presentation.components.image.AsyncImage import com.bobbyesp.metadator.presentation.components.text.ConditionedMarqueeText import com.bobbyesp.metadator.presentation.theme.MetadatorTheme -import com.bobbyesp.ui.components.text.MarqueeText -import com.bobbyesp.utilities.model.Song +import com.bobbyesp.utilities.mediastore.model.Song @Composable fun VerticalSongCard( diff --git a/app/src/main/java/com/bobbyesp/metadator/presentation/pages/MediaStorePage.kt b/app/src/main/java/com/bobbyesp/metadator/presentation/pages/MediaStorePage.kt index 996cb34..8341ea3 100644 --- a/app/src/main/java/com/bobbyesp/metadator/presentation/pages/MediaStorePage.kt +++ b/app/src/main/java/com/bobbyesp/metadator/presentation/pages/MediaStorePage.kt @@ -25,7 +25,7 @@ import com.bobbyesp.metadator.presentation.components.others.status.EmptyMediaSt import com.bobbyesp.metadator.presentation.pages.home.LayoutType import com.bobbyesp.ui.common.pages.ErrorPage import com.bobbyesp.ui.common.pages.LoadingPage -import com.bobbyesp.utilities.model.Song +import com.bobbyesp.utilities.mediastore.model.Song import com.bobbyesp.utilities.states.ResourceState import my.nanihadesuka.compose.LazyColumnScrollbar import my.nanihadesuka.compose.LazyVerticalGridScrollbar diff --git a/app/src/main/java/com/bobbyesp/metadator/presentation/pages/MediaStorePageViewModel.kt b/app/src/main/java/com/bobbyesp/metadator/presentation/pages/MediaStorePageViewModel.kt index d77d25e..581f85a 100644 --- a/app/src/main/java/com/bobbyesp/metadator/presentation/pages/MediaStorePageViewModel.kt +++ b/app/src/main/java/com/bobbyesp/metadator/presentation/pages/MediaStorePageViewModel.kt @@ -4,7 +4,7 @@ import android.content.Context import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.bobbyesp.utilities.mediastore.MediaStoreReceiver.Advanced.observeSongs -import com.bobbyesp.utilities.model.Song +import com.bobbyesp.utilities.mediastore.model.Song import com.bobbyesp.utilities.states.ResourceState import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.MutableStateFlow diff --git a/app/src/main/java/com/bobbyesp/metadator/presentation/pages/home/HomePage.kt b/app/src/main/java/com/bobbyesp/metadator/presentation/pages/home/HomePage.kt index cff506e..9082a85 100644 --- a/app/src/main/java/com/bobbyesp/metadator/presentation/pages/home/HomePage.kt +++ b/app/src/main/java/com/bobbyesp/metadator/presentation/pages/home/HomePage.kt @@ -17,7 +17,6 @@ import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.rounded.CropSquare import androidx.compose.material.icons.rounded.KeyboardDoubleArrowUp import androidx.compose.material.icons.rounded.Menu import androidx.compose.material.icons.rounded.MoreHoriz @@ -63,7 +62,7 @@ import com.bobbyesp.metadator.presentation.pages.MediaStorePageViewModel import com.bobbyesp.ui.components.dropdown.AnimatedDropdownMenu import com.bobbyesp.ui.components.dropdown.DropdownItemContainer import com.bobbyesp.ui.components.text.AutoResizableText -import com.bobbyesp.utilities.model.Song +import com.bobbyesp.utilities.mediastore.model.Song import com.bobbyesp.utilities.Preferences import com.bobbyesp.metadator.util.preferences.PreferencesKeys.DESIRED_LAYOUT import com.bobbyesp.metadator.util.preferences.PreferencesKeys.SONG_CARD_SIZE diff --git a/app/src/main/java/com/bobbyesp/metadator/presentation/pages/mediaplayer/MediaplayerViewModel.kt b/app/src/main/java/com/bobbyesp/metadator/presentation/pages/mediaplayer/MediaplayerViewModel.kt index 900e21a..00e7fab 100644 --- a/app/src/main/java/com/bobbyesp/metadator/presentation/pages/mediaplayer/MediaplayerViewModel.kt +++ b/app/src/main/java/com/bobbyesp/metadator/presentation/pages/mediaplayer/MediaplayerViewModel.kt @@ -19,7 +19,7 @@ import com.bobbyesp.mediaplayer.service.queue.SongsQueue import com.bobbyesp.utilities.Time.formatDuration import com.bobbyesp.utilities.mediastore.MediaStoreReceiver.Advanced.getSongs import com.bobbyesp.utilities.mediastore.MediaStoreReceiver.Advanced.observeSongs -import com.bobbyesp.utilities.model.Song +import com.bobbyesp.utilities.mediastore.model.Song import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.asStateFlow diff --git a/app/src/main/java/com/bobbyesp/metadator/presentation/pages/utilities/tageditor/MetadataEditorVM.kt b/app/src/main/java/com/bobbyesp/metadator/presentation/pages/utilities/tageditor/MetadataEditorVM.kt index b0679b6..343e133 100644 --- a/app/src/main/java/com/bobbyesp/metadator/presentation/pages/utilities/tageditor/MetadataEditorVM.kt +++ b/app/src/main/java/com/bobbyesp/metadator/presentation/pages/utilities/tageditor/MetadataEditorVM.kt @@ -117,7 +117,7 @@ class MetadataEditorVM( mutableState.update { it.copy( audioProperties = ResourceState.Error( - message = error.message ?: error.stackTraceToString() + errorMessage = error.message ?: error.stackTraceToString() ) ) } @@ -125,7 +125,7 @@ class MetadataEditorVM( mutableState.update { it.copy( metadata = ResourceState.Error( - message = error.message ?: error.stackTraceToString() + errorMessage = error.message ?: error.stackTraceToString() ) ) } diff --git a/app/src/main/java/com/bobbyesp/metadator/presentation/pages/utilities/tageditor/spotify/MetadataBsVM.kt b/app/src/main/java/com/bobbyesp/metadator/presentation/pages/utilities/tageditor/spotify/MetadataBsVM.kt index 49a222b..860d19f 100644 --- a/app/src/main/java/com/bobbyesp/metadator/presentation/pages/utilities/tageditor/spotify/MetadataBsVM.kt +++ b/app/src/main/java/com/bobbyesp/metadator/presentation/pages/utilities/tageditor/spotify/MetadataBsVM.kt @@ -56,7 +56,7 @@ class MetadataBsVM( mutableViewStateFlow.update { it.copy( searchedTracks = ResourceState.Error( - message = th.message ?: th.stackTrace.toString() + errorMessage = th.message ?: th.stackTrace.toString() ) ) } diff --git a/app/utilities/src/main/java/com/bobbyesp/utilities/mediastore/MediaStoreReceiver.kt b/app/utilities/src/main/java/com/bobbyesp/utilities/mediastore/MediaStoreReceiver.kt index 1426840..6a87294 100644 --- a/app/utilities/src/main/java/com/bobbyesp/utilities/mediastore/MediaStoreReceiver.kt +++ b/app/utilities/src/main/java/com/bobbyesp/utilities/mediastore/MediaStoreReceiver.kt @@ -11,7 +11,7 @@ import android.util.Log import com.bobbyesp.utilities.R import com.bobbyesp.utilities.mediastore.advanced.advancedQuery import com.bobbyesp.utilities.mediastore.advanced.observe -import com.bobbyesp.utilities.model.Song +import com.bobbyesp.utilities.mediastore.model.Song import kotlinx.coroutines.flow.map import java.io.FileNotFoundException diff --git a/app/utilities/src/main/java/com/bobbyesp/utilities/model/Song.kt b/app/utilities/src/main/java/com/bobbyesp/utilities/mediastore/model/Song.kt similarity index 96% rename from app/utilities/src/main/java/com/bobbyesp/utilities/model/Song.kt rename to app/utilities/src/main/java/com/bobbyesp/utilities/mediastore/model/Song.kt index a3a69ae..cdf8986 100644 --- a/app/utilities/src/main/java/com/bobbyesp/utilities/model/Song.kt +++ b/app/utilities/src/main/java/com/bobbyesp/utilities/mediastore/model/Song.kt @@ -1,4 +1,4 @@ -package com.bobbyesp.utilities.model +package com.bobbyesp.utilities.mediastore.model import android.net.Uri import android.os.Parcelable diff --git a/app/utilities/src/main/java/com/bobbyesp/utilities/navigation/CustomNavigationArguments.kt b/app/utilities/src/main/java/com/bobbyesp/utilities/navigation/CustomNavigationArguments.kt index cad84d8..38e1b8e 100644 --- a/app/utilities/src/main/java/com/bobbyesp/utilities/navigation/CustomNavigationArguments.kt +++ b/app/utilities/src/main/java/com/bobbyesp/utilities/navigation/CustomNavigationArguments.kt @@ -8,10 +8,25 @@ import androidx.navigation.NavType import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json +/** + * Creates a custom NavType for Parcelable types. + * + * @param T The type of Parcelable. + * @param isNullableAllowed Whether null values are allowed. + * @param json The Json instance used for serialization and deserialization. + * @return A NavType for the specified Parcelable type. + */ inline fun parcelableType( isNullableAllowed: Boolean = false, json: Json = Json, ) = object : NavType(isNullableAllowed = isNullableAllowed) { + /** + * Retrieves the Parcelable from the Bundle. + * + * @param bundle The Bundle containing the Parcelable. + * @param key The key associated with the Parcelable. + * @return The Parcelable object. + */ override fun get(bundle: Bundle, key: String) = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { bundle.getParcelable(key, T::class.java) @@ -19,24 +34,77 @@ inline fun parcelableType( @Suppress("DEPRECATION") bundle.getParcelable(key) } + /** + * Parses a Parcelable from a String. + * + * @param value The String to parse. + * @return The parsed Parcelable object. + */ override fun parseValue(value: String): T = json.decodeFromString(value) + /** + * Serializes a Parcelable to a String. + * + * @param value The Parcelable to serialize. + * @return The serialized String. + */ override fun serializeAsValue(value: T): String = Uri.encode(json.encodeToString(value)) + /** + * Puts a Parcelable into a Bundle. + * + * @param bundle The Bundle to put the Parcelable into. + * @param key The key associated with the Parcelable. + * @param value The Parcelable to put into the Bundle. + */ override fun put(bundle: Bundle, key: String, value: T) = bundle.putParcelable(key, value) } +/** + * Creates a custom NavType for serializable types. + * + * @param T The type of the serializable object. + * @param isNullableAllowed Whether null values are allowed. + * @param json The Json instance used for serialization and deserialization. + * @return A NavType for the specified serializable type. + */ inline fun serializableType( isNullableAllowed: Boolean = false, json: Json = Json, ) = object : NavType(isNullableAllowed = isNullableAllowed) { + /** + * Retrieves the serializable object from the Bundle. + * + * @param bundle The Bundle containing the serializable object. + * @param key The key associated with the serializable object. + * @return The serializable object. + */ override fun get(bundle: Bundle, key: String) = bundle.getString(key)?.let(json::decodeFromString) + /** + * Parses a serializable object from a String. + * + * @param value The String to parse. + * @return The parsed serializable object. + */ override fun parseValue(value: String): T = json.decodeFromString(value) + /** + * Serializes a serializable object to a String. + * + * @param value The serializable object to serialize. + * @return The serialized String. + */ override fun serializeAsValue(value: T): String = Uri.encode(json.encodeToString(value)) + /** + * Puts a serializable object into a Bundle. + * + * @param bundle The Bundle to put the serializable object into. + * @param key The key associated with the serializable object. + * @param value The serializable object to put into the Bundle. + */ override fun put(bundle: Bundle, key: String, value: T) { bundle.putString(key, json.encodeToString(value)) } diff --git a/app/utilities/src/main/java/com/bobbyesp/utilities/states/ResourceState.kt b/app/utilities/src/main/java/com/bobbyesp/utilities/states/ResourceState.kt index b0b4c98..a7c5645 100644 --- a/app/utilities/src/main/java/com/bobbyesp/utilities/states/ResourceState.kt +++ b/app/utilities/src/main/java/com/bobbyesp/utilities/states/ResourceState.kt @@ -1,7 +1,54 @@ package com.bobbyesp.utilities.states -sealed class ResourceState(val data: T? = null, val message: String? = null) { - class Loading(data: T? = null) : ResourceState(data) - class Success(data: T?) : ResourceState(data) - class Error(message: String, data: T? = null) : ResourceState(data, message) +/** + * A sealed class representing the state of a resource. + * + * @param T The type of data held by this state. + * @property data The data associated with the state, if any. + * @property message The message associated with the state, if any. + */ +sealed class ResourceState( + val data: T? = null, + val message: String? = null +) { + /** + * Represents a loading state with optional partial data. + * + * @param T The type of data held by this state. + * @property partialData The partial data associated with the loading state, if any. + */ + data class Loading(val partialData: T? = null) : ResourceState(partialData) + + /** + * Represents a successful state with required data. + * + * @param T The type of data held by this state. + * @property result The result data associated with the successful state. + */ + data class Success(val result: T) : ResourceState(result) + + /** + * Represents an error state with a message and optional data. + * + * @param T The type of data held by this state. + * @property errorMessage The error message associated with the error state. + * @property errorData The data associated with the error state, if any. + */ + data class Error( + val errorMessage: String, + val errorData: T? = null + ) : ResourceState(errorData, errorMessage) + + /** + * Returns a string representation of the resource state. + * + * @return A string describing the current state. + */ + override fun toString(): String { + return when (this) { + is Loading -> "Loading(data=$data)" + is Success -> "Success(data=$data)" + is Error -> "Error(message=$message, data=$data)" + } + } } \ No newline at end of file diff --git a/app/utilities/src/main/java/com/bobbyesp/utilities/states/ScreenState.kt b/app/utilities/src/main/java/com/bobbyesp/utilities/states/ScreenState.kt index 1178dce..bb7e7f8 100644 --- a/app/utilities/src/main/java/com/bobbyesp/utilities/states/ScreenState.kt +++ b/app/utilities/src/main/java/com/bobbyesp/utilities/states/ScreenState.kt @@ -1,7 +1,28 @@ package com.bobbyesp.utilities.states -sealed class ScreenState { - data object Loading : ScreenState() - data class Success(val data: T?) : ScreenState() - data class Error(val exception: Throwable) : ScreenState() +/** + * A sealed interface representing the state of a screen. + * + * @param T The type of data held by this state. + */ +sealed interface ScreenState { + /** + * Represents a loading state. + */ + object Loading : ScreenState + + /** + * Represents a successful state with data. + * + * @param T The type of data held by this state. + * @property data The data associated with the successful state. + */ + data class Success(val data: T?) : ScreenState + + /** + * Represents an error state with an exception. + * + * @property exception The exception associated with the error state. + */ + data class Error(val exception: Throwable) : ScreenState } \ No newline at end of file