Complete contentDescription for all icons - verse selection on print settings

This commit is contained in:
Hasinjato 2026-09-02 14:00:10 +03:00
parent f5eb92a374
commit 9b783200df
19 changed files with 312 additions and 104 deletions

View file

@ -3,8 +3,9 @@ package mg.dot.feufaro.pdf
import com.tom_roush.pdfbox.pdmodel.PDDocument import com.tom_roush.pdfbox.pdmodel.PDDocument
import com.tom_roush.pdfbox.pdmodel.PDPage import com.tom_roush.pdfbox.pdmodel.PDPage
import com.tom_roush.pdfbox.pdmodel.PDPageContentStream import com.tom_roush.pdfbox.pdmodel.PDPageContentStream
import com.tom_roush.pdfbox.pdmodel.common.PDRectangle
import com.tom_roush.pdfbox.pdmodel.font.PDType0Font import com.tom_roush.pdfbox.pdmodel.font.PDType0Font
import com.tom_roush.pdfbox.pdmodel.graphics.image.PDImageXObject
import com.tom_roush.pdfbox.pdmodel.graphics.state.PDExtendedGraphicsState
import com.tom_roush.pdfbox.util.Matrix import com.tom_roush.pdfbox.util.Matrix
import feufaro.composeapp.generated.resources.Res import feufaro.composeapp.generated.resources.Res
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
@ -249,26 +250,49 @@ private fun drawNoteWithModulation(
// ── drawNoteWithSubscript ───────────────────────────────────────────────────── // ── drawNoteWithSubscript ─────────────────────────────────────────────────────
private fun drawNoteWithSubscript( private fun drawNoteWithSubscript(
cs: PDPageContentStream, font: PDType0Font, fontSize: Float, cs: PDPageContentStream, font: PDType0Font,
boldFont: PDType0Font?,
fontSize: Float,
text: String, x: Float, y: Float text: String, x: Float, y: Float
) { ) {
var curX = x var curX = x
val superscriptOffset = fontSize * 0.35f val superscriptOffset = fontSize * 0.35f
val subscriptOffset = fontSize * 0.2f
for (char in text) { for (char in text) {
val str = char.toString().sanitize() val str = char.toString().sanitize()
val isSuperscript = char in setOf('¹', '²', '³') val isSuperscript = char in setOf('¹', '²', '³', '⁴', '⁵')
val isSubscript = char in setOf('₁', '₂', '₃') val isSubscript = char in setOf('₁', '₂', '₃', '₄', '₅')
val isSpecialSymbol = char == '•' || char == ','
val isPunctuation = char in setOf('•', ',')
val activeFont = if (isSpecialSymbol && boldFont != null) boldFont else font
val currentSize = if (isSuperscript || isSubscript) fontSize * 0.6f else fontSize val currentSize = if (isSuperscript || isSubscript) fontSize * 0.6f else fontSize
val currentY = if (isSuperscript) y + superscriptOffset else y val currentY = when {
isSuperscript -> y + superscriptOffset
isSubscript -> y - subscriptOffset
else -> y
}
cs.beginText() cs.beginText()
cs.setFont(font, currentSize) cs.setFont(activeFont, currentSize)
cs.newLineAtOffset(curX, currentY)
if (isSuperscript || isSubscript) {
cs.newLineAtOffset(curX - (currentSize * 0.2f), currentY)
} else {
cs.newLineAtOffset(curX, currentY)
}
cs.showText(str) cs.showText(str)
cs.endText() cs.endText()
curX += font.getStringWidth(str) / 1000f * currentSize + 0.5f
val charWidth = font.getStringWidth(str) / 1000f * currentSize
curX += when {
isSuperscript || isSubscript -> charWidth * 0.3f
isPunctuation -> charWidth
else -> charWidth + 0.5f
}
} }
} }
@ -384,6 +408,33 @@ private fun drawHeader(
cs.stroke() cs.stroke()
} }
private fun drawFooterLogo(
doc: PDDocument,
cs: PDPageContentStream,
logoBytes: ByteArray,
pageWidth: Float
) {
try {
val pdImage = PDImageXObject.createFromByteArray(doc, logoBytes, "logo_footer")
val imgWidth = 100f
val imgHeight = 100f * (pdImage.height.toFloat() / pdImage.width.toFloat())
val x = (pageWidth - imgWidth) / 2f
val y = 40f
cs.saveGraphicsState()
val graphicsState = PDExtendedGraphicsState()
graphicsState.nonStrokingAlphaConstant = 0.15f
cs.setGraphicsStateParameters(graphicsState)
cs.drawImage(pdImage, x, y, imgWidth, imgHeight)
cs.restoreGraphicsState()
} catch (e: Exception) {
println("⚠️ Erreur lors du dessin du logo en bas de page : ${e.message}")
}
}
// ── actual fun ──────────────────────────────────────────────────────────────── // ── actual fun ────────────────────────────────────────────────────────────────
actual fun rememberPdfExportAction( actual fun rememberPdfExportAction(
scope: CoroutineScope, scope: CoroutineScope,
@ -452,11 +503,12 @@ private suspend fun generatePdfToBytes(
val customNbGrid = settings.nbGridOnMeasure val customNbGrid = settings.nbGridOnMeasure
// ── Polices ──────────────────────────────────────────────────────────────── // ── Polices ────────────────────────────────────────────────────────────────
val noteFontBytes = Res.readBytes("font/PTSerif-Regular.ttf") val noteFontBytes = Res.readBytes("font/Lucida-Sans-Unicode.ttf")
val lyricFontBytes = Res.readBytes("font/LinLibertine_R.ttf") val lyricFontBytes = Res.readBytes("font/LinLibertine_R.ttf")
val markerItalicBoldFontBytes = Res.readBytes("font/PT_Serif_Bold_Italic.ttf") val markerItalicBoldFontBytes = Res.readBytes("font/PT_Serif_Bold_Italic.ttf")
val markerBoldFontBytes = Res.readBytes("font/PTSerif_Bold.ttf") val markerBoldFontBytes = Res.readBytes("font/PTSerif_Bold.ttf")
val emmentalerFontBytes = Res.readBytes("font/Emmentaler.ttf") val emmentalerFontBytes = Res.readBytes("font/Emmentaler.ttf")
val logoBytes = Res.readBytes("drawable/icon.png")
PDDocument().use { doc -> PDDocument().use { doc ->
@ -479,11 +531,34 @@ private suspend fun generatePdfToBytes(
(1..nbStanza).maxOfOrNull { sz -> tuo.getSingleSyllable(sz).size } ?: 1 (1..nbStanza).maxOfOrNull { sz -> tuo.getSingleSyllable(sz).size } ?: 1
} ?: 1 } ?: 1
val hasOverrideLyrics = maxSylsSize >= 2
val allStanzas = (1..nbStanza).toList()
val selectedInSettings = settings.selectedStanzasInScore.filter { it in allStanzas }
val (stanzasRemaining, stanzasToShow) = when {
selectedInSettings.isNotEmpty() -> {
val bottom = if (!hasOverrideLyrics) {
selectedInSettings
} else {
listOf(selectedInSettings.first())
}
val score = allStanzas.filter { it !in bottom }
score to bottom
}
else -> {
emptyList<Int>() to emptyList<Int>()
}
}
// ── Fonctions de dessin locales ──────────────────────────────────────── // ── Fonctions de dessin locales ────────────────────────────────────────
fun newPage(): PDPageContentStream { fun newPage(): PDPageContentStream {
val page = PDPage(settings.pdRectangle) val page = PDPage(settings.pdRectangle)
doc.addPage(page) doc.addPage(page)
return PDPageContentStream(doc, page) val cs = PDPageContentStream(doc, page)
drawFooterLogo(doc, cs, logoBytes, pageWidth)
return cs
} }
fun drawCurlyBrace(cs: PDPageContentStream, x: Float, top: Float, bottom: Float) { fun drawCurlyBrace(cs: PDPageContentStream, x: Float, top: Float, bottom: Float) {
@ -837,7 +912,7 @@ private suspend fun generatePdfToBytes(
val currentY = notesStartY - (vLi * noteLineH) val currentY = notesStartY - (vLi * noteLineH)
if (line.isNotBlank()) { if (line.isNotBlank()) {
if (line.contains(">")) drawNoteWithModulation(cs, customFont, noteFontSize, line, noteX, currentY) if (line.contains(">")) drawNoteWithModulation(cs, customFont, noteFontSize, line, noteX, currentY)
else drawNoteWithSubscript(cs, customFont, noteFontSize, line, noteX, currentY) else drawNoteWithSubscript(cs, customFont, markerBoldFont, noteFontSize, line, noteX, currentY)
} }
} }
@ -850,7 +925,7 @@ private suspend fun generatePdfToBytes(
val totalAreaSlots = lastVirtualIndex + customSpacings[lastVoiceIndex] val totalAreaSlots = lastVirtualIndex + customSpacings[lastVoiceIndex]
val finalBraceBottom = notesStartY - (totalAreaSlots * noteLineH) val finalBraceBottom = notesStartY - (totalAreaSlots * noteLineH)
val stanzasToShow = if (maxSylsSize >= 2) listOf(1) else if (nbStanza >= 2) listOf(1, 2) else listOf(1) //val stanzasToShow = if (maxSylsSize >= 2) listOf(1) else if (nbStanza >= 2) listOf(1, 2) else listOf(1)
var lowestYOfThisRow = finalBraceBottom var lowestYOfThisRow = finalBraceBottom
stanzasToShow.forEachIndexed { stanzaIdx, currentStanza -> stanzasToShow.forEachIndexed { stanzaIdx, currentStanza ->
@ -1022,10 +1097,6 @@ private suspend fun generatePdfToBytes(
y = lowestYOfThisRow - interRowGap y = lowestYOfThisRow - interRowGap
} }
// ── Stanzas restantes en texte ─────────────────────────────────────────
val stanzasDisplayed = if (maxSylsSize >= 2) listOf(1) else if (nbStanza >= 2) listOf(1, 2) else listOf(1)
val stanzasRemaining = (1..nbStanza).filter { it !in stanzasDisplayed }
if (stanzasRemaining.isNotEmpty()) { if (stanzasRemaining.isNotEmpty()) {
val textFont = lyricFont val textFont = lyricFont
val textSize = lyricFontSize val textSize = lyricFontSize
@ -1059,7 +1130,7 @@ private suspend fun generatePdfToBytes(
val normal = syls.getOrNull(0)?.trim() ?: "" val normal = syls.getOrNull(0)?.trim() ?: ""
val dcPart = syls.drop(1).joinToString(" ") { it.trim() } val dcPart = syls.drop(1).joinToString(" ") { it.trim() }
if (normal.isNotEmpty()) result.append(normal).append(" ") if (normal.isNotEmpty()) result.append(normal).append(" ")
if (dcPart.isNotEmpty()) result.append("[$dcPart] ") /*if (dcPart.isNotEmpty()) result.append("[$dcPart] ")*/
val marker = tuo.pTemplate.markerToString() val marker = tuo.pTemplate.markerToString()
if (marker.contains("DC") && !inDcBlock && allDcLyrics.isNotEmpty()) { if (marker.contains("DC") && !inDcBlock && allDcLyrics.isNotEmpty()) {
result.append("(") result.append("(")

View file

@ -16,7 +16,8 @@ actual data class PrintSettings actual constructor(
actual val marginX : Float, actual val marginX : Float,
actual val marginY : Float, actual val marginY : Float,
actual val headerH : Float, actual val headerH : Float,
actual val nbGridOnMeasure: Int actual val nbGridOnMeasure: Int,
actual val selectedStanzasInScore: List<Int>
) { ) {
val pdRectangle: PDRectangle val pdRectangle: PDRectangle
get() { get() {

View file

@ -25,7 +25,8 @@ expect class PrintSettings(
marginX : Float, marginX : Float,
marginY : Float, marginY : Float,
headerH : Float, headerH : Float,
nbGridOnMeasure : Int nbGridOnMeasure : Int,
selectedStanzasInScore: List<Int> = listOf(1, 2)
) { ) {
val pageSize : PageSize val pageSize : PageSize
val orientation : PageOrientation val orientation : PageOrientation
@ -43,6 +44,7 @@ expect class PrintSettings(
val nbGridOnMeasure : Int val nbGridOnMeasure : Int
val pageWidth : Float val pageWidth : Float
val pageHeight : Float val pageHeight : Float
val selectedStanzasInScore: List<Int>
} }
expect fun defaultPrintSettings(): PrintSettings expect fun defaultPrintSettings(): PrintSettings

View file

@ -30,7 +30,7 @@ fun GridActionMenu(
Icon( Icon(
modifier = Modifier.width(50.dp), modifier = Modifier.width(50.dp),
imageVector = Icons.Default.Add, imageVector = Icons.Default.Add,
contentDescription = null contentDescription = "Ajoute une grille"
) )
} }
} }
@ -47,7 +47,7 @@ fun GridActionMenu(
Icon( Icon(
modifier = Modifier.width(50.dp), modifier = Modifier.width(50.dp),
imageVector = Icons.Default.Delete, imageVector = Icons.Default.Delete,
contentDescription = null contentDescription = "Enlèver une grille"
) )
} }
} }

View file

@ -221,7 +221,7 @@ private fun ExpandableGroup(
Icons.Default.RemoveCircleOutline Icons.Default.RemoveCircleOutline
else else
Icons.Default.AddCircleOutline, Icons.Default.AddCircleOutline,
contentDescription = null, contentDescription = "Btn marker ${group.title}",
tint = MaterialTheme.colorScheme.primary tint = MaterialTheme.colorScheme.primary
) )
} }

View file

@ -263,7 +263,7 @@ fun TUODetailDialog(
) { ) {
Icon( Icon(
imageVector = Icons.Default.KeyboardDoubleArrowLeft, imageVector = Icons.Default.KeyboardDoubleArrowLeft,
contentDescription = "Diminuer", contentDescription = "Diminuer z time",
tint = if (silentDurationOrder.indexOf(editState.silentDuration) > 0) Color.LightGray else Color.DarkGray tint = if (silentDurationOrder.indexOf(editState.silentDuration) > 0) Color.LightGray else Color.DarkGray
) )
} }
@ -297,7 +297,7 @@ fun TUODetailDialog(
) { ) {
Icon( Icon(
imageVector = Icons.Default.KeyboardDoubleArrowRight, imageVector = Icons.Default.KeyboardDoubleArrowRight,
contentDescription = "Augmenter", contentDescription = "Augmenter z time",
tint = if (silentDurationOrder.indexOf(editState.silentDuration) < silentDurationOrder.lastIndex) Color.LightGray else Color.DarkGray tint = if (silentDurationOrder.indexOf(editState.silentDuration) < silentDurationOrder.lastIndex) Color.LightGray else Color.DarkGray
) )
} }
@ -313,7 +313,7 @@ fun TUODetailDialog(
) { ) {
Icon( Icon(
imageVector = Icons.AutoMirrored.Filled.ArrowBack, imageVector = Icons.AutoMirrored.Filled.ArrowBack,
contentDescription = "Précédent", contentDescription = "Précédent grid",
tint = Color.White tint = Color.White
) )
} }
@ -335,7 +335,7 @@ fun TUODetailDialog(
) { ) {
Icon( Icon(
imageVector = Icons.AutoMirrored.Filled.ArrowForward, imageVector = Icons.AutoMirrored.Filled.ArrowForward,
contentDescription = "Suivant", contentDescription = "Suivant grid",
tint = Color.White tint = Color.White
) )
} }
@ -418,7 +418,7 @@ fun TUODetailDialog(
Icon( Icon(
imageVector = Icons.Default.Add, imageVector = Icons.Default.Add,
tint = MaterialTheme.colorScheme.secondary.copy(alpha = 1.5f), tint = MaterialTheme.colorScheme.secondary.copy(alpha = 1.5f),
contentDescription = null contentDescription = "btn add barre mesure"
) )
} }
} }
@ -479,7 +479,7 @@ fun TUODetailDialog(
Icon( Icon(
imageVector = Icons.Sharp.Delete, imageVector = Icons.Sharp.Delete,
tint = MaterialTheme.colorScheme.secondary.copy(alpha = 1.5f), tint = MaterialTheme.colorScheme.secondary.copy(alpha = 1.5f),
contentDescription = "Enlever" contentDescription = "Enlever marker"
) )
} }
} }
@ -512,7 +512,7 @@ fun TUODetailDialog(
Icon( Icon(
imageVector = Icons.Default.Check, imageVector = Icons.Default.Check,
tint = MaterialTheme.colorScheme.secondary.copy(alpha = 1.5f), tint = MaterialTheme.colorScheme.secondary.copy(alpha = 1.5f),
contentDescription = null contentDescription = "Complete marker"
) )
} }
} }
@ -541,7 +541,7 @@ fun TUODetailDialog(
Icon( Icon(
imageVector = Icons.Default.Edit, imageVector = Icons.Default.Edit,
tint = MaterialTheme.colorScheme.secondary.copy(alpha = 1.5f), tint = MaterialTheme.colorScheme.secondary.copy(alpha = 1.5f),
contentDescription = null contentDescription = "Btn add marker"
) )
} }
} }
@ -748,7 +748,7 @@ fun TUODetailDialog(
tint = if (index == 0) MaterialTheme.colorScheme.secondary.copy(alpha = 1.5f) else MaterialTheme.colorScheme.tertiary.copy( tint = if (index == 0) MaterialTheme.colorScheme.secondary.copy(alpha = 1.5f) else MaterialTheme.colorScheme.tertiary.copy(
alpha = 1.5f alpha = 1.5f
), ),
contentDescription = null contentDescription = "Ajouter enlever ligne lyrics"
) )
} }
} }
@ -766,7 +766,7 @@ fun TUODetailDialog(
IconButton(onClick = onDismiss, modifier = Modifier.size(20.dp)) { IconButton(onClick = onDismiss, modifier = Modifier.size(20.dp)) {
Icon( Icon(
Icons.Default.Clear, Icons.Default.Clear,
contentDescription = null, contentDescription = "Btn cancel edit",
tint = Color.LightGray tint = Color.LightGray
) )
} }
@ -795,7 +795,7 @@ fun TUODetailDialog(
) { ) {
Icon( Icon(
Icons.Default.Build, Icons.Default.Build,
contentDescription = null, contentDescription = "Btn save edit",
tint = MaterialTheme.colorScheme.secondary.copy(alpha = 1.5f) tint = MaterialTheme.colorScheme.secondary.copy(alpha = 1.5f)
) )
} }

