Resolve crash in TUO by refactoring composables - Android
This commit is contained in:
parent
10eca05472
commit
1d7273a531
1 changed files with 279 additions and 282 deletions
|
|
@ -320,84 +320,6 @@ fun TimeUnitComposable(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.background(animatedColor)
|
.background(animatedColor)
|
||||||
) {
|
) {
|
||||||
if (TimeUnitObject._hasMarker) {
|
|
||||||
val lineHeight = 20.sp
|
|
||||||
val density = LocalDensity.current
|
|
||||||
val lineHeightDp : Dp = with(density) {
|
|
||||||
lineHeight.toDp()
|
|
||||||
}
|
|
||||||
var fontStyle = FontStyle.Normal
|
|
||||||
var fontWeight = FontWeight.Normal
|
|
||||||
val hairPinSymbol = tuo.hasHairPin()
|
|
||||||
val yHeight = with(density) { lineHeightDp.toPx()}
|
|
||||||
|
|
||||||
/*if (tuo.isTriolet()) {
|
|
||||||
Canvas(modifier = Modifier.fillMaxSize()) {
|
|
||||||
val arcWidth = with(density) { size.width * 0.75f}
|
|
||||||
drawArc(
|
|
||||||
color = FEUFAROO_TRIOLET_COLOR,
|
|
||||||
startAngle = 200f,
|
|
||||||
sweepAngle = 140f,
|
|
||||||
useCenter = false,
|
|
||||||
topLeft = Offset(0f, yHeight / 2),
|
|
||||||
size = Size(arcWidth, yHeight),
|
|
||||||
style = Stroke(width = 2f)
|
|
||||||
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ((hairPinSymbol == '=') && (TimeUnitObject.lastHairPinSymbol != null)) {
|
|
||||||
println("LastHairpin: ${TimeUnitObject.lastHairPinSymbol} ${TimeUnitObject.lastHairPinStart}")
|
|
||||||
val hairPinStart = TimeUnitObject.lastHairPinStart
|
|
||||||
val lastHairPinSymbol = TimeUnitObject.lastHairPinSymbol
|
|
||||||
val hairPinStartLine: Int = (hairPinStart - 1) / gridColumnCount
|
|
||||||
val hairPinEndLine: Int = (tuo.numBlock - 1) / gridColumnCount
|
|
||||||
if (hairPinStartLine == hairPinEndLine) {
|
|
||||||
Canvas(
|
|
||||||
modifier = Modifier.fillMaxSize()
|
|
||||||
) {
|
|
||||||
val xStart = if (lastHairPinSymbol == '>') -size.width * (tuo.numBlock - hairPinStart) else size.width/2
|
|
||||||
val xEnd = if (lastHairPinSymbol == '>') size.width/2 else -size.width * (tuo.numBlock - hairPinStart)
|
|
||||||
drawLine(
|
|
||||||
Color.DarkGray,
|
|
||||||
start = Offset(x=xStart, y=0f),
|
|
||||||
end = Offset(xEnd, yHeight/2)
|
|
||||||
)
|
|
||||||
drawLine(
|
|
||||||
Color.DarkGray,
|
|
||||||
start = Offset(xStart, yHeight),
|
|
||||||
end = Offset(xEnd, yHeight/2)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
TimeUnitObject.endHairPin()
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
if (hairPinSymbol != null && hairPinSymbol != '=') {
|
|
||||||
TimeUnitObject.startHairPin(hairPinSymbol, tuo.numBlock)
|
|
||||||
}
|
|
||||||
// @todo pTemplate.markerToString retourne les marqueurs comme une seule chaîne
|
|
||||||
// problème si template = $QD:,-$QD
|
|
||||||
tuo.pTemplate.resetCalledMarker()
|
|
||||||
val text = tuo.pTemplate.markerToString()
|
|
||||||
if (text.contains(Regex("^([mfp]+|[rR]it.*)$"))) {
|
|
||||||
fontStyle = FontStyle.Italic
|
|
||||||
}
|
|
||||||
if (text.contains("p")) {
|
|
||||||
fontWeight = FontWeight.Bold
|
|
||||||
}*/
|
|
||||||
/*AutoResizingText(
|
|
||||||
text = text,
|
|
||||||
minFontSize = 18.sp,
|
|
||||||
maxFontSize = 18.sp,
|
|
||||||
maxLines = 2,
|
|
||||||
fontStyle = fontStyle,
|
|
||||||
fontWeight = fontWeight,
|
|
||||||
modifier = Modifier.fillMaxWidth()
|
|
||||||
.height(lineHeightDp))*/
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
Row (modifier = Modifier.height(IntrinsicSize.Min)){
|
Row (modifier = Modifier.height(IntrinsicSize.Min)){
|
||||||
if (tuo.sep0 == "/" || tuo.sep0 == "|") {
|
if (tuo.sep0 == "/" || tuo.sep0 == "|") {
|
||||||
Box(
|
Box(
|
||||||
|
|
@ -850,106 +772,20 @@ fun LazyVerticalGridTUO(
|
||||||
}
|
}
|
||||||
var fontStyle = FontStyle.Normal
|
var fontStyle = FontStyle.Normal
|
||||||
var fontWeight = FontWeight.Normal
|
var fontWeight = FontWeight.Normal
|
||||||
val hairPinSymbol = tuo.hasHairPin()
|
|
||||||
val yHeight = with(density) { lineHeightDp.toPx() }
|
val yHeight = with(density) { lineHeightDp.toPx() }
|
||||||
|
|
||||||
if (tuo.isTriolet()) {
|
TuoHeaderDecorations(
|
||||||
Canvas(modifier = Modifier.fillMaxSize()) {
|
tuo,
|
||||||
val arcWidth = size.width * 0.65f
|
colorUnderline,
|
||||||
drawArc(
|
yHeight,
|
||||||
color = colorUnderline,
|
hairpinByEndBlock,
|
||||||
startAngle = 200f,
|
ptSerifBoldItalic,
|
||||||
sweepAngle = 140f,
|
emmentaler,
|
||||||
useCenter = false,
|
ptSerif,
|
||||||
//topLeft = Offset(0f, yHeight/* / 2*/),
|
fontStyle
|
||||||
topLeft = Offset(size.width *0.05f, -yHeight * 0.1f),
|
|
||||||
size = Size(arcWidth, yHeight),
|
|
||||||
style = Stroke(width = 2f)
|
|
||||||
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val hairpinRange = hairpinByEndBlock[tuo.numBlock]
|
|
||||||
if (hairpinRange != null) {
|
|
||||||
Canvas(
|
|
||||||
modifier = Modifier.fillMaxSize()
|
|
||||||
) {
|
|
||||||
val xStart = if (hairpinRange.symbol == '>') -size.width * (tuo.numBlock - hairpinRange.startBlock) else size.width / 2
|
|
||||||
val xEnd = if (hairpinRange.symbol == '>') size.width / 2 else -size.width * (tuo.numBlock - hairpinRange.startBlock)
|
|
||||||
val offsetUp = -yHeight * 0.30f
|
|
||||||
val hairpinHeight = yHeight * 0.70f
|
|
||||||
|
|
||||||
val yTop = 0f + offsetUp
|
|
||||||
val yCenter = (hairpinHeight / 2) + offsetUp
|
|
||||||
val yBottom = hairpinHeight + offsetUp
|
|
||||||
|
|
||||||
drawLine(
|
|
||||||
color = colorUnderline,
|
|
||||||
start = Offset(x = xStart, y = yTop),
|
|
||||||
end = Offset(xEnd, yCenter),
|
|
||||||
strokeWidth = 0.5f
|
|
||||||
)
|
|
||||||
drawLine(
|
|
||||||
color = colorUnderline,
|
|
||||||
start = Offset(xStart, yBottom),
|
|
||||||
end = Offset(xEnd, yCenter),
|
|
||||||
strokeWidth = 0.5f
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// @todo pTemplate.markerToString retourne les marqueurs comme une seule chaîne
|
|
||||||
// problème si template = $QD:,-$QD
|
|
||||||
tuo.pTemplate.resetCalledMarker()
|
|
||||||
|
|
||||||
val markerList = tuo.pTemplate.markerToList()
|
|
||||||
Row(
|
|
||||||
modifier = Modifier.wrapContentSize(unbounded = true, align = Alignment.CenterStart),
|
|
||||||
verticalAlignment = Alignment.CenterVertically
|
|
||||||
) {
|
|
||||||
markerList.forEach { marker ->
|
|
||||||
Column {
|
|
||||||
var markerFontFamily: FontFamily = FontFamily.Default
|
|
||||||
var markerFontSize: Float = MaterialTheme.typography.titleMedium.fontSize.value
|
|
||||||
|
|
||||||
when {
|
|
||||||
musicForPtSerifBIRegex.matches(marker) -> {
|
|
||||||
markerFontSize = MaterialTheme.typography.titleMedium.fontSize.value
|
|
||||||
markerFontFamily = ptSerifBoldItalic
|
|
||||||
}
|
|
||||||
|
|
||||||
musicForEmmentRegex.matches(marker) -> {
|
|
||||||
markerFontSize = MaterialTheme.typography.titleMedium.fontSize.value + 11
|
|
||||||
markerFontFamily = emmentaler
|
|
||||||
}
|
|
||||||
|
|
||||||
else -> {
|
|
||||||
markerFontFamily = ptSerif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Text(
|
|
||||||
text = marker,
|
|
||||||
modifier = Modifier
|
|
||||||
.wrapContentSize(unbounded = true, align = Alignment.CenterStart,),
|
|
||||||
softWrap = false,
|
|
||||||
maxLines = 1,
|
|
||||||
fontStyle = fontStyle,
|
|
||||||
fontWeight = FontWeight.Bold,
|
|
||||||
style = MaterialTheme.typography.titleMedium.copy(
|
|
||||||
color = MaterialTheme.colorScheme.onSecondary,
|
|
||||||
fontSize = markerFontSize.sp,
|
|
||||||
fontFamily = markerFontFamily
|
|
||||||
)
|
|
||||||
)
|
|
||||||
if (marker != markerList.last()) {
|
|
||||||
Spacer(modifier = Modifier.width(2.dp))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(showFullChord) {
|
if(showFullChord) {
|
||||||
|
|
@ -959,55 +795,17 @@ fun LazyVerticalGridTUO(
|
||||||
verticalAlignment = Alignment.CenterVertically
|
verticalAlignment = Alignment.CenterVertically
|
||||||
) {
|
) {
|
||||||
measureTUOs.forEachIndexed { indexInMeasure, tuo ->
|
measureTUOs.forEachIndexed { indexInMeasure, tuo ->
|
||||||
val chordMap = (1..4).mapNotNull { voice ->
|
TuoChordRowItem(
|
||||||
val noteStr = tuo.tuNotes.getOrNull(voice)?.toString()
|
tuo,
|
||||||
if (noteStr != null) voice to noteStr else null
|
sharedScreenModel,
|
||||||
}.toMap()
|
gridWidthDp,
|
||||||
|
gridColumnCount,
|
||||||
val degreeName = remember(chordMap) {
|
toggleWithDegreeAndChord,
|
||||||
if (chordMap.isNotEmpty()) HarmonicAnalyzer.analyzeDegree(chordMap) else null
|
onToggleChange = {
|
||||||
}
|
toggleWithDegreeAndChord = it
|
||||||
val appliedInterval by sharedScreenModel.transpositionInterval.collectAsState()
|
|
||||||
val songKey = sharedScreenModel.songKey.value
|
|
||||||
val chordName = remember(chordMap, songKey, appliedInterval) {
|
|
||||||
if (chordMap.isNotEmpty()) HarmonicAnalyzer.analyzeChordName(chordMap, songKey, appliedInterval) else null
|
|
||||||
}
|
|
||||||
|
|
||||||
Column(
|
|
||||||
modifier = Modifier
|
|
||||||
.width(gridWidthDp / gridColumnCount)
|
|
||||||
) {
|
|
||||||
val maxFontSize = 12.sp
|
|
||||||
val minFontSize = 10.sp
|
|
||||||
var currentFontSize by remember { mutableStateOf(maxFontSize) }
|
|
||||||
|
|
||||||
TextButton(
|
|
||||||
onClick = { toggleWithDegreeAndChord = !toggleWithDegreeAndChord },
|
|
||||||
contentPadding = PaddingValues(0.dp),
|
|
||||||
modifier = Modifier.height(24.dp).fillMaxWidth()
|
|
||||||
) {
|
|
||||||
BoxWithConstraints(modifier = Modifier.fillMaxWidth()) {
|
|
||||||
val textToDisplay = if (toggleWithDegreeAndChord) (chordName ?: "") else (degreeName ?: "")
|
|
||||||
|
|
||||||
Text(
|
|
||||||
text = textToDisplay,
|
|
||||||
onTextLayout = { textLayoutResult ->
|
|
||||||
if (textLayoutResult.hasVisualOverflow && currentFontSize > minFontSize) {
|
|
||||||
currentFontSize = (currentFontSize.value * 0.9f).sp
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
softWrap = false,
|
modifier = Modifier.height(24.dp).fillMaxWidth()
|
||||||
maxLines = 1,
|
|
||||||
overflow = TextOverflow.Visible,
|
|
||||||
style = TextStyle(
|
|
||||||
color = if (!toggleWithDegreeAndChord) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.secondary.copy(red = MaterialTheme.colorScheme.secondary.red * 0.4f, green = MaterialTheme.colorScheme.secondary.green * 0.4f, blue = MaterialTheme.colorScheme.secondary.blue * 0.4f ),
|
|
||||||
fontWeight = FontWeight.Bold,
|
|
||||||
fontSize = currentFontSize
|
|
||||||
)
|
)
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1192,73 +990,21 @@ fun LazyVerticalGridTUO(
|
||||||
|
|
||||||
val currentSelected = selectedTUO
|
val currentSelected = selectedTUO
|
||||||
if ((showEditDialog || showDetailDialog) && currentSelected != null && selectedIndex == globalIndex) {
|
if ((showEditDialog || showDetailDialog) && currentSelected != null && selectedIndex == globalIndex) {
|
||||||
val canAdd = showAddDialog
|
|
||||||
val canEdit = showEditDialog || canAdd
|
|
||||||
|
|
||||||
val template = oneTUO.pTemplate.template
|
|
||||||
val expectedTemplate = template.count { it.isLetter() } == 2 && template.contains(".")
|
|
||||||
|
|
||||||
val fileC = sharedScreenModel.fileContent.value ?: ""
|
val fileC = sharedScreenModel.fileContent.value ?: ""
|
||||||
val lines = fileC.split("\n").toMutableList()
|
val lines = fileC.split("\n")
|
||||||
val u0Idx = lines.indexOfFirst { it.startsWith("U0:") }
|
TuoEditDialogWrapper(
|
||||||
val t0Idx = lines.indexOfFirst { it.startsWith("T0:") }
|
oneTUO = currentSelected,
|
||||||
|
|
||||||
val fullLine = when {
|
|
||||||
t0Idx != -1 -> {
|
|
||||||
lines[t0Idx]
|
|
||||||
}
|
|
||||||
u0Idx != -1 -> {
|
|
||||||
lines[u0Idx]
|
|
||||||
}
|
|
||||||
else -> ""
|
|
||||||
}
|
|
||||||
val afterU0T0 = fullLine.substringAfter("0:")
|
|
||||||
val match = blankPrefixRegex.find(afterU0T0)
|
|
||||||
val blankPrefix = match?.groups?.get(1)?.value ?: ""
|
|
||||||
|
|
||||||
val anchorsByVoice = (0..3).associate { voiceIdx ->
|
|
||||||
val linePrefix = "N${voiceIdx + 1}:"
|
|
||||||
val fullLine = lines.firstOrNull { it.startsWith(linePrefix) } ?: ""
|
|
||||||
voiceIdx to extractAnchorFromNoteLine(fullLine)
|
|
||||||
}
|
|
||||||
val editState = TUOEditState(
|
|
||||||
tuoIndex = oneTUO.firstTuoIndex,
|
|
||||||
notesByVoice = (0..3).associate { i ->
|
|
||||||
val rawNote = oneTUO.tuNotes.getOrNull(i + 1)?.toString() ?: ""
|
|
||||||
val fixedNote = autoFixNote(rawNote, template)
|
|
||||||
i to fixedNote
|
|
||||||
},
|
|
||||||
lyricsByStanza = (1..currentStanza).associate { s ->
|
|
||||||
s to oneTUO.lyricsAsMultiString(currentStanza)
|
|
||||||
}.toMutableMap(),
|
|
||||||
templateFragment = oneTUO.pTemplate.template,
|
|
||||||
marker = listOfNotNull(
|
|
||||||
oneTUO.pTemplate.markerToString().takeIf { it.isNotBlank() },
|
|
||||||
oneTUO.hasHairPin()?.toString()?.takeIf { it.isNotBlank() }
|
|
||||||
).joinToString(" "),
|
|
||||||
silentDuration = blankPrefix,
|
|
||||||
sep = oneTUO.sep0
|
|
||||||
)
|
|
||||||
TUODetailDialog(
|
|
||||||
editState = editState,
|
|
||||||
tuo = currentSelected,
|
|
||||||
currentStanza = currentStanza,
|
|
||||||
menuPosition = IntOffset(
|
|
||||||
menuOffset.x.roundToInt(),
|
|
||||||
menuOffset.y.roundToInt()
|
|
||||||
),
|
|
||||||
globalIndex = globalIndex,
|
globalIndex = globalIndex,
|
||||||
isEditable = canEdit,
|
currentStanza = currentStanza,
|
||||||
canAdd = canAdd,
|
menuOffset = menuOffset,
|
||||||
sharedScreenModel = sharedScreenModel,
|
sharedScreenModel = sharedScreenModel,
|
||||||
anchorsByVoice = anchorsByVoice,
|
lines = lines,
|
||||||
onDismiss = {
|
onDismiss = {
|
||||||
showAddDialog = false
|
showAddDialog = false
|
||||||
showDetailDialog = false
|
showDetailDialog = false
|
||||||
showEditDialog = false
|
showEditDialog = false
|
||||||
},
|
},
|
||||||
onSave = { newState ->
|
onSaveSuccess = {
|
||||||
sharedScreenModel.openTUOEditor(newState)
|
|
||||||
showAddDialog = false
|
showAddDialog = false
|
||||||
showEditDialog = false
|
showEditDialog = false
|
||||||
},
|
},
|
||||||
|
|
@ -1378,6 +1124,257 @@ fun LazyVerticalGridTUO(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun TuoChordRowItem(
|
||||||
|
tuo: TimeUnitObject,
|
||||||
|
sharedScreenModel: SharedScreenModel,
|
||||||
|
gridWidthDp: Dp,
|
||||||
|
gridColumnCount: Int,
|
||||||
|
toggleWithDegreeAndChord: Boolean,
|
||||||
|
onToggleChange: (Boolean) -> Unit,
|
||||||
|
modifier: Modifier
|
||||||
|
) {
|
||||||
|
val chordMap = (1..4).mapNotNull { voice ->
|
||||||
|
val noteStr = tuo.tuNotes.getOrNull(voice)?.toString()
|
||||||
|
if (noteStr != null) voice to noteStr else null
|
||||||
|
}.toMap()
|
||||||
|
|
||||||
|
val degreeName = remember(chordMap) {
|
||||||
|
if (chordMap.isNotEmpty()) HarmonicAnalyzer.analyzeDegree(chordMap) else null
|
||||||
|
}
|
||||||
|
val appliedInterval by sharedScreenModel.transpositionInterval.collectAsState()
|
||||||
|
val songKey = sharedScreenModel.songKey.value
|
||||||
|
val chordName = remember(chordMap, songKey, appliedInterval) {
|
||||||
|
if (chordMap.isNotEmpty()) HarmonicAnalyzer.analyzeChordName(chordMap, songKey, appliedInterval) else null
|
||||||
|
}
|
||||||
|
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.width(gridWidthDp / gridColumnCount)
|
||||||
|
) {
|
||||||
|
val maxFontSize = 12.sp
|
||||||
|
val minFontSize = 10.sp
|
||||||
|
var currentFontSize by remember { mutableStateOf(maxFontSize) }
|
||||||
|
|
||||||
|
TextButton(
|
||||||
|
onClick = { onToggleChange(!toggleWithDegreeAndChord) },
|
||||||
|
contentPadding = PaddingValues(0.dp),
|
||||||
|
modifier = modifier
|
||||||
|
) {
|
||||||
|
BoxWithConstraints(modifier = Modifier.fillMaxWidth()) {
|
||||||
|
val textToDisplay = if (toggleWithDegreeAndChord) (chordName ?: "") else (degreeName ?: "")
|
||||||
|
|
||||||
|
Text(
|
||||||
|
text = textToDisplay,
|
||||||
|
onTextLayout = { textLayoutResult ->
|
||||||
|
if (textLayoutResult.hasVisualOverflow && currentFontSize > minFontSize) {
|
||||||
|
currentFontSize = (currentFontSize.value * 0.9f).sp
|
||||||
|
}
|
||||||
|
},
|
||||||
|
softWrap = false,
|
||||||
|
maxLines = 1,
|
||||||
|
overflow = TextOverflow.Visible,
|
||||||
|
style = TextStyle(
|
||||||
|
color = if (!toggleWithDegreeAndChord) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.secondary.copy(
|
||||||
|
red = MaterialTheme.colorScheme.secondary.red * 0.4f,
|
||||||
|
green = MaterialTheme.colorScheme.secondary.green * 0.4f,
|
||||||
|
blue = MaterialTheme.colorScheme.secondary.blue * 0.4f
|
||||||
|
),
|
||||||
|
fontWeight = FontWeight.Bold,
|
||||||
|
fontSize = currentFontSize
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun TuoHeaderDecorations(
|
||||||
|
tuo: TimeUnitObject,
|
||||||
|
colorUnderline: Color,
|
||||||
|
yHeight: Float,
|
||||||
|
hairpinByEndBlock: Map<Int, HairpinRange>,
|
||||||
|
ptSerifBoldItalic: FontFamily,
|
||||||
|
emmentaler: FontFamily,
|
||||||
|
ptSerif: FontFamily,
|
||||||
|
fontStyle: FontStyle
|
||||||
|
) {
|
||||||
|
if (tuo.isTriolet()) {
|
||||||
|
Canvas(modifier = Modifier.fillMaxSize()) {
|
||||||
|
val arcWidth = size.width * 0.65f
|
||||||
|
drawArc(
|
||||||
|
color = colorUnderline,
|
||||||
|
startAngle = 200f,
|
||||||
|
sweepAngle = 140f,
|
||||||
|
useCenter = false,
|
||||||
|
//topLeft = Offset(0f, yHeight/* / 2*/),
|
||||||
|
topLeft = Offset(size.width * 0.05f, -yHeight * 0.1f),
|
||||||
|
size = Size(arcWidth, yHeight),
|
||||||
|
style = Stroke(width = 2f)
|
||||||
|
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val hairpinRange = hairpinByEndBlock[tuo.numBlock]
|
||||||
|
if (hairpinRange != null) {
|
||||||
|
Canvas(
|
||||||
|
modifier = Modifier.fillMaxSize()
|
||||||
|
) {
|
||||||
|
val xStart =
|
||||||
|
if (hairpinRange.symbol == '>') -size.width * (tuo.numBlock - hairpinRange.startBlock) else size.width / 2
|
||||||
|
val xEnd =
|
||||||
|
if (hairpinRange.symbol == '>') size.width / 2 else -size.width * (tuo.numBlock - hairpinRange.startBlock)
|
||||||
|
val offsetUp = -yHeight * 0.30f
|
||||||
|
val hairpinHeight = yHeight * 0.70f
|
||||||
|
|
||||||
|
val yTop = 0f + offsetUp
|
||||||
|
val yCenter = (hairpinHeight / 2) + offsetUp
|
||||||
|
val yBottom = hairpinHeight + offsetUp
|
||||||
|
|
||||||
|
drawLine(
|
||||||
|
color = colorUnderline,
|
||||||
|
start = Offset(x = xStart, y = yTop),
|
||||||
|
end = Offset(xEnd, yCenter),
|
||||||
|
strokeWidth = 0.5f
|
||||||
|
)
|
||||||
|
drawLine(
|
||||||
|
color = colorUnderline,
|
||||||
|
start = Offset(xStart, yBottom),
|
||||||
|
end = Offset(xEnd, yCenter),
|
||||||
|
strokeWidth = 0.5f
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// problème si template = $QD:,-$QD
|
||||||
|
tuo.pTemplate.resetCalledMarker()
|
||||||
|
|
||||||
|
val markerList = tuo.pTemplate.markerToList()
|
||||||
|
Row(
|
||||||
|
modifier = Modifier.wrapContentSize(unbounded = true, align = Alignment.CenterStart),
|
||||||
|
verticalAlignment = Alignment.CenterVertically
|
||||||
|
) {
|
||||||
|
markerList.forEach { marker ->
|
||||||
|
Column {
|
||||||
|
var markerFontFamily: FontFamily = FontFamily.Default
|
||||||
|
var markerFontSize: Float = MaterialTheme.typography.titleMedium.fontSize.value
|
||||||
|
|
||||||
|
when {
|
||||||
|
musicForPtSerifBIRegex.matches(marker) -> {
|
||||||
|
markerFontSize = MaterialTheme.typography.titleMedium.fontSize.value
|
||||||
|
markerFontFamily = ptSerifBoldItalic
|
||||||
|
}
|
||||||
|
|
||||||
|
musicForEmmentRegex.matches(marker) -> {
|
||||||
|
markerFontSize = MaterialTheme.typography.titleMedium.fontSize.value + 11
|
||||||
|
markerFontFamily = emmentaler
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> {
|
||||||
|
markerFontFamily = ptSerif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Text(
|
||||||
|
text = marker,
|
||||||
|
modifier = Modifier
|
||||||
|
.wrapContentSize(unbounded = true, align = Alignment.CenterStart),
|
||||||
|
softWrap = false,
|
||||||
|
maxLines = 1,
|
||||||
|
fontStyle = fontStyle,
|
||||||
|
fontWeight = FontWeight.Bold,
|
||||||
|
style = MaterialTheme.typography.titleMedium.copy(
|
||||||
|
color = MaterialTheme.colorScheme.onSecondary,
|
||||||
|
fontSize = markerFontSize.sp,
|
||||||
|
fontFamily = markerFontFamily
|
||||||
|
)
|
||||||
|
)
|
||||||
|
if (marker != markerList.last()) {
|
||||||
|
Spacer(modifier = Modifier.width(2.dp))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun TuoEditDialogWrapper(
|
||||||
|
oneTUO: TimeUnitObject,
|
||||||
|
globalIndex: Int,
|
||||||
|
currentStanza: Int,
|
||||||
|
menuOffset: Offset,
|
||||||
|
sharedScreenModel: SharedScreenModel,
|
||||||
|
lines: List<String>,
|
||||||
|
onDismiss: () -> Unit,
|
||||||
|
onSaveSuccess: () -> Unit,
|
||||||
|
onIndexChanged: (Int) -> Unit
|
||||||
|
) {
|
||||||
|
val template = oneTUO.pTemplate.template
|
||||||
|
|
||||||
|
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 match = blankPrefixRegex.find(afterU0T0)
|
||||||
|
val blankPrefix = match?.groups?.get(1)?.value ?: ""
|
||||||
|
|
||||||
|
val anchorsByVoice = (0..3).associate { voiceIdx ->
|
||||||
|
val linePrefix = "N${voiceIdx + 1}:"
|
||||||
|
val fullLine = lines.firstOrNull { it.startsWith(linePrefix) } ?: ""
|
||||||
|
voiceIdx to extractAnchorFromNoteLine(fullLine)
|
||||||
|
}
|
||||||
|
val editState = TUOEditState(
|
||||||
|
tuoIndex = oneTUO.firstTuoIndex,
|
||||||
|
notesByVoice = (0..3).associate { i ->
|
||||||
|
val rawNote = oneTUO.tuNotes.getOrNull(i + 1)?.toString() ?: ""
|
||||||
|
val fixedNote = autoFixNote(rawNote, template)
|
||||||
|
i to fixedNote
|
||||||
|
},
|
||||||
|
lyricsByStanza = (1..currentStanza).associate { s ->
|
||||||
|
s to oneTUO.lyricsAsMultiString(currentStanza)
|
||||||
|
}.toMutableMap(),
|
||||||
|
templateFragment = oneTUO.pTemplate.template,
|
||||||
|
marker = listOfNotNull(
|
||||||
|
oneTUO.pTemplate.markerToString().takeIf { it.isNotBlank() },
|
||||||
|
oneTUO.hasHairPin()?.toString()?.takeIf { it.isNotBlank() }
|
||||||
|
).joinToString(" "),
|
||||||
|
silentDuration = blankPrefix,
|
||||||
|
sep = oneTUO.sep0
|
||||||
|
)
|
||||||
|
TUODetailDialog(
|
||||||
|
editState = editState,
|
||||||
|
tuo = oneTUO,
|
||||||
|
currentStanza = currentStanza,
|
||||||
|
menuPosition = IntOffset(
|
||||||
|
menuOffset.x.roundToInt(),
|
||||||
|
menuOffset.y.roundToInt()
|
||||||
|
),
|
||||||
|
globalIndex = globalIndex,
|
||||||
|
isEditable = true,
|
||||||
|
canAdd = false,
|
||||||
|
sharedScreenModel = sharedScreenModel,
|
||||||
|
anchorsByVoice = anchorsByVoice,
|
||||||
|
onDismiss = onDismiss,
|
||||||
|
onSave = { newState ->
|
||||||
|
sharedScreenModel.openTUOEditor(newState)
|
||||||
|
onSaveSuccess()
|
||||||
|
},
|
||||||
|
onIndexChanged = onIndexChanged
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun makeSpaceBetweenSyllables(
|
fun makeSpaceBetweenSyllables(
|
||||||
textMeasurer: TextMeasurer,
|
textMeasurer: TextMeasurer,
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue