Centered songKey & take Included Source & filename on QR Content
This commit is contained in:
parent
997f5e87b4
commit
76f99cadce
4 changed files with 135 additions and 39 deletions
|
|
@ -15,7 +15,8 @@
|
||||||
android:theme="@android:style/Theme.Material.Light.NoActionBar">
|
android:theme="@android:style/Theme.Material.Light.NoActionBar">
|
||||||
<activity
|
<activity
|
||||||
android:exported="true"
|
android:exported="true"
|
||||||
android:name=".MainActivity">
|
android:name=".MainActivity"
|
||||||
|
android:windowSoftInputMode="adjustResize">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN" />
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -89,12 +89,10 @@ class MainActivity : ComponentActivity() {
|
||||||
|
|
||||||
println("DeepLink: rawContent = $rawContent")
|
println("DeepLink: rawContent = $rawContent")
|
||||||
|
|
||||||
val fileName = rawContent
|
val fileName = data.getQueryParameter("name") ?: run {
|
||||||
.split("|")
|
println("DeepLink: paramètre 'name' introuvable")
|
||||||
.firstOrNull { it.startsWith("t:") }
|
return
|
||||||
?.removePrefix("t:")
|
}
|
||||||
?.trim()
|
|
||||||
|
|
||||||
println("DeepLink: fileName extrait = $fileName")
|
println("DeepLink: fileName extrait = $fileName")
|
||||||
|
|
||||||
if (fileName.isNullOrBlank()) {
|
if (fileName.isNullOrBlank()) {
|
||||||
|
|
@ -111,7 +109,7 @@ class MainActivity : ComponentActivity() {
|
||||||
appDir.mkdirs()
|
appDir.mkdirs()
|
||||||
// docsDir.mkdirs()
|
// docsDir.mkdirs()
|
||||||
|
|
||||||
val file = File(appDir, "$fileName.txt")
|
val file = File(appDir, fileName)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
file.writeText(rawContent)
|
file.writeText(rawContent)
|
||||||
|
|
|
||||||
|
|
@ -145,9 +145,10 @@ LaunchedEffect(isPlay, isPos) {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
val favoritePaths by sharedScreenModel.playlistItems.collectAsState()
|
val favoritePaths by sharedScreenModel.playlistItems.collectAsState()
|
||||||
Scaffold(contentWindowInsets = WindowInsets(0, 0, 0, 0), topBar = {
|
Scaffold(contentWindowInsets = WindowInsets.safeDrawing, topBar = {
|
||||||
TopAppBar(
|
TopAppBar(
|
||||||
modifier = Modifier.height(55.dp).windowInsetsPadding(WindowInsets.statusBars), title = {
|
modifier = Modifier.height(55.dp).windowInsetsPadding(WindowInsets.safeDrawing),
|
||||||
|
title = {
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier.fillMaxSize().verticalScroll(scrollState),
|
modifier = Modifier.fillMaxSize().verticalScroll(scrollState),
|
||||||
verticalArrangement = Arrangement.Center
|
verticalArrangement = Arrangement.Center
|
||||||
|
|
@ -169,13 +170,17 @@ LaunchedEffect(isPlay, isPos) {
|
||||||
Icon(Icons.Filled.Menu, contentDescription = "Ouvrir Menu")
|
Icon(Icons.Filled.Menu, contentDescription = "Ouvrir Menu")
|
||||||
}
|
}
|
||||||
}, actions = {
|
}, actions = {
|
||||||
Text(
|
Box(
|
||||||
text = songKey,
|
modifier = Modifier.fillMaxHeight(),
|
||||||
fontSize = 25.sp,
|
contentAlignment = Alignment.Center
|
||||||
fontWeight = FontWeight.Black,
|
) {
|
||||||
)
|
Text(
|
||||||
Spacer(Modifier.width(8.dp))
|
text = songKey,
|
||||||
|
fontSize = 25.sp,
|
||||||
|
fontWeight = FontWeight.Black,
|
||||||
|
modifier = Modifier.padding(end = 16.dp)
|
||||||
|
)
|
||||||
|
}
|
||||||
}, colors = TopAppBarColors(
|
}, colors = TopAppBarColors(
|
||||||
containerColor = MaterialTheme.colorScheme.primary,
|
containerColor = MaterialTheme.colorScheme.primary,
|
||||||
titleContentColor = MaterialTheme.colorScheme.onPrimary,
|
titleContentColor = MaterialTheme.colorScheme.onPrimary,
|
||||||
|
|
@ -228,6 +233,24 @@ LaunchedEffect(isPlay, isPos) {
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
/*AnimatedVisibility(
|
||||||
|
visible = isExpanded and !showMidiCtrl,
|
||||||
|
enter = fadeIn() + scaleIn() + slideInVertically { it / 2 },
|
||||||
|
exit = fadeOut() + scaleOut() + slideOutVertically { it / 2 }
|
||||||
|
) {
|
||||||
|
FloatingActionButton(
|
||||||
|
onClick = {
|
||||||
|
sharedScreenModel.toggleEditMode()
|
||||||
|
sharedScreenModel.setExpandedFAB(false)
|
||||||
|
}, modifier = Modifier.alpha(0.45f)
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Filled.Edit,
|
||||||
|
contentDescription = "null",
|
||||||
|
tint = Color.Blue
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}*/
|
||||||
AnimatedVisibility(
|
AnimatedVisibility(
|
||||||
visible = isExpanded and !showMidiCtrl,
|
visible = isExpanded and !showMidiCtrl,
|
||||||
enter = fadeIn() + scaleIn() + slideInVertically { it / 2 },
|
enter = fadeIn() + scaleIn() + slideInVertically { it / 2 },
|
||||||
|
|
@ -345,11 +368,14 @@ LaunchedEffect(isPlay, isPos) {
|
||||||
}) { paddingValues ->
|
}) { paddingValues ->
|
||||||
|
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier.fillMaxSize().padding(paddingValues).windowInsetsPadding(WindowInsets.ime)
|
modifier = Modifier.fillMaxSize().padding(paddingValues).consumeWindowInsets(paddingValues).windowInsetsPadding(WindowInsets.ime)
|
||||||
) {
|
) {
|
||||||
content(PaddingValues(0.dp))
|
content(PaddingValues(0.dp))
|
||||||
if (sharedScreenModel.isQRCodeVisible.value) {
|
if (sharedScreenModel.isQRCodeVisible.value) {
|
||||||
QRDisplay(sharedScreenModel = sharedScreenModel)
|
QRDisplay(
|
||||||
|
sharedScreenModel = sharedScreenModel,
|
||||||
|
fileRepository = solfaScreenModel.fileRepository
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
if (filteredSongs.isNotEmpty()) {
|
if (filteredSongs.isNotEmpty()) {
|
||||||
Column(
|
Column(
|
||||||
|
|
|
||||||
|
|
@ -6,42 +6,48 @@ import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.clickable
|
||||||
import androidx.compose.foundation.layout.*
|
import androidx.compose.foundation.layout.*
|
||||||
import androidx.compose.material3.Card
|
import androidx.compose.material3.Card
|
||||||
|
import androidx.compose.material3.CircularProgressIndicator
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.produceState
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.shadow
|
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 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.io.ByteArrayOutputStream
|
||||||
import java.net.URLEncoder
|
|
||||||
import java.util.zip.GZIPOutputStream
|
import java.util.zip.GZIPOutputStream
|
||||||
import kotlin.io.encoding.Base64
|
import kotlin.io.encoding.Base64
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun QRDisplay(sharedScreenModel: SharedScreenModel) {
|
fun QRDisplay(sharedScreenModel: SharedScreenModel, fileRepository: FileRepository) {
|
||||||
|
|
||||||
val content by sharedScreenModel.fileContent
|
val content by sharedScreenModel.fileContent
|
||||||
|
val path by sharedScreenModel.activeFilePath
|
||||||
|
val fileName = path.substringAfterLast('/').substringAfterLast(':')
|
||||||
|
|
||||||
fun compressAndEncode(content: String?): String {
|
val qrCodeImage by produceState<ImageBitmap?>(initialValue = null, content, path) {
|
||||||
val bos = ByteArrayOutputStream()
|
val expandedSource = expandInclusions(
|
||||||
GZIPOutputStream(bos).use { it.write(content?.toByteArray(Charsets.UTF_8)) }
|
content = content,
|
||||||
val compressedBytes = bos.toByteArray()
|
currentFilePath = path,
|
||||||
return Base64.UrlSafe.encode(compressedBytes).trim('=')
|
fileRepository = fileRepository
|
||||||
}
|
)
|
||||||
|
if(expandedSource.isNotEmpty()) {
|
||||||
|
val bos = ByteArrayOutputStream()
|
||||||
|
GZIPOutputStream(bos).use { it.write(expandedSource.toByteArray(Charsets.UTF_8)) }
|
||||||
|
val compressedBytes = bos.toByteArray()
|
||||||
|
|
||||||
val compressedData = compressAndEncode(content)
|
val compressedData = Base64.UrlSafe.encode(compressedBytes).trim('=')
|
||||||
val uri = "feufaro://song?file=$compressedData"
|
|
||||||
// val encodedContent = URLEncoder.encode(content, "UTF-8")
|
|
||||||
// val uri = "feufaro://song?file=$encodedContent"
|
|
||||||
|
|
||||||
val qrCodeImage = remember(content) {
|
val uri = "feufaro://song?file=${compressedData}&name=$fileName"
|
||||||
if (content != null) {
|
value = generateQRCode(uri, size = 800)
|
||||||
generateQRCode(uri, size = 800)
|
|
||||||
} else {
|
|
||||||
null
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -64,14 +70,79 @@ fun QRDisplay(sharedScreenModel: SharedScreenModel) {
|
||||||
Text("Scanner pour ouvrir ce partition")
|
Text("Scanner pour ouvrir ce partition")
|
||||||
if (qrCodeImage != null) {
|
if (qrCodeImage != null) {
|
||||||
Image(
|
Image(
|
||||||
bitmap = qrCodeImage,
|
bitmap = qrCodeImage!!,
|
||||||
contentDescription = "Code QR du fichier actif",
|
contentDescription = "Code QR du fichier actif",
|
||||||
modifier = Modifier.size(400.dp)
|
modifier = Modifier.size(400.dp)
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
Text("Chargement du Code QR ou contenu vide...", modifier = Modifier.padding(16.dp))
|
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()
|
||||||
|
}
|
||||||
Loading…
Add table
Reference in a new issue