View file

@ -1501,7 +1501,7 @@ fun EditSourceCompose(
Modifier.fillMaxWidth().background(Color(0xFFF5F5F5)).padding(2.dp), Modifier.fillMaxWidth().background(Color(0xFFF5F5F5)).padding(2.dp),
verticalAlignment = Alignment.CenterVertically verticalAlignment = Alignment.CenterVertically
) { ) {
Icon(Icons.Default.Description, contentDescription = null, modifier = Modifier.size(16.dp)) Icon(Icons.Default.Description, contentDescription = "new partition", modifier = Modifier.size(16.dp))
Text( Text(
text = sourceTitle.ifEmpty { "nouveau_feufaro.txt" }, text = sourceTitle.ifEmpty { "nouveau_feufaro.txt" },
modifier = Modifier.padding(start = 8.dp).widthIn(max = 160.dp), modifier = Modifier.padding(start = 8.dp).widthIn(max = 160.dp),

View file

@ -233,14 +233,14 @@ fun AboutDialog(onDismiss: () -> Unit) {
leadingIcon = { leadingIcon = {
Icon( Icon(
imageVector = Icons.Default.Code, imageVector = Icons.Default.Code,
contentDescription = null, contentDescription = "Developpers",
modifier = Modifier.size(16.dp) modifier = Modifier.size(16.dp)
) )
}, },
trailingIcon = { trailingIcon = {
Icon( Icon(
imageVector = Icons.AutoMirrored.Default.OpenInNew, imageVector = Icons.AutoMirrored.Default.OpenInNew,
contentDescription = null, contentDescription = "Open in tab",
modifier = Modifier.size(14.dp), modifier = Modifier.size(14.dp),
tint = MaterialTheme.colorScheme.primary tint = MaterialTheme.colorScheme.primary
) )

View file

@ -263,7 +263,7 @@ fun MainScreenWithDrawer(
if (showPrintSettings) { if (showPrintSettings) {
PrintSettingsDialog( PrintSettingsDialog(
initialSettings = defaultPrintSettings(), initialSettings = defaultPrintSettings(),
// nbStanza = nbStanzas, totalStanzas = nbStanzas,
onDismiss = { showPrintSettings = false }, onDismiss = { showPrintSettings = false },
onConfirm = { settings -> onConfirm = { settings ->
showPrintSettings = false showPrintSettings = false
@ -389,7 +389,7 @@ fun MainScreenWithDrawer(
leadingIcon = { leadingIcon = {
Icon( Icon(
imageVector = Icons.Default.Search, imageVector = Icons.Default.Search,
contentDescription = null, contentDescription = "Icon search on leading",
tint = Color.White.copy(alpha = 0.8f), tint = Color.White.copy(alpha = 0.8f),
modifier = Modifier.size(20.dp) modifier = Modifier.size(20.dp)
) )
@ -408,7 +408,7 @@ fun MainScreenWithDrawer(
) { ) {
Icon( Icon(
imageVector = if (isNumericKeyboard) Icons.Default.Abc else Icons.Filled._123, imageVector = if (isNumericKeyboard) Icons.Default.Abc else Icons.Filled._123,
contentDescription = null, contentDescription = "Btn to switch abc 123",
tint = MaterialTheme.colorScheme.tertiary, tint = MaterialTheme.colorScheme.tertiary,
modifier = Modifier.size(22.dp) modifier = Modifier.size(22.dp)
) )
@ -424,7 +424,7 @@ fun MainScreenWithDrawer(
) { ) {
Icon( Icon(
imageVector = Icons.Default.Clear, imageVector = Icons.Default.Clear,
contentDescription = null, contentDescription = "Annuler recherche",
tint = Color.White.copy(alpha = 0.8f), tint = Color.White.copy(alpha = 0.8f),
modifier = Modifier.size(18.dp) modifier = Modifier.size(18.dp)
) )
@ -483,7 +483,7 @@ fun MainScreenWithDrawer(
IconButton(onClick = { IconButton(onClick = {
scope.launch { drawerState.open() } scope.launch { drawerState.open() }
}) { }) {
Icon(Icons.Filled.Menu, contentDescription = "Ouvrir Menu") Icon(Icons.Filled.Menu, contentDescription = "Ouvrir Menu Latéral")
} }
} }
}, actions = { }, actions = {
@ -566,7 +566,7 @@ fun MainScreenWithDrawer(
) { ) {
Icon( Icon(
imageVector = Icons.AutoMirrored.Filled.KeyboardArrowLeft, imageVector = Icons.AutoMirrored.Filled.KeyboardArrowLeft,
contentDescription = null, contentDescription = "Transposer de moins",
tint = Color.White tint = Color.White
) )
} }
@ -609,7 +609,7 @@ fun MainScreenWithDrawer(
) { ) {
Icon( Icon(
imageVector = centralIcon, imageVector = centralIcon,
contentDescription = null, contentDescription = "Valider transpose",
tint = centralTint tint = centralTint
) )
} }
@ -633,7 +633,7 @@ fun MainScreenWithDrawer(
) { ) {
Icon( Icon(
imageVector = Icons.AutoMirrored.Filled.KeyboardArrowRight, imageVector = Icons.AutoMirrored.Filled.KeyboardArrowRight,
contentDescription = null, contentDescription = "Transposer de plus",
tint = Color.White tint = Color.White
) )
} }
@ -1024,7 +1024,7 @@ fun MainScreenWithDrawer(
) { ) {
Icon( Icon(
imageVector = if (isSearchActive) Icons.Default.Close else Icons.Default.Search, imageVector = if (isSearchActive) Icons.Default.Close else Icons.Default.Search,
contentDescription = null, contentDescription = "Btn search",
tint = MaterialTheme.colorScheme.onTertiary tint = MaterialTheme.colorScheme.onTertiary
) )
} }
@ -1098,7 +1098,7 @@ fun MainScreenWithDrawer(
leadingContent = { leadingContent = {
Icon( Icon(
imageVector = Icons.Default.SearchOff, imageVector = Icons.Default.SearchOff,
contentDescription = null, contentDescription = "Not result search",
tint = MaterialTheme.colorScheme.error tint = MaterialTheme.colorScheme.error
) )
} }
@ -1142,7 +1142,7 @@ fun MainScreenWithDrawer(
) { ) {
Icon( Icon(
imageVector = if (isFavorite) Icons.Default.FavoriteBorder else Icons.Default.Favorite, imageVector = if (isFavorite) Icons.Default.FavoriteBorder else Icons.Default.Favorite,
contentDescription = null, contentDescription = "Favorite btn",
modifier = Modifier.scale(scale), modifier = Modifier.scale(scale),
tint = MaterialTheme.colorScheme.onSecondary tint = MaterialTheme.colorScheme.onSecondary
) )
@ -1153,7 +1153,7 @@ fun MainScreenWithDrawer(
leadingContent = { leadingContent = {
Icon( Icon(
imageVector = if (item.path.startsWith("assets://")) Icons.Default.ArrowDropDownCircle else Icons.Default.Folder, imageVector = if (item.path.startsWith("assets://")) Icons.Default.ArrowDropDownCircle else Icons.Default.Folder,
contentDescription = null, contentDescription = "Part interne ou personnel",
modifier = Modifier.size(30.dp) modifier = Modifier.size(30.dp)
) )
}, },
@ -1166,7 +1166,7 @@ fun MainScreenWithDrawer(
) { ) {
Icon( Icon(
imageVector = Icons.AutoMirrored.Default.PlaylistAdd, imageVector = Icons.AutoMirrored.Default.PlaylistAdd,
contentDescription = null, contentDescription = "Btn add playlist",
tint = if (!onPlaylist) Color.LightGray else Color( tint = if (!onPlaylist) Color.LightGray else Color(
0xFFFFD700 0xFFFFD700
) )
@ -1295,7 +1295,7 @@ private fun getIntervalToC(key: String): Int {
@Composable @Composable
private fun MyFAB( private fun MyFAB(
onClick: () -> Unit, onClick: () -> Unit,
size: Dp ?= 55.dp, size: Dp = 55.dp,
icon: ImageVector icon: ImageVector
) { ) {
FloatingActionButton( FloatingActionButton(
@ -1306,7 +1306,7 @@ private fun MyFAB(
) { ) {
Icon( Icon(
imageVector = icon, imageVector = icon,
contentDescription = null, contentDescription = "FAB ${icon.name}",
tint = MaterialTheme.colorScheme.primary tint = MaterialTheme.colorScheme.primary
) )
} }

View file

@ -398,7 +398,7 @@ fun MidiControlPanel(
Icon( Icon(
imageVector = Icons.Default.Loop, imageVector = Icons.Default.Loop,
contentDescription = null, contentDescription = "AB Looping",
tint = if (isLooping) Color.White else Color.Black, tint = if (isLooping) Color.White else Color.Black,
modifier = Modifier.size(16.dp) modifier = Modifier.size(16.dp)
) )

View file

@ -44,7 +44,7 @@ fun ModernVolumeSlider(
volume < 0.5f -> Icons.AutoMirrored.Filled.VolumeDown volume < 0.5f -> Icons.AutoMirrored.Filled.VolumeDown
else -> Icons.AutoMirrored.Filled.VolumeUp else -> Icons.AutoMirrored.Filled.VolumeUp
}, },
contentDescription = null, contentDescription = "Volume slider",
tint = if (volume > 0) MaterialTheme.colorScheme.onSecondary else Color.Gray, tint = if (volume > 0) MaterialTheme.colorScheme.onSecondary else Color.Gray,
modifier = Modifier.size(20.dp) modifier = Modifier.size(20.dp)
) )

View file

@ -110,7 +110,7 @@ fun NewPartition(
) { ) {
Icon( Icon(
imageVector = Icons.Filled.MusicNote, imageVector = Icons.Filled.MusicNote,
contentDescription = null, contentDescription = "music note title",
tint = AccentBlue tint = AccentBlue
) )
} }
@ -373,7 +373,7 @@ fun NewPartition(
) { ) {
Icon( Icon(
imageVector = Icons.Filled.Add, imageVector = Icons.Filled.Add,
contentDescription = null, contentDescription = "Btn create part",
modifier = Modifier.size(18.dp) modifier = Modifier.size(18.dp)
) )
Spacer(Modifier.width(6.dp)) Spacer(Modifier.width(6.dp))

View file

@ -33,6 +33,7 @@ import kotlin.math.roundToInt
@Composable @Composable
fun PrintSettingsDialog( fun PrintSettingsDialog(
initialSettings: PrintSettings = defaultPrintSettings(), initialSettings: PrintSettings = defaultPrintSettings(),
totalStanzas: Int = 4,
onDismiss: () -> Unit, onDismiss: () -> Unit,
onConfirm: (PrintSettings) -> Unit onConfirm: (PrintSettings) -> Unit
) { ) {
@ -51,6 +52,7 @@ fun PrintSettingsDialog(
var marginY by remember { mutableStateOf(initialSettings.marginY) } var marginY by remember { mutableStateOf(initialSettings.marginY) }
var headerH by remember { mutableStateOf(initialSettings.headerH) } var headerH by remember { mutableStateOf(initialSettings.headerH) }
var nbGridOnMeasure by remember { mutableStateOf(initialSettings.nbGridOnMeasure) } var nbGridOnMeasure by remember { mutableStateOf(initialSettings.nbGridOnMeasure) }
var selectedStanzasInScore by remember { mutableStateOf(initialSettings.selectedStanzasInScore) }
Dialog( Dialog(
properties = DialogProperties( properties = DialogProperties(
@ -134,8 +136,6 @@ fun PrintSettingsDialog(
} }
} }
Spacer(Modifier.height(4.dp))
// Taille papier // Taille papier
LabelRow("Taille du papier") LabelRow("Taille du papier")
SegmentedRow( SegmentedRow(
@ -144,17 +144,76 @@ fun PrintSettingsDialog(
onSelect = { pageSize = PageSize.entries[it] } onSelect = { pageSize = PageSize.entries[it] }
) )
Spacer(Modifier.height(4.dp))
// Orientation // Orientation
LabelRow("Orientation") Row(
SegmentedRow( modifier = Modifier.fillMaxWidth(),
options = PageOrientation.entries.map { it.label }, horizontalArrangement = Arrangement.spacedBy(16.dp)
selected = orientation.ordinal, ) {
onSelect = { orientation = PageOrientation.entries[it] } Column(
) modifier = Modifier.weight(1f)
) {
LabelRow("Orientation")
Spacer(Modifier.height(4.dp))
SegmentedRow(
options = PageOrientation.entries.map { it.label },
selected = orientation.ordinal,
onSelect = { orientation = PageOrientation.entries[it] }
)
}
Spacer(Modifier.height(8.dp)) Column(
modifier = Modifier.weight(1f)
) {
LabelRow("Versets sous les notes")
Spacer(Modifier.height(12.dp))
Row(
modifier = Modifier.horizontalScroll(rememberScrollState()),
horizontalArrangement = Arrangement.spacedBy(4.dp),
verticalAlignment = Alignment.CenterVertically
) {
(1..totalStanzas).forEach { stanza ->
val isSelected = stanza in selectedStanzasInScore
val backgroundColor = if (isSelected) {
MaterialTheme.colorScheme.primary
} else {
Color.DarkGray
}
val contentColor = if (isSelected) {
MaterialTheme.colorScheme.onPrimary
} else {
MaterialTheme.colorScheme.onPrimary.copy(alpha = 0.6f)
}
Box(
contentAlignment = Alignment.Center,
modifier = Modifier
.size(22.dp)
.clip(RoundedCornerShape(4.dp))
.background(backgroundColor)
.clickable {
selectedStanzasInScore = if (isSelected) {
selectedStanzasInScore - stanza
} else {
if (selectedStanzasInScore.size >= 2) {
(selectedStanzasInScore.drop(1) + stanza).sorted()
} else {
(selectedStanzasInScore + stanza).sorted()
}
}
}
) {
Text(
text = "$stanza",
color = contentColor,
fontSize = 12.sp,
fontWeight = FontWeight.Bold
)
}
}
}
}
}
// ── Preview miniature de la page ────────────────────── // ── Preview miniature de la page ──────────────────────
SectionTitle("Aperçu") SectionTitle("Aperçu")
@ -306,10 +365,11 @@ fun PrintSettingsDialog(
marginX = def.marginX marginX = def.marginX
marginY = def.marginY marginY = def.marginY
headerH = def.headerH headerH = def.headerH
selectedStanzasInScore = def.selectedStanzasInScore
}) { }) {
Icon( Icon(
imageVector = Icons.Default.RestartAlt, imageVector = Icons.Default.RestartAlt,
contentDescription = null, contentDescription = "Réinitialiser paramètre impression",
modifier = Modifier.size(18.dp) modifier = Modifier.size(18.dp)
) )
} }
@ -319,7 +379,7 @@ fun PrintSettingsDialog(
OutlinedButton(onClick = onDismiss) { OutlinedButton(onClick = onDismiss) {
Icon( Icon(
imageVector = Icons.Default.Close, imageVector = Icons.Default.Close,
contentDescription = null, contentDescription = "Fermer paramètre impression",
modifier = Modifier.size(18.dp) modifier = Modifier.size(18.dp)
) )
} }
@ -340,13 +400,14 @@ fun PrintSettingsDialog(
marginX = marginX, marginX = marginX,
marginY = marginY, marginY = marginY,
headerH = headerH, headerH = headerH,
nbGridOnMeasure = nbGridOnMeasure nbGridOnMeasure = nbGridOnMeasure,
selectedStanzasInScore = selectedStanzasInScore
) )
) )
}) { }) {
Icon( Icon(
imageVector = Icons.Default.PictureAsPdf, imageVector = Icons.Default.PictureAsPdf,
contentDescription = null, contentDescription = "Enregistrer en pdf",
modifier = Modifier.size(18.dp) modifier = Modifier.size(18.dp)
) )
} }

View file

@ -188,7 +188,7 @@ fun Settings(
thumbContent = { thumbContent = {
Icon( Icon(
imageVector = if (tempDarkMode) Icons.Default.DarkMode else Icons.Default.LightMode, imageVector = if (tempDarkMode) Icons.Default.DarkMode else Icons.Default.LightMode,
contentDescription = null, contentDescription = "Btn dark mode",
tint = MaterialTheme.colorScheme.onSecondary tint = MaterialTheme.colorScheme.onSecondary
) )
}, },
@ -411,7 +411,7 @@ fun Settings(
) { ) {
Icon( Icon(
imageVector = Icons.AutoMirrored.Default.Undo, imageVector = Icons.AutoMirrored.Default.Undo,
contentDescription = null, contentDescription = "Btn reset dynamic volumes",
tint = MaterialTheme.colorScheme.error tint = MaterialTheme.colorScheme.error
) )
} }
@ -661,7 +661,7 @@ fun Settings(
if (isSelected) { if (isSelected) {
Icon( Icon(
imageVector = Icons.Default.Check, imageVector = Icons.Default.Check,
contentDescription = null, contentDescription = "Selected instru",
tint = MaterialTheme.colorScheme.primary, tint = MaterialTheme.colorScheme.primary,
modifier = Modifier.size(18.dp) modifier = Modifier.size(18.dp)
) )
@ -809,7 +809,7 @@ fun SettingsAccordion(
Icon( Icon(
imageVector = Icons.Default.KeyboardArrowDown, imageVector = Icons.Default.KeyboardArrowDown,
contentDescription = null, contentDescription = "Setting $title",
tint = if (isExpanded) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.onSurfaceVariant, tint = if (isExpanded) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.onSurfaceVariant,
modifier = Modifier.rotate(arrowRotationDegree) modifier = Modifier.rotate(arrowRotationDegree)
) )

View file

@ -114,7 +114,7 @@ fun SimpleDrawerContent(
) )
) { ) {
Icon( Icon(
imageVector = Icons.AutoMirrored.Default.NoteAdd, contentDescription = null, tint = MaterialTheme.colorScheme.error imageVector = Icons.AutoMirrored.Default.NoteAdd, contentDescription = "Btn create partition", tint = MaterialTheme.colorScheme.error
) )
} }
@ -172,7 +172,7 @@ fun SimpleDrawerContent(
) { ) {
Icon( Icon(
imageVector = Icons.Default.PlaylistAddCircle, imageVector = Icons.Default.PlaylistAddCircle,
contentDescription = null, contentDescription = "Btn add playlist drawer intern",
tint = if (!onPlaylist) Color.LightGray else Color(0xFFFFD700), tint = if (!onPlaylist) Color.LightGray else Color(0xFFFFD700),
modifier = Modifier.size(18.dp) modifier = Modifier.size(18.dp)
) )
@ -225,7 +225,7 @@ fun SimpleDrawerContent(
) { ) {
Icon( Icon(
imageVector = Icons.Default.PlaylistAddCircle, imageVector = Icons.Default.PlaylistAddCircle,
contentDescription = null, contentDescription = "Btn add playlist drawer perso",
tint = if (!onPlaylist) Color.LightGray else Color(0xFFFFD700), tint = if (!onPlaylist) Color.LightGray else Color(0xFFFFD700),
modifier = Modifier.size(18.dp) modifier = Modifier.size(18.dp)
) )
@ -279,7 +279,7 @@ fun SimpleDrawerContent(
) { ) {
Icon( Icon(
imageVector = Icons.Default.VerticalAlignTop, imageVector = Icons.Default.VerticalAlignTop,
contentDescription = null, contentDescription = "Btn align playlist drawer",
modifier = Modifier.size(16.dp), modifier = Modifier.size(16.dp),
tint = MaterialTheme.colorScheme.onSecondary tint = MaterialTheme.colorScheme.onSecondary
) )
@ -291,7 +291,7 @@ fun SimpleDrawerContent(
) { ) {
Icon( Icon(
imageVector = Icons.Default.PlaylistRemove, imageVector = Icons.Default.PlaylistRemove,
contentDescription = null, contentDescription = "Btn remove playlist drawer",
tint = if (isSelected) Color.LightGray else Color(0xFFFFD700) tint = if (isSelected) Color.LightGray else Color(0xFFFFD700)
) )
} }
@ -343,7 +343,7 @@ fun SimpleDrawerContent(
) { ) {
Icon( Icon(
imageVector = Icons.Default.StarRate, imageVector = Icons.Default.StarRate,
contentDescription = null, contentDescription = "Btn add favorite",
tint = if (isSelected) MaterialTheme.colorScheme.background else MaterialTheme.colorScheme.tertiary tint = if (isSelected) MaterialTheme.colorScheme.background else MaterialTheme.colorScheme.tertiary
) )
} }
@ -383,7 +383,7 @@ fun SimpleDrawerContent(
) { ) {
Image( Image(
painter = painterResource(Res.drawable.icon), painter = painterResource(Res.drawable.icon),
contentDescription = null, contentDescription = "Icon feufarooo",
modifier = Modifier.size(45.dp) modifier = Modifier.size(45.dp)
) )
} }
@ -397,7 +397,7 @@ fun SimpleDrawerContent(
solfaScreenModel.loadCustomFile() solfaScreenModel.loadCustomFile()
scope.launch { drawerState.close() } scope.launch { drawerState.close() }
}) { }) {
Icon(Icons.Default.FolderOpen, contentDescription = null, tint = MaterialTheme.colorScheme.onSecondary) Icon(Icons.Default.FolderOpen, contentDescription = "Btn to load custom file", tint = MaterialTheme.colorScheme.onSecondary)
} }
} }
@ -410,7 +410,7 @@ fun SimpleDrawerContent(
onSettingsCheck() onSettingsCheck()
scope.launch { drawerState.close() } scope.launch { drawerState.close() }
}) { }) {
Icon(Icons.Default.Settings, contentDescription = null, tint = MaterialTheme.colorScheme.onSecondary) Icon(Icons.Default.Settings, contentDescription = "Btn to settings", tint = MaterialTheme.colorScheme.onSecondary)
} }
} }
@ -423,7 +423,7 @@ fun SimpleDrawerContent(
onAboutCheck() onAboutCheck()
scope.launch { drawerState.close() } scope.launch { drawerState.close() }
}) { }) {
Icon(Icons.Default.Info, contentDescription = null, tint = MaterialTheme.colorScheme.onSecondary) Icon(Icons.Default.Info, contentDescription = "Btn to about", tint = MaterialTheme.colorScheme.onSecondary)
} }
} }
} }
@ -449,7 +449,7 @@ fun DrawerHeaderSticky(
modifier = Modifier.padding(16.dp), modifier = Modifier.padding(16.dp),
verticalAlignment = Alignment.CenterVertically verticalAlignment = Alignment.CenterVertically
) { ) {
Icon(icon, contentDescription = null, tint = MaterialTheme.colorScheme.primary, modifier = Modifier.size(20.dp)) Icon(icon, contentDescription = "Title $title", tint = MaterialTheme.colorScheme.primary, modifier = Modifier.size(20.dp))
Spacer(Modifier.width(12.dp)) Spacer(Modifier.width(12.dp))
Text( Text(
text = title.uppercase(), text = title.uppercase(),
@ -470,7 +470,7 @@ fun DrawerHeaderSticky(
} }
Icon( Icon(
imageVector = Icons.Default.KeyboardArrowDown, imageVector = Icons.Default.KeyboardArrowDown,
contentDescription = null, contentDescription = "Title $title arrow",
modifier = Modifier.rotate(rotation) modifier = Modifier.rotate(rotation)
) )
} }
@ -526,7 +526,7 @@ fun CustomSwitchItem(
thumbContent = { thumbContent = {
Icon( Icon(
imageVector = if (checked) thumbIcon else Icons.Default.Visibility, imageVector = if (checked) thumbIcon else Icons.Default.Visibility,
contentDescription = null, contentDescription = "Toggle $label",
modifier = Modifier.size(SwitchDefaults.IconSize) modifier = Modifier.size(SwitchDefaults.IconSize)
) )
} }

View file

@ -73,7 +73,7 @@ fun SolfaKeyboard(
) { ) {
Icon( Icon(
imageVector = Icons.AutoMirrored.Default.KeyboardTab, imageVector = Icons.AutoMirrored.Default.KeyboardTab,
contentDescription = null, contentDescription = "Solfakey tab",
modifier = Modifier.size(18.dp) modifier = Modifier.size(18.dp)
) )
Spacer(Modifier.width(2.dp)) Spacer(Modifier.width(2.dp))
@ -181,7 +181,7 @@ fun SolfaKeyboard(
) { ) {
Icon( Icon(
imageVector = Icons.Default.Close, imageVector = Icons.Default.Close,
contentDescription = null, contentDescription = "Solfakey close",
tint = MaterialTheme.colorScheme.onErrorContainer tint = MaterialTheme.colorScheme.onErrorContainer
) )
} }
@ -197,7 +197,7 @@ fun SolfaKeyboard(
) { ) {
Icon( Icon(
imageVector = Icons.AutoMirrored.Default.KeyboardBackspace, imageVector = Icons.AutoMirrored.Default.KeyboardBackspace,
contentDescription = null, contentDescription = "Solfakey backspace",
tint = Color.White tint = Color.White
) )
} }
@ -213,7 +213,7 @@ fun SolfaKeyboard(
) { ) {
Icon( Icon(
imageVector = Icons.Default.Save, imageVector = Icons.Default.Save,
contentDescription = null, contentDescription = "Solfakey save",
tint = Color.White tint = Color.White
) )
} }

