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 9e09050..7ac2bf9 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 @@ -19,6 +19,7 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp 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 @@ -50,13 +51,13 @@ fun HorizontalSongCard( .padding(vertical = 8.dp, horizontal = 6.dp) .weight(1f) ) { - MarqueeText( + ConditionedMarqueeText( text = song.title, style = MaterialTheme.typography.bodyLarge, fontWeight = FontWeight.Bold, fontSize = 15.sp ) - MarqueeText( + ConditionedMarqueeText( text = song.artist, style = MaterialTheme.typography.bodyMedium.copy( color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.6f) 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 90d1276..3fef5f5 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 @@ -16,6 +16,7 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp 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 @@ -41,13 +42,13 @@ fun VerticalSongCard( Column( horizontalAlignment = Alignment.Start, modifier = Modifier.padding(8.dp) ) { - MarqueeText( + ConditionedMarqueeText( text = song.title, style = MaterialTheme.typography.bodyLarge, fontWeight = FontWeight.Bold, fontSize = 15.sp ) - MarqueeText( + ConditionedMarqueeText( text = song.artist, style = MaterialTheme.typography.bodyMedium.copy( color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.6f) diff --git a/app/src/main/java/com/bobbyesp/metadator/presentation/components/cards/songs/compact/CompactCardSize.kt b/app/src/main/java/com/bobbyesp/metadator/presentation/components/cards/songs/compact/CompactCardSize.kt new file mode 100644 index 0000000..4afbd23 --- /dev/null +++ b/app/src/main/java/com/bobbyesp/metadator/presentation/components/cards/songs/compact/CompactCardSize.kt @@ -0,0 +1,27 @@ +package com.bobbyesp.metadator.presentation.components.cards.songs.compact + +import androidx.compose.foundation.shape.CornerBasedShape +import androidx.compose.material3.MaterialTheme +import androidx.compose.runtime.Composable +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.dp + +enum class CompactCardSize(val value: Dp) { + SMALL(96.dp), + MEDIUM(120.dp), + LARGE(144.dp), + EXTRA_LARGE(168.dp); + + companion object { + + fun Int.toCompactCardSize(): CompactCardSize = CompactCardSize.entries.first { it.ordinal == this } + + @Composable + fun CompactCardSize.toShape(): CornerBasedShape = when(this) { + SMALL -> MaterialTheme.shapes.small + MEDIUM -> MaterialTheme.shapes.medium + LARGE -> MaterialTheme.shapes.large + EXTRA_LARGE -> MaterialTheme.shapes.extraLarge + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/bobbyesp/metadator/presentation/components/cards/songs/compact/CompactSongCard.kt b/app/src/main/java/com/bobbyesp/metadator/presentation/components/cards/songs/compact/CompactSongCard.kt new file mode 100644 index 0000000..47eb27b --- /dev/null +++ b/app/src/main/java/com/bobbyesp/metadator/presentation/components/cards/songs/compact/CompactSongCard.kt @@ -0,0 +1,118 @@ +package com.bobbyesp.metadator.presentation.components.cards.songs.compact + +import android.net.Uri +import android.util.Log +import androidx.compose.animation.animateContentSize +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.draw.shadow +import androidx.compose.ui.graphics.Brush +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.Shape +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.TextOverflow +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.dp +import com.bobbyesp.metadator.presentation.components.cards.songs.compact.CompactCardSize.Companion.toShape +import com.bobbyesp.metadator.presentation.components.image.AsyncImage +import com.bobbyesp.metadator.presentation.components.text.ConditionedMarqueeText + +@Composable +fun CompactSongCard( + modifier: Modifier = Modifier, + name: String, + artists: String, + artworkUri: Uri? = null, + listIndex: Int? = null, + shadow: Dp? = 4.dp, + size: CompactCardSize = CompactCardSize.LARGE, + shape: Shape? = MaterialTheme.shapes.large, + onClick: () -> Unit +) { + val cardSize by remember(size) { + mutableStateOf(size.value) + } + + val formalizedShape = shape ?: size.toShape() + + Box( + modifier = modifier + .shadow( + elevation = shadow ?: 0.dp, + shape = formalizedShape + ) + .clip(formalizedShape) + .size(cardSize) + .clickable(onClick = onClick) + + ) { + AsyncImage( + modifier = Modifier.fillMaxSize(), + imageModel = artworkUri, + ) + + listIndex?.let { + Text( + text = "$it.", + style = MaterialTheme.typography.bodySmall, + color = Color.White.copy(alpha = 0.8f), + fontWeight = FontWeight.Bold, + modifier = Modifier + .padding(8.dp) + .align(Alignment.TopEnd) + ) + } + Column( + modifier = Modifier + .background( + brush = Brush.verticalGradient( + colors = listOf( + Color.Transparent, + MaterialTheme.colorScheme.scrim + ), + startY = 0f, + endY = 500f + ), + alpha = 0.6f + ) + .fillMaxSize() + .padding(horizontal = 8.dp, vertical = 6.dp), + verticalArrangement = Arrangement.Bottom, + horizontalAlignment = Alignment.Start + ) { + ConditionedMarqueeText( + text = name, + style = MaterialTheme.typography.titleSmall, + color = Color.White, + overflow = TextOverflow.Ellipsis, + maxLines = 1 + ) + + if(artists.isNotEmpty()) { + ConditionedMarqueeText( + text = artists, + style = MaterialTheme.typography.bodySmall, + color = Color.White.copy(alpha = 0.6f), + overflow = TextOverflow.Ellipsis, + maxLines = 1 + ) + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/bobbyesp/metadator/presentation/components/cards/songs/spotify/SpotifyHorizontalSongCard.kt b/app/src/main/java/com/bobbyesp/metadator/presentation/components/cards/songs/spotify/SpotifyHorizontalSongCard.kt index 71c7c59..ef2da50 100644 --- a/app/src/main/java/com/bobbyesp/metadator/presentation/components/cards/songs/spotify/SpotifyHorizontalSongCard.kt +++ b/app/src/main/java/com/bobbyesp/metadator/presentation/components/cards/songs/spotify/SpotifyHorizontalSongCard.kt @@ -22,6 +22,7 @@ import androidx.compose.ui.unit.dp import com.adamratzman.spotify.models.Track import com.bobbyesp.metadator.ext.formatArtists import com.bobbyesp.metadator.presentation.components.image.AsyncImage +import com.bobbyesp.metadator.presentation.components.text.ConditionedMarqueeText import com.bobbyesp.ui.components.text.MarqueeText @OptIn(ExperimentalFoundationApi::class) @@ -80,12 +81,12 @@ fun SpotifyHorizontalSongCard( .padding(8.dp) .weight(1f) ) { - MarqueeText( + ConditionedMarqueeText( text = track.name, style = MaterialTheme.typography.bodyLarge, fontWeight = FontWeight.Bold, ) - MarqueeText( + ConditionedMarqueeText( text = track.artists.formatArtists(), style = MaterialTheme.typography.bodyMedium.copy( color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.6f) diff --git a/app/src/main/java/com/bobbyesp/metadator/presentation/components/text/ConditionedMarqueeText.kt b/app/src/main/java/com/bobbyesp/metadator/presentation/components/text/ConditionedMarqueeText.kt new file mode 100644 index 0000000..31e2014 --- /dev/null +++ b/app/src/main/java/com/bobbyesp/metadator/presentation/components/text/ConditionedMarqueeText.kt @@ -0,0 +1,93 @@ +package com.bobbyesp.metadator.presentation.components.text + +import androidx.compose.animation.core.Easing +import androidx.compose.material3.LocalTextStyle +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.text.TextLayoutResult +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.font.FontFamily +import androidx.compose.ui.text.font.FontStyle +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.text.style.TextDecoration +import androidx.compose.ui.text.style.TextOverflow +import androidx.compose.ui.unit.TextUnit +import com.bobbyesp.ui.components.text.MarqueeText +import com.bobbyesp.ui.components.text.MarqueeTextGradientOptions +import com.bobbyesp.utilities.preferences.PreferencesKeys.MARQUEE_TEXT +import com.bobbyesp.utilities.preferences.booleanState + +@Composable +fun ConditionedMarqueeText( + text: String, + modifier: Modifier = Modifier, + textModifier: Modifier = Modifier, + color: Color = Color.Unspecified, + fontSize: TextUnit = TextUnit.Unspecified, + fontStyle: FontStyle? = null, + fontWeight: FontWeight? = null, + fontFamily: FontFamily? = null, + letterSpacing: TextUnit = TextUnit.Unspecified, + textDecoration: TextDecoration? = null, + textAlign: TextAlign? = null, + lineHeight: TextUnit = TextUnit.Unspecified, + maxLines: Int = 1, + overflow: TextOverflow = TextOverflow.Clip, + softWrap: Boolean = true, + onTextLayout: (TextLayoutResult) -> Unit = {}, + style: TextStyle = LocalTextStyle.current.plus(TextStyle()), + sideGradient: MarqueeTextGradientOptions = MarqueeTextGradientOptions(), + customEasing: Easing? = null, + animationDuration: Float = 4000f, + delayBetweenAnimations: Long = 500L +) { + val useMarqueeText = MARQUEE_TEXT.booleanState + + if(useMarqueeText.value) { + MarqueeText( + text, + modifier, + textModifier, + color, + fontSize, + fontStyle, + fontWeight, + fontFamily, + letterSpacing, + textDecoration, + textAlign, + lineHeight, + maxLines, + overflow, + softWrap, + onTextLayout, + style, + sideGradient, + customEasing, + animationDuration, + delayBetweenAnimations + ) + } else { + Text( + text = text, + modifier = textModifier, + color = color, + fontSize = fontSize, + fontStyle = fontStyle, + fontWeight = fontWeight, + fontFamily = fontFamily, + letterSpacing = letterSpacing, + textDecoration = textDecoration, + textAlign = textAlign, + lineHeight = lineHeight, + maxLines = maxLines, + overflow = overflow, + softWrap = softWrap, + onTextLayout = onTextLayout, + style = style + ) + } +} \ No newline at end of file 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 e2fef46..7cae32a 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 @@ -1,6 +1,7 @@ package com.bobbyesp.metadator.presentation.pages import androidx.compose.animation.Crossfade +import androidx.compose.animation.animateContentSize import androidx.compose.animation.core.tween import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement @@ -15,17 +16,24 @@ import androidx.compose.foundation.lazy.grid.LazyVerticalGrid import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.runtime.State +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import com.bobbyesp.metadator.R import com.bobbyesp.metadator.presentation.components.cards.songs.HorizontalSongCard -import com.bobbyesp.metadator.presentation.components.cards.songs.VerticalSongCard +import com.bobbyesp.metadator.presentation.components.cards.songs.compact.CompactCardSize +import com.bobbyesp.metadator.presentation.components.cards.songs.compact.CompactCardSize.Companion.toCompactCardSize +import com.bobbyesp.metadator.presentation.components.cards.songs.compact.CompactSongCard import com.bobbyesp.metadator.presentation.components.others.status.EmptyMediaStore 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.preferences.PreferencesKeys.SONG_CARD_SIZE +import com.bobbyesp.utilities.preferences.intState import com.bobbyesp.utilities.states.ResourceState import my.nanihadesuka.compose.LazyColumnScrollbar import my.nanihadesuka.compose.LazyVerticalGridScrollbar @@ -39,10 +47,12 @@ fun MediaStorePage( lazyGridState: LazyGridState, lazyListState: LazyListState, desiredLayout: LayoutType, + compactCardSize: CompactCardSize, onReloadMediaStore: () -> Unit, onItemClicked: (Song) -> Unit ) { val songsList = songs.value + Box( modifier = modifier.fillMaxSize() ) { @@ -58,7 +68,7 @@ fun MediaStorePage( ) { onReloadMediaStore() } is ResourceState.Success -> { - val dataSongsList = songsList.data!! + val dataSongsList = songsList.data ?: throw IllegalStateException("Data is null") if (dataSongsList.isEmpty()) { EmptyMediaStore( modifier = Modifier.fillMaxSize() @@ -88,11 +98,16 @@ fun MediaStorePage( key = { index -> dataSongsList[index].id }, contentType = { _ -> "songItem" }) { index -> val song = dataSongsList[index] - VerticalSongCard( - song = song, - modifier = Modifier.animateItem( - fadeInSpec = null, fadeOutSpec = null - ), + + CompactSongCard( + modifier = Modifier + .animateItem( + fadeInSpec = null, fadeOutSpec = null + ), + size = compactCardSize, + name = song.title, + artists = song.artist, + artworkUri = song.artworkPath, onClick = { onItemClicked(song) }) 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 9fa8fa6..e8bcc74 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,12 +17,11 @@ 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.automirrored.rounded.List -import androidx.compose.material.icons.rounded.GridView +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.MoreVert -import androidx.compose.material3.CenterAlignedTopAppBar +import androidx.compose.material.icons.rounded.Settings import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.FloatingActionButton import androidx.compose.material3.Icon @@ -33,19 +32,18 @@ import androidx.compose.material3.SegmentedButton import androidx.compose.material3.SegmentedButtonDefaults import androidx.compose.material3.SingleChoiceSegmentedButtonRow import androidx.compose.material3.Text +import androidx.compose.material3.TopAppBar import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.State import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableIntStateOf import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontFamily @@ -57,15 +55,16 @@ import com.bobbyesp.metadator.ext.toParcelableSong import com.bobbyesp.metadator.presentation.common.LocalDrawerState import com.bobbyesp.metadator.presentation.common.LocalNavController import com.bobbyesp.metadator.presentation.common.Route +import com.bobbyesp.metadator.presentation.components.cards.songs.compact.CompactCardSize import com.bobbyesp.metadator.presentation.pages.MediaStorePage import com.bobbyesp.metadator.presentation.pages.MediaStorePageViewModel -import com.bobbyesp.metadator.presentation.pages.home.LayoutType.entries 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.preferences.Preferences -import com.bobbyesp.utilities.preferences.PreferencesKeys.DESIRED_OVERLAY +import com.bobbyesp.utilities.preferences.PreferencesKeys.DESIRED_LAYOUT +import com.bobbyesp.utilities.preferences.PreferencesKeys.SONG_CARD_SIZE import com.bobbyesp.utilities.states.ResourceState import com.bobbyesp.utilities.ui.permission.PermissionNotGrantedDialog import com.bobbyesp.utilities.ui.permission.PermissionRequestHandler @@ -114,70 +113,99 @@ fun HomePage( var desiredLayout by remember { mutableStateOf( Preferences.Enumerations.getValue( - DESIRED_OVERLAY, LayoutType.Grid + DESIRED_LAYOUT, LayoutType.Grid ) ) } - val gridIsFirstItemVisible by remember { derivedStateOf { mediaStoreLazyGridState.firstVisibleItemIndex == 0 } } - val listIsFirstItemVisible by remember { derivedStateOf { mediaStoreLazyColumnState.firstVisibleItemIndex == 0 } } + var desiredCardSize by remember { + mutableStateOf( + Preferences.Enumerations.getValue( + SONG_CARD_SIZE, CompactCardSize.LARGE + ) + ) + } + + val gridIsFirstItemVisible by remember { + derivedStateOf { + mediaStoreLazyGridState.firstVisibleItemIndex == 0 + } + } + val listIsFirstItemVisible by remember { + derivedStateOf { + mediaStoreLazyColumnState.firstVisibleItemIndex == 0 + } + } Scaffold(modifier = modifier.fillMaxSize(), topBar = { - CenterAlignedTopAppBar( - navigationIcon = { - IconButton(onClick = { - scope.launch { - drawerState.open() - } - }) { - Icon( - imageVector = Icons.Rounded.Menu, - contentDescription = stringResource(id = R.string.open_navigation) - ) + TopAppBar(navigationIcon = { + IconButton(onClick = { + scope.launch { + drawerState.open() } - }, title = { - Column( - horizontalAlignment = Alignment.CenterHorizontally, - ) { - Text( - text = stringResource(id = R.string.app_name).uppercase(), - fontWeight = FontWeight.SemiBold, - fontFamily = FontFamily.Monospace, - style = MaterialTheme.typography.titleLarge.copy( - letterSpacing = 4.sp, - ), - ) - AutoResizableText( - text = stringResource(id = R.string.app_desc).uppercase(), - fontWeight = FontWeight.Normal, - fontFamily = FontFamily.Monospace, - style = MaterialTheme.typography.bodySmall.copy( - letterSpacing = 2.sp, - ), - color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.7f) + }) { + Icon( + imageVector = Icons.Rounded.Menu, + contentDescription = stringResource(id = R.string.open_navigation) + ) + } + }, title = { + Column( + horizontalAlignment = Alignment.Start, + ) { + Text( + text = stringResource(id = R.string.app_name).uppercase(), + fontWeight = FontWeight.SemiBold, + fontFamily = FontFamily.Monospace, + style = MaterialTheme.typography.titleLarge.copy( + letterSpacing = 4.sp, + ), + ) + AutoResizableText( + text = stringResource(id = R.string.app_desc).uppercase(), + fontWeight = FontWeight.Normal, + fontFamily = FontFamily.Monospace, + style = MaterialTheme.typography.bodySmall.copy( + letterSpacing = 2.sp, + ), + color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.7f) + ) + } + }, actions = { + IconButton( + onClick = { navController.navigate(Route.SettingsNavigator.Settings) }) { + Icon( + imageVector = Icons.Rounded.Settings, contentDescription = stringResource( + id = R.string.settings ) - } - }, actions = { - IconButton( - onClick = { - moreOptionsVisible = !moreOptionsVisible - }) { - Icon( - imageVector = Icons.Rounded.MoreVert, contentDescription = stringResource( - id = R.string.open_more_options - ) + ) + } + IconButton( + onClick = { + moreOptionsVisible = !moreOptionsVisible + }) { + Icon( + imageVector = Icons.Rounded.MoreVert, contentDescription = stringResource( + id = R.string.open_more_options ) - } - AnimatedDropdownMenu( - expanded = moreOptionsVisible, onDismissRequest = { - moreOptionsVisible = false - }) { - DropdownMenuContent(onLayoutChanged = { + ) + } + AnimatedDropdownMenu( + expanded = moreOptionsVisible, onDismissRequest = { + moreOptionsVisible = false + }) { + DropdownMenuContent( + desiredLayout = desiredLayout, + desiredCardSize = desiredCardSize, + onLayoutChanged = { desiredLayout = it + }, + onCardSizeChanged = { + desiredCardSize = it }) - } + } - }) + }) }, floatingActionButton = { when (desiredLayout) { LayoutType.Grid -> { @@ -244,6 +272,7 @@ fun HomePage( lazyGridState = mediaStoreLazyGridState, lazyListState = mediaStoreLazyColumnState, desiredLayout = desiredLayout, + compactCardSize = desiredCardSize, onReloadMediaStore = { onEvent(MediaStorePageViewModel.Companion.Events.ReloadMediaStore) }, @@ -258,17 +287,13 @@ fun HomePage( @Composable private fun DropdownMenuContent( - onLayoutChanged: (LayoutType) -> Unit = {} + desiredLayout: LayoutType, + desiredCardSize: CompactCardSize, + onLayoutChanged: (LayoutType) -> Unit = {}, + onCardSizeChanged: (CompactCardSize) -> Unit = {} ) { val availableLayoutType = LayoutType.entries.toImmutableList() - var desiredOverlay by remember { - mutableIntStateOf( - Preferences.Enumerations.getValue( - DESIRED_OVERLAY, LayoutType.Grid - ).ordinal - ) - } Column( modifier = Modifier.padding(horizontal = 8.dp), verticalArrangement = Arrangement.spacedBy(8.dp), @@ -280,37 +305,61 @@ private fun DropdownMenuContent( color = MaterialTheme.colorScheme.primary, style = MaterialTheme.typography.labelMedium ) - DropdownItemContainer(content = { - SingleChoiceSegmentedButtonRow { - availableLayoutType.forEachIndexed { index, listType -> - SegmentedButton( - selected = desiredOverlay == listType.ordinal, - onClick = { - desiredOverlay = listType.ordinal - Preferences.Enumerations.encodeValue( - DESIRED_OVERLAY, listType + DropdownItemContainer( + content = { + SingleChoiceSegmentedButtonRow { + availableLayoutType.forEachIndexed { index, listType -> + SegmentedButton( + selected = desiredLayout.ordinal == listType.ordinal, + onClick = { + Preferences.Enumerations.encodeValue( + DESIRED_LAYOUT, listType + ) + onLayoutChanged(listType) + }, + shape = SegmentedButtonDefaults.itemShape( + index = index, count = availableLayoutType.size + ), + ) { + Icon( + imageVector = listType.icon, + contentDescription = stringResource(id = R.string.list_type) ) - onLayoutChanged(listType) - }, - shape = SegmentedButtonDefaults.itemShape( - index = index, count = availableLayoutType.size - ), - ) { - Icon( - imageVector = listType.icon, - contentDescription = stringResource(id = R.string.list_type) - ) + } } } - } - }) + }) + Text( + text = stringResource(id = R.string.card_size), + modifier = Modifier.fillMaxWidth(), + color = MaterialTheme.colorScheme.primary, + style = MaterialTheme.typography.labelMedium + ) + + DropdownItemContainer( + content = { + SingleChoiceSegmentedButtonRow { + CompactCardSize.entries.forEachIndexed { index, cardSize -> + SegmentedButton( + selected = desiredCardSize.ordinal == cardSize.ordinal, + onClick = { + Preferences.Enumerations.encodeValue( + SONG_CARD_SIZE, cardSize + ) + onCardSizeChanged(cardSize) + }, + shape = SegmentedButtonDefaults.itemShape( + index = index, count = CompactCardSize.entries.size + ), + ) { + Icon( + imageVector = Icons.Rounded.CropSquare, + contentDescription = stringResource(id = R.string.card_size) + ) + } + } + } + }) } } -enum class LayoutType(val icon: ImageVector) { - Grid(icon = Icons.Rounded.GridView), List(icon = Icons.AutoMirrored.Rounded.List); - - companion object { - fun Int.toListType(): LayoutType = entries.first { it.ordinal == this } - } -} \ No newline at end of file diff --git a/app/src/main/java/com/bobbyesp/metadator/presentation/pages/home/LayoutType.kt b/app/src/main/java/com/bobbyesp/metadator/presentation/pages/home/LayoutType.kt new file mode 100644 index 0000000..05261ea --- /dev/null +++ b/app/src/main/java/com/bobbyesp/metadator/presentation/pages/home/LayoutType.kt @@ -0,0 +1,15 @@ +package com.bobbyesp.metadator.presentation.pages.home + +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.automirrored.rounded.List +import androidx.compose.material.icons.rounded.GridView +import androidx.compose.ui.graphics.vector.ImageVector + +enum class LayoutType(val icon: ImageVector) { + Grid(icon = Icons.Rounded.GridView), + List(icon = Icons.AutoMirrored.Rounded.List); + + companion object { + fun Int.toListType(): LayoutType = entries.first { it.ordinal == this } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/bobbyesp/metadator/presentation/pages/mediaplayer/player/PlayerControls.kt b/app/src/main/java/com/bobbyesp/metadator/presentation/pages/mediaplayer/player/PlayerControls.kt index b68e8b1..bbe0bc0 100644 --- a/app/src/main/java/com/bobbyesp/metadator/presentation/pages/mediaplayer/player/PlayerControls.kt +++ b/app/src/main/java/com/bobbyesp/metadator/presentation/pages/mediaplayer/player/PlayerControls.kt @@ -44,6 +44,7 @@ import com.bobbyesp.metadator.R import com.bobbyesp.metadator.presentation.components.buttons.PlayPauseAnimatedButton import com.bobbyesp.metadator.presentation.components.others.RepeatStateIcon import com.bobbyesp.metadator.presentation.components.others.ShuffleStateIcon +import com.bobbyesp.metadator.presentation.components.text.ConditionedMarqueeText import com.bobbyesp.metadator.presentation.pages.mediaplayer.MediaplayerViewModel import com.bobbyesp.ui.components.text.MarqueeText import com.bobbyesp.ui.components.text.MarqueeTextGradientOptions @@ -110,7 +111,7 @@ fun PlayerControls( text = it?.title.toString(), style = MaterialTheme.typography.titleLarge.copy(fontWeight = FontWeight.Medium) ) - MarqueeText( + ConditionedMarqueeText( text = it?.artist.toString(), style = MaterialTheme.typography.bodyLarge, customEasing = EaseInOutSine, diff --git a/app/src/main/java/com/bobbyesp/metadator/presentation/pages/mediaplayer/player/views/MiniplayerContent.kt b/app/src/main/java/com/bobbyesp/metadator/presentation/pages/mediaplayer/player/views/MiniplayerContent.kt index 4025773..f3e4012 100644 --- a/app/src/main/java/com/bobbyesp/metadator/presentation/pages/mediaplayer/player/views/MiniplayerContent.kt +++ b/app/src/main/java/com/bobbyesp/metadator/presentation/pages/mediaplayer/player/views/MiniplayerContent.kt @@ -31,6 +31,7 @@ import androidx.compose.ui.unit.sp import androidx.media3.common.MediaMetadata import com.bobbyesp.metadator.R import com.bobbyesp.metadator.presentation.components.image.AsyncImage +import com.bobbyesp.metadator.presentation.components.text.ConditionedMarqueeText import com.bobbyesp.metadator.presentation.pages.mediaplayer.player.AnimatedTextContentTransformation import com.bobbyesp.ui.components.button.DynamicButton import com.bobbyesp.ui.components.text.MarqueeText @@ -84,14 +85,14 @@ fun MiniplayerContent( ) { transition.AnimatedContent(transitionSpec = { AnimatedTextContentTransformation }) { Column { - MarqueeText( + ConditionedMarqueeText( text = it.title.toString(), style = MaterialTheme.typography.bodyLarge, fontWeight = FontWeight.Bold, fontSize = 16.sp ) - MarqueeText( + ConditionedMarqueeText( text = it.artist.toString(), style = MaterialTheme.typography.bodyMedium.copy( color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.6f) diff --git a/app/src/main/java/com/bobbyesp/metadator/presentation/pages/settings/modules/GeneralSettingsPage.kt b/app/src/main/java/com/bobbyesp/metadator/presentation/pages/settings/modules/GeneralSettingsPage.kt index 49c57e2..04935d0 100644 --- a/app/src/main/java/com/bobbyesp/metadator/presentation/pages/settings/modules/GeneralSettingsPage.kt +++ b/app/src/main/java/com/bobbyesp/metadator/presentation/pages/settings/modules/GeneralSettingsPage.kt @@ -28,7 +28,7 @@ fun GeneralSettingsPage() { val navController = LocalNavController.current val scrollBehavior = TopAppBarDefaults.exitUntilCollapsedScrollBehavior( - rememberTopAppBarState(), + state = rememberTopAppBarState(), canScroll = { true } ) diff --git a/app/src/main/java/com/bobbyesp/metadator/presentation/pages/utilities/tageditor/MetadataEditorPage.kt b/app/src/main/java/com/bobbyesp/metadator/presentation/pages/utilities/tageditor/MetadataEditorPage.kt index f74d8ab..045a6ef 100644 --- a/app/src/main/java/com/bobbyesp/metadator/presentation/pages/utilities/tageditor/MetadataEditorPage.kt +++ b/app/src/main/java/com/bobbyesp/metadator/presentation/pages/utilities/tageditor/MetadataEditorPage.kt @@ -175,7 +175,7 @@ fun MetadataEditorPage( TopAppBar( title = { Column(modifier = Modifier.fillMaxWidth()) { - MarqueeText( + Text( text = stringResource(id = R.string.viewing_metadata), style = MaterialTheme.typography.bodyLarge, fontSize = 20.sp, diff --git a/app/src/main/java/com/bobbyesp/metadator/presentation/pages/utilities/tageditor/spotify/stages/SpMetadataBsDetails.kt b/app/src/main/java/com/bobbyesp/metadator/presentation/pages/utilities/tageditor/spotify/stages/SpMetadataBsDetails.kt index 89476fc..2cc7395 100644 --- a/app/src/main/java/com/bobbyesp/metadator/presentation/pages/utilities/tageditor/spotify/stages/SpMetadataBsDetails.kt +++ b/app/src/main/java/com/bobbyesp/metadator/presentation/pages/utilities/tageditor/spotify/stages/SpMetadataBsDetails.kt @@ -43,6 +43,7 @@ import com.bobbyesp.metadator.ext.TagLib.toLocalizedName import com.bobbyesp.metadator.ext.format import com.bobbyesp.metadator.ext.formatArtists import com.bobbyesp.metadator.presentation.components.image.AsyncImage +import com.bobbyesp.metadator.presentation.components.text.ConditionedMarqueeText import com.bobbyesp.metadator.presentation.pages.utilities.tageditor.spotify.MetadataBsVM import com.bobbyesp.ui.components.button.BackButton import com.bobbyesp.ui.components.others.SelectableSurface @@ -198,7 +199,7 @@ private fun TrackInfo( .padding(8.dp) .weight(1f) ) { - MarqueeText( + ConditionedMarqueeText( text = track.name, style = MaterialTheme.typography.bodyLarge, fontWeight = FontWeight.Bold, diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 130c736..a221df9 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -81,4 +81,5 @@ The lyrics retrievement process has been cancelled The lyrics sent from the provider app were null or empty Something unexpected occurred! + Card size \ No newline at end of file diff --git a/app/utilities/src/main/java/com/bobbyesp/utilities/preferences/Preferences.kt b/app/utilities/src/main/java/com/bobbyesp/utilities/preferences/Preferences.kt index 2c7ebf7..bf9d8d9 100644 --- a/app/utilities/src/main/java/com/bobbyesp/utilities/preferences/Preferences.kt +++ b/app/utilities/src/main/java/com/bobbyesp/utilities/preferences/Preferences.kt @@ -5,6 +5,7 @@ import com.bobbyesp.utilities.preferences.PreferencesKeys.DYNAMIC_COLOR import com.bobbyesp.utilities.preferences.PreferencesKeys.HIGH_CONTRAST import com.bobbyesp.utilities.preferences.PreferencesKeys.MARQUEE_TEXT import com.bobbyesp.utilities.preferences.PreferencesKeys.MMKV_PREFERENCES_NAME +import com.bobbyesp.utilities.preferences.PreferencesKeys.SONG_CARD_SIZE import com.bobbyesp.utilities.preferences.PreferencesKeys.THEME_COLOR import com.bobbyesp.utilities.preferences.settings.AppMainSettings import com.bobbyesp.utilities.theme.DarkThemePreference @@ -23,7 +24,8 @@ private val BooleanPreferenceDefaults: Map = private val IntPreferenceDefaults: Map = mapOf( - DARK_THEME_VALUE to DarkThemePreference.FOLLOW_SYSTEM + DARK_THEME_VALUE to DarkThemePreference.FOLLOW_SYSTEM, + SONG_CARD_SIZE to 2 //CompactCardSize.LARGE (com.bobbyesp.metadator.presentation.components.cards.songs.compact.CompactCardSize) ) object Preferences { diff --git a/app/utilities/src/main/java/com/bobbyesp/utilities/preferences/PreferencesKeys.kt b/app/utilities/src/main/java/com/bobbyesp/utilities/preferences/PreferencesKeys.kt index be1bd64..e9d6cbb 100644 --- a/app/utilities/src/main/java/com/bobbyesp/utilities/preferences/PreferencesKeys.kt +++ b/app/utilities/src/main/java/com/bobbyesp/utilities/preferences/PreferencesKeys.kt @@ -2,8 +2,8 @@ package com.bobbyesp.utilities.preferences object PreferencesKeys { //------------GENERAL-------------- - const val DESIRED_OVERLAY = "desired_overlay" - + const val DESIRED_LAYOUT = "desired_overlay" + const val SONG_CARD_SIZE = "song_card_size" const val MARQUEE_TEXT = "marquee_text" //------------THEME----------------