Skip to content

Commit

Permalink
Merge pull request #29 from enteraname74/develop
Browse files Browse the repository at this point in the history
v0.6.0
  • Loading branch information
enteraname74 authored May 3, 2024
2 parents c7cb8b7 + fc58931 commit 6131e47
Show file tree
Hide file tree
Showing 21 changed files with 437 additions and 119 deletions.
4 changes: 2 additions & 2 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
accompanist = "0.28.0"
accompanist-system-ui-controller = "0.30.1"
agp = "8.2.1"
android-version-name = "0.5.0"
android-version-code = "15"
android-version-name = "0.6.0"
android-version-code = "16"
android-target-sdk = "34"
android-compile-sdk = "34"
android-min-sdk = "26"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -131,14 +131,12 @@ class PlaybackManagerAndroidImpl(
}

override fun updateNotification() {
CoroutineScope(Dispatchers.IO).launch {
mediaSessionManager.updateMetadata()
mediaSessionManager.updateState()
mediaSessionManager.updateMetadata()
mediaSessionManager.updateState()

val intentForUpdatingNotification = Intent(PlayerService.SERVICE_BROADCAST)
intentForUpdatingNotification.putExtra(PlayerService.UPDATE_WITH_PLAYING_STATE, isPlaying)
context.sendBroadcast(intentForUpdatingNotification)
}
val intentForUpdatingNotification = Intent(PlayerService.SERVICE_BROADCAST)
intentForUpdatingNotification.putExtra(PlayerService.UPDATE_WITH_PLAYING_STATE, isPlaying)
context.sendBroadcast(intentForUpdatingNotification)
}

