Add store favorites songs; swipe to favorite & load on search result sorted
This commit is contained in:
parent
f85dfd9e9d
commit
57cbb3e441
4 changed files with 214 additions and 75 deletions
|
|
@ -126,7 +126,7 @@ class AndroidFileRepository(private val context: Context) : FileRepository {
|
||||||
val shortDisplayPath = longPathToShort(displayPath)
|
val shortDisplayPath = longPathToShort(displayPath)
|
||||||
|
|
||||||
val message = if (shortDisplayPath.endsWith(".json", ignoreCase = true)) {
|
val message = if (shortDisplayPath.endsWith(".json", ignoreCase = true)) {
|
||||||
"Playlist mise à jour"
|
"${shortDisplayPath.substringBeforeLast(".").replaceFirstChar { it.uppercase() }} mis à jour"
|
||||||
} else {
|
} else {
|
||||||
"Sauvegarde réussie dans : $shortDisplayPath"
|
"Sauvegarde réussie dans : $shortDisplayPath"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ package mg.dot.feufaro.ui
|
||||||
import SharedScreenModel
|
import SharedScreenModel
|
||||||
import androidx.compose.animation.*
|
import androidx.compose.animation.*
|
||||||
import androidx.compose.animation.core.animateDpAsState
|
import androidx.compose.animation.core.animateDpAsState
|
||||||
|
import androidx.compose.animation.core.animateFloatAsState
|
||||||
import androidx.compose.foundation.*
|
import androidx.compose.foundation.*
|
||||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||||
import androidx.compose.foundation.layout.*
|
import androidx.compose.foundation.layout.*
|
||||||
|
|
@ -15,6 +16,7 @@ import androidx.compose.foundation.text.KeyboardOptions
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.automirrored.filled.KeyboardArrowLeft
|
import androidx.compose.material.icons.automirrored.filled.KeyboardArrowLeft
|
||||||
import androidx.compose.material.icons.automirrored.filled.KeyboardArrowRight
|
import androidx.compose.material.icons.automirrored.filled.KeyboardArrowRight
|
||||||
|
import androidx.compose.material.icons.automirrored.filled.PlaylistAdd
|
||||||
import androidx.compose.material.icons.automirrored.filled.Undo
|
import androidx.compose.material.icons.automirrored.filled.Undo
|
||||||
import androidx.compose.material.icons.filled.*
|
import androidx.compose.material.icons.filled.*
|
||||||
import androidx.compose.material3.*
|
import androidx.compose.material3.*
|
||||||
|
|
@ -22,6 +24,7 @@ import androidx.compose.runtime.*
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.alpha
|
import androidx.compose.ui.draw.alpha
|
||||||
|
import androidx.compose.ui.draw.scale
|
||||||
import androidx.compose.ui.focus.FocusRequester
|
import androidx.compose.ui.focus.FocusRequester
|
||||||
import androidx.compose.ui.focus.focusRequester
|
import androidx.compose.ui.focus.focusRequester
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
|
|
@ -46,6 +49,7 @@ import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
|
import mg.dot.feufaro.data.DrawerItem
|
||||||
import mg.dot.feufaro.getPlatform
|
import mg.dot.feufaro.getPlatform
|
||||||
import mg.dot.feufaro.pdf.PrintSettings
|
import mg.dot.feufaro.pdf.PrintSettings
|
||||||
import mg.dot.feufaro.pdf.defaultPrintSettings
|
import mg.dot.feufaro.pdf.defaultPrintSettings
|
||||||
|
|
@ -283,7 +287,8 @@ fun MainScreenWithDrawer(
|
||||||
if (showAboutDialog) {
|
if (showAboutDialog) {
|
||||||
AboutDialog(onDismiss = { showAboutDialog = false })
|
AboutDialog(onDismiss = { showAboutDialog = false })
|
||||||
}
|
}
|
||||||
val favoritePaths by sharedScreenModel.playlistItems.collectAsState()
|
val playlistPaths by sharedScreenModel.playlistItems.collectAsState()
|
||||||
|
val favoritePaths by sharedScreenModel.favItems.collectAsState()
|
||||||
|
|
||||||
val keyboardController = LocalSoftwareKeyboardController.current
|
val keyboardController = LocalSoftwareKeyboardController.current
|
||||||
var isNumericKeyboard by remember { mutableStateOf(true) }
|
var isNumericKeyboard by remember { mutableStateOf(true) }
|
||||||
|
|
@ -1028,9 +1033,34 @@ fun MainScreenWithDrawer(
|
||||||
modifier = Modifier.fillMaxHeight()
|
modifier = Modifier.fillMaxHeight()
|
||||||
) {
|
) {
|
||||||
val sortedSongs = remember(filteredSongs) {
|
val sortedSongs = remember(filteredSongs) {
|
||||||
filteredSongs.sortedBy { item ->
|
filteredSongs.sortedWith(
|
||||||
item.path.startsWith("assets://")
|
compareBy<DrawerItem> { item ->
|
||||||
|
!item.path.startsWith("assets://")
|
||||||
|
}.thenComparing { a, b ->
|
||||||
|
val regex = Regex("(?<=\\D)(?=\\d)|(?<=\\d)(?=\\D)")
|
||||||
|
val chunksA = a.title.lowercase().split(regex)
|
||||||
|
val chunksB = b.title.lowercase().split(regex)
|
||||||
|
var result = 0
|
||||||
|
val size = minOf(chunksA.size, chunksB.size)
|
||||||
|
for (i in 0 until size) {
|
||||||
|
val chunkA = chunksA[i]
|
||||||
|
val chunkB = chunksB[i]
|
||||||
|
val numA = chunkA.toLongOrNull()
|
||||||
|
val numB = chunkB.toLongOrNull()
|
||||||
|
result = if (numA != null && numB != null) {
|
||||||
|
numA.compareTo(numB)
|
||||||
|
} else {
|
||||||
|
chunkA.compareTo(chunkB)
|
||||||
}
|
}
|
||||||
|
if (result != 0) break
|
||||||
|
}
|
||||||
|
if (result == 0) {
|
||||||
|
chunksA.size.compareTo(chunksB.size)
|
||||||
|
} else {
|
||||||
|
result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
LazyColumn(Modifier.fillMaxSize()) {
|
LazyColumn(Modifier.fillMaxSize()) {
|
||||||
if (sortedSongs.isEmpty() && textInput.isNotEmpty()) {
|
if (sortedSongs.isEmpty() && textInput.isNotEmpty()) {
|
||||||
|
|
@ -1063,6 +1093,48 @@ fun MainScreenWithDrawer(
|
||||||
}
|
}
|
||||||
itemsIndexed(sortedSongs, key = { _, item -> item.path }) { index, item ->
|
itemsIndexed(sortedSongs, key = { _, item -> item.path }) { index, item ->
|
||||||
val isFavorite = favoritePaths.contains(item)
|
val isFavorite = favoritePaths.contains(item)
|
||||||
|
val onPlaylist = playlistPaths.contains(item)
|
||||||
|
val dismissState = rememberSwipeToDismissBoxState(
|
||||||
|
confirmValueChange = { dismissValue ->
|
||||||
|
if (dismissValue == SwipeToDismissBoxValue.StartToEnd || dismissValue == SwipeToDismissBoxValue.EndToStart) {
|
||||||
|
sharedScreenModel.toFavorite(item.path)
|
||||||
|
sharedScreenModel.updateSearchTxt("")
|
||||||
|
sharedScreenModel.reset()
|
||||||
|
solfaScreenModel.loadFromFile(item.path)
|
||||||
|
sharedScreenModel.stopMidi()
|
||||||
|
sharedScreenModel.seekTo(0f)
|
||||||
|
sharedScreenModel.setTranspositionInterval(0)
|
||||||
|
false
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
SwipeToDismissBox(
|
||||||
|
state = dismissState,
|
||||||
|
backgroundContent = {
|
||||||
|
val color = if (isFavorite) Color.Gray else MaterialTheme.colorScheme.tertiary
|
||||||
|
val scale by animateFloatAsState(
|
||||||
|
targetValue = if (dismissState.progress > 0.1f) 1.2f else 0.8f,
|
||||||
|
label = "iconScale"
|
||||||
|
)
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.background(color)
|
||||||
|
.padding(horizontal = 20.dp),
|
||||||
|
contentAlignment = if (dismissState.dismissDirection == SwipeToDismissBoxValue.StartToEnd)
|
||||||
|
Alignment.CenterStart else Alignment.CenterEnd
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
imageVector = if (isFavorite) Icons.Default.FavoriteBorder else Icons.Default.Favorite,
|
||||||
|
contentDescription = null,
|
||||||
|
modifier = Modifier.scale(scale),
|
||||||
|
tint = MaterialTheme.colorScheme.onSecondary
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
) {
|
||||||
ListItem(
|
ListItem(
|
||||||
leadingContent = {
|
leadingContent = {
|
||||||
Icon(
|
Icon(
|
||||||
|
|
@ -1075,13 +1147,13 @@ fun MainScreenWithDrawer(
|
||||||
supportingContent = { Text(item.contentTitle, maxLines = 1) },
|
supportingContent = { Text(item.contentTitle, maxLines = 1) },
|
||||||
trailingContent = {
|
trailingContent = {
|
||||||
IconButton(
|
IconButton(
|
||||||
onClick = { sharedScreenModel.toggleFavorite(item.path) },
|
onClick = { sharedScreenModel.toPlaylist(item.path) },
|
||||||
modifier = Modifier.size(25.dp)
|
modifier = Modifier.size(35.dp)
|
||||||
) {
|
) {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = Icons.Default.Star,
|
imageVector = Icons.AutoMirrored.Default.PlaylistAdd,
|
||||||
contentDescription = null,
|
contentDescription = null,
|
||||||
tint = if (!isFavorite) Color.LightGray else Color(
|
tint = if (!onPlaylist) Color.LightGray else Color(
|
||||||
0xFFFFD700
|
0xFFFFD700
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
@ -1095,6 +1167,7 @@ fun MainScreenWithDrawer(
|
||||||
sharedScreenModel.seekTo(0f)
|
sharedScreenModel.seekTo(0f)
|
||||||
sharedScreenModel.setTranspositionInterval(0)
|
sharedScreenModel.setTranspositionInterval(0)
|
||||||
})
|
})
|
||||||
|
}
|
||||||
HorizontalDivider()
|
HorizontalDivider()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,10 +23,8 @@ import androidx.compose.ui.draw.rotate
|
||||||
import androidx.compose.ui.draw.scale
|
import androidx.compose.ui.draw.scale
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.graphics.vector.ImageVector
|
import androidx.compose.ui.graphics.vector.ImageVector
|
||||||
import androidx.compose.ui.text.TextStyle
|
|
||||||
import androidx.compose.ui.text.font.FontStyle
|
import androidx.compose.ui.text.font.FontStyle
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
import androidx.compose.ui.text.style.TextDecoration
|
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.unit.sp
|
import androidx.compose.ui.unit.sp
|
||||||
import feufaro.composeapp.generated.resources.Res
|
import feufaro.composeapp.generated.resources.Res
|
||||||
|
|
@ -61,12 +59,13 @@ fun SimpleDrawerContent(
|
||||||
val internalList by sharedScreenModel.internalItems.collectAsState()
|
val internalList by sharedScreenModel.internalItems.collectAsState()
|
||||||
val externalList by sharedScreenModel.externalItems.collectAsState()
|
val externalList by sharedScreenModel.externalItems.collectAsState()
|
||||||
val playList by sharedScreenModel.playlistItems.collectAsState()
|
val playList by sharedScreenModel.playlistItems.collectAsState()
|
||||||
val favoriteLists by sharedScreenModel.playlistItems.collectAsState()
|
val favoList by sharedScreenModel.favItems.collectAsState()
|
||||||
val listState = rememberLazyListState()
|
val listState = rememberLazyListState()
|
||||||
|
|
||||||
var internalExpanded by remember { mutableStateOf(false) }
|
var internalExpanded by remember { mutableStateOf(false) }
|
||||||
var externalExpanded by remember { mutableStateOf(false) }
|
var externalExpanded by remember { mutableStateOf(false) }
|
||||||
var playListExpanded by remember { mutableStateOf(false) }
|
var playListExpanded by remember { mutableStateOf(false) }
|
||||||
|
var favoriteExpanded by remember { mutableStateOf(false) }
|
||||||
|
|
||||||
val editMode by sharedScreenModel.modeEditor.collectAsState()
|
val editMode by sharedScreenModel.modeEditor.collectAsState()
|
||||||
val chordView by sharedScreenModel.harmonyView.collectAsState()
|
val chordView by sharedScreenModel.harmonyView.collectAsState()
|
||||||
|
|
@ -156,7 +155,8 @@ fun SimpleDrawerContent(
|
||||||
if (internalExpanded) {
|
if (internalExpanded) {
|
||||||
items(internalList) { item ->
|
items(internalList) { item ->
|
||||||
val isSelected = item.path == activePath
|
val isSelected = item.path == activePath
|
||||||
val isFavorite = favoriteLists.contains(item)
|
val onPlaylist = playList.contains(item)
|
||||||
|
val isCurrentFavorite = favoList.contains(item)
|
||||||
|
|
||||||
NavigationDrawerItem(
|
NavigationDrawerItem(
|
||||||
icon = {
|
icon = {
|
||||||
|
|
@ -166,14 +166,14 @@ fun SimpleDrawerContent(
|
||||||
badge = {
|
badge = {
|
||||||
IconButton(
|
IconButton(
|
||||||
onClick = {
|
onClick = {
|
||||||
sharedScreenModel.toggleFavorite(item.path)
|
sharedScreenModel.toPlaylist(item.path)
|
||||||
},
|
},
|
||||||
modifier = Modifier.size(32.dp)
|
modifier = Modifier.size(32.dp)
|
||||||
) {
|
) {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = Icons.Default.PlaylistAddCircle,
|
imageVector = Icons.Default.PlaylistAddCircle,
|
||||||
contentDescription = null,
|
contentDescription = null,
|
||||||
tint = if (!isFavorite) Color.LightGray else Color(0xFFFFD700),
|
tint = if (!onPlaylist) Color.LightGray else Color(0xFFFFD700),
|
||||||
modifier = Modifier.size(18.dp)
|
modifier = Modifier.size(18.dp)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -208,7 +208,7 @@ fun SimpleDrawerContent(
|
||||||
if (externalExpanded) {
|
if (externalExpanded) {
|
||||||
items(externalList) { item ->
|
items(externalList) { item ->
|
||||||
val isSelected = item.path == activePath
|
val isSelected = item.path == activePath
|
||||||
val isFavorite = favoriteLists.contains(item)
|
val onPlaylist = playList.contains(item)
|
||||||
|
|
||||||
if (item.path != "") {
|
if (item.path != "") {
|
||||||
NavigationDrawerItem(
|
NavigationDrawerItem(
|
||||||
|
|
@ -219,14 +219,14 @@ fun SimpleDrawerContent(
|
||||||
badge = {
|
badge = {
|
||||||
IconButton(
|
IconButton(
|
||||||
onClick = {
|
onClick = {
|
||||||
sharedScreenModel.toggleFavorite(item.path)
|
sharedScreenModel.toPlaylist(item.path)
|
||||||
},
|
},
|
||||||
modifier = Modifier.size(32.dp)
|
modifier = Modifier.size(32.dp)
|
||||||
) {
|
) {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = Icons.Default.PlaylistAddCircle,
|
imageVector = Icons.Default.PlaylistAddCircle,
|
||||||
contentDescription = null,
|
contentDescription = null,
|
||||||
tint = if (!isFavorite) Color.LightGray else Color(0xFFFFD700),
|
tint = if (!onPlaylist) Color.LightGray else Color(0xFFFFD700),
|
||||||
modifier = Modifier.size(18.dp)
|
modifier = Modifier.size(18.dp)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -286,11 +286,63 @@ fun SimpleDrawerContent(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
IconButton(
|
IconButton(
|
||||||
onClick = { sharedScreenModel.toggleFavorite(item.path) },
|
onClick = { sharedScreenModel.toPlaylist(item.path) },
|
||||||
modifier = Modifier.size(30.dp)
|
modifier = Modifier.size(30.dp)
|
||||||
) {
|
) {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = Icons.Default.Star,
|
imageVector = Icons.Default.PlaylistRemove,
|
||||||
|
contentDescription = null,
|
||||||
|
tint = if (isSelected) Color.LightGray else Color(0xFFFFD700)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
selected = isSelected,
|
||||||
|
onClick = {
|
||||||
|
scope.launch { drawerState.close() }
|
||||||
|
sharedScreenModel.reset()
|
||||||
|
solfaScreenModel.loadFromFile(item.path)
|
||||||
|
onSongSelected(midi)
|
||||||
|
},
|
||||||
|
shape = RoundedCornerShape(5.dp),
|
||||||
|
modifier = Modifier.padding(horizontal = 12.dp, vertical = 2.dp),
|
||||||
|
colors = NavigationDrawerItemDefaults.colors(
|
||||||
|
selectedContainerColor = MaterialTheme.colorScheme.secondary.copy(alpha = 0.5f),
|
||||||
|
selectedTextColor = MaterialTheme.colorScheme.onSecondary,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
stickyHeader {
|
||||||
|
DrawerHeaderSticky(
|
||||||
|
title = "Favoris",
|
||||||
|
icon = Icons.Default.FavoriteBorder,
|
||||||
|
isExpanded = favoriteExpanded,
|
||||||
|
onToggle = { favoriteExpanded = !favoriteExpanded },
|
||||||
|
count = favoList.size
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if(favoriteExpanded) {
|
||||||
|
itemsIndexed(favoList) { index, item ->
|
||||||
|
if (item.path.isNotBlank()) {
|
||||||
|
val isSelected = item.path == activePath
|
||||||
|
NavigationDrawerItem(
|
||||||
|
icon = {
|
||||||
|
Text("\uD83D\uDDA4", fontSize = 22.sp)
|
||||||
|
},
|
||||||
|
label = {
|
||||||
|
DrawerItemLabel(item)
|
||||||
|
},
|
||||||
|
badge = {
|
||||||
|
IconButton(
|
||||||
|
onClick = { sharedScreenModel.toFavorite(item.path) },
|
||||||
|
modifier = Modifier.size(30.dp)
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Default.StarRate,
|
||||||
contentDescription = null,
|
contentDescription = null,
|
||||||
tint = if (isSelected) MaterialTheme.colorScheme.background else MaterialTheme.colorScheme.tertiary
|
tint = if (isSelected) MaterialTheme.colorScheme.background else MaterialTheme.colorScheme.tertiary
|
||||||
)
|
)
|
||||||
|
|
@ -306,8 +358,8 @@ fun SimpleDrawerContent(
|
||||||
shape = RoundedCornerShape(5.dp),
|
shape = RoundedCornerShape(5.dp),
|
||||||
modifier = Modifier.padding(horizontal = 12.dp, vertical = 2.dp),
|
modifier = Modifier.padding(horizontal = 12.dp, vertical = 2.dp),
|
||||||
colors = NavigationDrawerItemDefaults.colors(
|
colors = NavigationDrawerItemDefaults.colors(
|
||||||
selectedContainerColor = MaterialTheme.colorScheme.tertiary.copy(alpha = 0.5f),
|
selectedContainerColor = MaterialTheme.colorScheme.secondary.copy(alpha = 0.5f),
|
||||||
selectedTextColor = MaterialTheme.colorScheme.onTertiary,
|
selectedTextColor = MaterialTheme.colorScheme.onSecondary,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
import androidx.compose.runtime.State
|
import androidx.compose.runtime.State
|
||||||
import androidx.compose.runtime.collectAsState
|
|
||||||
import androidx.compose.runtime.mutableStateOf
|
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
import cafe.adriel.voyager.core.model.ScreenModel
|
import cafe.adriel.voyager.core.model.ScreenModel
|
||||||
import cafe.adriel.voyager.core.model.screenModelScope
|
import cafe.adriel.voyager.core.model.screenModelScope
|
||||||
|
|
@ -9,23 +8,16 @@ import com.russhwolf.settings.Settings
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.*
|
||||||
import kotlinx.coroutines.flow.SharingStarted
|
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
|
||||||
import kotlinx.coroutines.flow.asStateFlow
|
|
||||||
import kotlinx.coroutines.flow.combine
|
|
||||||
import kotlinx.coroutines.flow.map
|
|
||||||
import kotlinx.coroutines.flow.mapLatest
|
|
||||||
import kotlinx.coroutines.flow.stateIn
|
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import mg.dot.feufaro.FileRepository
|
import mg.dot.feufaro.FileRepository
|
||||||
import mg.dot.feufaro.data.DrawerItem
|
import mg.dot.feufaro.data.DrawerItem
|
||||||
import mg.dot.feufaro.data.GridTUOData
|
import mg.dot.feufaro.data.GridTUOData
|
||||||
import mg.dot.feufaro.data.getCombinedList
|
import mg.dot.feufaro.data.getCombinedList
|
||||||
import mg.dot.feufaro.solfa.TimeUnitObject
|
|
||||||
import mg.dot.feufaro.midi.FMediaPlayer
|
import mg.dot.feufaro.midi.FMediaPlayer
|
||||||
import mg.dot.feufaro.provideSettings
|
import mg.dot.feufaro.provideSettings
|
||||||
import mg.dot.feufaro.solfa.TUOEditState
|
import mg.dot.feufaro.solfa.TUOEditState
|
||||||
|
import mg.dot.feufaro.solfa.TimeUnitObject
|
||||||
import mg.dot.feufaro.solfa.getAllMarker
|
import mg.dot.feufaro.solfa.getAllMarker
|
||||||
import mg.dot.feufaro.viewmodel.MidiMarkers
|
import mg.dot.feufaro.viewmodel.MidiMarkers
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
@ -122,28 +114,33 @@ class SharedScreenModel(private val fileRepository: FileRepository) : ScreenMode
|
||||||
paths.mapNotNull { path -> allItems.find { it.path == path } }
|
paths.mapNotNull { path -> allItems.find { it.path == path } }
|
||||||
}.stateIn(screenModelScope, SharingStarted.Lazily, emptyList())
|
}.stateIn(screenModelScope, SharingStarted.Lazily, emptyList())
|
||||||
|
|
||||||
fun savePlaylistToDisk(playlist: List<String>) {
|
private val favoriteFilename = "favoris.json"
|
||||||
|
private val _favoritePaths = MutableStateFlow<List<String>>(emptyList())
|
||||||
|
val favItems: StateFlow<List<DrawerItem>> = combine(_favoritePaths, _drawerItems) { paths, allItems ->
|
||||||
|
paths.mapNotNull { path -> allItems.find { it.path == path } }
|
||||||
|
}.stateIn(screenModelScope, SharingStarted.Lazily, emptyList())
|
||||||
|
|
||||||
|
fun saveItToDisk(list: List<String>, name: String) {
|
||||||
screenModelScope.launch {
|
screenModelScope.launch {
|
||||||
try {
|
try {
|
||||||
val itemsJson = playlist.joinToString(
|
val itemsJson = list.joinToString(
|
||||||
separator = "\",\"",
|
separator = "\",\"",
|
||||||
prefix = "[\"",
|
prefix = "[\"",
|
||||||
postfix = "\"]"
|
postfix = "\"]"
|
||||||
).replace("[\"\"]", "[]")
|
).replace("[\"\"]", "[]")
|
||||||
|
|
||||||
val finalJson = "{\"playlist\": $itemsJson}"
|
val finalJson = "{\"$name\": $itemsJson}"
|
||||||
|
|
||||||
val data = finalJson.encodeToByteArray()
|
val data = finalJson.encodeToByteArray()
|
||||||
|
|
||||||
fileRepository.saveLocalFile(playlistFilename, data)
|
fileRepository.saveLocalFile("${name}.json", data)
|
||||||
|
|
||||||
println("Playlist sauvegardée avec succès !")
|
println("${name.replaceFirstChar { it.uppercaseChar() }} sauvegardée avec succès !")
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
println("Erreur lors de la sauvegarde : ${e.message}")
|
println("Erreur lors de la sauvegarde : ${e.message}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fun toggleFavorite(path: String) {
|
fun toPlaylist(path: String) {
|
||||||
val current = _playlistPaths.value.toMutableList()
|
val current = _playlistPaths.value.toMutableList()
|
||||||
if (current.contains(path)) {
|
if (current.contains(path)) {
|
||||||
current.remove(path)
|
current.remove(path)
|
||||||
|
|
@ -151,7 +148,7 @@ class SharedScreenModel(private val fileRepository: FileRepository) : ScreenMode
|
||||||
current.add(path)
|
current.add(path)
|
||||||
}
|
}
|
||||||
_playlistPaths.value = current
|
_playlistPaths.value = current
|
||||||
savePlaylistToDisk(current)
|
saveItToDisk(current, "playlist")
|
||||||
}
|
}
|
||||||
|
|
||||||
fun moveUp(index: Int) {
|
fun moveUp(index: Int) {
|
||||||
|
|
@ -160,7 +157,7 @@ class SharedScreenModel(private val fileRepository: FileRepository) : ScreenMode
|
||||||
val item = current.removeAt(index)
|
val item = current.removeAt(index)
|
||||||
current.add(index - 1, item)
|
current.add(index - 1, item)
|
||||||
_playlistPaths.value = current
|
_playlistPaths.value = current
|
||||||
savePlaylistToDisk(current)
|
saveItToDisk(current, "playlist")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fun moveToTop(index: Int) {
|
fun moveToTop(index: Int) {
|
||||||
|
|
@ -168,7 +165,7 @@ class SharedScreenModel(private val fileRepository: FileRepository) : ScreenMode
|
||||||
val item = current.removeAt(index)
|
val item = current.removeAt(index)
|
||||||
current.add(0, item)
|
current.add(0, item)
|
||||||
_playlistPaths.value = current
|
_playlistPaths.value = current
|
||||||
savePlaylistToDisk(current)
|
saveItToDisk(current, "playlist")
|
||||||
}
|
}
|
||||||
|
|
||||||
fun moveDown(index: Int) {
|
fun moveDown(index: Int) {
|
||||||
|
|
@ -177,13 +174,25 @@ class SharedScreenModel(private val fileRepository: FileRepository) : ScreenMode
|
||||||
val item = current.removeAt(index)
|
val item = current.removeAt(index)
|
||||||
current.add(index + 1, item)
|
current.add(index + 1, item)
|
||||||
_playlistPaths.value = current
|
_playlistPaths.value = current
|
||||||
savePlaylistToDisk(current)
|
saveItToDisk(current, "playlist")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun isInPlaylist(path: String): Boolean {
|
fun isInPlaylist(path: String): Boolean {
|
||||||
return _playlistPaths.value.contains(path)
|
return _playlistPaths.value.contains(path)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun toFavorite(path: String) {
|
||||||
|
val current = _favoritePaths.value.toMutableList()
|
||||||
|
if (current.contains(path)) {
|
||||||
|
current.remove(path)
|
||||||
|
} else {
|
||||||
|
current.add(path)
|
||||||
|
}
|
||||||
|
_favoritePaths.value = current
|
||||||
|
saveItToDisk(current, "favoris")
|
||||||
|
}
|
||||||
|
|
||||||
init {
|
init {
|
||||||
loadItems()
|
loadItems()
|
||||||
}
|
}
|
||||||
|
|
@ -192,20 +201,20 @@ class SharedScreenModel(private val fileRepository: FileRepository) : ScreenMode
|
||||||
screenModelScope.launch {
|
screenModelScope.launch {
|
||||||
_drawerItems.value = getCombinedList(fileRepository)
|
_drawerItems.value = getCombinedList(fileRepository)
|
||||||
}
|
}
|
||||||
loadPlaylistFromDisk()
|
loadPlaylistFromDisk("favoris")
|
||||||
|
loadPlaylistFromDisk("playlist")
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun loadPlaylistFromDisk() {
|
private fun loadPlaylistFromDisk(name: String) {
|
||||||
screenModelScope.launch {
|
screenModelScope.launch {
|
||||||
try {
|
try {
|
||||||
val publicFolder = fileRepository.getAppPublicFolder()
|
val publicFolder = fileRepository.getAppPublicFolder()
|
||||||
val playlistFilePath = "$publicFolder/$playlistFilename"
|
val tFilePath = "$publicFolder/${name}.json"
|
||||||
|
val jsonString = fileRepository.readFileContent(tFilePath)
|
||||||
val jsonString = fileRepository.readFileContent(playlistFilePath)
|
|
||||||
|
|
||||||
if (jsonString.isNotBlank()) {
|
if (jsonString.isNotBlank()) {
|
||||||
val paths = jsonString
|
val paths = jsonString
|
||||||
.replace("{\"playlist\":", "")
|
.replace("{\"$name\":", "")
|
||||||
.replace("}", "")
|
.replace("}", "")
|
||||||
.replace("[", "")
|
.replace("[", "")
|
||||||
.replace("]", "")
|
.replace("]", "")
|
||||||
|
|
@ -214,11 +223,16 @@ class SharedScreenModel(private val fileRepository: FileRepository) : ScreenMode
|
||||||
.map { it.trim() }
|
.map { it.trim() }
|
||||||
.filter { it.isNotBlank() }
|
.filter { it.isNotBlank() }
|
||||||
|
|
||||||
_playlistPaths.value = paths
|
when(name) {
|
||||||
println("Playlist chargée : ${paths.size} chants")
|
"playlist" -> { _playlistPaths.value = paths }
|
||||||
|
"favoris" -> { _favoritePaths.value = paths }
|
||||||
|
else -> { }
|
||||||
|
}
|
||||||
|
|
||||||
|
println("${name.replaceFirstChar { it.uppercase() }} chargée : ${paths.size} chants")
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
println("Erreur lors du chargement de la playlist : ${e.message}")
|
println("Erreur lors du chargement de la $name : ${e.message}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue