148 lines
No EOL
5.6 KiB
Kotlin
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()
|
|
} |