Compare commits
3 commits
a5977d5dd1
...
6b8ce0cecf
| Author | SHA1 | Date | |
|---|---|---|---|
| 6b8ce0cecf | |||
| 1f05027f1f | |||
| 23d025899b |
6 changed files with 316 additions and 75 deletions
|
|
@ -384,13 +384,27 @@ class Solfa(val sharedScreenModel: SharedScreenModel, private val fileRepository
|
||||||
// println("fullLine = '$fullLine'")
|
// println("fullLine = '$fullLine'")
|
||||||
|
|
||||||
val afterU0 = fullLine.substringAfter("U0:")
|
val afterU0 = fullLine.substringAfter("U0:")
|
||||||
val blankPrefixRegex = Regex("^(.*?z[0-9A-Z]:)")
|
val blankPrefixRegex = Regex("^(.*?z)([0-9A-Z_+\\-]+)(:)")
|
||||||
val match = blankPrefixRegex.find(afterU0)
|
val match = blankPrefixRegex.find(afterU0)
|
||||||
val blankPrefix = match?.value ?: ""
|
var blankPrefix: String = ""
|
||||||
val body = if (match != null) {
|
var body: String = ""
|
||||||
afterU0.substring(blankPrefix.length)
|
if (match != null) {
|
||||||
|
body = afterU0.substring(blankPrefix.length)
|
||||||
|
|
||||||
|
if (editState.silentDuration == "-1") {
|
||||||
|
blankPrefix = match.value
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
println("voici ${match.groupValues.joinToString(",")}")
|
||||||
|
val beforeDuration = match.groups[1]?.value ?: ""
|
||||||
|
val restOfSilenceBlock = match.groups[3]?.value ?: ":"
|
||||||
|
|
||||||
|
blankPrefix = "$beforeDuration${editState.silentDuration}$restOfSilenceBlock"
|
||||||
|
}
|
||||||
|
body = afterU0.substring(match.value.length)
|
||||||
} else {
|
} else {
|
||||||
afterU0
|
blankPrefix = afterU0.substringBefore(":") + ":"
|
||||||
|
body = afterU0.substringAfter(":")
|
||||||
}
|
}
|
||||||
|
|
||||||
val measure = measureString.split("/")[0].toIntOrNull() ?: 4
|
val measure = measureString.split("/")[0].toIntOrNull() ?: 4
|
||||||
|
|
@ -506,29 +520,26 @@ class Solfa(val sharedScreenModel: SharedScreenModel, private val fileRepository
|
||||||
val fullPath = directory + fileName
|
val fullPath = directory + fileName
|
||||||
val rawIncludedContent = fileRepository.readFileLines(fullPath)
|
val rawIncludedContent = fileRepository.readFileLines(fullPath)
|
||||||
|
|
||||||
if (parts.size > 2 && parts[2].startsWith("^")) {
|
if (parts.size > 2 && parts[2].isNotEmpty()) {
|
||||||
val patternInside = parts[2]
|
val regexIgnoreString = parts[2]
|
||||||
.substringAfter("(", "")
|
|
||||||
.substringBefore(")", "")
|
|
||||||
|
|
||||||
val prefixesToIgnore = if (patternInside.isNotEmpty()) {
|
val ignoredLinesRegex = try {
|
||||||
patternInside.split("|")
|
Regex(regexIgnoreString)
|
||||||
} else {
|
} catch (e: Exception) {
|
||||||
listOf(parts[2].substring(1))
|
Regex("^:")
|
||||||
}
|
}
|
||||||
|
|
||||||
val filteredLines = rawIncludedContent.filter { incLine ->
|
val filteredLines = rawIncludedContent.filter { incLine ->
|
||||||
prefixesToIgnore.none { prefix ->
|
ignoredLinesRegex.find(incLine) == null
|
||||||
incLine.trim().startsWith(prefix)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
lineBuilder.append(filteredLines.joinToString("\n"))
|
lineBuilder.append(filteredLines.joinToString("\n"))
|
||||||
} else {
|
} else {
|
||||||
lineBuilder.append(rawIncludedContent.joinToString("\n"))
|
lineBuilder.append(rawIncludedContent.joinToString("\n"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
lineBuilder.append("// Erreur: ${e.message}")
|
lineBuilder.append("// Erreur inclusion: ${e.message}")
|
||||||
}
|
}
|
||||||
lastIndex = match.range.last + 1
|
lastIndex = match.range.last + 1
|
||||||
}
|
}
|
||||||
|
|
@ -768,6 +779,12 @@ class Solfa(val sharedScreenModel: SharedScreenModel, private val fileRepository
|
||||||
newMarkerValue: String,
|
newMarkerValue: String,
|
||||||
editState: TUOEditState
|
editState: TUOEditState
|
||||||
): String {
|
): String {
|
||||||
|
/* On ne modifie pas le template tant que les notes ne sont pas modifiées
|
||||||
|
* Et tant qu'une marker est ajouter */
|
||||||
|
if (newMarkerValue.isEmpty()) {
|
||||||
|
println("Aucune modification détectée (marqueur vide), on retourne le template original.")
|
||||||
|
return templateLine
|
||||||
|
}
|
||||||
val isT0 = templateLine.startsWith("T0")
|
val isT0 = templateLine.startsWith("T0")
|
||||||
|
|
||||||
val prefix: String
|
val prefix: String
|
||||||
|
|
@ -1291,6 +1308,7 @@ class Solfa(val sharedScreenModel: SharedScreenModel, private val fileRepository
|
||||||
var lookK = k
|
var lookK = k
|
||||||
var lookC = charIdx + 1
|
var lookC = charIdx + 1
|
||||||
var searching = true
|
var searching = true
|
||||||
|
var crossedParenthesis = false
|
||||||
|
|
||||||
while (searching) {
|
while (searching) {
|
||||||
if (lookC >= buff[lookK].length) {
|
if (lookC >= buff[lookK].length) {
|
||||||
|
|
@ -1317,20 +1335,28 @@ class Solfa(val sharedScreenModel: SharedScreenModel, private val fileRepository
|
||||||
lookC++
|
lookC++
|
||||||
}
|
}
|
||||||
|
|
||||||
|
next == '(' || next == ')' -> {
|
||||||
|
crossedParenthesis = true
|
||||||
|
lookC++
|
||||||
|
}
|
||||||
next == 'z' && lookK == k && char == 'D' -> {
|
next == 'z' && lookK == k && char == 'D' -> {
|
||||||
var hasFutureResonance = false
|
if (crossedParenthesis) {
|
||||||
if (k + 1 < buff.size) {
|
|
||||||
if (buff[k + 1].replace(Regex("\\$\\{.*?\\}|\\$."), "")
|
|
||||||
.startsWith("-")
|
|
||||||
) hasFutureResonance = true
|
|
||||||
}
|
|
||||||
if (!hasFutureResonance && currentStr.contains(".") && currentStr.contains(",")) {
|
|
||||||
val resDur = getDurationAt(currentStr, lookC, k)
|
|
||||||
totalDuration += resDur
|
|
||||||
consumedGlobally.add(lookK to lookC)
|
|
||||||
lookC++
|
|
||||||
} else {
|
|
||||||
searching = false
|
searching = false
|
||||||
|
} else {
|
||||||
|
var hasFutureResonance = false
|
||||||
|
if (k + 1 < buff.size) {
|
||||||
|
if (buff[k + 1].replace(Regex("\\$\\{.*?\\}|\\$."), "")
|
||||||
|
.startsWith("-")
|
||||||
|
) hasFutureResonance = true
|
||||||
|
}
|
||||||
|
if (!hasFutureResonance && currentStr.contains(".") && currentStr.contains(",")) {
|
||||||
|
val resDur = getDurationAt(currentStr, lookC, k)
|
||||||
|
totalDuration += resDur
|
||||||
|
consumedGlobally.add(lookK to lookC)
|
||||||
|
lookC++
|
||||||
|
} else {
|
||||||
|
searching = false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1411,6 +1437,15 @@ class Solfa(val sharedScreenModel: SharedScreenModel, private val fileRepository
|
||||||
}
|
}
|
||||||
|
|
||||||
val cleanedBlocks = buff2.map { it.replace(" ", "") }
|
val cleanedBlocks = buff2.map { it.replace(" ", "") }
|
||||||
|
/*val durationModifierRegex = Regex("^(.*?z)[0-9A-Z_+\\-](:|/)")
|
||||||
|
val match = durationModifierRegex.find(prefix)
|
||||||
|
|
||||||
|
val newPrefix = if (match != null) {
|
||||||
|
val beforeDuration = match.groups[1]?.value ?: ""
|
||||||
|
val separator = match.groups[2]?.value ?: ":"
|
||||||
|
"$beforeDuration${editState.silentDuration}$separator"
|
||||||
|
} else prefix*/
|
||||||
|
|
||||||
val finalLines = (prefix + cleanedBlocks.joinToString(""))
|
val finalLines = (prefix + cleanedBlocks.joinToString(""))
|
||||||
.replace("2z11", "y")
|
.replace("2z11", "y")
|
||||||
.replace("/", "/ ")
|
.replace("/", "/ ")
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,8 @@ import androidx.compose.material.icons.automirrored.filled.ArrowForward
|
||||||
import androidx.compose.material.icons.filled.Add
|
import androidx.compose.material.icons.filled.Add
|
||||||
import androidx.compose.material.icons.filled.Build
|
import androidx.compose.material.icons.filled.Build
|
||||||
import androidx.compose.material.icons.filled.Clear
|
import androidx.compose.material.icons.filled.Clear
|
||||||
|
import androidx.compose.material.icons.filled.KeyboardDoubleArrowLeft
|
||||||
|
import androidx.compose.material.icons.filled.KeyboardDoubleArrowRight
|
||||||
import androidx.compose.material3.*
|
import androidx.compose.material3.*
|
||||||
import androidx.compose.runtime.*
|
import androidx.compose.runtime.*
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
|
|
@ -63,6 +65,7 @@ fun TUODetailDialog(
|
||||||
var templateFragment by remember { mutableStateOf(editState.templateFragment) }
|
var templateFragment by remember { mutableStateOf(editState.templateFragment) }
|
||||||
|
|
||||||
var marker by remember { mutableStateOf(editState.marker) }
|
var marker by remember { mutableStateOf(editState.marker) }
|
||||||
|
val initialMarker = remember { editState.marker }
|
||||||
|
|
||||||
LaunchedEffect(notes.toMap()) {
|
LaunchedEffect(notes.toMap()) {
|
||||||
val tempState = TUOEditState(
|
val tempState = TUOEditState(
|
||||||
|
|
@ -116,6 +119,79 @@ fun TUODetailDialog(
|
||||||
horizontalArrangement = Arrangement.SpaceBetween,
|
horizontalArrangement = Arrangement.SpaceBetween,
|
||||||
verticalAlignment = Alignment.CenterVertically
|
verticalAlignment = Alignment.CenterVertically
|
||||||
) {
|
) {
|
||||||
|
// Modif silence duration
|
||||||
|
if (currentIndex == 0) {
|
||||||
|
val silentDurationOrder = listOf(
|
||||||
|
"0", "4", "8", "A", "C", "E", "G", "K", "O", "S", "W"
|
||||||
|
)
|
||||||
|
Row(
|
||||||
|
modifier = Modifier.width(125.dp),
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
horizontalArrangement = Arrangement.SpaceBetween
|
||||||
|
) {
|
||||||
|
IconButton(
|
||||||
|
onClick = {
|
||||||
|
val currentIdx = silentDurationOrder.indexOf(editState.silentDuration)
|
||||||
|
val newIdx = if (currentIdx > 0) currentIdx - 1 else 0
|
||||||
|
val newDuration = silentDurationOrder[newIdx]
|
||||||
|
|
||||||
|
val state = TUOEditState(
|
||||||
|
tuoIndex = globalIndex,
|
||||||
|
notesByVoice = notes.toMap(),
|
||||||
|
originalNotes = originalNotes.toMap(),
|
||||||
|
originalLyricsByStanza = originalLyricsByStz.toMutableMap(),
|
||||||
|
lyricsByStanza = mutableMapOf(currentStanza to lyricsLines.joinToString(" ")),
|
||||||
|
templateFragment = templateFragment,
|
||||||
|
marker = if(marker != initialMarker) marker else "",
|
||||||
|
silentDuration = newDuration
|
||||||
|
)
|
||||||
|
onSave(state)
|
||||||
|
},
|
||||||
|
enabled = silentDurationOrder.indexOf(editState.silentDuration) >= 0,
|
||||||
|
modifier = Modifier.size(20.dp)
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Default.KeyboardDoubleArrowLeft,
|
||||||
|
contentDescription = "Diminuer",
|
||||||
|
tint = if (silentDurationOrder.indexOf(editState.silentDuration) > 0) Color.LightGray else Color.DarkGray
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
Text(
|
||||||
|
text = editState.silentDuration,
|
||||||
|
color = Color.White,
|
||||||
|
style = MaterialTheme.typography.bodyLarge
|
||||||
|
)
|
||||||
|
|
||||||
|
IconButton(
|
||||||
|
onClick = {
|
||||||
|
val currentIdx = silentDurationOrder.indexOf(editState.silentDuration)
|
||||||
|
val newIdx = if (currentIdx != -1 && currentIdx < silentDurationOrder.lastIndex) currentIdx + 1 else currentIdx
|
||||||
|
val newDuration = silentDurationOrder[newIdx]
|
||||||
|
|
||||||
|
val state = TUOEditState(
|
||||||
|
tuoIndex = globalIndex,
|
||||||
|
notesByVoice = notes.toMap(),
|
||||||
|
originalNotes = originalNotes.toMap(),
|
||||||
|
originalLyricsByStanza = originalLyricsByStz.toMutableMap(),
|
||||||
|
lyricsByStanza = mutableMapOf(currentStanza to lyricsLines.joinToString(" ")),
|
||||||
|
templateFragment = templateFragment,
|
||||||
|
marker = if(marker != initialMarker) marker else "",
|
||||||
|
silentDuration = newDuration
|
||||||
|
)
|
||||||
|
onSave(state)
|
||||||
|
},
|
||||||
|
enabled = silentDurationOrder.indexOf(editState.silentDuration) < silentDurationOrder.lastIndex,
|
||||||
|
modifier = Modifier.size(20.dp)
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Default.KeyboardDoubleArrowRight,
|
||||||
|
contentDescription = "Augmenter",
|
||||||
|
tint = if (silentDurationOrder.indexOf(editState.silentDuration) < silentDurationOrder.lastIndex) Color.LightGray else Color.DarkGray
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
if (currentIndex > 0) {
|
if (currentIndex > 0) {
|
||||||
IconButton(
|
IconButton(
|
||||||
onClick = {
|
onClick = {
|
||||||
|
|
@ -130,14 +206,14 @@ fun TUODetailDialog(
|
||||||
tint = Color.White
|
tint = Color.White
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
Text(
|
Text(
|
||||||
text = "N°$currentIndex",
|
text = "N°$currentIndex",
|
||||||
fontSize = 15.sp,
|
fontSize = 15.sp,
|
||||||
fontWeight = FontWeight.Bold,
|
fontWeight = FontWeight.Bold,
|
||||||
color = Color.White
|
color = Color.White
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
|
||||||
IconButton(
|
IconButton(
|
||||||
onClick = {
|
onClick = {
|
||||||
|
|
@ -288,7 +364,9 @@ fun TUODetailDialog(
|
||||||
if (isEditable || canAdd) {
|
if (isEditable || canAdd) {
|
||||||
IconButton(
|
IconButton(
|
||||||
onClick = {
|
onClick = {
|
||||||
if (index == 0) lyricsLines.add("_") else lyricsLines.removeAt(index)
|
if (index >= 0) {
|
||||||
|
if (index == 0) lyricsLines.add("_") else lyricsLines.removeAt(index)
|
||||||
|
}
|
||||||
}) {
|
}) {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = if (index == 0) Icons.Default.Add else Icons.Default.Clear,
|
imageVector = if (index == 0) Icons.Default.Add else Icons.Default.Clear,
|
||||||
|
|
@ -323,7 +401,8 @@ fun TUODetailDialog(
|
||||||
originalLyricsByStanza = originalLyricsByStz.toMutableMap(),
|
originalLyricsByStanza = originalLyricsByStz.toMutableMap(),
|
||||||
lyricsByStanza = mutableMapOf(currentStanza to lyricsLines.joinToString(" ")),
|
lyricsByStanza = mutableMapOf(currentStanza to lyricsLines.joinToString(" ")),
|
||||||
templateFragment = templateFragment,
|
templateFragment = templateFragment,
|
||||||
marker = marker
|
/* On ne ré-insere pas la même marker*/
|
||||||
|
marker = if(marker != initialMarker) marker else "",
|
||||||
)
|
)
|
||||||
onSave(state)
|
onSave(state)
|
||||||
},
|
},
|
||||||
|
|
@ -567,7 +646,7 @@ private fun notesToTemplate(notes: String): String {
|
||||||
.replace("si", "S")
|
.replace("si", "S")
|
||||||
.replace("ta", "T")
|
.replace("ta", "T")
|
||||||
|
|
||||||
val noteRegex = Regex("""([drmfsltDRFSTz]+|[.,()\s-])""")
|
val noteRegex = Regex("""([drmfsltDRFSTz][ia]?|[.,()\s-])""")
|
||||||
val template = StringBuilder()
|
val template = StringBuilder()
|
||||||
val matches = noteRegex.findAll(cleaned)
|
val matches = noteRegex.findAll(cleaned)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,5 +7,6 @@ data class TUOEditState(
|
||||||
val lyricsByStanza: MutableMap<Int, String> = mutableMapOf(),
|
val lyricsByStanza: MutableMap<Int, String> = mutableMapOf(),
|
||||||
val originalLyricsByStanza: MutableMap<Int, String> = mutableMapOf(),
|
val originalLyricsByStanza: MutableMap<Int, String> = mutableMapOf(),
|
||||||
val templateFragment: String = "",
|
val templateFragment: String = "",
|
||||||
val marker: String = ""
|
val marker: String = "",
|
||||||
|
val silentDuration: String = "-1"
|
||||||
)
|
)
|
||||||
|
|
@ -16,9 +16,11 @@ import androidx.compose.foundation.text.BasicTextField
|
||||||
import androidx.compose.foundation.text.KeyboardOptions
|
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.Undo
|
import androidx.compose.material.icons.automirrored.filled.Undo
|
||||||
|
import androidx.compose.material.icons.filled.ArrowBackIosNew
|
||||||
import androidx.compose.material.icons.filled.Build
|
import androidx.compose.material.icons.filled.Build
|
||||||
import androidx.compose.material.icons.filled.Close
|
import androidx.compose.material.icons.filled.Close
|
||||||
import androidx.compose.material.icons.filled.Description
|
import androidx.compose.material.icons.filled.Description
|
||||||
|
import androidx.compose.material.icons.filled.KeyboardDoubleArrowLeft
|
||||||
import androidx.compose.material.icons.filled.Save
|
import androidx.compose.material.icons.filled.Save
|
||||||
import androidx.compose.material3.*
|
import androidx.compose.material3.*
|
||||||
import androidx.compose.runtime.*
|
import androidx.compose.runtime.*
|
||||||
|
|
@ -274,7 +276,7 @@ fun TimeUnitComposable(
|
||||||
)
|
)
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.background(/*if(gridActive) Color.Cyan.copy(alpha = 0.5f) else col*/animatedColor)
|
.background(animatedColor)
|
||||||
) {
|
) {
|
||||||
if (TimeUnitObject._hasMarker) {
|
if (TimeUnitObject._hasMarker) {
|
||||||
val lineHeight = 20.sp
|
val lineHeight = 20.sp
|
||||||
|
|
@ -841,6 +843,25 @@ fun LazyVerticalGridTUO(
|
||||||
val template = oneTUO.pTemplate.template
|
val template = oneTUO.pTemplate.template
|
||||||
val expectedTemplate = template.count { it.isLetter() } == 2 && template.contains(".")
|
val expectedTemplate = template.count { it.isLetter() } == 2 && template.contains(".")
|
||||||
|
|
||||||
|
val fileC = sharedScreenModel.fileContent.value ?: ""
|
||||||
|
val lines = fileC.split("\n").toMutableList()
|
||||||
|
val u0Idx = lines.indexOfFirst { it.startsWith("U0:") }
|
||||||
|
val t0Idx = lines.indexOfFirst { it.startsWith("T0:") }
|
||||||
|
|
||||||
|
val fullLine = when {
|
||||||
|
t0Idx != -1 -> {
|
||||||
|
lines[t0Idx]
|
||||||
|
}
|
||||||
|
u0Idx != -1 -> {
|
||||||
|
lines[u0Idx]
|
||||||
|
}
|
||||||
|
else -> ""
|
||||||
|
}
|
||||||
|
val afterU0T0 = fullLine.substringAfter("0:")
|
||||||
|
val blankPrefixRegex =Regex("""z([0-9A-Z])[:]""")
|
||||||
|
val match = blankPrefixRegex.find(afterU0T0)
|
||||||
|
val blankPrefix = match?.groups?.get(1)?.value ?: ""
|
||||||
|
|
||||||
val editState = TUOEditState(
|
val editState = TUOEditState(
|
||||||
tuoIndex = oneTUO.firstTuoIndex,
|
tuoIndex = oneTUO.firstTuoIndex,
|
||||||
notesByVoice = (0..3).associate { i ->
|
notesByVoice = (0..3).associate { i ->
|
||||||
|
|
@ -855,7 +876,8 @@ fun LazyVerticalGridTUO(
|
||||||
marker = listOfNotNull(
|
marker = listOfNotNull(
|
||||||
oneTUO.pTemplate.markerToString().takeIf { it.isNotBlank() },
|
oneTUO.pTemplate.markerToString().takeIf { it.isNotBlank() },
|
||||||
oneTUO.hasHairPin()?.toString()?.takeIf { it.isNotBlank() }
|
oneTUO.hasHairPin()?.toString()?.takeIf { it.isNotBlank() }
|
||||||
).joinToString(" ")
|
).joinToString(" "),
|
||||||
|
silentDuration = blankPrefix
|
||||||
)
|
)
|
||||||
TUODetailDialog(
|
TUODetailDialog(
|
||||||
editState = editState,
|
editState = editState,
|
||||||
|
|
@ -1274,12 +1296,16 @@ fun EditorActionButtons(isUndoVisible: Boolean, onUndo: () -> Unit, onBuild: ()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun autoFixNote(rawNote: String, template: String): String {
|
fun autoFixNote(rawNote: String, template: String): String {
|
||||||
println("ça on a t $template => $rawNote")
|
// println("\n==================================================")
|
||||||
|
// println(" ENTRÉE autoFixNote")
|
||||||
|
// println(" • Template : \"$template\"")
|
||||||
|
// println(" • RawNote : \"$rawNote\"")
|
||||||
|
// println("==================================================")
|
||||||
if (rawNote == "_") return rawNote
|
if (rawNote == "_") return rawNote
|
||||||
|
|
||||||
val noteRegex = Regex("([drmfsltDRFSTw][ia]?|―)[0-9'¹²³⁴₁₂₃₄,]*")
|
val noteRegex = Regex("([drmfsltDRFSTw][ia]?|―)[0-9'¹²³⁴₁₂₃₄,]*")
|
||||||
val actualNotes = if (rawNote.isEmpty()) emptyList() else noteRegex.findAll(rawNote).map { it.value }.toList()
|
val actualNotes = if (rawNote.isEmpty()) emptyList() else noteRegex.findAll(rawNote).map { it.value }.toList()
|
||||||
|
// println(" • Notes détectées dans RawNote : $actualNotes (Taille: ${actualNotes.size})")
|
||||||
/*if (rawNote.contains("•") || rawNote.contains("―") || rawNote.contains(",")) {
|
/*if (rawNote.contains("•") || rawNote.contains("―") || rawNote.contains(",")) {
|
||||||
val templateNotesCount = template.count { c ->
|
val templateNotesCount = template.count { c ->
|
||||||
c in 'A'..'Y' || c in 'a'..'y'
|
c in 'A'..'Y' || c in 'a'..'y'
|
||||||
|
|
@ -1289,24 +1315,32 @@ fun autoFixNote(rawNote: String, template: String): String {
|
||||||
val requiredNotesCount = template.count { it in 'A'..'Y' || it in 'a'..'y' }
|
val requiredNotesCount = template.count { it in 'A'..'Y' || it in 'a'..'y' }
|
||||||
|
|
||||||
val shouldIncludeParentheses = actualNotes.size >= requiredNotesCount
|
val shouldIncludeParentheses = actualNotes.size >= requiredNotesCount
|
||||||
|
// println(" • Notes requises par le template : $requiredNotesCount")
|
||||||
|
// println(" • Inclusion des parenthèses autorisée ? : $shouldIncludeParentheses")
|
||||||
|
// println("--------------------------------------------------")
|
||||||
val result = StringBuilder()
|
val result = StringBuilder()
|
||||||
var noteIdx = 0
|
var noteIdx = 0
|
||||||
|
|
||||||
for (i in template.indices) {
|
for (i in template.indices) {
|
||||||
val char = template[i]
|
val char = template[i]
|
||||||
|
// print("[Étape $i] Caractère template = '$char' | Index note actuel = $noteIdx -> ")
|
||||||
when {
|
when {
|
||||||
(char in 'A'..'Y' || char in 'a'..'y') -> {
|
(char in 'A'..'Y' || char in 'a'..'y') -> {
|
||||||
if (noteIdx < actualNotes.size) {
|
if (noteIdx < actualNotes.size) {
|
||||||
val noteToAdd = actualNotes[noteIdx]
|
val noteToAdd = actualNotes[noteIdx]
|
||||||
if (noteIdx > 0 && result.isNotEmpty()) {
|
if (noteIdx > 0 && result.isNotEmpty()) {
|
||||||
val lastChar = result.last()
|
val lastChar = result.last()
|
||||||
if (lastChar != '•' && lastChar != ',' && lastChar != '(' && lastChar != ' ') {
|
// println()
|
||||||
|
// println(" [INFO ESPACE] lastC '$lastChar' avant d'ajouter la note \"$noteToAdd\"")
|
||||||
|
/* if (lastChar != '•' && lastChar != ',' && lastChar != '(' && lastChar != ')') {
|
||||||
result.append(" ")
|
result.append(" ")
|
||||||
}
|
} */
|
||||||
|
// println(" [INFO ESPACE] Maintenant res est \"${result.toString()}\"")
|
||||||
|
// print(" -> Continuité Étape $i : ")
|
||||||
}
|
}
|
||||||
|
|
||||||
result.append(noteToAdd)
|
result.append(noteToAdd)
|
||||||
|
// println("Action : Ajout de la note utilisateur \"$noteToAdd\"")
|
||||||
noteIdx++
|
noteIdx++
|
||||||
} else {
|
} else {
|
||||||
/*if (rawNote.isEmpty()) {*/
|
/*if (rawNote.isEmpty()) {*/
|
||||||
|
|
@ -1314,35 +1348,78 @@ fun autoFixNote(rawNote: String, template: String): String {
|
||||||
/*} else {
|
/*} else {
|
||||||
result.append("―")
|
result.append("―")
|
||||||
}*/
|
}*/
|
||||||
|
// println("Action : Plus de notes utilisateur ! Ajout du silence par défaut \"z\"")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
char == '-' -> {
|
char == '-' -> {
|
||||||
if (noteIdx < actualNotes.size && actualNotes[noteIdx] == "―") {
|
if (noteIdx < actualNotes.size && actualNotes[noteIdx] == "―") {
|
||||||
result.append("―")
|
result.append("―")
|
||||||
|
// println("Action : Consommation et ajout du tiret utilisateur \"―\"")
|
||||||
noteIdx++
|
noteIdx++
|
||||||
} else {
|
} else {
|
||||||
val prev = if (i > 0) template[i - 1] else null
|
val prev = if (i > 0) template[i - 1] else null
|
||||||
val next = if (i < template.lastIndex) template[i + 1] else null
|
val next = if (i < template.lastIndex) template[i + 1] else null
|
||||||
if (prev == '.' && next == ',') result.append(" ") else result.append("―")
|
if (prev == '.' && next == ',') {
|
||||||
|
result.append(" ")
|
||||||
|
// println("Action : Structure .-, détectée -> Ajout d'un espace \" \"")
|
||||||
|
} else {
|
||||||
|
result.append("―")
|
||||||
|
// println("Action : Ajout du tiret automatique \"―\"")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
char == 'z' -> result.append(" ")
|
char == 'z' -> {
|
||||||
|
result.append(" ")
|
||||||
|
// println("Action : Caractère 'z' du template -> Ajout d'un espace \" \"")
|
||||||
|
}
|
||||||
char == '.' -> {
|
char == '.' -> {
|
||||||
val currentText = result.toString()
|
val currentText = result.toString()
|
||||||
if (!currentText.endsWith("•")) result.append("•")
|
if (!currentText.endsWith("•")) {
|
||||||
|
result.append("•")
|
||||||
|
// println("Action : Ajout du point musical \"•\"")
|
||||||
|
} else {
|
||||||
|
// println("Action : Ignoré (se termine déjà par un point)")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
char == ',' -> {
|
char == ',' -> {
|
||||||
val currentText = result.toString()
|
val currentText = result.toString()
|
||||||
if (!currentText.endsWith(",")) result.append(",")
|
if (!currentText.endsWith(",")) {
|
||||||
|
result.append(",")
|
||||||
|
// println("Action : Ajout de la virgule \",\"")
|
||||||
|
} else {
|
||||||
|
// println("Action : Ignoré (se termine déjà par une virgule)")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
char == '(' -> {
|
char == '(' -> {
|
||||||
if (shouldIncludeParentheses) result.append("(")
|
if (shouldIncludeParentheses) {
|
||||||
|
result.append("(")
|
||||||
|
// println("Action : Ajout parenthèse ouvrante \"(\"")
|
||||||
|
} else {
|
||||||
|
// println("Action : Ignoré (pas assez de notes)")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
char == ')' -> {
|
char == ')' -> {
|
||||||
if (shouldIncludeParentheses) result.append(")")
|
if (shouldIncludeParentheses) {
|
||||||
|
result.append(")")
|
||||||
|
// println("Action : Ajout parenthèse fermante \")\"")
|
||||||
|
} else {
|
||||||
|
// println("Action : Ignoré (pas assez de notes)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
// println("Action : Aucun comportement défini pour '$char'")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// println(" ↳ État actuel du buffer : \"${result.toString()}\"")
|
||||||
}
|
}
|
||||||
// println("on a RES ${result.toString()}")
|
var finalResult = result.toString()
|
||||||
return result.toString()
|
// println(" • Avant formatage final : \"$finalResult\"")
|
||||||
|
|
||||||
|
finalResult = finalResult
|
||||||
|
.replace("( ", "(")
|
||||||
|
.replace(" )", ")")
|
||||||
|
.replace("•,", "• ,")
|
||||||
|
|
||||||
|
// println("on a RES ${finalResult}")
|
||||||
|
return finalResult
|
||||||
}
|
}
|
||||||
|
|
@ -16,6 +16,7 @@ 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.filled.*
|
import androidx.compose.material.icons.filled.*
|
||||||
|
import androidx.compose.material.icons.filled.KeyboardDoubleArrowRight
|
||||||
import androidx.compose.material3.*
|
import androidx.compose.material3.*
|
||||||
import androidx.compose.runtime.*
|
import androidx.compose.runtime.*
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
|
|
@ -249,7 +250,7 @@ fun MidiControlPanel(
|
||||||
modifier = Modifier.background(Color(0XFF2C3130)),
|
modifier = Modifier.background(Color(0XFF2C3130)),
|
||||||
onClick = { updateTempoByBpmStep(-10) }) {
|
onClick = { updateTempoByBpmStep(-10) }) {
|
||||||
Icon(
|
Icon(
|
||||||
Icons.AutoMirrored.Filled.KeyboardArrowLeft,
|
Icons.Default.KeyboardDoubleArrowLeft,
|
||||||
"gauche",
|
"gauche",
|
||||||
tint = Color.White.copy(0.7f),
|
tint = Color.White.copy(0.7f),
|
||||||
modifier = Modifier.size(22.dp)
|
modifier = Modifier.size(22.dp)
|
||||||
|
|
@ -297,7 +298,7 @@ fun MidiControlPanel(
|
||||||
modifier = Modifier.background(Color(0XFF2C3130)),
|
modifier = Modifier.background(Color(0XFF2C3130)),
|
||||||
onClick = { updateTempoByBpmStep(10) }) {
|
onClick = { updateTempoByBpmStep(10) }) {
|
||||||
Icon(
|
Icon(
|
||||||
Icons.AutoMirrored.Filled.KeyboardArrowRight,
|
Icons.Default.KeyboardDoubleArrowRight,
|
||||||
"droite",
|
"droite",
|
||||||
tint = Color.White.copy(0.7f),
|
tint = Color.White.copy(0.7f),
|
||||||
modifier = Modifier.size(22.dp)
|
modifier = Modifier.size(22.dp)
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,9 @@ import androidx.compose.foundation.Image
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.clickable
|
||||||
import androidx.compose.foundation.layout.*
|
import androidx.compose.foundation.layout.*
|
||||||
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
import androidx.compose.material3.Card
|
import androidx.compose.material3.Card
|
||||||
|
import androidx.compose.material3.CardDefaults
|
||||||
import androidx.compose.material3.CircularProgressIndicator
|
import androidx.compose.material3.CircularProgressIndicator
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
|
|
@ -14,14 +16,20 @@ import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.produceState
|
import androidx.compose.runtime.produceState
|
||||||
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.clip
|
||||||
import androidx.compose.ui.draw.shadow
|
import androidx.compose.ui.draw.shadow
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.graphics.ImageBitmap
|
import androidx.compose.ui.graphics.ImageBitmap
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.compose.ui.unit.sp
|
||||||
|
import feufaro.composeapp.generated.resources.Res
|
||||||
|
import feufaro.composeapp.generated.resources.compose_multiplatform
|
||||||
import mg.dot.feufaro.FileRepository
|
import mg.dot.feufaro.FileRepository
|
||||||
import mg.dot.feufaro.solfa.ColorPrefixA
|
import mg.dot.feufaro.solfa.ColorPrefixA
|
||||||
import mg.dot.feufaro.solfa.ColorPrefixB
|
import mg.dot.feufaro.solfa.ColorPrefixB
|
||||||
import mg.dot.feufaro.solfa.ColorValue
|
import mg.dot.feufaro.solfa.ColorValue
|
||||||
|
import org.jetbrains.compose.resources.painterResource
|
||||||
import java.io.ByteArrayOutputStream
|
import java.io.ByteArrayOutputStream
|
||||||
import java.util.zip.GZIPOutputStream
|
import java.util.zip.GZIPOutputStream
|
||||||
import kotlin.io.encoding.Base64
|
import kotlin.io.encoding.Base64
|
||||||
|
|
@ -47,53 +55,91 @@ fun QRDisplay(sharedScreenModel: SharedScreenModel, fileRepository: FileReposito
|
||||||
val compressedData = Base64.UrlSafe.encode(compressedBytes).trim('=')
|
val compressedData = Base64.UrlSafe.encode(compressedBytes).trim('=')
|
||||||
|
|
||||||
val uri = "feufaro://song?file=${compressedData}&name=$fileName"
|
val uri = "feufaro://song?file=${compressedData}&name=$fileName"
|
||||||
value = generateQRCode(uri, size = 800)
|
value = generateQRCode(uri, size = 1200)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
.background(MaterialTheme.colorScheme.scrim.copy(alpha = 0.5f)) // Fond semi-transparent
|
.background(Color.Black.copy(alpha = 0.6f)) // Assombrissement moderne
|
||||||
.clickable { sharedScreenModel.toggleQRCodeVisibility() } // Fermer au clic
|
.clickable { sharedScreenModel.toggleQRCodeVisibility() } // Fermer au clic
|
||||||
.imePadding()
|
.imePadding()
|
||||||
.systemBarsPadding(),
|
.systemBarsPadding(),
|
||||||
contentAlignment = Alignment.Center
|
contentAlignment = Alignment.Center
|
||||||
) {
|
) {
|
||||||
Card(
|
Card(
|
||||||
modifier = Modifier.wrapContentSize().shadow(16.dp, shape = MaterialTheme.shapes.large)
|
modifier = Modifier
|
||||||
|
.width(400.dp)
|
||||||
|
.wrapContentHeight()
|
||||||
|
.shadow(24.dp, shape = RoundedCornerShape(28.dp)),
|
||||||
|
shape = RoundedCornerShape(28.dp),
|
||||||
|
colors = CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.surface)
|
||||||
) {
|
) {
|
||||||
Column(
|
Column(
|
||||||
horizontalAlignment = Alignment.CenterHorizontally,
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
modifier = Modifier.padding(24.dp)
|
modifier = Modifier.padding(24.dp)
|
||||||
) {
|
) {
|
||||||
Text("Scanner pour ouvrir ce partition")
|
Text(
|
||||||
if (qrCodeImage != null) {
|
text = "Partager la partition",
|
||||||
Image(
|
style = MaterialTheme.typography.titleLarge.copy(
|
||||||
bitmap = qrCodeImage!!,
|
fontWeight = FontWeight.Bold,
|
||||||
contentDescription = "Code QR du fichier actif",
|
letterSpacing = 0.5.sp
|
||||||
modifier = Modifier.size(400.dp)
|
|
||||||
)
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
Text(
|
||||||
|
text = "Scannez pour ouvrir instantanément",
|
||||||
|
style = MaterialTheme.typography.bodyMedium.copy(
|
||||||
|
color = MaterialTheme.colorScheme.onSurfaceVariant
|
||||||
|
),
|
||||||
|
modifier = Modifier.padding(top = 4.dp, bottom = 24.dp)
|
||||||
|
)
|
||||||
|
|
||||||
|
if (qrCodeImage != null) {
|
||||||
|
Box(
|
||||||
|
contentAlignment = Alignment.Center,
|
||||||
|
modifier = Modifier
|
||||||
|
.size(350.dp)
|
||||||
|
.clip(RoundedCornerShape(16.dp))
|
||||||
|
.background(Color.White)
|
||||||
|
.padding(5.dp)
|
||||||
|
) {
|
||||||
|
Image(
|
||||||
|
bitmap = qrCodeImage!!,
|
||||||
|
contentDescription = "Code QR du fichier actif",
|
||||||
|
modifier = Modifier.fillMaxSize()
|
||||||
|
)
|
||||||
|
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.size(54.dp)
|
||||||
|
.background(Color.White, shape = RoundedCornerShape(12.dp))
|
||||||
|
.padding(4.dp),
|
||||||
|
contentAlignment = Alignment.Center
|
||||||
|
) {
|
||||||
|
Image(
|
||||||
|
painter = painterResource(Res.drawable.compose_multiplatform),
|
||||||
|
contentDescription = "App Logo",
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.clip(RoundedCornerShape(8.dp))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier.size(280.dp),
|
||||||
.size(400.dp)
|
|
||||||
.padding(16.dp),
|
|
||||||
contentAlignment = Alignment.Center
|
contentAlignment = Alignment.Center
|
||||||
) {
|
) {
|
||||||
Column(
|
Column(horizontalAlignment = Alignment.CenterHorizontally) {
|
||||||
horizontalAlignment = Alignment.CenterHorizontally,
|
|
||||||
verticalArrangement = Arrangement.Center
|
|
||||||
) {
|
|
||||||
CircularProgressIndicator(
|
CircularProgressIndicator(
|
||||||
modifier = Modifier.size(48.dp),
|
modifier = Modifier.size(48.dp),
|
||||||
color = ColorPrefixA,
|
color = ColorPrefixA,
|
||||||
strokeWidth = 4.dp,
|
strokeWidth = 4.dp,
|
||||||
trackColor = ColorPrefixB.copy(alpha = 0.2f)
|
trackColor = ColorPrefixB.copy(alpha = 0.2f)
|
||||||
)
|
)
|
||||||
|
|
||||||
Spacer(modifier = Modifier.height(16.dp))
|
Spacer(modifier = Modifier.height(16.dp))
|
||||||
|
|
||||||
Text(
|
Text(
|
||||||
text = "Génération du QR Code...",
|
text = "Génération du QR Code...",
|
||||||
style = MaterialTheme.typography.bodyMedium.copy(
|
style = MaterialTheme.typography.bodyMedium.copy(
|
||||||
|
|
@ -104,6 +150,8 @@ fun QRDisplay(sharedScreenModel: SharedScreenModel, fileRepository: FileReposito
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.height(12.dp))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue