Skip to content

Commit

Permalink
feat: Refactor states, move Song model
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
BobbyESP committed Dec 20, 2024
1 parent d79860a commit b52baf3
Show file tree
Hide file tree
Showing 16 changed files with 158 additions and 25 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
2 changes: 1 addition & 1 deletion app/src/main/java/com/bobbyesp/metadator/ext/MediaItem.kt
Original file line number Diff line number Diff line change
@@ -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 =
Expand Down
2 changes: 1 addition & 1 deletion app/src/main/java/com/bobbyesp/metadator/ext/Song.kt
Original file line number Diff line number Diff line change
@@ -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(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,15 +117,15 @@ class MetadataEditorVM(
mutableState.update {
it.copy(
audioProperties = ResourceState.Error(
message = error.message ?: error.stackTraceToString()
errorMessage = error.message ?: error.stackTraceToString()
)
)
}
} else {
mutableState.update {
it.copy(
metadata = ResourceState.Error(
message = error.message ?: error.stackTraceToString()
errorMessage = error.message ?: error.stackTraceToString()
)
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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()
)
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.bobbyesp.utilities.model
package com.bobbyesp.utilities.mediastore.model

import android.net.Uri
import android.os.Parcelable
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,35 +8,103 @@ 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 <reified T : Parcelable> parcelableType(
isNullableAllowed: Boolean = false,
json: Json = Json,
) = object : NavType<T>(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)
} else {
@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 <reified T : Any> serializableType(
isNullableAllowed: Boolean = false,
json: Json = Json,
) = object : NavType<T>(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<String, T>(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))
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,54 @@
package com.bobbyesp.utilities.states

sealed class ResourceState<T>(val data: T? = null, val message: String? = null) {
class Loading<T>(data: T? = null) : ResourceState<T>(data)
class Success<T>(data: T?) : ResourceState<T>(data)
class Error<T>(message: String, data: T? = null) : ResourceState<T>(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<T>(
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<T>(val partialData: T? = null) : ResourceState<T>(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<T>(val result: T) : ResourceState<T>(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<T>(
val errorMessage: String,
val errorData: T? = null
) : ResourceState<T>(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)"
}
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,28 @@
package com.bobbyesp.utilities.states

sealed class ScreenState<out T> {
data object Loading : ScreenState<Nothing>()
data class Success<T>(val data: T?) : ScreenState<T>()
data class Error(val exception: Throwable) : ScreenState<Nothing>()
/**
* A sealed interface representing the state of a screen.
*
* @param T The type of data held by this state.
*/
sealed interface ScreenState<out T> {
/**
* Represents a loading state.
*/
object Loading : ScreenState<Nothing>

/**
* 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<T>(val data: T?) : ScreenState<T>

/**
* Represents an error state with an exception.
*
* @property exception The exception associated with the error state.
*/
data class Error(val exception: Throwable) : ScreenState<Nothing>
}

0 comments on commit b52baf3

Please sign in to comment.