Compare commits

...

2 commits

4 changed files with 146 additions and 30 deletions

View file

@ -780,9 +780,12 @@ class Solfa(val sharedScreenModel: SharedScreenModel, private val fileRepository
editState: TUOEditState editState: TUOEditState
): String { ): String {
/* On ne modifie pas le template tant que les notes ne sont pas modifiées /* On ne modifie pas le template tant que les notes ne sont pas modifiées
* Et tant qu'une marker est ajouter */ * Et tant qu'un marker est ajouter
* Ou une séparateur de mesure est ajouter */
val notesByVoice = editState.notesByVoice val notesByVoice = editState.notesByVoice
val originalNotes = editState.originalNotes val originalNotes = editState.originalNotes
val separat = editState.sep
val originalSeparat = editState.originalSep
var anyNoteModified = false var anyNoteModified = false
for (voiceNum in 0..3) { for (voiceNum in 0..3) {
val newNot = notesByVoice[voiceNum] ?: "" val newNot = notesByVoice[voiceNum] ?: ""
@ -793,6 +796,9 @@ class Solfa(val sharedScreenModel: SharedScreenModel, private val fileRepository
break break
} }
} }
if((originalSeparat != separat)) {
anyNoteModified = true
}
if (!anyNoteModified && newMarkerValue.isEmpty()) { if (!anyNoteModified && newMarkerValue.isEmpty()) {
println("Aucune modification détectée, on retourne le template original.") println("Aucune modification détectée, on retourne le template original.")
return templateLine return templateLine
@ -885,7 +891,7 @@ class Solfa(val sharedScreenModel: SharedScreenModel, private val fileRepository
} }
} }
val rawProcessed = leadingCloseParentheses + newMarkerValue + existingMarker + adjustedTemplate val rawProcessed = separat + leadingCloseParentheses + newMarkerValue + existingMarker + adjustedTemplate
var cleanedProcessed = rawProcessed var cleanedProcessed = rawProcessed
while (cleanedProcessed.contains("((") || cleanedProcessed.contains("))")) { while (cleanedProcessed.contains("((") || cleanedProcessed.contains("))")) {
@ -969,7 +975,14 @@ class Solfa(val sharedScreenModel: SharedScreenModel, private val fileRepository
// 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) {
// println("$currentLogicalIdx == ${targetPointer - 1} && ($separat) && ${body[i]} in separators")
if (currentLogicalIdx == (targetPointer-1) && separat.isEmpty() && body[i] in separators) {
resultBody.append('|')
} else {
resultBody.append(body[i])
}
}
currentBlock.clear() currentBlock.clear()
currentLogicalIdx++ currentLogicalIdx++

View file

@ -11,11 +11,7 @@ import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.ArrowBack import androidx.compose.material.icons.automirrored.filled.ArrowBack
import androidx.compose.material.icons.automirrored.filled.ArrowForward import androidx.compose.material.icons.automirrored.filled.ArrowForward
import androidx.compose.material.icons.filled.Add import androidx.compose.material.icons.filled.*
import androidx.compose.material.icons.filled.Build
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
@ -23,12 +19,11 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Brush import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.SolidColor import androidx.compose.ui.graphics.SolidColor
import androidx.compose.ui.text.TextRange
import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontFamily import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.input.TextFieldValue import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.* import androidx.compose.ui.unit.*
import androidx.compose.ui.window.Popup import androidx.compose.ui.window.Popup
import androidx.compose.ui.window.PopupProperties import androidx.compose.ui.window.PopupProperties
@ -63,10 +58,14 @@ fun TUODetailDialog(
} }
var templateFragment by remember { mutableStateOf(editState.templateFragment) } var templateFragment by remember { mutableStateOf(editState.templateFragment) }
var newSep by remember { mutableStateOf(editState.sep) }
var marker by remember { mutableStateOf(editState.marker) } var marker by remember { mutableStateOf(editState.marker) }
val initialSep = remember { editState.sep }
val initialMarker = remember { editState.marker } val initialMarker = remember { editState.marker }
var canAddSep = mutableStateOf(false)
LaunchedEffect(notes.toMap()) { LaunchedEffect(notes.toMap()) {
val tempState = TUOEditState( val tempState = TUOEditState(
tuoIndex = editState.tuoIndex, tuoIndex = editState.tuoIndex,
@ -237,7 +236,62 @@ fun TUODetailDialog(
.verticalScroll(rememberScrollState()) .verticalScroll(rememberScrollState())
) { ) {
// --- SECTION TEMPLATE --- // --- SECTION TEMPLATE ---
Row(horizontalArrangement = Arrangement.spacedBy(8.dp)) { Row(horizontalArrangement = Arrangement.SpaceEvenly, verticalAlignment = Alignment.CenterVertically) {
if(globalIndex != 0) {
Column(
modifier = Modifier.width(20.dp)
) {
val isSeparator = (newSep.isNotEmpty() || canAddSep.value) && newSep == "/"
val tooltipText = if (isSeparator) {
"Enlever la barre de mesure"
} else {
"Ajouter une barre de mesure"
}
TooltipBox(
positionProvider = TooltipDefaults.rememberPlainTooltipPositionProvider(),
tooltip = {
PlainTooltip(
containerColor = Color.DarkGray,
contentColor = Color.White
) {
Text(text = tooltipText, fontSize = 12.sp)
}
},
state = rememberTooltipState()
) {
if(isSeparator) {
IconButton(
modifier = Modifier.size(20.dp),
onClick = {
canAddSep.value = false
newSep = ""
}) {
Text(
text = "/",
color = Color.Cyan,
fontSize = 18.sp,
fontWeight = FontWeight.Bold,
textAlign = TextAlign.Center
)
}
} else {
IconButton(
modifier = Modifier.size(20.dp),
onClick = {
canAddSep.value = true
newSep = "/"
}) {
Icon(
imageVector = Icons.Default.Add,
tint = Color.Cyan,
contentDescription = null
)
}
}
}
}
}
Column( Column(
modifier = Modifier.weight(1f) modifier = Modifier.weight(1f)
) { ) {
@ -269,19 +323,19 @@ fun TUODetailDialog(
onValueChng = { marker = it } onValueChng = { marker = it }
) )
} }
} else { } else {
IconButton( IconButton(
modifier = Modifier.size(30.dp), modifier = Modifier.size(30.dp),
onClick = { onClick = {
canAddMark.value = true canAddMark.value = true
}) { }) {
Icon( Icon(
imageVector = Icons.Default.Add, imageVector = Icons.Default.Add,
tint = Color.Green, tint = Color.Green,
contentDescription = null contentDescription = null
) )
}
} }
}
} }
Spacer(modifier = Modifier.height(8.dp)) Spacer(modifier = Modifier.height(8.dp))
@ -403,6 +457,8 @@ fun TUODetailDialog(
templateFragment = templateFragment, templateFragment = templateFragment,
/* On ne ré-insere pas la même marker*/ /* On ne ré-insere pas la même marker*/
marker = if(marker != initialMarker) marker else "", marker = if(marker != initialMarker) marker else "",
originalSep = initialSep,
sep = if(newSep != initialSep) newSep else ""
) )
onSave(state) onSave(state)
}, },
@ -420,7 +476,7 @@ fun TUODetailDialog(
} }
} }
} }
fun transformMusicalInput(input: String): String { private fun transformMusicalInput(input: String): String {
return input.lowercase() return input.lowercase()
.replace(";", "• ,") .replace(";", "• ,")
.replace(".", "") .replace(".", "")

View file

@ -8,5 +8,7 @@ data class TUOEditState(
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" val silentDuration: String = "-1",
val originalSep: String = " ",
val sep: String = " "
) )

View file

@ -6,7 +6,9 @@ import androidx.compose.animation.core.tween
import androidx.compose.foundation.Canvas import androidx.compose.foundation.Canvas
import androidx.compose.foundation.LocalIndication import androidx.compose.foundation.LocalIndication
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.combinedClickable import androidx.compose.foundation.combinedClickable
import androidx.compose.foundation.focusable
import androidx.compose.foundation.gestures.detectTapGestures import androidx.compose.foundation.gestures.detectTapGestures
import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.interaction.collectIsHoveredAsState import androidx.compose.foundation.interaction.collectIsHoveredAsState
@ -16,11 +18,9 @@ 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.*
@ -28,6 +28,8 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.drawBehind import androidx.compose.ui.draw.drawBehind
import androidx.compose.ui.draw.drawWithContent import androidx.compose.ui.draw.drawWithContent
import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.geometry.Offset import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.geometry.Size import androidx.compose.ui.geometry.Size
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
@ -36,6 +38,7 @@ import androidx.compose.ui.graphics.drawscope.Stroke
import androidx.compose.ui.input.pointer.pointerInput import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.layout.onSizeChanged import androidx.compose.ui.layout.onSizeChanged
import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.text.* import androidx.compose.ui.text.*
import androidx.compose.ui.text.font.FontFamily import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.font.FontStyle import androidx.compose.ui.text.font.FontStyle
@ -265,7 +268,9 @@ fun TimeUnitComposable(
tuo: TimeUnitObject, tuo: TimeUnitObject,
stanzaNumber: Int, stanzaNumber: Int,
gridColumnCount: Int, gridColumnCount: Int,
gridActive: Boolean gridActive: Boolean,
isCurrentBlock: Boolean = false,
parentFocusRequester: FocusRequester? = null
) { ) {
val col = if (tuo.getNum() % 2 == 0) Color(0xff, 0xfa, 0xf7) else Color(0xfb, 0xf3, 0xff) val col = if (tuo.getNum() % 2 == 0) Color(0xff, 0xfa, 0xf7) else Color(0xfb, 0xf3, 0xff)
val currentDensity = LocalDensity.current val currentDensity = LocalDensity.current
@ -274,6 +279,8 @@ fun TimeUnitComposable(
targetValue = if (gridActive) Color.Cyan.copy(alpha = 0.5f) else col, targetValue = if (gridActive) Color.Cyan.copy(alpha = 0.5f) else col,
animationSpec = tween(durationMillis = 100) // Très court pour rester réactif animationSpec = tween(durationMillis = 100) // Très court pour rester réactif
) )
val focusRequesters = remember { List(4) { FocusRequester() } }
Column( Column(
modifier = Modifier modifier = Modifier
.background(animatedColor) .background(animatedColor)
@ -569,6 +576,9 @@ fun LazyVerticalGridTUO(
var selectedIndex by remember { mutableStateOf(-1) } var selectedIndex by remember { mutableStateOf(-1) }
val regexMeasure = Regex("(\\d)/\\d").find(viewModel.measure) val regexMeasure = Regex("(\\d)/\\d").find(viewModel.measure)
val focusRequester = remember { FocusRequester() }
var selectedGridIndex by remember { mutableStateOf(0) }
LaunchedEffect(tuoList) { LaunchedEffect(tuoList) {
showContextualMenu = false showContextualMenu = false
showEditDialog = false showEditDialog = false
@ -580,13 +590,21 @@ fun LazyVerticalGridTUO(
val editMode by sharedScreenModel.modeEditor.collectAsState() val editMode by sharedScreenModel.modeEditor.collectAsState()
val focusManager = LocalFocusManager.current
Column( Column(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.onSizeChanged { size -> .onSizeChanged { size ->
onGridWidthMeasured(size.width) onGridWidthMeasured(size.width)
} }
.focusRequester(focusRequester)
.focusable()
) { ) {
LaunchedEffect(editMode) {
if (editMode) {
focusRequester.requestFocus()
}
}
val density = LocalDensity.current val density = LocalDensity.current
val horizontalArrangementSpacing: Dp = 0.dp val horizontalArrangementSpacing: Dp = 0.dp
val columnGroupString = regexMeasure?.groupValues?.get(1) ?: "1" val columnGroupString = regexMeasure?.groupValues?.get(1) ?: "1"
@ -765,6 +783,7 @@ fun LazyVerticalGridTUO(
measureTUOs.forEachIndexed { indexInMeasure, oneTUO -> measureTUOs.forEachIndexed { indexInMeasure, oneTUO ->
val globalIndex = (measureIndex * gridColumnCount) + indexInMeasure val globalIndex = (measureIndex * gridColumnCount) + indexInMeasure
val isActive = (globalIndex == activeRowIndex) val isActive = (globalIndex == activeRowIndex)
val isSelectedByKeyboard = (globalIndex == selectedGridIndex)
val myTimestamp = sharedScreenModel.tuoTimestamps.value.getOrElse(globalIndex) { 0L } val myTimestamp = sharedScreenModel.tuoTimestamps.value.getOrElse(globalIndex) { 0L }
var menuOffset by remember { mutableStateOf(Offset.Zero) } var menuOffset by remember { mutableStateOf(Offset.Zero) }
@ -774,6 +793,11 @@ fun LazyVerticalGridTUO(
key(oneTUO.numBlock) { key(oneTUO.numBlock) {
Box(modifier = Modifier Box(modifier = Modifier
.width(gridWidthDp / gridColumnCount) .width(gridWidthDp / gridColumnCount)
.border(
width = if (isSelectedByKeyboard && editMode) 2.dp else 0.dp,
color = if (isSelectedByKeyboard && editMode) Color(0xFF9C27B0) else Color.Transparent,
shape = RoundedCornerShape(4.dp)
)
.background( .background(
if (isHovered) Color.Black.copy(alpha = 0.05f) else Color.Transparent, if (isHovered) Color.Black.copy(alpha = 0.05f) else Color.Transparent,
RoundedCornerShape(4.dp) RoundedCornerShape(4.dp)
@ -787,6 +811,7 @@ fun LazyVerticalGridTUO(
detectTapGestures( detectTapGestures(
onTap = { offset -> onTap = { offset ->
if(editMode) { if(editMode) {
selectedGridIndex = globalIndex
menuOffset = offset menuOffset = offset
selectedTUO = oneTUO selectedTUO = oneTUO
selectedIndex = globalIndex selectedIndex = globalIndex
@ -802,7 +827,9 @@ fun LazyVerticalGridTUO(
tuo = oneTUO, tuo = oneTUO,
stanzaNumber = currentStanza, stanzaNumber = currentStanza,
gridColumnCount = gridColumnCount, gridColumnCount = gridColumnCount,
gridActive = isActive gridActive = isActive,
isCurrentBlock = isSelectedByKeyboard && editMode,
parentFocusRequester = focusRequester
) )
if (showContextualMenu && selectedIndex == globalIndex) { if (showContextualMenu && selectedIndex == globalIndex) {
@ -877,7 +904,8 @@ fun LazyVerticalGridTUO(
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 silentDuration = blankPrefix,
sep = oneTUO.sep0
) )
TUODetailDialog( TUODetailDialog(
editState = editState, editState = editState,
@ -1422,4 +1450,21 @@ fun autoFixNote(rawNote: String, template: String): String {
// println("on a RES ${finalResult}") // println("on a RES ${finalResult}")
return finalResult return finalResult
}
private fun transformMusicalInput(input: String): String {
return input.lowercase()
.replace(";", "• ,")
.replace(".", "")
.replace("-", "")
.replace("(?<=[a-z])[']".toRegex(), "¹")
.replace("(?<=[a-z])[,]".toRegex(), "")
.replace("¹¹", "²")
.replace("¹'", "²")
.replace("²¹", "³")
.replace("²'", "³")
.replace("₁,", "")
.replace("₁₁", "")
.replace("₂,", "")
.replace("₂₁", "")
.replace("'", "¹")
} }