Skip to content

Commit

Permalink
perf: Improved song info loading performance
Browse files Browse the repository at this point in the history
Signed-off-by: Gabriel Fontán <[email protected]>
  • Loading branch information
BobbyESP committed Apr 5, 2024
1 parent 844a4d4 commit 4f23f39
Show file tree
Hide file tree
Showing 6 changed files with 87 additions and 38 deletions.
8 changes: 4 additions & 4 deletions .idea/deploymentTargetSelector.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

22 changes: 22 additions & 0 deletions .idea/other.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@ package com.bobbyesp.metadator.model

import android.net.Uri
import android.os.Parcelable
import androidx.compose.runtime.Immutable
import com.bobbyesp.model.UriSerializer
import kotlinx.parcelize.Parcelize
import kotlinx.serialization.Serializable

@Parcelize
@Serializable
@Immutable
data class ParcelableSong(
val name: String,
val mainArtist: String,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,6 @@ import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.viewModelScope
import com.bobbyesp.ext.joinOrNullToString
import com.bobbyesp.ext.toMinutes
import com.bobbyesp.metadator.R
Expand Down Expand Up @@ -79,13 +78,10 @@ fun ID3MetadataEditorPage(

var propertiesCopy = viewModel.propertiesCopy.value

val vmScope = viewModel.viewModelScope
LaunchedEffect(true) {
vmScope.launch(vmScope.coroutineContext + Dispatchers.IO) {
viewModel.loadTrackMetadata(
path = parcelableSong.localSongPath!!
)
}
LaunchedEffect(parcelableSong.localSongPath) {
viewModel.loadTrackMetadata(
path = parcelableSong.localSongPath!!
)
}

val sendActivityIntent =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,27 @@ import android.content.Context
import android.os.Build
import android.util.Log
import androidx.compose.runtime.mutableStateOf
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.SpanStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.bobbyesp.metadator.R
import com.bobbyesp.utilities.mediastore.AudioFileMetadata
import com.bobbyesp.utilities.mediastore.MediaStoreReceiver
import com.bobbyesp.utilities.mediastore.MetadataChangesDiff
import com.kyant.taglib.AudioPropertiesReadStyle
import com.kyant.taglib.Metadata
import com.kyant.taglib.TagLib
import dagger.hilt.android.lifecycle.HiltViewModel
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.io.IOException
import javax.inject.Inject

Expand All @@ -32,36 +42,42 @@ class ID3MetadataEditorPageViewModel @Inject constructor(
data class PageViewState(
val metadata: Metadata? = null,
val state: ID3MetadataEditorPageState = ID3MetadataEditorPageState.Loading,
val lyrics: String = "",
)

fun loadTrackMetadata(path: String) {
suspend fun loadTrackMetadata(path: String) {
updateState(ID3MetadataEditorPageState.Loading)
try {
kotlin.runCatching {
MediaStoreReceiver.getFileDescriptorFromPath(context, path, mode = "r")?.use { songFd ->
val fd = songFd.dup()?.detachFd() ?: throw IOException("File descriptor is null")
val metadata = TagLib.getMetadata(
fd,
readStyle = AudioPropertiesReadStyle.Fast
)
val fd = songFd.dup()?.detachFd()
?: throw IllegalStateException("File descriptor is null")

val metadataDeferred =
withContext(viewModelScope.coroutineContext + Dispatchers.IO) {
async {
TagLib.getMetadata(
fd,
readStyle = AudioPropertiesReadStyle.Fast
)
}
}

val metadata = metadataDeferred.await()

if (metadata == null) {
updateState(ID3MetadataEditorPageState.Error(Exception("Metadata is null")))
return
}

val lyrics = metadata.propertyMap["LYRICS"]?.get(0) ?: ""

updateLyrics(lyrics)
updateMetadata(metadata)

updateState(ID3MetadataEditorPageState.Success(metadata))
}
} catch (e: IOException) {
}.onFailure { error ->
Log.e(
"ID3MetadataEditorPageViewModel",
"Error while trying to load metadata: ${e.message}"
"Error while trying to load metadata: ${error.message}"
)
updateState(ID3MetadataEditorPageState.Error(e))
updateState(ID3MetadataEditorPageState.Error(error))
}
}

Expand All @@ -74,8 +90,12 @@ class ID3MetadataEditorPageViewModel @Inject constructor(
?.dup()?.detachFd()
?: throw IOException("File descriptor is null")

TagLib.savePropertyMap(fd, propertyMap = newMetadata.propertyMap)
updateState(ID3MetadataEditorPageState.Success(newMetadata))
viewModelScope.launch(Dispatchers.IO) {
TagLib.savePropertyMap(
fd,
propertyMap = newMetadata.propertyMap
)
}
true
} catch (securityException: SecurityException) {
handleSecurityException(securityException, intentPassthrough)
Expand Down Expand Up @@ -105,19 +125,30 @@ class ID3MetadataEditorPageViewModel @Inject constructor(
}
}


private fun updateState(state: ID3MetadataEditorPageState) {
mutablePageViewState.update {
it.copy(
state = state
)
fun generateUnsavedChangesText(
context: Context,
changes: MetadataChangesDiff
): AnnotatedString {
val builder = AnnotatedString.Builder()
val localizedInfoText = context.getString(R.string.unsaved_changes_info)
builder.append("$localizedInfoText \n")

changes.forEach { (key, value) ->
val start = builder.length
builder.append("$key: ")
val end = builder.length
builder.addStyle(SpanStyle(fontWeight = FontWeight.Bold), start, end)
builder.append("${value.first?.joinToString()} -> ${value.second?.joinToString()}\n")
}

return builder.toAnnotatedString()
}

private fun updateLyrics(lyrics: String) {

private fun updateState(state: ID3MetadataEditorPageState) {
mutablePageViewState.update {
it.copy(
lyrics = lyrics
state = state
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,13 @@ package com.bobbyesp.metadator.presentation.pages.utilities.tageditor

import androidx.compose.foundation.layout.Column
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import com.bobbyesp.metadator.R

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun MediaStoreInfoDialog(
modifier: Modifier = Modifier,
Expand Down

0 comments on commit 4f23f39

Please sign in to comment.