Skip to content

Commit

Permalink
feat/WIP: Added Spotify metadata retrieve
Browse files Browse the repository at this point in the history
Signed-off-by: Gabriel Fontán <[email protected]>
  • Loading branch information
BobbyESP committed May 19, 2024
1 parent 73d2945 commit 1a05385
Show file tree
Hide file tree
Showing 10 changed files with 358 additions and 32 deletions.
59 changes: 59 additions & 0 deletions app/src/main/java/com/bobbyesp/metadator/ext/String.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package com.bobbyesp.metadator.ext

import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.rounded.Album
import androidx.compose.material.icons.rounded.CalendarMonth
import androidx.compose.material.icons.rounded.GeneratingTokens
import androidx.compose.material.icons.rounded.Numbers
import androidx.compose.material.icons.rounded.Person
import androidx.compose.material.icons.rounded.RunningWithErrors
import androidx.compose.material.icons.rounded.Subtitles
import androidx.compose.material.icons.rounded.Title
import androidx.compose.runtime.Composable
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.res.stringResource
import com.bobbyesp.metadator.R

object TagLib {
@Composable
fun String.toLocalizedName(): String {
return when (this) {
"TITLE" -> stringResource(id = R.string.title)
"ARTIST" -> stringResource(id = R.string.artist)
"ALBUM" -> stringResource(id = R.string.album)
"ALBUMARTIST" -> stringResource(id = R.string.album_artist)
"TRACKNUMBER" -> stringResource(id = R.string.track_number)
"DISCNUMBER" -> stringResource(id = R.string.disc_number)
"DATE" -> stringResource(id = R.string.date)
"GENRE" -> stringResource(id = R.string.genre)
"COMPOSER" -> stringResource(id = R.string.composer)
"LYRICIST" -> stringResource(id = R.string.lyricist)
"PERFORMER" -> stringResource(id = R.string.performer)
"CONDUCTOR" -> stringResource(id = R.string.conductor)
"REMIXER" -> stringResource(id = R.string.remixer)
"COMMENT" -> stringResource(id = R.string.comment)
else -> this
}
}

@Composable
fun String.toImageVector(): ImageVector {
return when (this) {
"TITLE" -> Icons.Rounded.Title
"ARTIST" -> Icons.Rounded.Person
"ALBUM" -> Icons.Rounded.Album
"ALBUMARTIST" -> Icons.Rounded.Person
"TRACKNUMBER" -> Icons.Rounded.Numbers
"DISCNUMBER" -> Icons.Rounded.Numbers
"DATE" -> Icons.Rounded.CalendarMonth
"GENRE" -> Icons.Rounded.GeneratingTokens
"COMPOSER" -> Icons.Rounded.Person
"LYRICIST" -> Icons.Rounded.Person
"PERFORMER" -> Icons.Rounded.Person
"CONDUCTOR" -> Icons.Rounded.Person
"REMIXER" -> Icons.Rounded.Person
"COMMENT" -> Icons.Rounded.Subtitles
else -> Icons.Rounded.RunningWithErrors
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package com.bobbyesp.metadator.presentation.pages.utilities.tageditor

import android.app.Activity
import android.net.Uri
import android.util.Log
import androidx.activity.compose.BackHandler
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.IntentSenderRequest
Expand Down Expand Up @@ -100,7 +101,6 @@ fun ID3MetadataEditorPage(
val metadata = viewState.metadata
val modifiablePropertyMap = viewState.metadata?.propertyMap?.toModifiableMap()


var newArtworkAddress by remember {
mutableStateOf<Uri?>(null)
}
Expand All @@ -116,10 +116,10 @@ fun ID3MetadataEditorPage(
rememberLauncherForActivityResult(contract = ActivityResultContracts.StartIntentSenderForResult()) { result ->
if (result.resultCode == Activity.RESULT_OK) {
scope.launch(Dispatchers.IO) {
modifiablePropertyMap?.let {
modifiablePropertyMap?.let { newMetadata ->
viewModel.saveMetadata(
newMetadata = viewState.metadata.copy(
propertyMap = it.toAudioFileMetadata().toPropertyMap()
propertyMap = newMetadata.toAudioFileMetadata().toPropertyMap()
), path = path!!, imageUri = newArtworkAddress
)
}
Expand Down Expand Up @@ -173,7 +173,6 @@ fun ID3MetadataEditorPage(
IconButton(onClick = {
scope.launch {
scaffoldState.bottomSheetState.partialExpand()
//TODO: Add other things (if is I/O, use withContext(Dispatchers.IO) { ... })
}
}) {
Icon(
Expand All @@ -184,7 +183,8 @@ fun ID3MetadataEditorPage(
)
}
TextButton(onClick = {
if (saveInMediaStore()) {
val isInfoSavedInMediaStore = saveInMediaStore()
if (isInfoSavedInMediaStore) {
navController.popBackStack()
}
}) {
Expand All @@ -200,7 +200,17 @@ fun ID3MetadataEditorPage(
SpMetadataBottomSheetContent(
name = modifiablePropertyMap?.get("TITLE") ?: "",
artist = modifiablePropertyMap?.get("ARTIST") ?: "",
state = scaffoldState.bottomSheetState
state = scaffoldState.bottomSheetState,
onUpdateMetadata = { modifiedFields ->
modifiablePropertyMap?.putAll(modifiedFields)
Log.i("ID3MetadataEditorPage", "Modified fields: $modifiedFields")
viewModel.updateStatePropertyMap(modifiedFields)
},
onCloseSheet = {
scope.launch {
scaffoldState.bottomSheetState.hide()
}
}
)
}) { innerPadding ->
Crossfade(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@ import android.os.Build
import android.util.Log
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.adamratzman.spotify.models.Track
import com.bobbyesp.metadator.features.spotify.domain.repositories.SearchRepository
import com.bobbyesp.ext.toModifiableMap
import com.bobbyesp.utilities.mediastore.AudioFileMetadata.Companion.toAudioFileMetadata
import com.bobbyesp.utilities.mediastore.AudioFileMetadata.Companion.toPropertyMap
import com.bobbyesp.utilities.mediastore.MediaStoreReceiver
import com.kyant.taglib.AudioProperties
import com.kyant.taglib.AudioPropertiesReadStyle
Expand All @@ -31,7 +32,6 @@ import javax.inject.Inject
@HiltViewModel
class ID3MetadataEditorPageViewModel @Inject constructor(
@ApplicationContext private val context: Context,
private val searchRepository: SearchRepository
) : ViewModel() {
private val mutablePageViewState = MutableStateFlow(PageViewState())
val pageViewState = mutablePageViewState.asStateFlow()
Expand Down Expand Up @@ -152,16 +152,20 @@ class ID3MetadataEditorPageViewModel @Inject constructor(
}
}

suspend fun getSpotifyResults(query: String): List<Track> {
val result = searchRepository.searchTracks(query)
return if (result.isSuccess) {
result.getOrNull() ?: emptyList()
} else {
result.exceptionOrNull()?.printStackTrace()
emptyList()
fun updateStatePropertyMap(propertyMap: Map<String, String>) {
val mutableStateMap = mutablePageViewState.value.metadata?.propertyMap?.toModifiableMap()
val updatedPropertyMap = mutableStateMap?.apply {
putAll(propertyMap)
} ?: propertyMap

mutablePageViewState.update {
it.copy(
metadata = it.metadata?.copy(
propertyMap = updatedPropertyMap.toAudioFileMetadata().toPropertyMap()
)
)
}
}

private fun updateState(state: ID3MetadataEditorPageState) {
mutablePageViewState.update {
it.copy(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,16 @@ import com.bobbyesp.metadator.presentation.pages.utilities.tageditor.spotify.sta
import com.bobbyesp.ui.motion.MotionConstants.DURATION_EXIT_SHORT
import com.bobbyesp.ui.motion.tweenEnter
import com.bobbyesp.ui.motion.tweenExit
import kotlinx.coroutines.flow.collectLatest

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun SpMetadataBottomSheetContent(
name: String,
artist: String,
state: SheetState,
onUpdateMetadata: (modifiedFields: Map<String, String>) -> Unit,
onCloseSheet: () -> Unit,
viewModel: SpMetadataBottomSheetContentViewModel = hiltViewModel()
) {
val viewState = viewModel.viewStateFlow.collectAsStateWithLifecycle().value
Expand All @@ -53,6 +56,16 @@ fun SpMetadataBottomSheetContent(
}
}

LaunchedEffect(key1 = true) {
viewModel.eventFlow.collectLatest { event ->
when (event) {
is SpMetadataBottomSheetContentViewModel.Events.SaveMetadata -> {
onUpdateMetadata(event.modifiedFields)
}
}
}
}

AnimatedContent(targetState = bottomSheetState,
label = "Transition between bs states",
transitionSpec = {
Expand All @@ -71,7 +84,9 @@ fun SpMetadataBottomSheetContent(

BottomSheetStage.TRACK_DETAILS -> {
SpMetadataBsDetails(
modifier = Modifier.fillMaxSize(), viewModel = viewModel
modifier = Modifier.fillMaxSize(),
viewModel = viewModel,
onCloseSheet = onCloseSheet
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@ import com.bobbyesp.metadator.features.spotify.domain.services.SpotifyService
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asSharedFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.emptyFlow
import kotlinx.coroutines.flow.update
Expand All @@ -35,6 +37,9 @@ class SpMetadataBottomSheetContentViewModel @Inject constructor(
private val mutableViewStateFlow = MutableStateFlow(ViewState())
val viewStateFlow = mutableViewStateFlow.asStateFlow()

private val _eventFlow = MutableSharedFlow<Events>()
val eventFlow = _eventFlow.asSharedFlow()

data class ViewState(
val stage: BottomSheetStage = BottomSheetStage.SEARCH,
val searchedTracks: Flow<PagingData<Track>> = emptyFlow(),
Expand Down Expand Up @@ -97,14 +102,24 @@ class SpMetadataBottomSheetContentViewModel @Inject constructor(
}
}

fun updateQuery(query: String) {
fun saveMetadata(modifiedFields: Map<String, String>) {
viewModelScope.launch {
_eventFlow.emit(Events.SaveMetadata(modifiedFields))
}
}

private fun updateQuery(query: String) {
mutableViewStateFlow.update {
it.copy(
lastQuery = query
)
}
}

sealed class Events {
data class SaveMetadata(val modifiedFields: Map<String, String>) : Events()
}

companion object {
enum class BottomSheetStage {
SEARCH,
Expand Down
Loading

0 comments on commit 1a05385

Please sign in to comment.