Skip to content
This repository has been archived by the owner on Aug 7, 2024. It is now read-only.

Commit

Permalink
Merge pull request #257 from SuhasDissa/mini-player
Browse files Browse the repository at this point in the history
fix: unresponsive mini player
  • Loading branch information
SuhasDissa authored Feb 14, 2024
2 parents 1d93637 + 234cf92 commit f9f5069
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 118 deletions.
111 changes: 48 additions & 63 deletions app/src/main/java/com/bnyro/recorder/ui/components/MiniPlayer.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package com.bnyro.recorder.ui.components

import android.text.format.DateUtils
import android.view.SoundEffectConstants
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
Expand All @@ -14,10 +13,9 @@ import androidx.compose.material.icons.filled.PlayArrow
import androidx.compose.material3.ElevatedCard
import androidx.compose.material3.FloatingActionButton
import androidx.compose.material3.Icon
import androidx.compose.material3.Slider
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
Expand All @@ -27,14 +25,26 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalView
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.documentfile.provider.DocumentFile
import androidx.lifecycle.viewmodel.compose.viewModel
import com.bnyro.recorder.R
import com.bnyro.recorder.ui.models.PlayerModel
import kotlinx.coroutines.delay
import com.google.android.exoplayer2.MediaItem
import com.google.android.exoplayer2.Player

@Composable
fun MiniPlayer(playerModel: PlayerModel = viewModel()) {
fun MiniPlayer(inputFile: DocumentFile, playerModel: PlayerModel = viewModel()) {
val view = LocalView.current
DisposableEffect(inputFile) {
with(playerModel.player) {
val mediaItem = MediaItem.Builder().setUri(inputFile.uri).build()
setMediaItem(mediaItem)
playWhenReady = true
prepare()
onDispose {
stop()
}
}
}
ElevatedCard(
modifier = Modifier
.height(140.dp)
Expand All @@ -47,77 +57,52 @@ fun MiniPlayer(playerModel: PlayerModel = viewModel()) {
Row(
verticalAlignment = Alignment.CenterVertically
) {
val fileName = playerModel.currentPlayingFile?.name.orEmpty()
val fileName = inputFile.name.orEmpty()
Text(
modifier = Modifier.weight(1f),
text = fileName.substringBeforeLast(".").takeIf {
it.isNotBlank()
} ?: fileName
)
FloatingActionButton(
onClick = {
view.playSoundEffect(SoundEffectConstants.CLICK)
if (playerModel.isPlaying) {
playerModel.pausePlaying()
with(playerModel.player) {

var playState by remember { mutableStateOf(false) }

DisposableEffect(key1 = this) {
val listener = object : Player.Listener {
override fun onIsPlayingChanged(isPlaying: Boolean) {
playState = isPlaying
}
}
addListener(listener)
onDispose {
removeListener(listener)
}
}
FloatingActionButton(
onClick = {
view.playSoundEffect(SoundEffectConstants.CLICK)
playPause()
}
) {
if (playState) {
Icon(
Icons.Default.Pause,
contentDescription = stringResource(id = com.bnyro.recorder.R.string.pause)
)
} else {
playerModel.resumePlaying()
Icon(
Icons.Default.PlayArrow,
contentDescription = stringResource(id = com.bnyro.recorder.R.string.play)
)
}
}
) {
Icon(
if (playerModel.isPlaying) Icons.Default.Pause else Icons.Default.PlayArrow,
contentDescription = stringResource(
if (playerModel.isPlaying) R.string.pause else R.string.resume
)
)
}
}

Spacer(modifier = Modifier.height(10.dp))

playerModel.player?.let { player ->
var position by remember {
mutableStateOf(0)
}

LaunchedEffect(Unit) {
while (true) {
runCatching {
position = player.currentPosition
}
delay(50)
}
}

Row(
verticalAlignment = Alignment.CenterVertically
) {
val duration = player.duration.toFloat()
Text(
text = DateUtils.formatElapsedTime(
(position / 1000).toLong()
)
)
Slider(
modifier = Modifier
.padding(horizontal = 10.dp)
.weight(1f),
value = position.toFloat(),
onValueChange = {
runCatching {
player.seekTo(it.toInt())
position = it.toInt()
}
},
valueRange = 0f..duration
)
Text(
text = DateUtils.formatElapsedTime(
(duration / 1000).toLong()
)
)
}
}
PlayerController(exoPlayer = playerModel.player)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.documentfile.provider.DocumentFile
Expand All @@ -39,10 +38,10 @@ fun RecordingItemList(
isVideoList: Boolean,
playerModel: PlayerModel = viewModel()
) {
val context = LocalContext.current
val icon = if (isVideoList) Icons.Default.VideoFile else Icons.Default.AudioFile
var chosenFile by remember { mutableStateOf<DocumentFile?>(null) }
var showTrimmer by remember { mutableStateOf(false) }
var showMiniPlayer by remember { mutableStateOf(false) }
if (items.isNotEmpty()) {
Column {
LazyColumn(
Expand Down Expand Up @@ -71,17 +70,18 @@ fun RecordingItemList(
showTrimmer = true
}
) {
playerModel.startPlaying(context, it.recordingFile)
chosenFile = it.recordingFile
showMiniPlayer = true
}
}
}
if (!isVideoList) {
if (!isVideoList && chosenFile != null) {
AnimatedVisibility(
modifier = Modifier
.padding(bottom = 10.dp),
visible = playerModel.currentPlayingFile != null
visible = showMiniPlayer
) {
MiniPlayer()
MiniPlayer(chosenFile!!)
}
}
}
Expand Down
54 changes: 5 additions & 49 deletions app/src/main/java/com/bnyro/recorder/ui/models/PlayerModel.kt
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
package com.bnyro.recorder.ui.models

import android.content.Context
import android.media.MediaPlayer
import android.util.Log
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
Expand All @@ -16,13 +14,11 @@ import com.bnyro.recorder.App
import com.bnyro.recorder.enums.SortOrder
import com.bnyro.recorder.obj.RecordingItemData
import com.bnyro.recorder.util.FileRepository
import com.bnyro.recorder.util.PlayerHelper
import java.io.IOException
import com.google.android.exoplayer2.ExoPlayer
import kotlinx.coroutines.launch

class PlayerModel(private val fileRepository: FileRepository) : ViewModel() {
var isPlaying by mutableStateOf(false)
var player by mutableStateOf<MediaPlayer?>(null)
class PlayerModel(context: Context, private val fileRepository: FileRepository) : ViewModel() {
var player = ExoPlayer.Builder(context).build()
var currentPlayingFile by mutableStateOf<DocumentFile?>(null)

var selectedFiles by mutableStateOf(listOf<RecordingItemData>())
Expand Down Expand Up @@ -62,55 +58,15 @@ class PlayerModel(private val fileRepository: FileRepository) : ViewModel() {
}
}

fun startPlaying(context: Context, file: DocumentFile) {
stopPlaying()

currentPlayingFile = file
player = getMediaPlayer().apply {
try {
context.contentResolver.openFileDescriptor(file.uri, "r")?.use {
setDataSource(it.fileDescriptor)
}
prepare()
start()
} catch (e: IOException) {
Log.e("reading file", e.toString())
}
}
player?.setOnCompletionListener {
stopPlaying()
}
isPlaying = true
}

fun stopPlaying() {
currentPlayingFile = null
player?.release()
player = null
isPlaying = false
}

fun pausePlaying() {
player?.pause()
isPlaying = false
}

fun resumePlaying() {
player?.start()
isPlaying = true
}

private fun getMediaPlayer(): MediaPlayer {
return MediaPlayer().apply {
setAudioAttributes(PlayerHelper.getAudioAttributes())
}
player.stop()
}

companion object {
val Factory = viewModelFactory {
initializer {
val application = (this[APPLICATION_KEY] as App)
PlayerModel(application.fileRepository)
PlayerModel(application, application.fileRepository)
}
}
}
Expand Down

0 comments on commit f9f5069

Please sign in to comment.