Bug Fix! Auto Update Template struct when Editing notes - template with note format

This commit is contained in:
Hasinjato 2026-05-26 15:31:32 +03:00
parent 2f536ba45b
commit dc86d9ddc4
3 changed files with 137 additions and 34 deletions

View file

@ -612,6 +612,8 @@ class Solfa(val sharedScreenModel: SharedScreenModel, private val fileRepository
) { ) {
val notesByVoice = editState.notesByVoice val notesByVoice = editState.notesByVoice
val originalNotes = editState.originalNotes val originalNotes = editState.originalNotes
val templateFragment = editState.templateFragment
val pureTemplate = templateFragment.replace(Regex("[()]"), "")
for (voiceNum in 0..3) { for (voiceNum in 0..3) {
val linePrefix = "N${voiceNum + 1}:" val linePrefix = "N${voiceNum + 1}:"
@ -631,10 +633,10 @@ class Solfa(val sharedScreenModel: SharedScreenModel, private val fileRepository
val isNoteModified = newNot != oldNot val isNoteModified = newNot != oldNot
// println("est-ce? $isNoteModified = $newNot != $oldNot") // println("est-ce? $isNoteModified = $newNot != $oldNot")
if (!isNoteModified) { /*if (!isNoteModified) {
// println("Voix $linePrefix : Aucune modification détectée (Note: $oldNot ).") println("Voix $linePrefix : Aucune modification détectée (Note: $oldNot ).")
continue continue
} }*/
val newNote = notesByVoice[voiceNum] ?: "" val newNote = notesByVoice[voiceNum] ?: ""
if (newNote.isEmpty()) continue if (newNote.isEmpty()) continue
@ -733,6 +735,7 @@ class Solfa(val sharedScreenModel: SharedScreenModel, private val fileRepository
} }
i++ i++
} }
currentLogicalIdx++
} else { } else {
// AFFICHAGE NOTE NORMALE // AFFICHAGE NOTE NORMALE
// println( // println(
@ -797,6 +800,7 @@ class Solfa(val sharedScreenModel: SharedScreenModel, private val fileRepository
var i = 0 var i = 0
var currentBlock = StringBuilder() var currentBlock = StringBuilder()
val separators = listOf(':', '|', '!', '/') val separators = listOf(':', '|', '!', '/')
var dropNextCloseParenthesis = false
while (i <= body.length) { while (i <= body.length) {
if (i < body.length && body[i] == '$' && i + 1 < body.length && body[i + 1] == '{') { if (i < body.length && body[i] == '$' && i + 1 < body.length && body[i + 1] == '{') {
@ -833,12 +837,48 @@ class Solfa(val sharedScreenModel: SharedScreenModel, private val fileRepository
val markerMatch = Regex("""\$\{.*?\}|\$.""").find(rawBlockText) val markerMatch = Regex("""\$\{.*?\}|\$.""").find(rawBlockText)
val existingMarker = markerMatch?.value ?: "" val existingMarker = markerMatch?.value ?: ""
val leadingCloseParentheses = rawBlockText.takeWhile { it == ')' }
val oldCleaned = rawBlockText.substring(leadingCloseParentheses.length)
val newTemplate = getGlobalTemplate(editState) val newTemplate = getGlobalTemplate(editState)
newMarkerValue + existingMarker + newTemplate val oldHadOpen = oldCleaned.contains("(")
val newHasOpen = newTemplate.contains("(")
if (oldHadOpen && !newHasOpen) {
dropNextCloseParenthesis = true
}
var adjustedTemplate = newTemplate
if (newTemplate.endsWith(")")) {
val remainingText = body.substring(i).trimStart { it in separators }
if (remainingText.startsWith(")")) {
adjustedTemplate = newTemplate.dropLast(1)
}
}
val rawProcessed = leadingCloseParentheses + newMarkerValue + existingMarker + adjustedTemplate
var cleanedProcessed = rawProcessed
while (cleanedProcessed.contains("((") || cleanedProcessed.contains("))")) {
cleanedProcessed = cleanedProcessed.replace("((", "(").replace("))", ")")
}
cleanedProcessed
} else {
if (dropNextCloseParenthesis && rawBlockText.startsWith(")")) {
actionTaken = "FIX_ORPHEL_)"
dropNextCloseParenthesis = false
rawBlockText.substring(1)
} else { } else {
rawBlockText rawBlockText
} }
}
if (blockToProcess.contains("((") || blockToProcess.contains("))")) {
while (blockToProcess.contains("((") || blockToProcess.contains("))")) {
blockToProcess = blockToProcess.replace("((", "(").replace("))", ")")
}
}
val compactedBlock = StringBuilder() val compactedBlock = StringBuilder()
if (blockToProcess.isNotEmpty()) { if (blockToProcess.isNotEmpty()) {
var k = 0 var k = 0
@ -896,8 +936,8 @@ class Solfa(val sharedScreenModel: SharedScreenModel, private val fileRepository
compactedBlock.append("") compactedBlock.append("")
} }
// println(String.format("%-4d | %-25s | %-15s | %-25s", println(String.format("%-4d | %-25s | %-15s | %-25s",
// currentLogicalIdx, rawBlockText, actionTaken, compactedBlock.toString())) currentLogicalIdx, rawBlockText, actionTaken, compactedBlock.toString()))
resultBody.append(compactedBlock) resultBody.append(compactedBlock)
if (i < body.length) resultBody.append(body[i]) if (i < body.length) resultBody.append(body[i])
@ -911,9 +951,9 @@ class Solfa(val sharedScreenModel: SharedScreenModel, private val fileRepository
} }
val finalResult = "$prefix$resultBody$suffix" val finalResult = "$prefix$resultBody$suffix"
// println("-".repeat(100)) println("-".repeat(100))
// println("RÉSULTAT FINAL COMPACTÉ : $finalResult") println("RÉSULTAT FINAL COMPACTÉ : $finalResult")
// println("=".repeat(100)) println("=".repeat(100))
return finalResult return finalResult
} }

View file

@ -60,10 +60,10 @@ fun TUODetailDialog(
var marker by remember { mutableStateOf(editState.marker) } var marker by remember { mutableStateOf(editState.marker) }
LaunchedEffect(notes.values.toList()) { LaunchedEffect(notes.toMap()) {
val tempState = TUOEditState( val tempState = TUOEditState(
tuoIndex = editState.tuoIndex, tuoIndex = editState.tuoIndex,
notesByVoice = notes, notesByVoice = notes.toMap(),
originalNotes = editState.originalNotes, originalNotes = editState.originalNotes,
lyricsByStanza = editState.lyricsByStanza, lyricsByStanza = editState.lyricsByStanza,
originalLyricsByStanza = editState.originalLyricsByStanza, originalLyricsByStanza = editState.originalLyricsByStanza,
@ -382,7 +382,7 @@ fun validateMusicalInput(input: String, template: String): Boolean {
cleanTemplate.forEachIndexed { index, char -> cleanTemplate.forEachIndexed { index, char ->
when (char) { when (char) {
in 'A'..'Y', in 'a'..'y' -> { in 'A'..'Y', in 'a'..'y' -> {
append("(?:―|di|ri|fi|si|ta|[drmfslt])[¹²³₁₂₃]*") append("(?:―|di|ri|fi|si|ta|[drmfsltz])[¹²³₁₂₃]*")
} }
'z' -> { 'z' -> {
append(" ?") append(" ?")
@ -431,32 +431,83 @@ public fun getGlobalTemplate(editState: TUOEditState): String {
tpl tpl
} }
val maxLen = voiceTemplates.maxOfOrNull { it.length } ?: 1 val rythmicTemplates = voiceTemplates.map { tpl -> tpl.replace(Regex("[()]"), "") }
// println("Longueur max détectée: $maxLen") val maxLen = rythmicTemplates.maxOfOrNull { it.length } ?: 1
// println("Longueur rythmique max détectée: $maxLen")
val openBefore = BooleanArray(maxLen)
val closeBefore = BooleanArray(maxLen)
val openAfter = BooleanArray(maxLen)
val closeAfter = BooleanArray(maxLen)
var openAtTheEnd = false
var closeAtTheEnd = false
voiceTemplates.forEach { tpl ->
var rythmicIdx = 0
for (i in tpl.indices) {
val char = tpl[i]
if (char == '(' || char == ')') {
val textAfter = tpl.substring(i + 1)
val hasRythmicAfter = textAfter.any { it != '(' && it != ')' }
if (hasRythmicAfter) {
if (rythmicIdx < maxLen) {
if (char == '(') openBefore[rythmicIdx] = true
if (char == ')') closeBefore[rythmicIdx] = true
}
} else {
if (rythmicIdx > 0) {
if (char == '(') openAfter[rythmicIdx - 1] = true
if (char == ')') closeAfter[rythmicIdx - 1] = true
} else {
if (char == '(') openAtTheEnd = true
if (char == ')') closeAtTheEnd = true
}
}
} else {
rythmicIdx++
}
}
}
val result = StringBuilder() val result = StringBuilder()
for (i in 0 until maxLen) { for (i in 0 until maxLen) {
val chars = voiceTemplates.mapNotNull { it.getOrNull(i) }.toSet() if (openBefore[i]) result.append('(')
if (closeBefore[i]) result.append(')')
val lastChar = if (result.isNotEmpty()) result.last() else null val chars = rythmicTemplates.mapNotNull { it.getOrNull(i) }.toSet()
val previousChars = if(i>0) rythmicTemplates.mapNotNull { it.getOrNull(i-1) }.toSet() else "".toSet()
if (lastChar == '.' && chars.contains(',')) { val activeChars = rythmicTemplates.mapNotNull { it.getOrNull(i) }
result.append('z') val isAllHyphen = activeChars.isNotEmpty() && activeChars.all { it == '-' }
}
// println(" Indice $i | Caractères collectés: $chars")
val combinedChar = when { val combinedChar = when {
chars.contains('D') || chars.contains('-') -> 'D' chars.contains('D') -> 'D'
isAllHyphen -> '-'
chars.contains('.') -> '.' chars.contains('.') -> '.'
chars.contains(',') -> ',' chars.contains(',') -> ','
chars.contains('(') -> '(' previousChars.contains('.') && chars.contains(' ') -> 'z'
chars.contains(')') -> ')' else -> ' '
else -> 'z'
} }
// Supprimer espace avant une virgule
if (combinedChar == ',' && result.isNotEmpty() && result.last() == ' ') {
result.deleteCharAt(result.length - 1)
}
println("Pour $i = ${chars.toString()} on a > ${combinedChar.toString()}")
val lastChar = if (result.isNotEmpty()) result.last() else null
if (!((combinedChar == '.' && lastChar == '.') || (combinedChar == ',' && lastChar == ','))) {
result.append(combinedChar) result.append(combinedChar)
} }
println("all = ${result.toString()}")
if (openAfter[i]) result.append('(')
if (closeAfter[i]) result.append(')')
}
if (openAtTheEnd) result.append('(')
if (closeAtTheEnd) result.append(')')
// println("Template Global Final: '${result.toString()}'") // println("Template Global Final: '${result.toString()}'")
// println("----------------------------------\n") // println("----------------------------------\n")
@ -476,7 +527,7 @@ private fun notesToTemplate(notes: String): String {
.replace("si", "S") .replace("si", "S")
.replace("ta", "T") .replace("ta", "T")
val noteRegex = Regex("([drmfsltDRFSTz]+|[.,()-])") val noteRegex = Regex("""([drmfsltDRFSTz]+|[.,()\s-])""")
val template = StringBuilder() val template = StringBuilder()
val matches = noteRegex.findAll(cleaned) val matches = noteRegex.findAll(cleaned)
@ -484,6 +535,7 @@ private fun notesToTemplate(notes: String): String {
val value = match.value val value = match.value
when { when {
value.matches(Regex("[.,()-]")) -> template.append(value) value.matches(Regex("[.,()-]")) -> template.append(value)
value.trim().isEmpty() -> template.append(" ")
else -> template.append("D") else -> template.append("D")
} }
} }

View file

@ -1262,10 +1262,10 @@ 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("ça on a t $template => $rawNote")
if (rawNote.isEmpty() || rawNote == "_") return rawNote if (rawNote == "_") return rawNote
val noteRegex = Regex("([drmfsltDRFSTw][ia]?|―)[0-9'¹²³⁴₁₂₃₄,]*") val noteRegex = Regex("([drmfsltDRFSTw][ia]?|―)[0-9'¹²³⁴₁₂₃₄,]*")
val actualNotes = noteRegex.findAll(rawNote).map { it.value }.toList() val actualNotes = if (rawNote.isEmpty()) emptyList() else noteRegex.findAll(rawNote).map { it.value }.toList()
if (rawNote.contains("") || rawNote.contains("") || rawNote.contains(",")) { if (rawNote.contains("") || rawNote.contains("") || rawNote.contains(",")) {
val templateNotesCount = template.count { c -> val templateNotesCount = template.count { c ->
@ -1273,6 +1273,9 @@ fun autoFixNote(rawNote: String, template: String): String {
} }
if (actualNotes.size >= templateNotesCount) return rawNote if (actualNotes.size >= templateNotesCount) return rawNote
} }
val requiredNotesCount = template.count { it in 'A'..'Y' || it in 'a'..'y' }
val shouldIncludeParentheses = actualNotes.size >= requiredNotesCount
val result = StringBuilder() val result = StringBuilder()
var noteIdx = 0 var noteIdx = 0
@ -1289,10 +1292,14 @@ fun autoFixNote(rawNote: String, template: String): String {
result.append(noteToAdd) result.append(noteToAdd)
noteIdx++ noteIdx++
} else {
if (rawNote.isEmpty()) {
result.append("z")
} else { } else {
result.append("") result.append("")
} }
} }
}
char == '-' -> { char == '-' -> {
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
@ -1307,8 +1314,12 @@ fun autoFixNote(rawNote: String, template: String): String {
val currentText = result.toString() val currentText = result.toString()
if (!currentText.endsWith(",")) result.append(",") if (!currentText.endsWith(",")) result.append(",")
} }
char == '(' -> result.append("(") char == '(' -> {
char == ')' -> result.append(")") if (shouldIncludeParentheses) result.append("(")
}
char == ')' -> {
if (shouldIncludeParentheses) result.append(")")
}
} }
} }
return result.toString() return result.toString()