View file

@ -15,6 +15,8 @@ import org.apache.pdfbox.pdmodel.PDDocument
import org.apache.pdfbox.pdmodel.PDPage import org.apache.pdfbox.pdmodel.PDPage
import org.apache.pdfbox.pdmodel.PDPageContentStream import org.apache.pdfbox.pdmodel.PDPageContentStream
import org.apache.pdfbox.pdmodel.font.PDType0Font import org.apache.pdfbox.pdmodel.font.PDType0Font
import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject
import org.apache.pdfbox.pdmodel.graphics.state.PDExtendedGraphicsState
import org.apache.pdfbox.util.Matrix import org.apache.pdfbox.util.Matrix
import java.awt.Color import java.awt.Color
import java.awt.geom.GeneralPath import java.awt.geom.GeneralPath
@ -441,6 +443,7 @@ private fun drawNoteWithModulation(
private fun drawNoteWithSubscript( private fun drawNoteWithSubscript(
cs: PDPageContentStream, cs: PDPageContentStream,
font: PDType0Font, font: PDType0Font,
boldFont: PDType0Font?,
fontSize: Float, fontSize: Float,
text: String, text: String,
x: Float, x: Float,
@ -448,21 +451,41 @@ private fun drawNoteWithSubscript(
) { ) {
var curX = x var curX = x
val superscriptOffset = fontSize * 0.35f val superscriptOffset = fontSize * 0.35f
val subscriptOffset = fontSize * 0.2f
for (char in text) { for (char in text) {
val str = char.toString().sanitize() val str = char.toString().sanitize()
val isSuperscript = char in setOf('¹', '²', '³') val isSuperscript = char in setOf('¹', '²', '³', '⁴', '⁵')
val isSubscript = char in setOf('₁', '₂', '₃') val isSubscript = char in setOf('₁', '₂', '₃', '₄', '₅')
val isSpecialSymbol = char == '•' || char == ','
val isPunctuation = char in setOf('•', ',')
val activeFont = if (isSpecialSymbol && boldFont != null) boldFont else font
val currentSize = if (isSuperscript || isSubscript) fontSize * 0.6f else fontSize val currentSize = if (isSuperscript || isSubscript) fontSize * 0.6f else fontSize
val currentY = if (isSuperscript) y + superscriptOffset else y val currentY = when {
isSuperscript -> y + superscriptOffset
isSubscript -> y - subscriptOffset
else -> y
}
cs.beginText() cs.beginText()
cs.setFont(font, currentSize) cs.setFont(activeFont, currentSize)
cs.newLineAtOffset(curX, currentY)
if (isSuperscript || isSubscript) {
cs.newLineAtOffset(curX - (currentSize * 0.2f), currentY)
} else {
cs.newLineAtOffset(curX, currentY)
}
cs.showText(str) cs.showText(str)
cs.endText() cs.endText()
curX += font.getStringWidth(str) / 1000f * currentSize + 0.5f
val charWidth = font.getStringWidth(str) / 1000f * currentSize
curX += when {
isSuperscript || isSubscript -> charWidth * 0.3f
isPunctuation -> charWidth
else -> charWidth + 0.5f
}
} }
} }
@ -578,6 +601,34 @@ private fun drawHeader(
cs.stroke() cs.stroke()
} }
fun drawWatermark(
doc: PDDocument,
cs: PDPageContentStream,
logoBytes: ByteArray,
pageWidth: Float,
pageHeight: Float
) {
try {
val pdImage = PDImageXObject.createFromByteArray(doc, logoBytes, "logo_footer")
val imgWidth = 100f
val imgHeight = 100f * (pdImage.height.toFloat() / pdImage.width.toFloat())
val x = (pageWidth - imgWidth) / 2f
val y = 40f
cs.saveGraphicsState()
val graphicsState = PDExtendedGraphicsState()
graphicsState.nonStrokingAlphaConstant = 0.15f
cs.setGraphicsStateParameters(graphicsState)
cs.drawImage(pdImage, x, y, imgWidth, imgHeight)
cs.restoreGraphicsState()
} catch (e: Exception) {
println("⚠️ Erreur lors du chargement du logo du bas de page : ${e.message}")
}
}
actual fun rememberPdfExportAction( actual fun rememberPdfExportAction(
scope: CoroutineScope, scope: CoroutineScope,
@ -650,11 +701,13 @@ private suspend fun generatePdfToBytes(
val customNbGrid = settings.nbGridOnMeasure val customNbGrid = settings.nbGridOnMeasure
// ── Polices ──────────────────────────────────────────────────── // ── Polices ────────────────────────────────────────────────────
val noteFontBytes = Res.readBytes("font/PTSerif-Regular.ttf") val noteFontBytes = Res.readBytes("font/Lucida-Sans-Unicode.ttf")
val lyricFontBytes = Res.readBytes("font/LinLibertine_R.ttf") val lyricFontBytes = Res.readBytes("font/LinLibertine_R.ttf")
val markerItalicBoldFontBytes = Res.readBytes("font/PT_Serif_Bold_Italic.ttf") val markerItalicBoldFontBytes = Res.readBytes("font/PT_Serif_Bold_Italic.ttf")
val markerBoldFontBytes = Res.readBytes("font/PTSerif_Bold.ttf") val markerBoldFontBytes = Res.readBytes("font/PTSerif_Bold.ttf")
val emmentalerFontBytes = Res.readBytes("font/Emmentaler.ttf") val emmentalerFontBytes = Res.readBytes("font/Emmentaler.ttf")
val logoBytes = Res.readBytes("drawable/icon.png")
PDDocument().use { doc -> PDDocument().use { doc ->
@ -692,12 +745,33 @@ private suspend fun generatePdfToBytes(
} ?: 1 } ?: 1
} ?: 1 } ?: 1
val hasOverrideLyrics = maxSylsSize >= 2
val allStanzas = (1..nbStanza).toList()
val selectedInSettings = settings.selectedStanzasInScore.filter { it in allStanzas }
val (stanzasRemaining, stanzasToShow) = when {
selectedInSettings.isNotEmpty() -> {
val bottom = if (!hasOverrideLyrics) {
selectedInSettings
} else {
listOf(selectedInSettings.first())
}
val score = allStanzas.filter { it !in bottom }
score to bottom
}
else -> {
emptyList<Int>() to emptyList<Int>()
}
}
// ── Fonctions de dessin ──────────────────────────────────── // ── Fonctions de dessin ────────────────────────────────────
fun newPage(): PDPageContentStream { fun newPage(): PDPageContentStream {
val page = PDPage(settings.pdRectangle) val page = PDPage(settings.pdRectangle)
doc.addPage(page) doc.addPage(page)
val cs = PDPageContentStream(doc, page) val cs = PDPageContentStream(doc, page)
drawWatermark(doc, cs, logoBytes, pageWidth, pageHeight)
return cs return cs
} }
@ -1225,7 +1299,7 @@ private suspend fun generatePdfToBytes(
if (line.contains(">")) { if (line.contains(">")) {
drawNoteWithModulation(cs, customFont, noteFontSize, line, noteX, currentY) drawNoteWithModulation(cs, customFont, noteFontSize, line, noteX, currentY)
} else { } else {
drawNoteWithSubscript(cs, customFont, noteFontSize, line, noteX, currentY) drawNoteWithSubscript(cs, customFont, markerBoldFont, noteFontSize, line, noteX, currentY)
} }
} }
// Pour écrire dans l'espace vide JUSTE en dessous de cette voix : // Pour écrire dans l'espace vide JUSTE en dessous de cette voix :
@ -1262,7 +1336,7 @@ private suspend fun generatePdfToBytes(
// La position Y réelle du bas de l'accolade // La position Y réelle du bas de l'accolade
val finalBraceBottom = notesStartY - (totalAreaSlots * noteLineH) val finalBraceBottom = notesStartY - (totalAreaSlots * noteLineH)
val stanzasToShow = if (maxSylsSize >= 2) listOf(1) else if (nbStanza >= 2) listOf(1, 2) else listOf(1) //val stanzasToShow = if (maxSylsSize >= 2) listOf(1) else if (nbStanza >= 2) listOf(1, 2) else listOf(1)
val verticalMargin = 25f // Espace de sécurité entre l'accolade et les paroles val verticalMargin = 25f // Espace de sécurité entre l'accolade et les paroles
// val finalBraceBottom = braceBottom // On l'a calculé plus haut // val finalBraceBottom = braceBottom // On l'a calculé plus haut
@ -1527,8 +1601,6 @@ private suspend fun generatePdfToBytes(
} else { } else {
if (nbStanza >= 2) listOf(1, 2) else listOf(1) if (nbStanza >= 2) listOf(1, 2) else listOf(1)
} }
val stanzasRemaining = (1..nbStanza).filter { it !in stanzasDisplayed }
if (stanzasRemaining.isNotEmpty()) { if (stanzasRemaining.isNotEmpty()) {
val textFont = if (lyricFont is PDType0Font) lyricFont else customFont val textFont = if (lyricFont is PDType0Font) lyricFont else customFont
val textSize = lyricFontSize val textSize = lyricFontSize
@ -1588,7 +1660,7 @@ private suspend fun generatePdfToBytes(
// CROCHET DC (TOUJOURS, même si normal vide) // CROCHET DC (TOUJOURS, même si normal vide)
if (dcPart.isNotEmpty()) { if (dcPart.isNotEmpty()) {
// dcPart // dcPart
result.append("[${cleanSyllable(dcPart)}] ") //result.append("[${cleanSyllable(dcPart)}] ")
} }
// 3. DC MARQUEUR (parenthèses) // 3. DC MARQUEUR (parenthèses)

View file

@ -16,7 +16,8 @@ actual data class PrintSettings actual constructor(
actual val marginX : Float, actual val marginX : Float,
actual val marginY : Float, actual val marginY : Float,
actual val headerH : Float, actual val headerH : Float,
actual val nbGridOnMeasure: Int actual val nbGridOnMeasure: Int,
actual val selectedStanzasInScore: List<Int>
) { ) {
val pdRectangle: PDRectangle val pdRectangle: PDRectangle
get() { get() {