feufaro/composeApp/src/commonMain/kotlin/mg/dot/feufaro/ui/QRDisplay.kt

148 lines
No EOL
5.6 KiB
Kotlin

package mg.dot.feufaro.ui
import SharedScreenModel
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.material3.Card
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.produceState
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.shadow
import androidx.compose.ui.graphics.ImageBitmap
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import mg.dot.feufaro.FileRepository
import mg.dot.feufaro.solfa.ColorPrefixA
import mg.dot.feufaro.solfa.ColorPrefixB
import mg.dot.feufaro.solfa.ColorValue
import java.io.ByteArrayOutputStream
import java.util.zip.GZIPOutputStream
import kotlin.io.encoding.Base64
@Composable
fun QRDisplay(sharedScreenModel: SharedScreenModel, fileRepository: FileRepository) {
val content by sharedScreenModel.fileContent
val path by sharedScreenModel.activeFilePath
val fileName = path.substringAfterLast('/').substringAfterLast(':')
val qrCodeImage by produceState<ImageBitmap?>(initialValue = null, content, path) {
val expandedSource = expandInclusions(
content = content,
currentFilePath = path,
fileRepository = fileRepository
)
if(expandedSource.isNotEmpty()) {
val bos = ByteArrayOutputStream()
GZIPOutputStream(bos).use { it.write(expandedSource.toByteArray(Charsets.UTF_8)) }
val compressedBytes = bos.toByteArray()
val compressedData = Base64.UrlSafe.encode(compressedBytes).trim('=')
val uri = "feufaro://song?file=${compressedData}&name=$fileName"
value = generateQRCode(uri, size = 800)
}
}
Box(
modifier = Modifier
.fillMaxSize()
.background(MaterialTheme.colorScheme.scrim.copy(alpha = 0.5f)) // Fond semi-transparent
.clickable { sharedScreenModel.toggleQRCodeVisibility() } // Fermer au clic
.imePadding()
.systemBarsPadding(),
contentAlignment = Alignment.Center
) {
Card(
modifier = Modifier.wrapContentSize().shadow(16.dp, shape = MaterialTheme.shapes.large)
) {
Column(
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier.padding(24.dp)
) {
Text("Scanner pour ouvrir ce partition")
if (qrCodeImage != null) {
Image(
bitmap = qrCodeImage!!,
contentDescription = "Code QR du fichier actif",
modifier = Modifier.size(400.dp)
)
} else {
Box(
modifier = Modifier
.size(400.dp)
.padding(16.dp),
contentAlignment = Alignment.Center
) {
Column(
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
) {
CircularProgressIndicator(
modifier = Modifier.size(48.dp),
color = ColorPrefixA,
strokeWidth = 4.dp,
trackColor = ColorPrefixB.copy(alpha = 0.2f)
)
Spacer(modifier = Modifier.height(16.dp))
Text(
text = "Génération du QR Code...",
style = MaterialTheme.typography.bodyMedium.copy(
color = ColorValue,
fontWeight = FontWeight.Medium
)
)
}
}
}
}
}
}
}
private suspend fun expandInclusions(
content: String?,
currentFilePath: String,
fileRepository: FileRepository
): String {
if(content.isNullOrEmpty()) return ""
val lines = content.split("\n")
val result = StringBuilder()
val lastSlash = currentFilePath.lastIndexOf('/')
val directory = if (lastSlash != -1) currentFilePath.substring(0, lastSlash + 1) else ""
lines.forEach { line ->
if (line.startsWith("I0:")) {
try {
val parts = line.substring(3).split(":")
val fileName = parts[0]
val ignorePattern = if (parts.size > 1) parts[1] else ""
val fullPath = directory + fileName
val includedLines = fileRepository.readFileLines(fullPath)
val regexIgnore = if (ignorePattern.isNotEmpty()) Regex(ignorePattern) else null
includedLines.forEach { incLine ->
if (regexIgnore == null || !regexIgnore.containsMatchIn(incLine)) {
result.append(incLine).append("\n")
}
}
} catch (e: Exception) {
result.append("// Erreur inclusion: ${e.message}\n")
}
} else {
result.append(line).append("\n")
}
}
return result.toString().trimEnd()
}