diff --git a/composeApp/src/commonMain/kotlin/dev/krtirtho/spotube/core/ui/base/AutocompleteTextField.kt b/composeApp/src/commonMain/kotlin/dev/krtirtho/spotube/core/ui/base/AutocompleteTextField.kt index 5744a69e..21a73c0f 100644 --- a/composeApp/src/commonMain/kotlin/dev/krtirtho/spotube/core/ui/base/AutocompleteTextField.kt +++ b/composeApp/src/commonMain/kotlin/dev/krtirtho/spotube/core/ui/base/AutocompleteTextField.kt @@ -125,12 +125,12 @@ private fun resolveTextFieldState( ) else -> ResolvedAutoCompleteTextFieldState( - theme.background.pressed, - theme.highlight.pressed, - theme.shape.pressed, - theme.border.pressed, - theme.shadow.pressed, - theme.foreground.pressed + theme.background.normal, + theme.highlight.normal, + theme.shape.normal, + theme.border.normal, + theme.shadow.normal, + theme.foreground.normal ) } } diff --git a/composeApp/src/commonMain/kotlin/dev/krtirtho/spotube/core/ui/base/Buttons.kt b/composeApp/src/commonMain/kotlin/dev/krtirtho/spotube/core/ui/base/Buttons.kt index 53b87ee8..a6ddc8d4 100644 --- a/composeApp/src/commonMain/kotlin/dev/krtirtho/spotube/core/ui/base/Buttons.kt +++ b/composeApp/src/commonMain/kotlin/dev/krtirtho/spotube/core/ui/base/Buttons.kt @@ -106,11 +106,11 @@ private fun resolveButtonState( ) else -> ResolvedButtonState( - style.colors.focused, - style.shape.focused, - style.shadow.focused, - style.border.focused, - style.padding.focused + style.colors.normal, + style.shape.normal, + style.shadow.normal, + style.border.normal, + style.padding.normal ) } } @@ -311,21 +311,28 @@ fun GhostIconButton( val outlineStyle = baseTheme.iconButtons.outline val ghostStyle = theme ?: BaseUITheme.ButtonStyle( colors = BaseUITheme.InteractionState( + normal = BaseUITheme.ButtonColors( + background = Brush.verticalGradient(listOf(Color.Transparent, Color.Transparent)), + foreground = outlineStyle.colors.normal.foreground, + highlight = outlineStyle.colors.normal.highlight, + ), hovered = outlineStyle.colors.hovered, pressed = outlineStyle.colors.pressed, focused = BaseUITheme.ButtonColors( background = Brush.verticalGradient(listOf(Color.Transparent, Color.Transparent)), - foreground = outlineStyle.colors.focused.foreground, - highlight = outlineStyle.colors.focused.highlight, + foreground = outlineStyle.colors.normal.foreground, + highlight = outlineStyle.colors.normal.highlight, ), ), shape = outlineStyle.shape, shadow = BaseUITheme.InteractionState( + normal = BaseUITheme.Shadow(0.dp, false, Color.Transparent, Color.Transparent), hovered = outlineStyle.shadow.hovered, pressed = outlineStyle.shadow.pressed, focused = BaseUITheme.Shadow(0.dp, false, Color.Transparent, Color.Transparent), ), border = BaseUITheme.InteractionState( + normal = BaseUITheme.Border(Color.Transparent, 0.dp), hovered = outlineStyle.border.hovered, pressed = outlineStyle.border.pressed, focused = BaseUITheme.Border(Color.Transparent, 0.dp), diff --git a/composeApp/src/commonMain/kotlin/dev/krtirtho/spotube/core/ui/base/CheckBox.kt b/composeApp/src/commonMain/kotlin/dev/krtirtho/spotube/core/ui/base/CheckBox.kt index 7fda42c7..23d66e55 100644 --- a/composeApp/src/commonMain/kotlin/dev/krtirtho/spotube/core/ui/base/CheckBox.kt +++ b/composeApp/src/commonMain/kotlin/dev/krtirtho/spotube/core/ui/base/CheckBox.kt @@ -85,7 +85,7 @@ private fun resolveCheckBoxState( return when { isPressed -> ResolvedCheckBoxState(style.colors.pressed, style.shape.pressed, style.shadow.pressed, style.border.pressed) isHovered -> ResolvedCheckBoxState(style.colors.hovered, style.shape.hovered, style.shadow.hovered, style.border.hovered) - else -> ResolvedCheckBoxState(style.colors.focused, style.shape.focused, style.shadow.focused, style.border.focused) + else -> ResolvedCheckBoxState(style.colors.normal, style.shape.normal, style.shadow.normal, style.border.normal) } } diff --git a/composeApp/src/commonMain/kotlin/dev/krtirtho/spotube/core/ui/base/ChipTabs.kt b/composeApp/src/commonMain/kotlin/dev/krtirtho/spotube/core/ui/base/ChipTabs.kt index 6afa99d9..38963781 100644 --- a/composeApp/src/commonMain/kotlin/dev/krtirtho/spotube/core/ui/base/ChipTabs.kt +++ b/composeApp/src/commonMain/kotlin/dev/krtirtho/spotube/core/ui/base/ChipTabs.kt @@ -70,7 +70,7 @@ private fun resolveChipState( return when { isPressed -> ResolvedChipState(style.colors.pressed, style.shape.pressed, style.shadow.pressed, style.border.pressed, style.padding.pressed) isHovered -> ResolvedChipState(style.colors.hovered, style.shape.hovered, style.shadow.hovered, style.border.hovered, style.padding.hovered) - else -> ResolvedChipState(style.colors.focused, style.shape.focused, style.shadow.focused, style.border.focused, style.padding.focused) + else -> ResolvedChipState(style.colors.normal, style.shape.normal, style.shadow.normal, style.border.normal, style.padding.normal) } } diff --git a/composeApp/src/commonMain/kotlin/dev/krtirtho/spotube/core/ui/base/Slider.kt b/composeApp/src/commonMain/kotlin/dev/krtirtho/spotube/core/ui/base/Slider.kt index e957797b..63de1990 100644 --- a/composeApp/src/commonMain/kotlin/dev/krtirtho/spotube/core/ui/base/Slider.kt +++ b/composeApp/src/commonMain/kotlin/dev/krtirtho/spotube/core/ui/base/Slider.kt @@ -95,22 +95,22 @@ fun Slider( val stateColor = when { isPressed -> sliderTheme.trackActiveColor.pressed isHovered -> sliderTheme.trackActiveColor.hovered - else -> sliderTheme.trackActiveColor.focused + else -> sliderTheme.trackActiveColor.normal } val inactiveColor = when { isPressed -> sliderTheme.trackInactiveColor.pressed isHovered -> sliderTheme.trackInactiveColor.hovered - else -> sliderTheme.trackInactiveColor.focused + else -> sliderTheme.trackInactiveColor.normal } val thumbColor = when { isPressed -> sliderTheme.thumbColor.pressed isHovered -> sliderTheme.thumbColor.hovered - else -> sliderTheme.thumbColor.focused + else -> sliderTheme.thumbColor.normal } val thumbShadowState = when { isPressed -> sliderTheme.thumbShadow.pressed isHovered -> sliderTheme.thumbShadow.hovered - else -> sliderTheme.thumbShadow.focused + else -> sliderTheme.thumbShadow.normal } val trackActiveColor = if (enabled) stateColor else stateColor.copy(alpha = 0.38f) diff --git a/composeApp/src/commonMain/kotlin/dev/krtirtho/spotube/core/ui/base/TextField.kt b/composeApp/src/commonMain/kotlin/dev/krtirtho/spotube/core/ui/base/TextField.kt index b75cc7ed..0c016aba 100644 --- a/composeApp/src/commonMain/kotlin/dev/krtirtho/spotube/core/ui/base/TextField.kt +++ b/composeApp/src/commonMain/kotlin/dev/krtirtho/spotube/core/ui/base/TextField.kt @@ -81,7 +81,7 @@ private fun resolveTextFieldState( return when { isFocused -> ResolvedTextFieldState(theme.background.focused, theme.highlight.focused, theme.shape.focused, theme.border.focused, theme.shadow.focused, theme.foreground.focused) isHovered -> ResolvedTextFieldState(theme.background.hovered, theme.highlight.hovered, theme.shape.hovered, theme.border.hovered, theme.shadow.hovered, theme.foreground.hovered) - else -> ResolvedTextFieldState(theme.background.pressed, theme.highlight.pressed, theme.shape.pressed, theme.border.pressed, theme.shadow.pressed, theme.foreground.pressed) + else -> ResolvedTextFieldState(theme.background.normal, theme.highlight.normal, theme.shape.normal, theme.border.normal, theme.shadow.normal, theme.foreground.normal) } } diff --git a/composeApp/src/commonMain/kotlin/dev/krtirtho/spotube/core/ui/base/Theme.kt b/composeApp/src/commonMain/kotlin/dev/krtirtho/spotube/core/ui/base/Theme.kt index 7039e867..c54f752c 100644 --- a/composeApp/src/commonMain/kotlin/dev/krtirtho/spotube/core/ui/base/Theme.kt +++ b/composeApp/src/commonMain/kotlin/dev/krtirtho/spotube/core/ui/base/Theme.kt @@ -54,19 +54,21 @@ data class BaseUITheme( @Stable data class InteractionState( + val normal: T, val hovered: T, val pressed: T, val focused: T, ) { companion object { fun fromSingleValue(value: T): InteractionState { - return InteractionState(value, value, value) + return InteractionState(value, value, value, value) } } } @Stable data class AdvancedInteractionState( + val normal: T, val hovered: T, val pressed: T, val focused: T, @@ -75,7 +77,7 @@ data class BaseUITheme( ) { companion object { fun fromSingleValue(value: T): AdvancedInteractionState { - return AdvancedInteractionState(value, value, value, value, value) + return AdvancedInteractionState(value, value, value, value, value, value) } } } @@ -200,23 +202,30 @@ fun rememberBaseUITheme(): BaseUITheme { val defaultShape = RoundedCornerShape(14.dp) val defaultShapeState = - BaseUITheme.InteractionState(defaultShape, defaultShape, defaultShape) + BaseUITheme.InteractionState(defaultShape, defaultShape, defaultShape, defaultShape) val noBorder = BaseUITheme.Border(Color.Transparent, 0.dp) - val noBorderState = BaseUITheme.InteractionState(noBorder, noBorder, noBorder) + val noBorderState = BaseUITheme.InteractionState(noBorder, noBorder, noBorder, noBorder) val noShadow = BaseUITheme.Shadow(0.dp, false, Color.Transparent, Color.Transparent) - val noShadowState = BaseUITheme.InteractionState(noShadow, noShadow, noShadow) + val noShadowState = BaseUITheme.InteractionState(noShadow, noShadow, noShadow, noShadow) val defaultButtonPadding = BaseUITheme.InteractionState( PaddingValues(horizontal = 20.dp, vertical = 10.dp), PaddingValues(horizontal = 20.dp, vertical = 10.dp), PaddingValues(horizontal = 20.dp, vertical = 10.dp), + PaddingValues(horizontal = 20.dp, vertical = 10.dp), ) val iconButtonPadding = BaseUITheme.InteractionState( PaddingValues(8.dp), PaddingValues(8.dp), PaddingValues(8.dp), + PaddingValues(8.dp), ) val outlineColors = BaseUITheme.InteractionState( + normal = BaseUITheme.ButtonColors( + background = Brush.verticalGradient(listOf(containerLighter, containerDarker)), + foreground = scheme.onSurface, + highlight = highlight, + ), hovered = BaseUITheme.ButtonColors( background = Brush.verticalGradient(listOf(containerLighter, containerDarker)), foreground = scheme.onSurface, @@ -234,6 +243,12 @@ fun rememberBaseUITheme(): BaseUITheme { ), ) val outlineShadow = BaseUITheme.InteractionState( + normal = BaseUITheme.Shadow( + 6.dp, + true, + shadowColor.copy(alpha = 0.15f), + shadowColor.copy(alpha = 0.18f) + ), hovered = BaseUITheme.Shadow( 9.dp, true, @@ -254,12 +269,18 @@ fun rememberBaseUITheme(): BaseUITheme { ), ) val outlineBorder = BaseUITheme.InteractionState( + normal = BaseUITheme.Border(border, 0.5.dp), hovered = BaseUITheme.Border(border, 0.5.dp), pressed = BaseUITheme.Border(border.copy(alpha = 0.7f), 0.5.dp), focused = BaseUITheme.Border(border, 0.5.dp), ) val primaryColors = BaseUITheme.InteractionState( + normal = BaseUITheme.ButtonColors( + background = Brush.verticalGradient(listOf(scheme.primary, scheme.primary)), + foreground = scheme.onPrimary, + highlight = Color.White.copy(alpha = 0.25f), + ), hovered = BaseUITheme.ButtonColors( background = Brush.verticalGradient(listOf(scheme.primary, scheme.primary)), foreground = scheme.onPrimary, @@ -282,6 +303,12 @@ fun rememberBaseUITheme(): BaseUITheme { ), ) val primaryShadow = BaseUITheme.InteractionState( + normal = BaseUITheme.Shadow( + 6.dp, + true, + scheme.primary.copy(alpha = 0.35f), + scheme.primary.copy(alpha = 0.4f) + ), hovered = BaseUITheme.Shadow( 9.dp, true, @@ -302,12 +329,23 @@ fun rememberBaseUITheme(): BaseUITheme { ), ) val primaryBorder = BaseUITheme.InteractionState( + normal = BaseUITheme.Border(scheme.primary, 0.5.dp), hovered = BaseUITheme.Border(scheme.primary, 0.5.dp), pressed = BaseUITheme.Border(scheme.primary, 0.5.dp), focused = BaseUITheme.Border(scheme.primary, 0.5.dp), ) val secondaryColors = BaseUITheme.InteractionState( + normal = BaseUITheme.ButtonColors( + background = Brush.verticalGradient( + listOf( + secondaryContainer, + secondaryContainer.copy(alpha = if (secondaryContainer.luminance() > 0.5f) 0.92f else 1f) + ) + ), + foreground = scheme.onSecondaryContainer, + highlight = secondaryHighlight, + ), hovered = BaseUITheme.ButtonColors( background = Brush.verticalGradient( listOf( @@ -340,6 +378,12 @@ fun rememberBaseUITheme(): BaseUITheme { ), ) val secondaryShadow = BaseUITheme.InteractionState( + normal = BaseUITheme.Shadow( + 6.dp, + true, + shadowColor.copy(alpha = 0.15f), + shadowColor.copy(alpha = 0.18f) + ), hovered = BaseUITheme.Shadow( 9.dp, true, @@ -360,12 +404,18 @@ fun rememberBaseUITheme(): BaseUITheme { ), ) val secondaryBorder = BaseUITheme.InteractionState( + normal = BaseUITheme.Border(secondaryContainer.copy(alpha = 0.5f), 0.5.dp), hovered = BaseUITheme.Border(secondaryContainer.copy(alpha = 0.5f), 0.5.dp), pressed = BaseUITheme.Border(secondaryContainer.copy(alpha = 0.5f), 0.5.dp), focused = BaseUITheme.Border(secondaryContainer.copy(alpha = 0.5f), 0.5.dp), ) val ghostColors = BaseUITheme.InteractionState( + normal = BaseUITheme.ButtonColors( + background = Brush.verticalGradient(listOf(Color.Transparent, Color.Transparent)), + foreground = scheme.onSurface, + highlight = Color.Transparent, + ), hovered = BaseUITheme.ButtonColors( background = Brush.verticalGradient( listOf( @@ -447,6 +497,7 @@ fun rememberBaseUITheme(): BaseUITheme { ) val textFieldForeground = BaseUITheme.InteractionState( + normal = scheme.onSurface, hovered = scheme.onSurface, pressed = scheme.onSurface, focused = scheme.onSurface, @@ -454,17 +505,18 @@ fun rememberBaseUITheme(): BaseUITheme { val checkBoxShape = RoundedCornerShape(6.dp) val checkBoxShapeState = - BaseUITheme.InteractionState(checkBoxShape, checkBoxShape, checkBoxShape) + BaseUITheme.InteractionState(checkBoxShape, checkBoxShape, checkBoxShape, checkBoxShape) val noPadding = - BaseUITheme.InteractionState(PaddingValues(0.dp), PaddingValues(0.dp), PaddingValues(0.dp)) + BaseUITheme.InteractionState(PaddingValues(0.dp), PaddingValues(0.dp), PaddingValues(0.dp), PaddingValues(0.dp)) val chipTabShape = RoundedCornerShape(10.dp) val chipTabShapeState = - BaseUITheme.InteractionState(chipTabShape, chipTabShape, chipTabShape) + BaseUITheme.InteractionState(chipTabShape, chipTabShape, chipTabShape, chipTabShape) val chipTabPadding = BaseUITheme.InteractionState( PaddingValues(horizontal = 14.dp, vertical = 4.dp), PaddingValues(horizontal = 14.dp, vertical = 4.dp), PaddingValues(horizontal = 14.dp, vertical = 4.dp), + PaddingValues(horizontal = 14.dp, vertical = 4.dp), ) return BaseUITheme( @@ -482,26 +534,36 @@ fun rememberBaseUITheme(): BaseUITheme { ), textField = TextFieldTheme( background = BaseUITheme.InteractionState( + normal = Brush.verticalGradient(listOf(containerLighter, containerDarker)), hovered = Brush.verticalGradient(listOf(containerLighter, containerDarker)), pressed = Brush.verticalGradient(listOf(containerLighter, containerDarker)), focused = Brush.verticalGradient(listOf(containerLighter, containerDarker)), ), highlight = BaseUITheme.InteractionState( + normal = highlight, hovered = highlight, pressed = highlight, focused = highlight, ), shape = BaseUITheme.InteractionState( + normal = defaultShape, hovered = defaultShape, pressed = defaultShape, focused = defaultShape, ), border = BaseUITheme.InteractionState( + normal = BaseUITheme.Border(border.copy(alpha = 0.85f), 0.5.dp), hovered = BaseUITheme.Border(border.copy(alpha = 0.85f), 0.5.dp), pressed = BaseUITheme.Border(border, 0.5.dp), focused = BaseUITheme.Border(scheme.primary, 0.5.dp), ), shadow = BaseUITheme.InteractionState( + normal = BaseUITheme.Shadow( + 9.dp, + true, + shadowColor.copy(alpha = 0.22f), + shadowColor.copy(alpha = 0.26f) + ), hovered = BaseUITheme.Shadow( 9.dp, true, @@ -540,21 +602,30 @@ fun rememberBaseUITheme(): BaseUITheme { ), slider = SliderTheme( trackActiveColor = BaseUITheme.InteractionState( + normal = scheme.primary, hovered = scheme.primary, pressed = scheme.primary, focused = scheme.primary, ), trackInactiveColor = BaseUITheme.InteractionState( + normal = border.copy(alpha = 0.6f), hovered = border.copy(alpha = 0.6f), pressed = border.copy(alpha = 0.6f), focused = border.copy(alpha = 0.6f), ), thumbColor = BaseUITheme.InteractionState( + normal = scheme.primary, hovered = scheme.primary, pressed = scheme.primary, focused = scheme.primary, ), thumbShadow = BaseUITheme.InteractionState( + normal = BaseUITheme.Shadow( + 5.dp, + true, + scheme.primary.copy(alpha = 0.35f), + scheme.primary.copy(alpha = 0.4f) + ), hovered = BaseUITheme.Shadow( 8.dp, true, @@ -582,6 +653,12 @@ fun rememberBaseUITheme(): BaseUITheme { colors = primaryColors, shape = checkBoxShapeState, shadow = BaseUITheme.InteractionState( + normal = BaseUITheme.Shadow( + 6.dp, + true, + scheme.primary.copy(alpha = 0.3f), + scheme.primary.copy(alpha = 0.35f) + ), hovered = BaseUITheme.Shadow( 8.dp, true, @@ -608,6 +685,12 @@ fun rememberBaseUITheme(): BaseUITheme { colors = outlineColors, shape = checkBoxShapeState, shadow = BaseUITheme.InteractionState( + normal = BaseUITheme.Shadow( + 3.dp, + true, + shadowColor.copy(alpha = 0.15f), + shadowColor.copy(alpha = 0.18f) + ), hovered = BaseUITheme.Shadow( 5.dp, true, @@ -662,6 +745,7 @@ fun rememberBaseUITheme(): BaseUITheme { ), listRowTile = BaseUITheme.ListRowTheme( background = BaseUITheme.AdvancedInteractionState( + normal = Brush.verticalGradient(listOf(Color.Transparent, Color.Transparent)), hovered = Brush.verticalGradient(listOf(containerLighter, containerDarker)), pressed = Brush.verticalGradient(listOf(containerPressed, containerPressed)), focused = Brush.verticalGradient(listOf(containerLighter, containerDarker)), @@ -679,6 +763,7 @@ fun rememberBaseUITheme(): BaseUITheme { ), ), shape = BaseUITheme.AdvancedInteractionState( + normal = RoundedCornerShape(8.dp), hovered = RoundedCornerShape(8.dp), pressed = RoundedCornerShape(8.dp), focused = RoundedCornerShape(8.dp), @@ -686,6 +771,7 @@ fun rememberBaseUITheme(): BaseUITheme { disabled = RoundedCornerShape(8.dp), ), border = BaseUITheme.AdvancedInteractionState( + normal = BaseUITheme.Border(Color.Transparent, 0.dp), hovered = BaseUITheme.Border(Color.Transparent, 0.dp), pressed = BaseUITheme.Border(Color.Transparent, 0.dp), focused = BaseUITheme.Border(Color.Transparent, 0.dp), @@ -693,6 +779,7 @@ fun rememberBaseUITheme(): BaseUITheme { disabled = BaseUITheme.Border(Color.Transparent, 0.dp), ), shadow = BaseUITheme.AdvancedInteractionState( + normal = BaseUITheme.Shadow(0.dp, false, Color.Transparent, Color.Transparent), hovered = BaseUITheme.Shadow(0.dp, false, Color.Transparent, Color.Transparent), pressed = BaseUITheme.Shadow(0.dp, false, Color.Transparent, Color.Transparent), focused = BaseUITheme.Shadow(0.dp, false, Color.Transparent, Color.Transparent), @@ -701,6 +788,7 @@ fun rememberBaseUITheme(): BaseUITheme { ), padding = PaddingValues(horizontal = 8.dp, vertical = 6.dp), textStyle = BaseUITheme.AdvancedInteractionState( + normal = TextStyle.Default, hovered = TextStyle.Default, pressed = TextStyle.Default, focused = TextStyle.Default, @@ -708,6 +796,7 @@ fun rememberBaseUITheme(): BaseUITheme { disabled = TextStyle.Default, ), foreground = BaseUITheme.AdvancedInteractionState( + normal = scheme.onSurface, hovered = scheme.onSurface, pressed = scheme.onSurface, focused = scheme.onSurface, @@ -766,6 +855,7 @@ fun invertedButtonStyle(): BaseUITheme.ButtonStyle { return BaseUITheme.ButtonStyle( colors = BaseUITheme.InteractionState( + normal = invertedColors, hovered = invertedColors, pressed = pressedColors, focused = invertedColors, diff --git a/composeApp/src/commonMain/kotlin/dev/krtirtho/spotube/core/ui/component/TrackList.kt b/composeApp/src/commonMain/kotlin/dev/krtirtho/spotube/core/ui/component/TrackList.kt index 603586fe..7228998d 100644 --- a/composeApp/src/commonMain/kotlin/dev/krtirtho/spotube/core/ui/component/TrackList.kt +++ b/composeApp/src/commonMain/kotlin/dev/krtirtho/spotube/core/ui/component/TrackList.kt @@ -562,7 +562,7 @@ private fun TrackListRow( isSelected -> rowTheme.background.selected isCurrentTrack && isCurrentTrackPlaying -> rowTheme.background.hovered isCurrentTrack -> rowTheme.background.focused - else -> Brush.verticalGradient(listOf(Color.Transparent, Color.Transparent)) + else -> rowTheme.background.normal } val highlightColor = Color.White.copy( alpha = if (isLight) 0.9f else 0.06f diff --git a/composeApp/src/commonMain/kotlin/dev/krtirtho/spotube/modules/shell/player_queue/PlayerQueueContent.kt b/composeApp/src/commonMain/kotlin/dev/krtirtho/spotube/modules/shell/player_queue/PlayerQueueContent.kt index dcf194c1..529af12f 100644 --- a/composeApp/src/commonMain/kotlin/dev/krtirtho/spotube/modules/shell/player_queue/PlayerQueueContent.kt +++ b/composeApp/src/commonMain/kotlin/dev/krtirtho/spotube/modules/shell/player_queue/PlayerQueueContent.kt @@ -53,12 +53,11 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.Color import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import coil3.compose.AsyncImage -import compose.icons.FeatherIcons -import compose.icons.feathericons.MoreVertical import dev.krtirtho.spotube.core.audioplayer.QueueEntry import dev.krtirtho.spotube.core.di.rememberLogger import dev.krtirtho.spotube.core.ui.base.GhostIconButton @@ -66,9 +65,13 @@ import dev.krtirtho.spotube.core.ui.base.LocalBaseUITheme import dev.krtirtho.spotube.core.ui.base.SecondaryIconButton import dev.krtirtho.spotube.core.ui.base.TextField import dev.krtirtho.spotube.core.ui.base.copyShape +import dev.krtirtho.spotube.core.ui.base.highlight import dev.krtirtho.spotube.resources.iconsax.Iconsax +import dev.krtirtho.spotube.resources.iconsax.Iconsax3DotsMore +import dev.krtirtho.spotube.resources.iconsax.IconsaxDragHandle import dev.krtirtho.spotube.resources.iconsax.IconsaxFilterSearch import dev.krtirtho.spotube.resources.iconsax.IconsaxMusicSquareRemove +import dev.krtirtho.spotube.resources.iconsax.IconsaxSetting import dev.krtirtho.spotube.resources.iconsax.IconsaxTrash import org.koin.compose.viewmodel.koinViewModel import sh.calvin.reorderable.ReorderableItem @@ -127,7 +130,7 @@ fun PlayerQueueContent( val filtered = if (isFiltered) { sourceItems.filter { item -> item.title.lowercase().contains(normalizedFilter) || - item.subtitle.lowercase().contains(normalizedFilter) + item.subtitle.lowercase().contains(normalizedFilter) } } else { sourceItems @@ -251,6 +254,7 @@ private fun QueueItemRow( modifier = Modifier .fillMaxWidth() .clip(MaterialTheme.shapes.medium) + .highlight(LocalBaseUITheme.current.buttons.secondary.colors.normal.highlight) .clickable(onClick = onPlayClick), shadowElevation = elevation, tonalElevation = if (item.isCurrent) 2.dp else 0.dp, @@ -264,7 +268,7 @@ private fun QueueItemRow( verticalAlignment = Alignment.CenterVertically, ) { Icon( - FeatherIcons.MoreVertical, + Iconsax.IconsaxDragHandle, contentDescription = if (reorderScope != null) "Reorder" else null, modifier = Modifier .size(24.dp) @@ -340,7 +344,7 @@ private fun QueueItemRow( modifier = Modifier.size(36.dp), ) { Icon( - FeatherIcons.MoreVertical, + Iconsax.Iconsax3DotsMore, contentDescription = "More options", modifier = Modifier.size(18.dp), ) diff --git a/composeApp/src/commonMain/kotlin/dev/krtirtho/spotube/resources/iconsax/IconsaxDragHandle.kt b/composeApp/src/commonMain/kotlin/dev/krtirtho/spotube/resources/iconsax/IconsaxDragHandle.kt new file mode 100644 index 00000000..d5d44e41 --- /dev/null +++ b/composeApp/src/commonMain/kotlin/dev/krtirtho/spotube/resources/iconsax/IconsaxDragHandle.kt @@ -0,0 +1,128 @@ +/* + * Copyright (C) 2026 Kingkor Roy Tirtho and Spotube Contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package dev.krtirtho.spotube.resources.iconsax + +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.SolidColor +import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.graphics.vector.PathData +import androidx.compose.ui.graphics.vector.group +import androidx.compose.ui.graphics.vector.path +import androidx.compose.ui.unit.dp + +val Iconsax.IconsaxDragHandle: ImageVector + get() { + if (_IconsaxDragHandle != null) { + return _IconsaxDragHandle!! + } + _IconsaxDragHandle = ImageVector.Builder( + name = "IconsaxDragHandle", + defaultWidth = 24.dp, + defaultHeight = 24.dp, + viewportWidth = 24f, + viewportHeight = 24f + ).apply { + group( + clipPathData = PathData { + moveTo(0f, 0f) + horizontalLineToRelative(24f) + verticalLineToRelative(24f) + horizontalLineToRelative(-24f) + close() + } + ) { + path( + fill = SolidColor(Color.White), + fillAlpha = 0.4f, + strokeAlpha = 0.4f + ) { + moveTo(8f, 4f) + curveTo(6.9f, 4f, 6f, 4.9f, 6f, 6f) + curveTo(6f, 7.1f, 6.9f, 8f, 8f, 8f) + curveTo(9.1f, 8f, 10f, 7.1f, 10f, 6f) + curveTo(10f, 4.9f, 9.1f, 4f, 8f, 4f) + close() + } + path( + fill = SolidColor(Color.White), + fillAlpha = 0.4f, + strokeAlpha = 0.4f + ) { + moveTo(16f, 4f) + curveTo(14.9f, 4f, 14f, 4.9f, 14f, 6f) + curveTo(14f, 7.1f, 14.9f, 8f, 16f, 8f) + curveTo(17.1f, 8f, 18f, 7.1f, 18f, 6f) + curveTo(18f, 4.9f, 17.1f, 4f, 16f, 4f) + close() + } + path( + fill = SolidColor(Color.White), + fillAlpha = 0.4f, + strokeAlpha = 0.4f + ) { + moveTo(8f, 10f) + curveTo(6.9f, 10f, 6f, 10.9f, 6f, 12f) + curveTo(6f, 13.1f, 6.9f, 14f, 8f, 14f) + curveTo(9.1f, 14f, 10f, 13.1f, 10f, 12f) + curveTo(10f, 10.9f, 9.1f, 10f, 8f, 10f) + close() + } + path( + fill = SolidColor(Color.White), + fillAlpha = 0.4f, + strokeAlpha = 0.4f + ) { + moveTo(16f, 10f) + curveTo(14.9f, 10f, 14f, 10.9f, 14f, 12f) + curveTo(14f, 13.1f, 14.9f, 14f, 16f, 14f) + curveTo(17.1f, 14f, 18f, 13.1f, 18f, 12f) + curveTo(18f, 10.9f, 17.1f, 10f, 16f, 10f) + close() + } + path( + fill = SolidColor(Color.White), + fillAlpha = 0.4f, + strokeAlpha = 0.4f + ) { + moveTo(8f, 16f) + curveTo(6.9f, 16f, 6f, 16.9f, 6f, 18f) + curveTo(6f, 19.1f, 6.9f, 20f, 8f, 20f) + curveTo(9.1f, 20f, 10f, 19.1f, 10f, 18f) + curveTo(10f, 16.9f, 9.1f, 16f, 8f, 16f) + close() + } + path( + fill = SolidColor(Color.White), + fillAlpha = 0.4f, + strokeAlpha = 0.4f + ) { + moveTo(16f, 16f) + curveTo(14.9f, 16f, 14f, 16.9f, 14f, 18f) + curveTo(14f, 19.1f, 14.9f, 20f, 16f, 20f) + curveTo(17.1f, 20f, 18f, 19.1f, 18f, 18f) + curveTo(18f, 16.9f, 17.1f, 16f, 16f, 16f) + close() + } + } + }.build() + + return _IconsaxDragHandle!! + } + +@Suppress("ObjectPropertyName") +private var _IconsaxDragHandle: ImageVector? = null