companion object {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import android.view.KeyEvent
import androidx.compose.ui.graphics.asAndroidBitmap
import com.github.soulsearching.R
import com.github.soulsearching.model.playback.PlaybackManagerAndroidImpl
import com.github.soulsearching.model.utils.AndroidUtils

/**
* Manage media session related things.
Expand All @@ -24,7 +25,12 @@ class MediaSessionManager(
private var mediaSession: MediaSessionCompat =
MediaSessionCompat(context, context.packageName + "soulSearchingMediaSession")

private val standardNotificationBitmap: Bitmap = BitmapFactory.decodeResource(context.resources, R.drawable.notification_default)
private val standardNotificationBitmap: Bitmap = Bitmap.createScaledBitmap(
BitmapFactory.decodeResource(context.resources, R.drawable.notification_default),
AndroidUtils.BITMAP_SIZE,
AndroidUtils.BITMAP_SIZE,
false
)

/**
* The token of the media session.
Expand Down Expand Up @@ -89,11 +95,8 @@ class MediaSessionManager(
* Update media session data with information the current played song in the player view model.
*/
fun updateMetadata() {
val bitmap = if (playbackManager.currentMusicCover != null) {
playbackManager.currentMusicCover!!.asAndroidBitmap()
} else {
standardNotificationBitmap
}
val bitmap = playbackManager.currentMusicCover?.asAndroidBitmap() ?: standardNotificationBitmap

mediaSession.setMetadata(
MediaMetadataCompat.Builder()
.putBitmap(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,15 @@ import android.content.IntentFilter
import android.media.AudioAttributes
import android.media.AudioFocusRequest
import android.media.AudioManager
import com.github.soulsearching.player.domain.model.SoulSearchingPlayer
import com.github.soulsearching.player.domain.model.PlaybackManager

/**
* Manage the audio of the application.
* Define if the application is able to play.
*/
class PlayerAudioManager(
private val context: Context,
private val player: SoulSearchingPlayer
private val playbackManager: PlaybackManager
): AudioManager.OnAudioFocusChangeListener {
private val audioManager = context.getSystemService(Context.AUDIO_SERVICE) as AudioManager
val audioAttributes: AudioAttributes = AudioAttributes.Builder()
Expand All @@ -30,7 +30,7 @@ class PlayerAudioManager(

private val audioBecomingNoisyReceiver: BroadcastReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
player.pause()
playbackManager.pause()
}
}

Expand Down Expand Up @@ -58,9 +58,9 @@ class PlayerAudioManager(

override fun onAudioFocusChange(focusChange: Int) {
when (focusChange) {
AudioManager.AUDIOFOCUS_GAIN -> player.play()
AudioManager.AUDIOFOCUS_LOSS -> player.pause()
else -> player.pause()
AudioManager.AUDIOFOCUS_GAIN -> playbackManager.play()
AudioManager.AUDIOFOCUS_LOSS -> playbackManager.pause()
else -> playbackManager.pause()
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ class SoulSearchingAndroidPlayerImpl(
private var player: MediaPlayer = MediaPlayer()
private var isOnlyLoadingMusic: Boolean = false
private var positionToReachWhenLoadingMusic: Int = 0
private val audioManager: PlayerAudioManager = PlayerAudioManager(context, this)
private val audioManager: PlayerAudioManager = PlayerAudioManager(context, playbackManager)

override fun init() {
audioManager.init()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,5 +93,7 @@ interface SoulSearchingSettings {

const val ARE_MUSICS_BY_FOLDERS_SHOWN = "ARE_MUSICS_BY_FOLDERS_SHOWN"
const val ARE_MUSICS_BY_MONTHS_SHOWN = "ARE_MUSICS_BY_MONTHS_SHOWN"

const val IS_PLAYER_SWIPE_ENABLED = "IS_PLAYER_SWIPE_ENABLED"
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package com.github.soulsearching.player.domain

import androidx.compose.animation.core.tween
import androidx.compose.material.ExperimentalMaterialApi
import androidx.compose.material.SwipeableState
import androidx.compose.ui.graphics.ImageBitmap
Expand All @@ -10,7 +9,6 @@ import com.github.enteraname74.domain.repository.MusicPlaylistRepository
import com.github.enteraname74.domain.repository.MusicRepository
import com.github.enteraname74.domain.repository.PlaylistRepository
import com.github.enteraname74.domain.util.LyricsProvider
import com.github.soulsearching.Constants
import com.github.soulsearching.colortheme.domain.model.ColorThemeManager
import com.github.soulsearching.domain.model.types.BottomSheetStates
import com.github.soulsearching.domain.utils.ColorPaletteUtils
Expand All @@ -20,7 +18,6 @@ import com.github.soulsearching.player.domain.model.PlaybackManager
import com.github.soulsearching.player.domain.model.PlayerMode
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.combine
Expand All @@ -40,7 +37,7 @@ class PlayerViewModelHandler(
private val playbackManager: PlaybackManager,
private val colorThemeManager: ColorThemeManager,
private val lyricsProvider: LyricsProvider,
private val coroutineScope: CoroutineScope
coroutineScope: CoroutineScope
) : ViewModelHandler {
private val _state = MutableStateFlow(PlayerState())

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -291,7 +291,7 @@ abstract class PlaybackManager(
* Return null if nothing is found.
* Return the first music if we are at the end of the playlist.
*/
private fun getNextMusic(currentIndex: Int): Music? {
fun getNextMusic(currentIndex: Int): Music? {
return if (playedList.isNotEmpty()) playedList[(currentIndex + 1) % playedList.size] else null
}

Expand All @@ -300,7 +300,7 @@ abstract class PlaybackManager(
* Return null if nothing is found.
* Return the last music if we are at the start of the playlist.
*/
private fun getPreviousMusic(currentIndex: Int): Music? {
fun getPreviousMusic(currentIndex: Int): Music? {
return if (playedList.isNotEmpty()) {
if (currentIndex == 0) {
playedList.last()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,19 +24,26 @@ import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.pager.HorizontalPager
import androidx.compose.foundation.pager.PagerState
import androidx.compose.foundation.pager.rememberPagerState
import androidx.compose.material.ExperimentalMaterialApi
import androidx.compose.material.SwipeableState
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.rounded.KeyboardArrowDown
import androidx.compose.material.swipeable
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.runtime.snapshotFlow
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.composed
Expand All @@ -53,6 +60,7 @@ import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.max
import androidx.compose.ui.unit.sp
import com.github.enteraname74.domain.model.ImageCover
import com.github.enteraname74.domain.model.Music
import com.github.soulsearching.Constants
import com.github.soulsearching.SoulSearchingContext
import com.github.soulsearching.colortheme.domain.model.ColorThemeManager
Expand All @@ -71,6 +79,8 @@ import com.github.soulsearching.player.domain.model.PlaybackManager
import com.github.soulsearching.player.presentation.composable.ExpandedPlayButtonsComposable
import com.github.soulsearching.player.presentation.composable.MinimisedPlayButtonsComposable
import com.github.soulsearching.playerpanel.presentation.PlayerPanelView
import com.github.soulsearching.settings.domain.ViewSettingsManager
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
Expand All @@ -95,7 +105,8 @@ fun PlayerDraggableView(
playerViewModel: PlayerViewModel,
coverList: ArrayList<ImageCover>,
playbackManager: PlaybackManager = injectElement(),
colorThemeManager: ColorThemeManager = injectElement()
colorThemeManager: ColorThemeManager = injectElement(),
viewSettingsManager: ViewSettingsManager = injectElement()
) {
val coroutineScope = rememberCoroutineScope()
val state by playerViewModel.handler.state.collectAsState()
Expand Down Expand Up @@ -235,7 +246,7 @@ fun PlayerDraggableView(
if (state.playedList.isEmpty() &&
draggableState.currentValue != BottomSheetStates.COLLAPSED &&
!draggableState.isAnimationRunning
) {
) {
coroutineScope.launch {
if (state.isMusicBottomSheetShown) {
playerViewModel.handler.onEvent(
Expand Down Expand Up @@ -520,14 +531,58 @@ fun PlayerDraggableView(
end = imagePaddingStart
)
) {
AppImage(
modifier = imageModifier,
bitmap =
retrieveCoverMethod(playbackManager.currentMusic?.coverId),
size = imageSize,
roundedPercent = (draggableState.offset.value / 100).roundToInt()
.coerceIn(3, 10)
)

var aroundSongs by remember {
mutableStateOf(listOf<Music?>())
}
aroundSongs = getAroundSongs(playbackManager = playbackManager)

if (
aroundSongs.filterNotNull().size > 1
&& draggableState.currentValue == BottomSheetStates.EXPANDED
&& viewSettingsManager.isPlayerSwipeEnabled
) {
val pagerState = remember(aroundSongs) {
object : PagerState(currentPage = 1) {
override val pageCount: Int = aroundSongs.size
}
}

LaunchedEffect(pagerState) {
snapshotFlow { pagerState.currentPage }.collect { page ->
CoroutineScope(Dispatchers.IO).launch {
when (page) {
0 -> playbackManager.previous()
2 -> playbackManager.next()
}
}
}
}

HorizontalPager(
state = pagerState,
pageSpacing = 120.dp
) { currentSongPos ->

AppImage(
modifier = imageModifier,
bitmap =
retrieveCoverMethod(aroundSongs.getOrNull(currentSongPos)?.coverId),
size = imageSize,
roundedPercent = (draggableState.offset.value / 100).roundToInt()
.coerceIn(3, 10)
)
}
} else {
AppImage(
modifier = imageModifier,
bitmap =
retrieveCoverMethod(playbackManager.currentMusic?.coverId),
size = imageSize,
roundedPercent = (draggableState.offset.value / 100).roundToInt()
.coerceIn(3, 10)
)
}
}

Column(
Expand All @@ -537,7 +592,7 @@ fun PlayerDraggableView(
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.SpaceBetween
) {
Row (
Row(
modifier = Modifier.fillMaxWidth(),
verticalAlignment = Alignment.CenterVertically
) {
Expand Down Expand Up @@ -781,6 +836,29 @@ fun PlayerDraggableView(
}
}

/**
* Retrieve a list containing the current song and its around songs (previous and next).
* If no songs are played, return a list containing null. If the played list contains only
* the current song, it will return a list with only the current song.
*/
private fun getAroundSongs(
playbackManager: PlaybackManager
): List<Music?> {
val currentSongIndex = playbackManager.currentMusicIndex

if (currentSongIndex == -1) return listOf(null)

if (playbackManager.playedList.size == 1) return listOf(
playbackManager.currentMusic
)

return listOf(
playbackManager.getPreviousMusic(currentSongIndex),
playbackManager.currentMusic,
playbackManager.getNextMusic(currentSongIndex)
)
}

private fun formatTextForEllipsis(text: String, orientation: ScreenOrientation): String {
if (orientation == ScreenOrientation.HORIZONTAL) {
return text
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,15 +89,17 @@ fun LyricsView(
state = rememberScrollState()
)
.padding(Constants.Spacing.medium),
verticalArrangement = Arrangement.spacedBy(Constants.Spacing.veryLarge)
verticalArrangement = Arrangement.SpaceBetween
) {
Text(
text = lyrics,
color = contentColor,
fontSize = 14.sp
)
Text(
modifier = Modifier.fillMaxWidth(),
modifier = Modifier
.fillMaxWidth()
.padding(top = Constants.Spacing.veryLarge),
text = strings.lyricsProvider,
fontSize = 12.sp,
color = subTextColor,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ class ViewSettingsManager(
var areMusicsByMonthsShown by mutableStateOf(false)
private set

var isPlayerSwipeEnabled by mutableStateOf(true)
private set

init {
initializeManager()
}
Expand Down Expand Up @@ -163,4 +166,15 @@ class ViewSettingsManager(
value = areMusicsByFoldersShown
)
}

/**
* Enable or disable the swipe to change current song on player view.
*/
fun togglePlayerSwipe() {
isPlayerSwipeEnabled = !isPlayerSwipeEnabled
settings.setBoolean(
key = SoulSearchingSettings.IS_PLAYER_SWIPE_ENABLED,
value = isPlayerSwipeEnabled
)
}
}
Loading

0 comments on commit 6131e47

Please sign in to comment.