From 70d0591014705f6075d14c9f5e42346ff13f3974 Mon Sep 17 00:00:00 2001 From: Boonapart Date: Thu, 19 Jun 2025 17:24:22 +0300 Subject: [PATCH 1/5] Audio Player Wrapper --- design/api/current.api | 98 ++++++++++++++ .../ui/player/models/AudioBookConstants.kt | 6 + .../ui/player/models/AudioPlayButtonColor.kt | 9 ++ .../ui/player/models/AudioPlayButtonDimens.kt | 8 ++ .../ui/player/models/AudioSliderColor.kt | 10 ++ .../ui/player/models/AudioSliderDimens.kt | 11 ++ .../design/ui/player/models/AudioStateType.kt | 7 + .../design/ui/player/models/PlayerDimens.kt | 10 ++ .../player/models/PlayerWrapperBottomColor.kt | 7 + .../models/PlayerWrapperBottomDimens.kt | 9 ++ .../design/ui/player/ui/AudioPlayButton.kt | 62 +++++++++ .../ui/player/ui/AudioPlayerTrackDetails.kt | 28 ++++ .../design/ui/player/ui/AudioSlider.kt | 77 +++++++++++ .../android/design/ui/player/ui/Player.kt | 50 ++++++++ .../design/ui/player/ui/PlayerWrapper.kt | 120 ++++++++++++++++++ 15 files changed, 512 insertions(+) create mode 100644 design/src/main/java/com/urlaunched/android/design/ui/player/models/AudioBookConstants.kt create mode 100644 design/src/main/java/com/urlaunched/android/design/ui/player/models/AudioPlayButtonColor.kt create mode 100644 design/src/main/java/com/urlaunched/android/design/ui/player/models/AudioPlayButtonDimens.kt create mode 100644 design/src/main/java/com/urlaunched/android/design/ui/player/models/AudioSliderColor.kt create mode 100644 design/src/main/java/com/urlaunched/android/design/ui/player/models/AudioSliderDimens.kt create mode 100644 design/src/main/java/com/urlaunched/android/design/ui/player/models/AudioStateType.kt create mode 100644 design/src/main/java/com/urlaunched/android/design/ui/player/models/PlayerDimens.kt create mode 100644 design/src/main/java/com/urlaunched/android/design/ui/player/models/PlayerWrapperBottomColor.kt create mode 100644 design/src/main/java/com/urlaunched/android/design/ui/player/models/PlayerWrapperBottomDimens.kt create mode 100644 design/src/main/java/com/urlaunched/android/design/ui/player/ui/AudioPlayButton.kt create mode 100644 design/src/main/java/com/urlaunched/android/design/ui/player/ui/AudioPlayerTrackDetails.kt create mode 100644 design/src/main/java/com/urlaunched/android/design/ui/player/ui/AudioSlider.kt create mode 100644 design/src/main/java/com/urlaunched/android/design/ui/player/ui/Player.kt create mode 100644 design/src/main/java/com/urlaunched/android/design/ui/player/ui/PlayerWrapper.kt diff --git a/design/api/current.api b/design/api/current.api index 0119fff6..54274ca6 100644 --- a/design/api/current.api +++ b/design/api/current.api @@ -236,6 +236,104 @@ package com.urlaunched.android.design.ui.paging { } +package com.urlaunched.android.design.ui.player.models { + + public final class AudioPlayButtonColor { + ctor public AudioPlayButtonColor(); + method public long getButtonColor(); + method public long getCircularProgressColor(); + property public final long buttonColor; + property public final long circularProgressColor; + } + + public final class AudioPlayButtonConstants { + ctor public AudioPlayButtonConstants(optional float PLAY_BUTTON_PROGRESS_SIZE_FRACTION, optional String AUDIO_PLAY_BUTTON_ICON_ANIMATION_LABEL); + method public float component1(); + method public String component2(); + method public com.urlaunched.android.design.ui.player.models.AudioPlayButtonConstants copy(float PLAY_BUTTON_PROGRESS_SIZE_FRACTION, String AUDIO_PLAY_BUTTON_ICON_ANIMATION_LABEL); + method public String getAUDIO_PLAY_BUTTON_ICON_ANIMATION_LABEL(); + method public float getPLAY_BUTTON_PROGRESS_SIZE_FRACTION(); + property public final String AUDIO_PLAY_BUTTON_ICON_ANIMATION_LABEL; + property public final float PLAY_BUTTON_PROGRESS_SIZE_FRACTION; + } + + public final class AudioPlayButtonDimens { + ctor public AudioPlayButtonDimens(optional float buttonSize); + method public float component1-D9Ej5fM(); + method public com.urlaunched.android.design.ui.player.models.AudioPlayButtonDimens copy-0680j_4(float buttonSize); + method public float getButtonSize(); + property public final float buttonSize; + } + + public final class AudioSliderColor { + ctor public AudioSliderColor(optional long thumbColor, optional long activeTrackColor, optional long inactiveTrackColor); + method public long component1-0d7_KjU(); + method public long component2-0d7_KjU(); + method public long component3-0d7_KjU(); + method public com.urlaunched.android.design.ui.player.models.AudioSliderColor copy-ysEtTa8(long thumbColor, long activeTrackColor, long inactiveTrackColor); + method public long getActiveTrackColor(); + method public long getInactiveTrackColor(); + method public long getThumbColor(); + property public final long activeTrackColor; + property public final long inactiveTrackColor; + property public final long thumbColor; + } + + public final class AudioSliderDimens { + ctor public AudioSliderDimens(optional float sliderThumbTrackGapSize, optional float sliderTrackInsideCornerSize, optional float sliderTrackHeight); + method public float component1-D9Ej5fM(); + method public float component2-D9Ej5fM(); + method public float component3-D9Ej5fM(); + method public com.urlaunched.android.design.ui.player.models.AudioSliderDimens copy-2z7ARbQ(float sliderThumbTrackGapSize, float sliderTrackInsideCornerSize, float sliderTrackHeight); + method public float getSliderThumbTrackGapSize(); + method public float getSliderTrackHeight(); + method public float getSliderTrackInsideCornerSize(); + property public final float sliderThumbTrackGapSize; + property public final float sliderTrackHeight; + property public final float sliderTrackInsideCornerSize; + } + + public enum AudioStateType { + method public static com.urlaunched.android.design.ui.player.models.AudioStateType valueOf(String value) throws java.lang.IllegalArgumentException, java.lang.NullPointerException; + method public static com.urlaunched.android.design.ui.player.models.AudioStateType[] values(); + enum_constant public static final com.urlaunched.android.design.ui.player.models.AudioStateType BUFFERING; + enum_constant public static final com.urlaunched.android.design.ui.player.models.AudioStateType PAUSE; + enum_constant public static final com.urlaunched.android.design.ui.player.models.AudioStateType PLAYING; + } + + public final class PlayerDimens { + ctor public PlayerDimens(optional float horizontalDimens, optional float verticalDimens); + method public float component1-D9Ej5fM(); + method public float component2-D9Ej5fM(); + method public com.urlaunched.android.design.ui.player.models.PlayerDimens copy-YgX7TsA(float horizontalDimens, float verticalDimens); + method public float getHorizontalDimens(); + method public float getVerticalDimens(); + property public final float horizontalDimens; + property public final float verticalDimens; + } + +} + +package com.urlaunched.android.design.ui.player.ui { + + public final class AudioPlayButtonKt { + method @androidx.compose.runtime.Composable public static void AudioPlayButton(optional androidx.compose.ui.Modifier modifier, com.urlaunched.android.design.ui.player.models.AudioStateType audioState, optional com.urlaunched.android.design.ui.player.models.AudioPlayButtonDimens audioPlayButtonDimens, optional com.urlaunched.android.design.ui.player.models.AudioPlayButtonColor audioPlayButtonColor, optional com.urlaunched.android.design.ui.player.models.AudioPlayButtonConstants audioPlayButtonConstants, kotlin.jvm.functions.Function0 onClick, kotlin.jvm.functions.Function0 playingButton, kotlin.jvm.functions.Function0 pauseButton); + } + + public final class AudioSliderKt { + method @androidx.compose.runtime.Composable public static void AudioSlider(float audioProgress, optional com.urlaunched.android.design.ui.player.models.AudioSliderDimens audioSliderDimens, optional com.urlaunched.android.design.ui.player.models.AudioSliderColor audioSliderColor, kotlin.jvm.functions.Function1 audioSliderOnValueChange, kotlin.jvm.functions.Function0 thumb, kotlin.jvm.functions.Function0 currentPositionText, kotlin.jvm.functions.Function0 timeLeftText); + } + + public final class PlayerKt { + method @androidx.compose.runtime.Composable public static void Player(com.urlaunched.android.design.ui.player.models.AudioStateType audioState, optional com.urlaunched.android.design.ui.player.models.PlayerDimens playerDimens, kotlin.jvm.functions.Function0 onPlayAudioClick, kotlin.jvm.functions.Function0 nextTrackButton, kotlin.jvm.functions.Function0 rotatePlusButton, kotlin.jvm.functions.Function0 previousTrackButton, kotlin.jvm.functions.Function0 rotateMinusButton, kotlin.jvm.functions.Function0 playingButton, kotlin.jvm.functions.Function0 pauseButton); + } + + public final class PlayerWrapperKt { + method @androidx.compose.runtime.Composable public static void PlayerWrapper(optional androidx.compose.ui.Modifier modifier, optional long backGround, float audioProgress, optional com.urlaunched.android.design.ui.player.models.AudioSliderDimens audioSliderDimens, optional com.urlaunched.android.design.ui.player.models.AudioSliderColor audioSliderColor, kotlin.jvm.functions.Function1 audioSliderOnValueChange, kotlin.jvm.functions.Function0 thumb, kotlin.jvm.functions.Function0 currentPositionText, kotlin.jvm.functions.Function0 timeLeftText, com.urlaunched.android.design.ui.player.models.AudioStateType audioState, optional com.urlaunched.android.design.ui.player.models.PlayerDimens playerDimens, kotlin.jvm.functions.Function0 onPlayAudioClick, kotlin.jvm.functions.Function0 nextTrackButton, kotlin.jvm.functions.Function0 rotatePlusButton, kotlin.jvm.functions.Function0 previousTrackButton, kotlin.jvm.functions.Function0 rotateMinusButton, kotlin.jvm.functions.Function0 playingButton, kotlin.jvm.functions.Function0 pauseButton); + } + +} + package com.urlaunched.android.design.ui.progressbarcontainer { public final class ProgressBarContainerKt { diff --git a/design/src/main/java/com/urlaunched/android/design/ui/player/models/AudioBookConstants.kt b/design/src/main/java/com/urlaunched/android/design/ui/player/models/AudioBookConstants.kt new file mode 100644 index 00000000..a98bca30 --- /dev/null +++ b/design/src/main/java/com/urlaunched/android/design/ui/player/models/AudioBookConstants.kt @@ -0,0 +1,6 @@ +package com.urlaunched.android.design.ui.player.models + +data class AudioPlayButtonConstants( + val playButtonProgressSizeFraction: Float = 0.5f, + val audioPlayButtonIconAnimationLabel: String = "PlayButtonIconAnimation" +) \ No newline at end of file diff --git a/design/src/main/java/com/urlaunched/android/design/ui/player/models/AudioPlayButtonColor.kt b/design/src/main/java/com/urlaunched/android/design/ui/player/models/AudioPlayButtonColor.kt new file mode 100644 index 00000000..376900ac --- /dev/null +++ b/design/src/main/java/com/urlaunched/android/design/ui/player/models/AudioPlayButtonColor.kt @@ -0,0 +1,9 @@ +package com.urlaunched.android.design.ui.player.models + +import androidx.compose.ui.graphics.Color + +data class AudioPlayButtonColor( + val buttonColor: Color = Color.White, + val circularProgressColor: Color = Color.White +) + diff --git a/design/src/main/java/com/urlaunched/android/design/ui/player/models/AudioPlayButtonDimens.kt b/design/src/main/java/com/urlaunched/android/design/ui/player/models/AudioPlayButtonDimens.kt new file mode 100644 index 00000000..affb3498 --- /dev/null +++ b/design/src/main/java/com/urlaunched/android/design/ui/player/models/AudioPlayButtonDimens.kt @@ -0,0 +1,8 @@ +package com.urlaunched.android.design.ui.player.models + +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.dp + +data class AudioPlayButtonDimens( + val buttonSize: Dp = 64.dp +) \ No newline at end of file diff --git a/design/src/main/java/com/urlaunched/android/design/ui/player/models/AudioSliderColor.kt b/design/src/main/java/com/urlaunched/android/design/ui/player/models/AudioSliderColor.kt new file mode 100644 index 00000000..d1c3506f --- /dev/null +++ b/design/src/main/java/com/urlaunched/android/design/ui/player/models/AudioSliderColor.kt @@ -0,0 +1,10 @@ +package com.urlaunched.android.design.ui.player.models + +import androidx.compose.ui.graphics.Color + + +data class AudioSliderColor( + val thumbColor: Color = Color.White, + val activeTrackColor: Color = Color.White, + val inactiveTrackColor: Color = Color.White, +) diff --git a/design/src/main/java/com/urlaunched/android/design/ui/player/models/AudioSliderDimens.kt b/design/src/main/java/com/urlaunched/android/design/ui/player/models/AudioSliderDimens.kt new file mode 100644 index 00000000..5d7bbe01 --- /dev/null +++ b/design/src/main/java/com/urlaunched/android/design/ui/player/models/AudioSliderDimens.kt @@ -0,0 +1,11 @@ +package com.urlaunched.android.design.ui.player.models + +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.dp + + +data class AudioSliderDimens( + val sliderThumbTrackGapSize: Dp = 0.dp, + val sliderTrackInsideCornerSize: Dp = 0.dp, + val sliderTrackHeight: Dp = 4.dp, +) \ No newline at end of file diff --git a/design/src/main/java/com/urlaunched/android/design/ui/player/models/AudioStateType.kt b/design/src/main/java/com/urlaunched/android/design/ui/player/models/AudioStateType.kt new file mode 100644 index 00000000..b3499b23 --- /dev/null +++ b/design/src/main/java/com/urlaunched/android/design/ui/player/models/AudioStateType.kt @@ -0,0 +1,7 @@ +package com.urlaunched.android.design.ui.player.models + +enum class AudioStateType { + PAUSE, + PLAYING, + BUFFERING +} \ No newline at end of file diff --git a/design/src/main/java/com/urlaunched/android/design/ui/player/models/PlayerDimens.kt b/design/src/main/java/com/urlaunched/android/design/ui/player/models/PlayerDimens.kt new file mode 100644 index 00000000..d6956181 --- /dev/null +++ b/design/src/main/java/com/urlaunched/android/design/ui/player/models/PlayerDimens.kt @@ -0,0 +1,10 @@ +package com.urlaunched.android.design.ui.player.models + +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.dp +import com.urlaunched.android.design.resources.dimens.Dimens + +data class PlayerDimens( + val horizontalDimens: Dp = Dimens.spacingNormalSpecial, + val verticalDimens: Dp = 0.dp +) diff --git a/design/src/main/java/com/urlaunched/android/design/ui/player/models/PlayerWrapperBottomColor.kt b/design/src/main/java/com/urlaunched/android/design/ui/player/models/PlayerWrapperBottomColor.kt new file mode 100644 index 00000000..8adb0bc0 --- /dev/null +++ b/design/src/main/java/com/urlaunched/android/design/ui/player/models/PlayerWrapperBottomColor.kt @@ -0,0 +1,7 @@ +package com.urlaunched.android.design.ui.player.models + +import androidx.compose.ui.graphics.Color + +data class PlayerWrapperBottomColor( + val backGround: Color = Color.White +) \ No newline at end of file diff --git a/design/src/main/java/com/urlaunched/android/design/ui/player/models/PlayerWrapperBottomDimens.kt b/design/src/main/java/com/urlaunched/android/design/ui/player/models/PlayerWrapperBottomDimens.kt new file mode 100644 index 00000000..594753dc --- /dev/null +++ b/design/src/main/java/com/urlaunched/android/design/ui/player/models/PlayerWrapperBottomDimens.kt @@ -0,0 +1,9 @@ +package com.urlaunched.android.design.ui.player.models + +import androidx.compose.ui.unit.Dp +import com.urlaunched.android.design.resources.dimens.Dimens + +data class PlayerWrapperBottomDimens( + val topStartShape: Dp = Dimens.cornerRadiusNormal, + val topEndShape: Dp = Dimens.cornerRadiusNormal +) \ No newline at end of file diff --git a/design/src/main/java/com/urlaunched/android/design/ui/player/ui/AudioPlayButton.kt b/design/src/main/java/com/urlaunched/android/design/ui/player/ui/AudioPlayButton.kt new file mode 100644 index 00000000..4803c8a5 --- /dev/null +++ b/design/src/main/java/com/urlaunched/android/design/ui/player/ui/AudioPlayButton.kt @@ -0,0 +1,62 @@ +package com.urlaunched.android.design.ui.player.ui + +import androidx.compose.animation.AnimatedContent +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.material3.CircularProgressIndicator +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.Color +import com.urlaunched.android.design.ui.player.models.AudioPlayButtonConstants +import com.urlaunched.android.design.ui.player.models.AudioPlayButtonDimens +import com.urlaunched.android.design.ui.player.models.AudioPlayButtonColor +import com.urlaunched.android.design.ui.player.models.AudioStateType + +@Composable +fun AudioPlayButton( + modifier: Modifier = Modifier, + audioState: Any, + audioPlayButtonDimens: AudioPlayButtonDimens = AudioPlayButtonDimens(), + audioPlayButtonColor: AudioPlayButtonColor = AudioPlayButtonColor(), + audioPlayButtonConstants: AudioPlayButtonConstants = AudioPlayButtonConstants(), + onClick: () -> Unit, + playingButton: @Composable () -> Unit, + pauseButton: @Composable () -> Unit +) { + Box( + modifier = modifier + .clip(CircleShape) + .clickable(onClick = onClick) + .size(audioPlayButtonDimens.buttonSize) + .background( + color = audioPlayButtonColor.buttonColor, + shape = CircleShape + ), + contentAlignment = Alignment.Center + ) { + AnimatedContent( + targetState = audioState, + contentAlignment = Alignment.Center, + label = audioPlayButtonConstants.audioPlayButtonIconAnimationLabel + ) { state -> + val name = (state as? Enum<*>)?.name + when (name) { + AudioStateType.PAUSE.name -> playingButton() + + AudioStateType.PLAYING.name -> pauseButton() + + AudioStateType.BUFFERING.name -> CircularProgressIndicator( + modifier = Modifier.fillMaxSize(audioPlayButtonConstants.playButtonProgressSizeFraction), + trackColor = Color.Transparent, + color = audioPlayButtonColor.circularProgressColor + ) + } + } + } +} diff --git a/design/src/main/java/com/urlaunched/android/design/ui/player/ui/AudioPlayerTrackDetails.kt b/design/src/main/java/com/urlaunched/android/design/ui/player/ui/AudioPlayerTrackDetails.kt new file mode 100644 index 00000000..0a69282f --- /dev/null +++ b/design/src/main/java/com/urlaunched/android/design/ui/player/ui/AudioPlayerTrackDetails.kt @@ -0,0 +1,28 @@ +package com.urlaunched.android.design.ui.player.ui + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.height +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import com.urlaunched.android.design.resources.dimens.Dimens + +@Composable +fun AudioPlayerTrackDetails( + modifier: Modifier = Modifier, + audioTrackDetails: @Composable () -> Unit, +) { + Column( + modifier = modifier, + verticalArrangement = Arrangement.Center, + horizontalAlignment = Alignment.CenterHorizontally + ) { + Spacer(modifier = Modifier.height(Dimens.spacingTinyHalf)) + + audioTrackDetails() + + Spacer(modifier = Modifier.height(Dimens.spacingBigSpecial)) + } +} \ No newline at end of file diff --git a/design/src/main/java/com/urlaunched/android/design/ui/player/ui/AudioSlider.kt b/design/src/main/java/com/urlaunched/android/design/ui/player/ui/AudioSlider.kt new file mode 100644 index 00000000..166d8c82 --- /dev/null +++ b/design/src/main/java/com/urlaunched/android/design/ui/player/ui/AudioSlider.kt @@ -0,0 +1,77 @@ +package com.urlaunched.android.design.ui.player.ui + +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.offset +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.Slider +import androidx.compose.material3.SliderDefaults +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.IntOffset +import com.urlaunched.android.design.resources.dimens.Dimens +import com.urlaunched.android.design.ui.player.models.AudioSliderDimens +import com.urlaunched.android.design.ui.player.models.AudioSliderColor +import kotlin.math.roundToInt + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun AudioSlider( + audioProgress: Float, + audioSliderDimens: AudioSliderDimens = AudioSliderDimens(), + audioSliderColor: AudioSliderColor = AudioSliderColor(), + audioSliderOnValueChange: (Float) -> Unit, + thumb: @Composable () -> Unit, + currentPositionText: @Composable () -> Unit, + timeLeftText: @Composable () -> Unit +) { + Slider( + modifier = Modifier.padding(horizontal = Dimens.spacingSmall), + value = audioProgress, + onValueChange = audioSliderOnValueChange, + colors = SliderDefaults.colors( + thumbColor = audioSliderColor.thumbColor, + activeTrackColor = audioSliderColor.activeTrackColor, + inactiveTrackColor = audioSliderColor.inactiveTrackColor + ), + thumb = { + thumb() + }, + track = { sliderState -> + SliderDefaults.Track( + modifier = Modifier.height(audioSliderDimens.sliderTrackHeight), + colors = SliderDefaults.colors( + thumbColor = audioSliderColor.thumbColor, + activeTrackColor = audioSliderColor.activeTrackColor, + inactiveTrackColor = audioSliderColor.inactiveTrackColor + ), + enabled = true, + sliderState = sliderState, + thumbTrackGapSize = audioSliderDimens.sliderThumbTrackGapSize, + trackInsideCornerSize = audioSliderDimens.sliderTrackInsideCornerSize, + drawStopIndicator = null + ) + } + ) + + Row( + modifier = Modifier + .offset { + IntOffset( + x = 0, + y = -Dimens.spacingNormalSpecial + .toPx() + .roundToInt() + ) + } + .padding(horizontal = Dimens.spacingNormal) + ) { + currentPositionText() + + Spacer(modifier = Modifier.weight(1f)) + + timeLeftText() + } +} \ No newline at end of file diff --git a/design/src/main/java/com/urlaunched/android/design/ui/player/ui/Player.kt b/design/src/main/java/com/urlaunched/android/design/ui/player/ui/Player.kt new file mode 100644 index 00000000..6c36be46 --- /dev/null +++ b/design/src/main/java/com/urlaunched/android/design/ui/player/ui/Player.kt @@ -0,0 +1,50 @@ +package com.urlaunched.android.design.ui.player.ui + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import com.urlaunched.android.design.ui.player.models.AudioPlayButtonColor +import com.urlaunched.android.design.ui.player.models.PlayerDimens + +@Composable +fun Player( + audioState: Any, + playerDimens: PlayerDimens = PlayerDimens(), + audioPlayButtonColor: AudioPlayButtonColor, + onPlayAudioClick: () -> Unit, + nextTrackButton: @Composable () -> Unit, + rotatePlusButton: @Composable () -> Unit, + previousTrackButton: @Composable () -> Unit, + rotateMinusButton: @Composable () -> Unit, + playingButton: @Composable () -> Unit, + pauseButton: @Composable () -> Unit +) { + Row( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = playerDimens.horizontalDimens, vertical = playerDimens.verticalDimens), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically + ) { + nextTrackButton() + + rotateMinusButton() + + AudioPlayButton( + audioState = audioState, + onClick = onPlayAudioClick, + playingButton = playingButton, + pauseButton = pauseButton, + audioPlayButtonColor = audioPlayButtonColor + ) + + rotatePlusButton() + + previousTrackButton() + + } +} \ No newline at end of file diff --git a/design/src/main/java/com/urlaunched/android/design/ui/player/ui/PlayerWrapper.kt b/design/src/main/java/com/urlaunched/android/design/ui/player/ui/PlayerWrapper.kt new file mode 100644 index 00000000..d0b33e65 --- /dev/null +++ b/design/src/main/java/com/urlaunched/android/design/ui/player/ui/PlayerWrapper.kt @@ -0,0 +1,120 @@ +package com.urlaunched.android.design.ui.player.ui + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.runtime.Composable +import androidx.compose.runtime.CompositionLocalProvider +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalLayoutDirection +import androidx.compose.ui.unit.LayoutDirection +import com.urlaunched.android.design.ui.player.models.AudioPlayButtonColor +import com.urlaunched.android.design.ui.player.models.AudioSliderColor +import com.urlaunched.android.design.ui.player.models.AudioSliderDimens +import com.urlaunched.android.design.ui.player.models.PlayerDimens +import com.urlaunched.android.design.ui.player.models.PlayerWrapperBottomColor +import com.urlaunched.android.design.ui.player.models.PlayerWrapperBottomDimens + +@Composable +fun PlayerWrapper( + // 🌐 Загальне оточення / структура + modifier: Modifier = Modifier, + isRtlEnabled: Boolean = false, + + // 🎨 Кольори + audioPlayButtonColor: AudioPlayButtonColor = AudioPlayButtonColor(), + audioSliderColor: AudioSliderColor = AudioSliderColor(), + playerWrapperBottomColor: PlayerWrapperBottomColor = PlayerWrapperBottomColor(), + + // 📐 Розміри + audioSliderDimens: AudioSliderDimens = AudioSliderDimens(), + playerWrapperBottomDimens: PlayerWrapperBottomDimens = PlayerWrapperBottomDimens(), + playerDimens: PlayerDimens = PlayerDimens(), + + // 📊 Стан / значення + audioProgress: Float, + audioState: Any, + + // 🔁 Колбеки (взаємодія) + audioSliderOnValueChange: (Float) -> Unit, + onPlayAudioClick: () -> Unit, + + // 🧩 Компоненти UI (Composable блоки) + // — елементи управління треком + nextTrackButton: @Composable () -> Unit, + previousTrackButton: @Composable () -> Unit, + rotatePlusButton: @Composable () -> Unit, + rotateMinusButton: @Composable () -> Unit, + + // — кнопки відтворення + playingButton: @Composable () -> Unit, + pauseButton: @Composable () -> Unit, + + // — прогрес + thumb: @Composable () -> Unit, + currentPositionText: @Composable () -> Unit, + timeLeftText: @Composable () -> Unit, + + // — додатковий контент + chapterDetails: @Composable () -> Unit, + bottomPanel: @Composable () -> Unit, + audioTrackDetails: @Composable () -> Unit +){ + + Column(modifier = Modifier.fillMaxSize()) { + + AudioPlayerTrackDetails( + modifier = Modifier + .weight(1f) + .fillMaxWidth(), + audioTrackDetails = audioTrackDetails + ) + + Column( + modifier = modifier + .fillMaxWidth() + .background( + color = playerWrapperBottomColor.backGround, + shape = RoundedCornerShape( + topStart = playerWrapperBottomDimens.topStartShape, + topEnd = playerWrapperBottomDimens.topEndShape + ) + ), + horizontalAlignment = Alignment.CenterHorizontally + ) { + chapterDetails() + + CompositionLocalProvider(LocalLayoutDirection provides if (isRtlEnabled) LayoutDirection.Rtl else LayoutDirection.Ltr) { + AudioSlider( + audioProgress = audioProgress, + audioSliderDimens = audioSliderDimens, + audioSliderColor = audioSliderColor, + audioSliderOnValueChange = audioSliderOnValueChange, + thumb = thumb, + currentPositionText = currentPositionText, + timeLeftText = timeLeftText + ) + + Player( + audioState = audioState, + playerDimens = playerDimens, + onPlayAudioClick = onPlayAudioClick, + nextTrackButton = nextTrackButton, + rotatePlusButton = rotatePlusButton, + previousTrackButton = previousTrackButton, + rotateMinusButton = rotateMinusButton, + playingButton = playingButton, + pauseButton = pauseButton, + audioPlayButtonColor = audioPlayButtonColor + + ) + } + + bottomPanel() + } + } +} + From 8046e450c6e0afb4bbc25fafa07b81e696a7e76b Mon Sep 17 00:00:00 2001 From: Boonapart Date: Thu, 19 Jun 2025 17:34:07 +0300 Subject: [PATCH 2/5] Refresh current API --- design/api/current.api | 46 +++++++++++++++++++++++++++++++++--------- 1 file changed, 36 insertions(+), 10 deletions(-) diff --git a/design/api/current.api b/design/api/current.api index 54274ca6..229c500c 100644 --- a/design/api/current.api +++ b/design/api/current.api @@ -239,7 +239,10 @@ package com.urlaunched.android.design.ui.paging { package com.urlaunched.android.design.ui.player.models { public final class AudioPlayButtonColor { - ctor public AudioPlayButtonColor(); + ctor public AudioPlayButtonColor(optional long buttonColor, optional long circularProgressColor); + method public long component1-0d7_KjU(); + method public long component2-0d7_KjU(); + method public com.urlaunched.android.design.ui.player.models.AudioPlayButtonColor copy--OWjLjI(long buttonColor, long circularProgressColor); method public long getButtonColor(); method public long getCircularProgressColor(); property public final long buttonColor; @@ -247,14 +250,14 @@ package com.urlaunched.android.design.ui.player.models { } public final class AudioPlayButtonConstants { - ctor public AudioPlayButtonConstants(optional float PLAY_BUTTON_PROGRESS_SIZE_FRACTION, optional String AUDIO_PLAY_BUTTON_ICON_ANIMATION_LABEL); + ctor public AudioPlayButtonConstants(optional float playButtonProgressSizeFraction, optional String audioPlayButtonIconAnimationLabel); method public float component1(); method public String component2(); - method public com.urlaunched.android.design.ui.player.models.AudioPlayButtonConstants copy(float PLAY_BUTTON_PROGRESS_SIZE_FRACTION, String AUDIO_PLAY_BUTTON_ICON_ANIMATION_LABEL); - method public String getAUDIO_PLAY_BUTTON_ICON_ANIMATION_LABEL(); - method public float getPLAY_BUTTON_PROGRESS_SIZE_FRACTION(); - property public final String AUDIO_PLAY_BUTTON_ICON_ANIMATION_LABEL; - property public final float PLAY_BUTTON_PROGRESS_SIZE_FRACTION; + method public com.urlaunched.android.design.ui.player.models.AudioPlayButtonConstants copy(float playButtonProgressSizeFraction, String audioPlayButtonIconAnimationLabel); + method public String getAudioPlayButtonIconAnimationLabel(); + method public float getPlayButtonProgressSizeFraction(); + property public final String audioPlayButtonIconAnimationLabel; + property public final float playButtonProgressSizeFraction; } public final class AudioPlayButtonDimens { @@ -312,12 +315,35 @@ package com.urlaunched.android.design.ui.player.models { property public final float verticalDimens; } + public final class PlayerWrapperBottomColor { + ctor public PlayerWrapperBottomColor(optional long backGround); + method public long component1-0d7_KjU(); + method public com.urlaunched.android.design.ui.player.models.PlayerWrapperBottomColor copy-8_81llA(long backGround); + method public long getBackGround(); + property public final long backGround; + } + + public final class PlayerWrapperBottomDimens { + ctor public PlayerWrapperBottomDimens(optional float topStartShape, optional float topEndShape); + method public float component1-D9Ej5fM(); + method public float component2-D9Ej5fM(); + method public com.urlaunched.android.design.ui.player.models.PlayerWrapperBottomDimens copy-YgX7TsA(float topStartShape, float topEndShape); + method public float getTopEndShape(); + method public float getTopStartShape(); + property public final float topEndShape; + property public final float topStartShape; + } + } package com.urlaunched.android.design.ui.player.ui { public final class AudioPlayButtonKt { - method @androidx.compose.runtime.Composable public static void AudioPlayButton(optional androidx.compose.ui.Modifier modifier, com.urlaunched.android.design.ui.player.models.AudioStateType audioState, optional com.urlaunched.android.design.ui.player.models.AudioPlayButtonDimens audioPlayButtonDimens, optional com.urlaunched.android.design.ui.player.models.AudioPlayButtonColor audioPlayButtonColor, optional com.urlaunched.android.design.ui.player.models.AudioPlayButtonConstants audioPlayButtonConstants, kotlin.jvm.functions.Function0 onClick, kotlin.jvm.functions.Function0 playingButton, kotlin.jvm.functions.Function0 pauseButton); + method @androidx.compose.runtime.Composable public static void AudioPlayButton(optional androidx.compose.ui.Modifier modifier, Object audioState, optional com.urlaunched.android.design.ui.player.models.AudioPlayButtonDimens audioPlayButtonDimens, optional com.urlaunched.android.design.ui.player.models.AudioPlayButtonColor audioPlayButtonColor, optional com.urlaunched.android.design.ui.player.models.AudioPlayButtonConstants audioPlayButtonConstants, kotlin.jvm.functions.Function0 onClick, kotlin.jvm.functions.Function0 playingButton, kotlin.jvm.functions.Function0 pauseButton); + } + + public final class AudioPlayerTrackDetailsKt { + method @androidx.compose.runtime.Composable public static void AudioPlayerTrackDetails(optional androidx.compose.ui.Modifier modifier, kotlin.jvm.functions.Function0 audioTrackDetails); } public final class AudioSliderKt { @@ -325,11 +351,11 @@ package com.urlaunched.android.design.ui.player.ui { } public final class PlayerKt { - method @androidx.compose.runtime.Composable public static void Player(com.urlaunched.android.design.ui.player.models.AudioStateType audioState, optional com.urlaunched.android.design.ui.player.models.PlayerDimens playerDimens, kotlin.jvm.functions.Function0 onPlayAudioClick, kotlin.jvm.functions.Function0 nextTrackButton, kotlin.jvm.functions.Function0 rotatePlusButton, kotlin.jvm.functions.Function0 previousTrackButton, kotlin.jvm.functions.Function0 rotateMinusButton, kotlin.jvm.functions.Function0 playingButton, kotlin.jvm.functions.Function0 pauseButton); + method @androidx.compose.runtime.Composable public static void Player(Object audioState, optional com.urlaunched.android.design.ui.player.models.PlayerDimens playerDimens, com.urlaunched.android.design.ui.player.models.AudioPlayButtonColor audioPlayButtonColor, kotlin.jvm.functions.Function0 onPlayAudioClick, kotlin.jvm.functions.Function0 nextTrackButton, kotlin.jvm.functions.Function0 rotatePlusButton, kotlin.jvm.functions.Function0 previousTrackButton, kotlin.jvm.functions.Function0 rotateMinusButton, kotlin.jvm.functions.Function0 playingButton, kotlin.jvm.functions.Function0 pauseButton); } public final class PlayerWrapperKt { - method @androidx.compose.runtime.Composable public static void PlayerWrapper(optional androidx.compose.ui.Modifier modifier, optional long backGround, float audioProgress, optional com.urlaunched.android.design.ui.player.models.AudioSliderDimens audioSliderDimens, optional com.urlaunched.android.design.ui.player.models.AudioSliderColor audioSliderColor, kotlin.jvm.functions.Function1 audioSliderOnValueChange, kotlin.jvm.functions.Function0 thumb, kotlin.jvm.functions.Function0 currentPositionText, kotlin.jvm.functions.Function0 timeLeftText, com.urlaunched.android.design.ui.player.models.AudioStateType audioState, optional com.urlaunched.android.design.ui.player.models.PlayerDimens playerDimens, kotlin.jvm.functions.Function0 onPlayAudioClick, kotlin.jvm.functions.Function0 nextTrackButton, kotlin.jvm.functions.Function0 rotatePlusButton, kotlin.jvm.functions.Function0 previousTrackButton, kotlin.jvm.functions.Function0 rotateMinusButton, kotlin.jvm.functions.Function0 playingButton, kotlin.jvm.functions.Function0 pauseButton); + method @androidx.compose.runtime.Composable public static void PlayerWrapper(optional androidx.compose.ui.Modifier modifier, optional boolean isRtlEnabled, optional com.urlaunched.android.design.ui.player.models.AudioPlayButtonColor audioPlayButtonColor, optional com.urlaunched.android.design.ui.player.models.AudioSliderColor audioSliderColor, optional com.urlaunched.android.design.ui.player.models.PlayerWrapperBottomColor playerWrapperBottomColor, optional com.urlaunched.android.design.ui.player.models.AudioSliderDimens audioSliderDimens, optional com.urlaunched.android.design.ui.player.models.PlayerWrapperBottomDimens playerWrapperBottomDimens, optional com.urlaunched.android.design.ui.player.models.PlayerDimens playerDimens, float audioProgress, Object audioState, kotlin.jvm.functions.Function1 audioSliderOnValueChange, kotlin.jvm.functions.Function0 onPlayAudioClick, kotlin.jvm.functions.Function0 nextTrackButton, kotlin.jvm.functions.Function0 previousTrackButton, kotlin.jvm.functions.Function0 rotatePlusButton, kotlin.jvm.functions.Function0 rotateMinusButton, kotlin.jvm.functions.Function0 playingButton, kotlin.jvm.functions.Function0 pauseButton, kotlin.jvm.functions.Function0 thumb, kotlin.jvm.functions.Function0 currentPositionText, kotlin.jvm.functions.Function0 timeLeftText, kotlin.jvm.functions.Function0 chapterDetails, kotlin.jvm.functions.Function0 bottomPanel, kotlin.jvm.functions.Function0 audioTrackDetails); } } From 99b389caa3e3b3172ebb8df946d3bb108e3aad3c Mon Sep 17 00:00:00 2001 From: Boonapart Date: Thu, 19 Jun 2025 17:56:19 +0300 Subject: [PATCH 3/5] Change vertical arrangement --- .../android/design/ui/player/ui/AudioPlayerTrackDetails.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/design/src/main/java/com/urlaunched/android/design/ui/player/ui/AudioPlayerTrackDetails.kt b/design/src/main/java/com/urlaunched/android/design/ui/player/ui/AudioPlayerTrackDetails.kt index 0a69282f..c7d189df 100644 --- a/design/src/main/java/com/urlaunched/android/design/ui/player/ui/AudioPlayerTrackDetails.kt +++ b/design/src/main/java/com/urlaunched/android/design/ui/player/ui/AudioPlayerTrackDetails.kt @@ -16,7 +16,7 @@ fun AudioPlayerTrackDetails( ) { Column( modifier = modifier, - verticalArrangement = Arrangement.Center, + verticalArrangement = Arrangement.Top, horizontalAlignment = Alignment.CenterHorizontally ) { Spacer(modifier = Modifier.height(Dimens.spacingTinyHalf)) From 99bd0c043994c5c555e39eabe0ba09d37d6c0ef1 Mon Sep 17 00:00:00 2001 From: Boonapart Date: Tue, 24 Jun 2025 12:13:03 +0300 Subject: [PATCH 4/5] Update bottom bar --- design/api/current.api | 80 +++++++++++++++---- .../ui/player/models/AudioPlayButtonColor.kt | 3 +- .../ui/player/models/AudioSliderColor.kt | 1 - .../ui/player/models/AudioSliderDimens.kt | 9 +-- .../design/ui/player/models/BottomBarItem.kt | 12 +++ .../ui/player/models/BottomItemColors.kt | 9 +++ .../ui/player/models/BottomItemDimens.kt | 11 +++ .../ui/player/models/BottomPanelDimens.kt | 10 +++ .../design/ui/player/models/PlayerDimens.kt | 5 +- .../design/ui/player/ui/AudioPlayButton.kt | 4 +- .../ui/player/ui/AudioPlayerTrackDetails.kt | 2 +- .../design/ui/player/ui/AudioSlider.kt | 2 +- .../android/design/ui/player/ui/BottomItem.kt | 65 +++++++++++++++ .../design/ui/player/ui/BottomPanel.kt | 42 ++++++++++ .../android/design/ui/player/ui/Player.kt | 3 +- .../design/ui/player/ui/PlayerWrapper.kt | 41 ++++++---- 16 files changed, 248 insertions(+), 51 deletions(-) create mode 100644 design/src/main/java/com/urlaunched/android/design/ui/player/models/BottomBarItem.kt create mode 100644 design/src/main/java/com/urlaunched/android/design/ui/player/models/BottomItemColors.kt create mode 100644 design/src/main/java/com/urlaunched/android/design/ui/player/models/BottomItemDimens.kt create mode 100644 design/src/main/java/com/urlaunched/android/design/ui/player/models/BottomPanelDimens.kt create mode 100644 design/src/main/java/com/urlaunched/android/design/ui/player/ui/BottomItem.kt create mode 100644 design/src/main/java/com/urlaunched/android/design/ui/player/ui/BottomPanel.kt diff --git a/design/api/current.api b/design/api/current.api index 229c500c..afbda4af 100644 --- a/design/api/current.api +++ b/design/api/current.api @@ -304,6 +304,68 @@ package com.urlaunched.android.design.ui.player.models { enum_constant public static final com.urlaunched.android.design.ui.player.models.AudioStateType PLAYING; } + public final class BottomBarItem { + ctor public BottomBarItem(String title, kotlin.jvm.functions.Function0 onClick, kotlin.jvm.functions.Function0 icon, optional androidx.compose.ui.Modifier modifier, optional boolean enabled); + method public String component1(); + method public kotlin.jvm.functions.Function0 component2(); + method public kotlin.jvm.functions.Function0 component3(); + method public androidx.compose.ui.Modifier component4(); + method public boolean component5(); + method public com.urlaunched.android.design.ui.player.models.BottomBarItem copy(String title, kotlin.jvm.functions.Function0 onClick, kotlin.jvm.functions.Function0 icon, androidx.compose.ui.Modifier modifier, boolean enabled); + method public boolean getEnabled(); + method public kotlin.jvm.functions.Function0 getIcon(); + method public androidx.compose.ui.Modifier getModifier(); + method public kotlin.jvm.functions.Function0 getOnClick(); + method public String getTitle(); + property public final boolean enabled; + property public final kotlin.jvm.functions.Function0 icon; + property public final androidx.compose.ui.Modifier modifier; + property public final kotlin.jvm.functions.Function0 onClick; + property public final String title; + } + + public final class BottomItemColors { + ctor public BottomItemColors(optional long background, optional long enabledTextColor, optional long disabledTextColor); + method public long component1-0d7_KjU(); + method public long component2-0d7_KjU(); + method public long component3-0d7_KjU(); + method public com.urlaunched.android.design.ui.player.models.BottomItemColors copy-ysEtTa8(long background, long enabledTextColor, long disabledTextColor); + method public long getBackground(); + method public long getDisabledTextColor(); + method public long getEnabledTextColor(); + property public final long background; + property public final long disabledTextColor; + property public final long enabledTextColor; + } + + public final class BottomItemDimens { + ctor public BottomItemDimens(optional float actionItemWidth, optional float actionItemHeight, optional float columnClip); + method public float component1-D9Ej5fM(); + method public float component2-D9Ej5fM(); + method public float component3-D9Ej5fM(); + method public com.urlaunched.android.design.ui.player.models.BottomItemDimens copy-2z7ARbQ(float actionItemWidth, float actionItemHeight, float columnClip); + method public float getActionItemHeight(); + method public float getActionItemWidth(); + method public float getColumnClip(); + property public final float actionItemHeight; + property public final float actionItemWidth; + property public final float columnClip; + } + + public final class BottomPanelDimens { + ctor public BottomPanelDimens(optional float rowHorizontalPadding, optional float rowVerticalPadding, optional float horizontalArrangementPadding); + method public float component1-D9Ej5fM(); + method public float component2-D9Ej5fM(); + method public float component3-D9Ej5fM(); + method public com.urlaunched.android.design.ui.player.models.BottomPanelDimens copy-2z7ARbQ(float rowHorizontalPadding, float rowVerticalPadding, float horizontalArrangementPadding); + method public float getHorizontalArrangementPadding(); + method public float getRowHorizontalPadding(); + method public float getRowVerticalPadding(); + property public final float horizontalArrangementPadding; + property public final float rowHorizontalPadding; + property public final float rowVerticalPadding; + } + public final class PlayerDimens { ctor public PlayerDimens(optional float horizontalDimens, optional float verticalDimens); method public float component1-D9Ej5fM(); @@ -338,24 +400,8 @@ package com.urlaunched.android.design.ui.player.models { package com.urlaunched.android.design.ui.player.ui { - public final class AudioPlayButtonKt { - method @androidx.compose.runtime.Composable public static void AudioPlayButton(optional androidx.compose.ui.Modifier modifier, Object audioState, optional com.urlaunched.android.design.ui.player.models.AudioPlayButtonDimens audioPlayButtonDimens, optional com.urlaunched.android.design.ui.player.models.AudioPlayButtonColor audioPlayButtonColor, optional com.urlaunched.android.design.ui.player.models.AudioPlayButtonConstants audioPlayButtonConstants, kotlin.jvm.functions.Function0 onClick, kotlin.jvm.functions.Function0 playingButton, kotlin.jvm.functions.Function0 pauseButton); - } - - public final class AudioPlayerTrackDetailsKt { - method @androidx.compose.runtime.Composable public static void AudioPlayerTrackDetails(optional androidx.compose.ui.Modifier modifier, kotlin.jvm.functions.Function0 audioTrackDetails); - } - - public final class AudioSliderKt { - method @androidx.compose.runtime.Composable public static void AudioSlider(float audioProgress, optional com.urlaunched.android.design.ui.player.models.AudioSliderDimens audioSliderDimens, optional com.urlaunched.android.design.ui.player.models.AudioSliderColor audioSliderColor, kotlin.jvm.functions.Function1 audioSliderOnValueChange, kotlin.jvm.functions.Function0 thumb, kotlin.jvm.functions.Function0 currentPositionText, kotlin.jvm.functions.Function0 timeLeftText); - } - - public final class PlayerKt { - method @androidx.compose.runtime.Composable public static void Player(Object audioState, optional com.urlaunched.android.design.ui.player.models.PlayerDimens playerDimens, com.urlaunched.android.design.ui.player.models.AudioPlayButtonColor audioPlayButtonColor, kotlin.jvm.functions.Function0 onPlayAudioClick, kotlin.jvm.functions.Function0 nextTrackButton, kotlin.jvm.functions.Function0 rotatePlusButton, kotlin.jvm.functions.Function0 previousTrackButton, kotlin.jvm.functions.Function0 rotateMinusButton, kotlin.jvm.functions.Function0 playingButton, kotlin.jvm.functions.Function0 pauseButton); - } - public final class PlayerWrapperKt { - method @androidx.compose.runtime.Composable public static void PlayerWrapper(optional androidx.compose.ui.Modifier modifier, optional boolean isRtlEnabled, optional com.urlaunched.android.design.ui.player.models.AudioPlayButtonColor audioPlayButtonColor, optional com.urlaunched.android.design.ui.player.models.AudioSliderColor audioSliderColor, optional com.urlaunched.android.design.ui.player.models.PlayerWrapperBottomColor playerWrapperBottomColor, optional com.urlaunched.android.design.ui.player.models.AudioSliderDimens audioSliderDimens, optional com.urlaunched.android.design.ui.player.models.PlayerWrapperBottomDimens playerWrapperBottomDimens, optional com.urlaunched.android.design.ui.player.models.PlayerDimens playerDimens, float audioProgress, Object audioState, kotlin.jvm.functions.Function1 audioSliderOnValueChange, kotlin.jvm.functions.Function0 onPlayAudioClick, kotlin.jvm.functions.Function0 nextTrackButton, kotlin.jvm.functions.Function0 previousTrackButton, kotlin.jvm.functions.Function0 rotatePlusButton, kotlin.jvm.functions.Function0 rotateMinusButton, kotlin.jvm.functions.Function0 playingButton, kotlin.jvm.functions.Function0 pauseButton, kotlin.jvm.functions.Function0 thumb, kotlin.jvm.functions.Function0 currentPositionText, kotlin.jvm.functions.Function0 timeLeftText, kotlin.jvm.functions.Function0 chapterDetails, kotlin.jvm.functions.Function0 bottomPanel, kotlin.jvm.functions.Function0 audioTrackDetails); + method @androidx.compose.runtime.Composable public static void PlayerWrapper(optional androidx.compose.ui.Modifier modifier, optional boolean isRtlEnabled, float audioProgress, Object audioState, kotlin.jvm.functions.Function1 audioSliderOnValueChange, kotlin.jvm.functions.Function0 onPlayAudioClick, optional com.urlaunched.android.design.ui.player.models.AudioPlayButtonColor audioPlayButtonColor, optional com.urlaunched.android.design.ui.player.models.AudioSliderColor audioSliderColor, optional com.urlaunched.android.design.ui.player.models.PlayerWrapperBottomColor playerWrapperBottomColor, optional com.urlaunched.android.design.ui.player.models.BottomItemColors bottomItemColors, optional com.urlaunched.android.design.ui.player.models.AudioSliderDimens audioSliderDimens, optional com.urlaunched.android.design.ui.player.models.PlayerWrapperBottomDimens playerWrapperBottomDimens, optional com.urlaunched.android.design.ui.player.models.PlayerDimens playerDimens, androidx.compose.ui.text.TextStyle bottomTextStyle, java.util.List bottomBarItems, kotlin.jvm.functions.Function0 nextTrackButton, kotlin.jvm.functions.Function0 previousTrackButton, kotlin.jvm.functions.Function0 rotatePlusButton, kotlin.jvm.functions.Function0 rotateMinusButton, kotlin.jvm.functions.Function0 playingButton, kotlin.jvm.functions.Function0 pauseButton, kotlin.jvm.functions.Function0 thumb, kotlin.jvm.functions.Function0 currentPositionText, kotlin.jvm.functions.Function0 timeLeftText, kotlin.jvm.functions.Function0 chapterDetails, kotlin.jvm.functions.Function0 audioTrackDetails); } } diff --git a/design/src/main/java/com/urlaunched/android/design/ui/player/models/AudioPlayButtonColor.kt b/design/src/main/java/com/urlaunched/android/design/ui/player/models/AudioPlayButtonColor.kt index 376900ac..a1b98344 100644 --- a/design/src/main/java/com/urlaunched/android/design/ui/player/models/AudioPlayButtonColor.kt +++ b/design/src/main/java/com/urlaunched/android/design/ui/player/models/AudioPlayButtonColor.kt @@ -5,5 +5,4 @@ import androidx.compose.ui.graphics.Color data class AudioPlayButtonColor( val buttonColor: Color = Color.White, val circularProgressColor: Color = Color.White -) - +) \ No newline at end of file diff --git a/design/src/main/java/com/urlaunched/android/design/ui/player/models/AudioSliderColor.kt b/design/src/main/java/com/urlaunched/android/design/ui/player/models/AudioSliderColor.kt index d1c3506f..69c5b3d7 100644 --- a/design/src/main/java/com/urlaunched/android/design/ui/player/models/AudioSliderColor.kt +++ b/design/src/main/java/com/urlaunched/android/design/ui/player/models/AudioSliderColor.kt @@ -2,7 +2,6 @@ package com.urlaunched.android.design.ui.player.models import androidx.compose.ui.graphics.Color - data class AudioSliderColor( val thumbColor: Color = Color.White, val activeTrackColor: Color = Color.White, diff --git a/design/src/main/java/com/urlaunched/android/design/ui/player/models/AudioSliderDimens.kt b/design/src/main/java/com/urlaunched/android/design/ui/player/models/AudioSliderDimens.kt index 5d7bbe01..56dd65ae 100644 --- a/design/src/main/java/com/urlaunched/android/design/ui/player/models/AudioSliderDimens.kt +++ b/design/src/main/java/com/urlaunched/android/design/ui/player/models/AudioSliderDimens.kt @@ -1,11 +1,10 @@ package com.urlaunched.android.design.ui.player.models import androidx.compose.ui.unit.Dp -import androidx.compose.ui.unit.dp - +import com.urlaunched.android.design.resources.dimens.Dimens data class AudioSliderDimens( - val sliderThumbTrackGapSize: Dp = 0.dp, - val sliderTrackInsideCornerSize: Dp = 0.dp, - val sliderTrackHeight: Dp = 4.dp, + val sliderThumbTrackGapSize: Dp = Dimens.zeroDp, + val sliderTrackInsideCornerSize: Dp = Dimens.zeroDp, + val sliderTrackHeight: Dp = Dimens.spacingTiny, ) \ No newline at end of file diff --git a/design/src/main/java/com/urlaunched/android/design/ui/player/models/BottomBarItem.kt b/design/src/main/java/com/urlaunched/android/design/ui/player/models/BottomBarItem.kt new file mode 100644 index 00000000..edbe492f --- /dev/null +++ b/design/src/main/java/com/urlaunched/android/design/ui/player/models/BottomBarItem.kt @@ -0,0 +1,12 @@ +package com.urlaunched.android.design.ui.player.models + +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier + +data class BottomBarItem( + val title: String, + val onClick: () -> Unit, + val icon: @Composable () -> Unit, + val modifier: Modifier = Modifier, + val enabled: Boolean = true +) \ No newline at end of file diff --git a/design/src/main/java/com/urlaunched/android/design/ui/player/models/BottomItemColors.kt b/design/src/main/java/com/urlaunched/android/design/ui/player/models/BottomItemColors.kt new file mode 100644 index 00000000..dec836b8 --- /dev/null +++ b/design/src/main/java/com/urlaunched/android/design/ui/player/models/BottomItemColors.kt @@ -0,0 +1,9 @@ +package com.urlaunched.android.design.ui.player.models + +import androidx.compose.ui.graphics.Color + +data class BottomItemColors( + val background: Color = Color.White, + val enabledTextColor: Color = Color.Gray, + val disabledTextColor: Color = Color.White +) \ No newline at end of file diff --git a/design/src/main/java/com/urlaunched/android/design/ui/player/models/BottomItemDimens.kt b/design/src/main/java/com/urlaunched/android/design/ui/player/models/BottomItemDimens.kt new file mode 100644 index 00000000..2930309a --- /dev/null +++ b/design/src/main/java/com/urlaunched/android/design/ui/player/models/BottomItemDimens.kt @@ -0,0 +1,11 @@ +package com.urlaunched.android.design.ui.player.models + +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.dp +import com.urlaunched.android.design.resources.dimens.Dimens + +data class BottomItemDimens( + val actionItemWidth: Dp = 53.dp, + val actionItemHeight: Dp = Dimens.spacingLarge, + val columnClip: Dp = Dimens.cornerRadiusNormalSpecial +) \ No newline at end of file diff --git a/design/src/main/java/com/urlaunched/android/design/ui/player/models/BottomPanelDimens.kt b/design/src/main/java/com/urlaunched/android/design/ui/player/models/BottomPanelDimens.kt new file mode 100644 index 00000000..f7bcc907 --- /dev/null +++ b/design/src/main/java/com/urlaunched/android/design/ui/player/models/BottomPanelDimens.kt @@ -0,0 +1,10 @@ +package com.urlaunched.android.design.ui.player.models + +import androidx.compose.ui.unit.Dp +import com.urlaunched.android.design.resources.dimens.Dimens + +data class BottomPanelDimens( + val rowHorizontalPadding: Dp = Dimens.spacingNormalSpecial, + val rowVerticalPadding: Dp = Dimens.spacingBigSpecial, + val horizontalArrangementPadding: Dp = Dimens.spacingNormalSpecial +) \ No newline at end of file diff --git a/design/src/main/java/com/urlaunched/android/design/ui/player/models/PlayerDimens.kt b/design/src/main/java/com/urlaunched/android/design/ui/player/models/PlayerDimens.kt index d6956181..62823674 100644 --- a/design/src/main/java/com/urlaunched/android/design/ui/player/models/PlayerDimens.kt +++ b/design/src/main/java/com/urlaunched/android/design/ui/player/models/PlayerDimens.kt @@ -1,10 +1,9 @@ package com.urlaunched.android.design.ui.player.models import androidx.compose.ui.unit.Dp -import androidx.compose.ui.unit.dp import com.urlaunched.android.design.resources.dimens.Dimens data class PlayerDimens( val horizontalDimens: Dp = Dimens.spacingNormalSpecial, - val verticalDimens: Dp = 0.dp -) + val verticalDimens: Dp = Dimens.zeroDp +) \ No newline at end of file diff --git a/design/src/main/java/com/urlaunched/android/design/ui/player/ui/AudioPlayButton.kt b/design/src/main/java/com/urlaunched/android/design/ui/player/ui/AudioPlayButton.kt index 4803c8a5..a08d9f34 100644 --- a/design/src/main/java/com/urlaunched/android/design/ui/player/ui/AudioPlayButton.kt +++ b/design/src/main/java/com/urlaunched/android/design/ui/player/ui/AudioPlayButton.kt @@ -19,7 +19,7 @@ import com.urlaunched.android.design.ui.player.models.AudioPlayButtonColor import com.urlaunched.android.design.ui.player.models.AudioStateType @Composable -fun AudioPlayButton( +internal fun AudioPlayButton( modifier: Modifier = Modifier, audioState: Any, audioPlayButtonDimens: AudioPlayButtonDimens = AudioPlayButtonDimens(), @@ -59,4 +59,4 @@ fun AudioPlayButton( } } } -} +} \ No newline at end of file diff --git a/design/src/main/java/com/urlaunched/android/design/ui/player/ui/AudioPlayerTrackDetails.kt b/design/src/main/java/com/urlaunched/android/design/ui/player/ui/AudioPlayerTrackDetails.kt index c7d189df..931e30c2 100644 --- a/design/src/main/java/com/urlaunched/android/design/ui/player/ui/AudioPlayerTrackDetails.kt +++ b/design/src/main/java/com/urlaunched/android/design/ui/player/ui/AudioPlayerTrackDetails.kt @@ -10,7 +10,7 @@ import androidx.compose.ui.Modifier import com.urlaunched.android.design.resources.dimens.Dimens @Composable -fun AudioPlayerTrackDetails( +internal fun AudioPlayerTrackDetails( modifier: Modifier = Modifier, audioTrackDetails: @Composable () -> Unit, ) { diff --git a/design/src/main/java/com/urlaunched/android/design/ui/player/ui/AudioSlider.kt b/design/src/main/java/com/urlaunched/android/design/ui/player/ui/AudioSlider.kt index 166d8c82..1166fefc 100644 --- a/design/src/main/java/com/urlaunched/android/design/ui/player/ui/AudioSlider.kt +++ b/design/src/main/java/com/urlaunched/android/design/ui/player/ui/AudioSlider.kt @@ -18,7 +18,7 @@ import kotlin.math.roundToInt @OptIn(ExperimentalMaterial3Api::class) @Composable -fun AudioSlider( +internal fun AudioSlider( audioProgress: Float, audioSliderDimens: AudioSliderDimens = AudioSliderDimens(), audioSliderColor: AudioSliderColor = AudioSliderColor(), diff --git a/design/src/main/java/com/urlaunched/android/design/ui/player/ui/BottomItem.kt b/design/src/main/java/com/urlaunched/android/design/ui/player/ui/BottomItem.kt new file mode 100644 index 00000000..8029dbe3 --- /dev/null +++ b/design/src/main/java/com/urlaunched/android/design/ui/player/ui/BottomItem.kt @@ -0,0 +1,65 @@ +package com.urlaunched.android.design.ui.player.ui + +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.interaction.MutableInteractionSource +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.BoxScope +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +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.text.TextStyle +import com.urlaunched.android.design.resources.dimens.Dimens +import com.urlaunched.android.design.ui.player.models.BottomItemColors +import com.urlaunched.android.design.ui.player.models.BottomItemDimens + +@Composable +internal fun BottomItem( + modifier: Modifier = Modifier, + title: String, + bottomItemDimens: BottomItemDimens = BottomItemDimens(), + bottomItemColors: BottomItemColors = BottomItemColors(), + textStyle: TextStyle, + enabled: Boolean = true, + onClick: () -> Unit, + content: @Composable BoxScope.() -> Unit +) { + Column( + modifier = modifier + .clip(RoundedCornerShape(Dimens.cornerRadiusNormalSpecial)) + .clickable( + onClick = onClick, + enabled = enabled, + interactionSource = remember { MutableInteractionSource() }, + indication = null, + ) + .padding(Dimens.spacingTiny), + horizontalAlignment = Alignment.CenterHorizontally + ) { + Box( + modifier = Modifier + .size(bottomItemDimens.actionItemWidth, bottomItemDimens.actionItemHeight) + .clip(RoundedCornerShape(Dimens.cornerRadiusBigSpecial)) + .background(bottomItemColors.background), + content = content, + contentAlignment = Alignment.Center + ) + + Spacer(modifier = Modifier.height(Dimens.spacingSmall)) + + Text( + text = title, + color = if (enabled) bottomItemColors.enabledTextColor else bottomItemColors.disabledTextColor, + style = textStyle + ) + } +} \ No newline at end of file diff --git a/design/src/main/java/com/urlaunched/android/design/ui/player/ui/BottomPanel.kt b/design/src/main/java/com/urlaunched/android/design/ui/player/ui/BottomPanel.kt new file mode 100644 index 00000000..34fcd70b --- /dev/null +++ b/design/src/main/java/com/urlaunched/android/design/ui/player/ui/BottomPanel.kt @@ -0,0 +1,42 @@ +package com.urlaunched.android.design.ui.player.ui + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.text.TextStyle +import com.urlaunched.android.design.ui.player.models.BottomBarItem +import com.urlaunched.android.design.ui.player.models.BottomItemColors +import com.urlaunched.android.design.ui.player.models.BottomPanelDimens + +@Composable +internal fun BottomPanel( + bottomBarItems: List, + bottomTextStyle: TextStyle, + bottomItemColors: BottomItemColors = BottomItemColors(), + bottomPanelDimens: BottomPanelDimens = BottomPanelDimens() +) { + Row( + modifier = Modifier + .padding( + vertical = bottomPanelDimens.rowVerticalPadding, + horizontal = bottomPanelDimens.rowHorizontalPadding + ) + .fillMaxWidth(), + horizontalArrangement = Arrangement.spacedBy(bottomPanelDimens.horizontalArrangementPadding) + ) { + bottomBarItems.forEach { item -> + BottomItem( + bottomItemColors = bottomItemColors, + modifier = item.modifier, + title = item.title, + textStyle = bottomTextStyle, + enabled = item.enabled, + onClick = item.onClick, + content = { item.icon() } + ) + } + } +} \ No newline at end of file diff --git a/design/src/main/java/com/urlaunched/android/design/ui/player/ui/Player.kt b/design/src/main/java/com/urlaunched/android/design/ui/player/ui/Player.kt index 6c36be46..592403cd 100644 --- a/design/src/main/java/com/urlaunched/android/design/ui/player/ui/Player.kt +++ b/design/src/main/java/com/urlaunched/android/design/ui/player/ui/Player.kt @@ -11,7 +11,7 @@ import com.urlaunched.android.design.ui.player.models.AudioPlayButtonColor import com.urlaunched.android.design.ui.player.models.PlayerDimens @Composable -fun Player( +internal fun Player( audioState: Any, playerDimens: PlayerDimens = PlayerDimens(), audioPlayButtonColor: AudioPlayButtonColor, @@ -45,6 +45,5 @@ fun Player( rotatePlusButton() previousTrackButton() - } } \ No newline at end of file diff --git a/design/src/main/java/com/urlaunched/android/design/ui/player/ui/PlayerWrapper.kt b/design/src/main/java/com/urlaunched/android/design/ui/player/ui/PlayerWrapper.kt index d0b33e65..bc538abc 100644 --- a/design/src/main/java/com/urlaunched/android/design/ui/player/ui/PlayerWrapper.kt +++ b/design/src/main/java/com/urlaunched/android/design/ui/player/ui/PlayerWrapper.kt @@ -10,7 +10,10 @@ import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalLayoutDirection +import androidx.compose.ui.text.TextStyle import androidx.compose.ui.unit.LayoutDirection +import com.urlaunched.android.design.ui.player.models.BottomItemColors +import com.urlaunched.android.design.ui.player.models.BottomBarItem import com.urlaunched.android.design.ui.player.models.AudioPlayButtonColor import com.urlaunched.android.design.ui.player.models.AudioSliderColor import com.urlaunched.android.design.ui.player.models.AudioSliderDimens @@ -24,46 +27,46 @@ fun PlayerWrapper( modifier: Modifier = Modifier, isRtlEnabled: Boolean = false, + // 📊 Стан / значення + audioProgress: Float, + audioState: Any, + + // 🔁 Колбеки + audioSliderOnValueChange: (Float) -> Unit, + onPlayAudioClick: () -> Unit, + // 🎨 Кольори audioPlayButtonColor: AudioPlayButtonColor = AudioPlayButtonColor(), audioSliderColor: AudioSliderColor = AudioSliderColor(), playerWrapperBottomColor: PlayerWrapperBottomColor = PlayerWrapperBottomColor(), + bottomItemColors: BottomItemColors = BottomItemColors(), // 📐 Розміри audioSliderDimens: AudioSliderDimens = AudioSliderDimens(), playerWrapperBottomDimens: PlayerWrapperBottomDimens = PlayerWrapperBottomDimens(), playerDimens: PlayerDimens = PlayerDimens(), - // 📊 Стан / значення - audioProgress: Float, - audioState: Any, + // 🎨 Стилі + bottomTextStyle: TextStyle, - // 🔁 Колбеки (взаємодія) - audioSliderOnValueChange: (Float) -> Unit, - onPlayAudioClick: () -> Unit, + // 📦 Дані + bottomBarItems: List, - // 🧩 Компоненти UI (Composable блоки) - // — елементи управління треком nextTrackButton: @Composable () -> Unit, previousTrackButton: @Composable () -> Unit, rotatePlusButton: @Composable () -> Unit, rotateMinusButton: @Composable () -> Unit, - // — кнопки відтворення playingButton: @Composable () -> Unit, pauseButton: @Composable () -> Unit, - - // — прогрес thumb: @Composable () -> Unit, currentPositionText: @Composable () -> Unit, timeLeftText: @Composable () -> Unit, // — додатковий контент chapterDetails: @Composable () -> Unit, - bottomPanel: @Composable () -> Unit, audioTrackDetails: @Composable () -> Unit -){ - +) { Column(modifier = Modifier.fillMaxSize()) { AudioPlayerTrackDetails( @@ -96,6 +99,7 @@ fun PlayerWrapper( thumb = thumb, currentPositionText = currentPositionText, timeLeftText = timeLeftText + ) Player( @@ -113,8 +117,11 @@ fun PlayerWrapper( ) } - bottomPanel() + BottomPanel( + bottomBarItems = bottomBarItems, + bottomTextStyle = bottomTextStyle, + bottomItemColors = bottomItemColors + ) } } -} - +} \ No newline at end of file From 1177c8e27454276c6d51cc13f2962a66ee454050 Mon Sep 17 00:00:00 2001 From: Boonapart Date: Wed, 25 Jun 2025 11:48:18 +0300 Subject: [PATCH 5/5] Add MiniPlayer base implementation --- design/api/current.api | 59 ++++- ...nstants.kt => AudioPlayButtonConstants.kt} | 0 .../ui/player/models/AudioSliderColor.kt | 2 +- .../ui/player/models/AudioSliderDimens.kt | 1 + .../ui/player/models/MiniPlayerColors.kt | 10 + .../ui/player/models/MiniPlayerConstants.kt | 9 + .../ui/player/models/MiniPlayerDimens.kt | 9 + .../design/ui/player/ui/AudioPlayButton.kt | 1 + .../design/ui/player/ui/AudioSlider.kt | 3 +- .../design/ui/player/ui/MiniPlayerWrapper.kt | 221 ++++++++++++++++++ .../design/ui/player/ui/PlayerWrapper.kt | 7 +- 11 files changed, 315 insertions(+), 7 deletions(-) rename design/src/main/java/com/urlaunched/android/design/ui/player/models/{AudioBookConstants.kt => AudioPlayButtonConstants.kt} (100%) create mode 100644 design/src/main/java/com/urlaunched/android/design/ui/player/models/MiniPlayerColors.kt create mode 100644 design/src/main/java/com/urlaunched/android/design/ui/player/models/MiniPlayerConstants.kt create mode 100644 design/src/main/java/com/urlaunched/android/design/ui/player/models/MiniPlayerDimens.kt create mode 100644 design/src/main/java/com/urlaunched/android/design/ui/player/ui/MiniPlayerWrapper.kt diff --git a/design/api/current.api b/design/api/current.api index afbda4af..f7e952c2 100644 --- a/design/api/current.api +++ b/design/api/current.api @@ -283,16 +283,19 @@ package com.urlaunched.android.design.ui.player.models { } public final class AudioSliderDimens { - ctor public AudioSliderDimens(optional float sliderThumbTrackGapSize, optional float sliderTrackInsideCornerSize, optional float sliderTrackHeight); + ctor public AudioSliderDimens(optional float sliderThumbTrackGapSize, optional float sliderTrackInsideCornerSize, optional float sliderTrackHeight, optional float sliderTrackHorizontalPadding); method public float component1-D9Ej5fM(); method public float component2-D9Ej5fM(); method public float component3-D9Ej5fM(); - method public com.urlaunched.android.design.ui.player.models.AudioSliderDimens copy-2z7ARbQ(float sliderThumbTrackGapSize, float sliderTrackInsideCornerSize, float sliderTrackHeight); + method public float component4-D9Ej5fM(); + method public com.urlaunched.android.design.ui.player.models.AudioSliderDimens copy-a9UjIt4(float sliderThumbTrackGapSize, float sliderTrackInsideCornerSize, float sliderTrackHeight, float sliderTrackHorizontalPadding); method public float getSliderThumbTrackGapSize(); method public float getSliderTrackHeight(); + method public float getSliderTrackHorizontalPadding(); method public float getSliderTrackInsideCornerSize(); property public final float sliderThumbTrackGapSize; property public final float sliderTrackHeight; + property public final float sliderTrackHorizontalPadding; property public final float sliderTrackInsideCornerSize; } @@ -366,6 +369,54 @@ package com.urlaunched.android.design.ui.player.models { property public final float rowVerticalPadding; } + public final class MiniPlayerColors { + ctor public MiniPlayerColors(optional long background, optional long textColor, optional long leadingLineColor, optional long trailingLineColor); + method public long component1-0d7_KjU(); + method public long component2-0d7_KjU(); + method public long component3-0d7_KjU(); + method public long component4-0d7_KjU(); + method public com.urlaunched.android.design.ui.player.models.MiniPlayerColors copy-jRlVdoo(long background, long textColor, long leadingLineColor, long trailingLineColor); + method public long getBackground(); + method public long getLeadingLineColor(); + method public long getTextColor(); + method public long getTrailingLineColor(); + property public final long background; + property public final long leadingLineColor; + property public final long textColor; + property public final long trailingLineColor; + } + + public final class MiniPlayerConstants { + ctor public MiniPlayerConstants(optional int defaultFadeInDuration, optional int defaultFadeInDelay, optional int defaultFadeOutDuration, optional String chapterNameAnimationLabel, optional String emptyString); + method public int component1(); + method public int component2(); + method public int component3(); + method public String component4(); + method public String component5(); + method public com.urlaunched.android.design.ui.player.models.MiniPlayerConstants copy(int defaultFadeInDuration, int defaultFadeInDelay, int defaultFadeOutDuration, String chapterNameAnimationLabel, String emptyString); + method public String getChapterNameAnimationLabel(); + method public int getDefaultFadeInDelay(); + method public int getDefaultFadeInDuration(); + method public int getDefaultFadeOutDuration(); + method public String getEmptyString(); + property public final String chapterNameAnimationLabel; + property public final int defaultFadeInDelay; + property public final int defaultFadeInDuration; + property public final int defaultFadeOutDuration; + property public final String emptyString; + } + + public final class MiniPlayerDimens { + ctor public MiniPlayerDimens(optional float sliderHalfHeightOffset, optional float audioSliderHeight); + method public float component1-D9Ej5fM(); + method public float component2-D9Ej5fM(); + method public com.urlaunched.android.design.ui.player.models.MiniPlayerDimens copy-YgX7TsA(float sliderHalfHeightOffset, float audioSliderHeight); + method public float getAudioSliderHeight(); + method public float getSliderHalfHeightOffset(); + property public final float audioSliderHeight; + property public final float sliderHalfHeightOffset; + } + public final class PlayerDimens { ctor public PlayerDimens(optional float horizontalDimens, optional float verticalDimens); method public float component1-D9Ej5fM(); @@ -400,6 +451,10 @@ package com.urlaunched.android.design.ui.player.models { package com.urlaunched.android.design.ui.player.ui { + public final class MiniPlayerWrapperKt { + method @androidx.compose.runtime.Composable public static void MiniPlayerWrapper(optional androidx.compose.ui.Modifier modifier, String? currentChapterName, String? bookInfoText, optional boolean isRtlEnabled, Object audioState, androidx.compose.ui.text.TextStyle chapterTextStyle, androidx.compose.ui.text.TextStyle bookInfoTextStyle, optional com.urlaunched.android.design.ui.player.models.MiniPlayerColors miniPlayerColors, optional com.urlaunched.android.design.ui.player.models.MiniPlayerConstants miniPlayerConstants, optional com.urlaunched.android.design.ui.player.models.MiniPlayerDimens miniPlayerDimens, kotlin.jvm.functions.Function0 onPlayAudioClick, kotlin.jvm.functions.Function0 onPlayerClick, kotlin.jvm.functions.Function1 onSizeChange, kotlin.jvm.functions.Function0 playingButton, kotlin.jvm.functions.Function0 pauseButton, kotlin.jvm.functions.Function0 rotateMinusButton, kotlin.jvm.functions.Function0 leadingContent, float audioProgress, kotlin.jvm.functions.Function1 audioSliderOnValueChange, optional com.urlaunched.android.design.ui.player.models.AudioSliderColor audioSliderColor, optional com.urlaunched.android.design.ui.player.models.AudioSliderDimens audioSliderDimens, optional com.urlaunched.android.design.ui.player.models.AudioPlayButtonColor audioPlayButtonColor, optional com.urlaunched.android.design.ui.player.models.AudioPlayButtonDimens audioPlayButtonDimens, kotlin.jvm.functions.Function0 thumb); + } + public final class PlayerWrapperKt { method @androidx.compose.runtime.Composable public static void PlayerWrapper(optional androidx.compose.ui.Modifier modifier, optional boolean isRtlEnabled, float audioProgress, Object audioState, kotlin.jvm.functions.Function1 audioSliderOnValueChange, kotlin.jvm.functions.Function0 onPlayAudioClick, optional com.urlaunched.android.design.ui.player.models.AudioPlayButtonColor audioPlayButtonColor, optional com.urlaunched.android.design.ui.player.models.AudioSliderColor audioSliderColor, optional com.urlaunched.android.design.ui.player.models.PlayerWrapperBottomColor playerWrapperBottomColor, optional com.urlaunched.android.design.ui.player.models.BottomItemColors bottomItemColors, optional com.urlaunched.android.design.ui.player.models.AudioSliderDimens audioSliderDimens, optional com.urlaunched.android.design.ui.player.models.PlayerWrapperBottomDimens playerWrapperBottomDimens, optional com.urlaunched.android.design.ui.player.models.PlayerDimens playerDimens, androidx.compose.ui.text.TextStyle bottomTextStyle, java.util.List bottomBarItems, kotlin.jvm.functions.Function0 nextTrackButton, kotlin.jvm.functions.Function0 previousTrackButton, kotlin.jvm.functions.Function0 rotatePlusButton, kotlin.jvm.functions.Function0 rotateMinusButton, kotlin.jvm.functions.Function0 playingButton, kotlin.jvm.functions.Function0 pauseButton, kotlin.jvm.functions.Function0 thumb, kotlin.jvm.functions.Function0 currentPositionText, kotlin.jvm.functions.Function0 timeLeftText, kotlin.jvm.functions.Function0 chapterDetails, kotlin.jvm.functions.Function0 audioTrackDetails); } diff --git a/design/src/main/java/com/urlaunched/android/design/ui/player/models/AudioBookConstants.kt b/design/src/main/java/com/urlaunched/android/design/ui/player/models/AudioPlayButtonConstants.kt similarity index 100% rename from design/src/main/java/com/urlaunched/android/design/ui/player/models/AudioBookConstants.kt rename to design/src/main/java/com/urlaunched/android/design/ui/player/models/AudioPlayButtonConstants.kt diff --git a/design/src/main/java/com/urlaunched/android/design/ui/player/models/AudioSliderColor.kt b/design/src/main/java/com/urlaunched/android/design/ui/player/models/AudioSliderColor.kt index 69c5b3d7..555f4bf6 100644 --- a/design/src/main/java/com/urlaunched/android/design/ui/player/models/AudioSliderColor.kt +++ b/design/src/main/java/com/urlaunched/android/design/ui/player/models/AudioSliderColor.kt @@ -6,4 +6,4 @@ data class AudioSliderColor( val thumbColor: Color = Color.White, val activeTrackColor: Color = Color.White, val inactiveTrackColor: Color = Color.White, -) +) \ No newline at end of file diff --git a/design/src/main/java/com/urlaunched/android/design/ui/player/models/AudioSliderDimens.kt b/design/src/main/java/com/urlaunched/android/design/ui/player/models/AudioSliderDimens.kt index 56dd65ae..397d1188 100644 --- a/design/src/main/java/com/urlaunched/android/design/ui/player/models/AudioSliderDimens.kt +++ b/design/src/main/java/com/urlaunched/android/design/ui/player/models/AudioSliderDimens.kt @@ -7,4 +7,5 @@ data class AudioSliderDimens( val sliderThumbTrackGapSize: Dp = Dimens.zeroDp, val sliderTrackInsideCornerSize: Dp = Dimens.zeroDp, val sliderTrackHeight: Dp = Dimens.spacingTiny, + val sliderTrackHorizontalPadding: Dp = Dimens.spacingSmall ) \ No newline at end of file diff --git a/design/src/main/java/com/urlaunched/android/design/ui/player/models/MiniPlayerColors.kt b/design/src/main/java/com/urlaunched/android/design/ui/player/models/MiniPlayerColors.kt new file mode 100644 index 00000000..3c8b2569 --- /dev/null +++ b/design/src/main/java/com/urlaunched/android/design/ui/player/models/MiniPlayerColors.kt @@ -0,0 +1,10 @@ +package com.urlaunched.android.design.ui.player.models + +import androidx.compose.ui.graphics.Color + +data class MiniPlayerColors( + val background: Color = Color.White, + val textColor: Color = Color.White, + val leadingLineColor: Color = Color.White, + val trailingLineColor: Color = Color.White +) \ No newline at end of file diff --git a/design/src/main/java/com/urlaunched/android/design/ui/player/models/MiniPlayerConstants.kt b/design/src/main/java/com/urlaunched/android/design/ui/player/models/MiniPlayerConstants.kt new file mode 100644 index 00000000..f2bb8213 --- /dev/null +++ b/design/src/main/java/com/urlaunched/android/design/ui/player/models/MiniPlayerConstants.kt @@ -0,0 +1,9 @@ +package com.urlaunched.android.design.ui.player.models + +data class MiniPlayerConstants( + val defaultFadeInDuration: Int = 220, + val defaultFadeInDelay: Int = 90, + val defaultFadeOutDuration: Int = 90, + val chapterNameAnimationLabel: String = "ChapterNameAnimation", + val emptyString: String = "" +) \ No newline at end of file diff --git a/design/src/main/java/com/urlaunched/android/design/ui/player/models/MiniPlayerDimens.kt b/design/src/main/java/com/urlaunched/android/design/ui/player/models/MiniPlayerDimens.kt new file mode 100644 index 00000000..dd297050 --- /dev/null +++ b/design/src/main/java/com/urlaunched/android/design/ui/player/models/MiniPlayerDimens.kt @@ -0,0 +1,9 @@ +package com.urlaunched.android.design.ui.player.models + +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.dp + +data class MiniPlayerDimens( + val sliderHalfHeightOffset: Dp = 14.dp, + val audioSliderHeight: Dp = 30.dp +) \ No newline at end of file diff --git a/design/src/main/java/com/urlaunched/android/design/ui/player/ui/AudioPlayButton.kt b/design/src/main/java/com/urlaunched/android/design/ui/player/ui/AudioPlayButton.kt index a08d9f34..db6fd1dd 100644 --- a/design/src/main/java/com/urlaunched/android/design/ui/player/ui/AudioPlayButton.kt +++ b/design/src/main/java/com/urlaunched/android/design/ui/player/ui/AudioPlayButton.kt @@ -46,6 +46,7 @@ internal fun AudioPlayButton( label = audioPlayButtonConstants.audioPlayButtonIconAnimationLabel ) { state -> val name = (state as? Enum<*>)?.name + when (name) { AudioStateType.PAUSE.name -> playingButton() diff --git a/design/src/main/java/com/urlaunched/android/design/ui/player/ui/AudioSlider.kt b/design/src/main/java/com/urlaunched/android/design/ui/player/ui/AudioSlider.kt index 1166fefc..6ce07713 100644 --- a/design/src/main/java/com/urlaunched/android/design/ui/player/ui/AudioSlider.kt +++ b/design/src/main/java/com/urlaunched/android/design/ui/player/ui/AudioSlider.kt @@ -19,6 +19,7 @@ import kotlin.math.roundToInt @OptIn(ExperimentalMaterial3Api::class) @Composable internal fun AudioSlider( + modifier: Modifier = Modifier, audioProgress: Float, audioSliderDimens: AudioSliderDimens = AudioSliderDimens(), audioSliderColor: AudioSliderColor = AudioSliderColor(), @@ -28,7 +29,7 @@ internal fun AudioSlider( timeLeftText: @Composable () -> Unit ) { Slider( - modifier = Modifier.padding(horizontal = Dimens.spacingSmall), + modifier = modifier, value = audioProgress, onValueChange = audioSliderOnValueChange, colors = SliderDefaults.colors( diff --git a/design/src/main/java/com/urlaunched/android/design/ui/player/ui/MiniPlayerWrapper.kt b/design/src/main/java/com/urlaunched/android/design/ui/player/ui/MiniPlayerWrapper.kt new file mode 100644 index 00000000..5ddf6530 --- /dev/null +++ b/design/src/main/java/com/urlaunched/android/design/ui/player/ui/MiniPlayerWrapper.kt @@ -0,0 +1,221 @@ +package com.urlaunched.android.design.ui.player.ui + +import androidx.compose.animation.AnimatedContent +import androidx.compose.animation.core.tween +import androidx.compose.animation.fadeIn +import androidx.compose.animation.fadeOut +import androidx.compose.animation.togetherWith +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.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.CompositionLocalProvider +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.layout.onSizeChanged +import androidx.compose.ui.platform.LocalLayoutDirection +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.style.TextOverflow +import androidx.compose.ui.unit.IntSize +import androidx.compose.ui.unit.LayoutDirection +import com.urlaunched.android.design.resources.dimens.Dimens +import com.urlaunched.android.design.ui.player.models.AudioPlayButtonColor +import com.urlaunched.android.design.ui.player.models.AudioPlayButtonDimens +import com.urlaunched.android.design.ui.player.models.AudioSliderColor +import com.urlaunched.android.design.ui.player.models.AudioSliderDimens +import com.urlaunched.android.design.ui.player.models.MiniPlayerColors +import com.urlaunched.android.design.ui.player.models.MiniPlayerConstants +import com.urlaunched.android.design.ui.player.models.MiniPlayerDimens +import com.urlaunched.android.design.ui.shimmer.shimmer + +@Composable +fun MiniPlayerWrapper( + // 🔷 Основні параметри + modifier: Modifier = Modifier, + currentChapterName: String?, + bookInfoText: String?, + isRtlEnabled: Boolean = false, + audioState: Any, + + // 🔤 Стилі + chapterTextStyle: TextStyle, + bookInfoTextStyle: TextStyle, + + // 🎨 Кольори, розміри, константи + miniPlayerColors: MiniPlayerColors = MiniPlayerColors(), + miniPlayerConstants: MiniPlayerConstants = MiniPlayerConstants(), + miniPlayerDimens: MiniPlayerDimens = MiniPlayerDimens(), + + // ▶️ Управління аудіо + onPlayAudioClick: () -> Unit, + onPlayerClick: () -> Unit, + onSizeChange: (IntSize) -> Unit, + + // 🔘 Кнопки + playingButton: @Composable () -> Unit, + pauseButton: @Composable () -> Unit, + rotateMinusButton: @Composable () -> Unit, + leadingContent: @Composable () -> Unit, + + // 🎚️ Прогрес і слайдер + audioProgress: Float, + audioSliderOnValueChange: (Float) -> Unit, + audioSliderColor: AudioSliderColor = AudioSliderColor(), + audioSliderDimens: AudioSliderDimens = AudioSliderDimens(), + + // ⏺️ Кнопка відтворення: стилі і розміри + audioPlayButtonColor: AudioPlayButtonColor = AudioPlayButtonColor(), + audioPlayButtonDimens: AudioPlayButtonDimens = AudioPlayButtonDimens(), + thumb: @Composable () -> Unit +) { + CompositionLocalProvider(LocalLayoutDirection provides if (isRtlEnabled) LayoutDirection.Rtl else LayoutDirection.Ltr) { + leadingContent() + + Column( + modifier = Modifier + .fillMaxWidth() + .clickable(onClick = onPlayerClick, indication = null, interactionSource = null) + ) { + Spacer(Modifier.height(miniPlayerDimens.sliderHalfHeightOffset)) + + Column( + modifier = Modifier + .fillMaxWidth() + .onSizeChanged(onSizeChange) + .background(color = miniPlayerColors.background) + ) { + Spacer(Modifier.height(Dimens.spacingNormalSpecial)) + + Row( + modifier = Modifier + .fillMaxWidth() + .background(color = miniPlayerColors.background) + .padding(end = Dimens.spacingNormal, start = Dimens.spacingExtraLarge), + verticalAlignment = Alignment.CenterVertically + ) { + val textAnimation = fadeIn( + animationSpec = tween( + durationMillis = miniPlayerConstants.defaultFadeInDuration, + delayMillis = miniPlayerConstants.defaultFadeInDelay + ) + ).togetherWith(fadeOut(animationSpec = tween(miniPlayerConstants.defaultFadeOutDuration))) + + Column( + modifier = Modifier.weight(1f), + verticalArrangement = Arrangement.spacedBy(Dimens.spacingSmallSpecial) + ) { + AnimatedContent( + targetState = currentChapterName, + transitionSpec = { textAnimation }, + label = miniPlayerConstants.chapterNameAnimationLabel + ) { chapterName -> + if (chapterName != null) { + Text( + modifier = Modifier.fillMaxWidth(), + text = chapterName, + style = chapterTextStyle, + color = miniPlayerColors.textColor, + maxLines = 1, + overflow = TextOverflow.Ellipsis + ) + } else { + Text( + modifier = Modifier + .fillMaxWidth() + .shimmer(), + text = miniPlayerConstants.emptyString, + style = chapterTextStyle + ) + } + } + + AnimatedContent( + targetState = bookInfoText, + transitionSpec = { textAnimation }, + label = miniPlayerConstants.chapterNameAnimationLabel + ) { bookName -> + if (bookName != null) { + Text( + modifier = Modifier.fillMaxWidth(), + text = bookName, + style = bookInfoTextStyle, + color = miniPlayerColors.textColor, + maxLines = 1, + overflow = TextOverflow.Ellipsis + ) + } else { + Text( + modifier = Modifier + .fillMaxWidth(0.6f) + .shimmer(), + text = miniPlayerConstants.emptyString, + style = bookInfoTextStyle + ) + } + } + } + + Spacer(modifier = Modifier.width(Dimens.spacingSmall)) + + rotateMinusButton() + + Spacer(modifier = Modifier.width(Dimens.spacingSmall)) + + AudioPlayButton( + audioPlayButtonDimens = audioPlayButtonDimens, + audioState = audioState, + onClick = onPlayAudioClick, + playingButton = playingButton, + pauseButton = pauseButton, + audioPlayButtonColor = audioPlayButtonColor + ) + } + + Spacer(modifier = Modifier.height(Dimens.spacingNormal)) + } + } + + Box( + contentAlignment = Alignment.Center, + modifier = Modifier.fillMaxWidth() + ) { + Row(modifier = Modifier.fillMaxWidth()) { + Box( + Modifier + .background(miniPlayerColors.leadingLineColor) + .height(Dimens.spacingTiny) + .width(Dimens.spacingNormal) + ) + + Box( + Modifier + .background(miniPlayerColors.trailingLineColor) + .height(Dimens.spacingTiny) + .weight(1f) + ) + } + + AudioSlider( + modifier = Modifier.height(miniPlayerDimens.audioSliderHeight), + audioProgress = audioProgress, + audioSliderDimens = audioSliderDimens, + audioSliderColor = audioSliderColor, + audioSliderOnValueChange = audioSliderOnValueChange, + thumb = thumb, + currentPositionText = {}, + timeLeftText = {} + ) + + Spacer(modifier = Modifier.height(Dimens.spacingNormal)) + } + } +} \ No newline at end of file diff --git a/design/src/main/java/com/urlaunched/android/design/ui/player/ui/PlayerWrapper.kt b/design/src/main/java/com/urlaunched/android/design/ui/player/ui/PlayerWrapper.kt index bc538abc..bbc05158 100644 --- a/design/src/main/java/com/urlaunched/android/design/ui/player/ui/PlayerWrapper.kt +++ b/design/src/main/java/com/urlaunched/android/design/ui/player/ui/PlayerWrapper.kt @@ -4,6 +4,7 @@ import androidx.compose.foundation.background import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.runtime.Composable import androidx.compose.runtime.CompositionLocalProvider @@ -12,6 +13,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalLayoutDirection import androidx.compose.ui.text.TextStyle import androidx.compose.ui.unit.LayoutDirection +import androidx.compose.ui.unit.dp import com.urlaunched.android.design.ui.player.models.BottomItemColors import com.urlaunched.android.design.ui.player.models.BottomBarItem import com.urlaunched.android.design.ui.player.models.AudioPlayButtonColor @@ -63,7 +65,7 @@ fun PlayerWrapper( currentPositionText: @Composable () -> Unit, timeLeftText: @Composable () -> Unit, - // — додатковий контент + // додатковий контент chapterDetails: @Composable () -> Unit, audioTrackDetails: @Composable () -> Unit ) { @@ -92,6 +94,7 @@ fun PlayerWrapper( CompositionLocalProvider(LocalLayoutDirection provides if (isRtlEnabled) LayoutDirection.Rtl else LayoutDirection.Ltr) { AudioSlider( + modifier = Modifier.padding(horizontal = audioSliderDimens.sliderTrackHorizontalPadding), audioProgress = audioProgress, audioSliderDimens = audioSliderDimens, audioSliderColor = audioSliderColor, @@ -99,7 +102,6 @@ fun PlayerWrapper( thumb = thumb, currentPositionText = currentPositionText, timeLeftText = timeLeftText - ) Player( @@ -113,7 +115,6 @@ fun PlayerWrapper( playingButton = playingButton, pauseButton = pauseButton, audioPlayButtonColor = audioPlayButtonColor - ) }