fix(ci): il pattern gitignore 'scores/' escludeva anche i sorgenti

'scores/' senza slash iniziale ignorava ogni directory 'scores' a
qualsiasi livello: mancavano dal repo il package com.notemusicali.scores,
ScoresScreen e i 12 spartiti bundled. Ancorato a '/scores/' (solo la
libreria alla radice) e aggiunti i file mancanti.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
lucianoandClaude Fable 5 committed 2026-07-22 10:38:51 +02:00
1 parent 9387b50b67
commit 0add6de716
27 files changed
+890 -3

No files matched your search

@@ -0,0 +1,25 @@
package com.notemusicali.scores
import java.util.zip.ZipInputStream
actual fun extractMusicXmlFromBytes(bytes: ByteArray): String? {
// Check for ZIP magic bytes (PK\x03\x04) = MXL file
if (bytes.size >= 4 && bytes[0] == 0x50.toByte() && bytes[1] == 0x4B.toByte()) {
return try {
ZipInputStream(bytes.inputStream()).use { zis ->
var entry = zis.nextEntry
while (entry != null) {
if (entry.name.endsWith(".xml") && !entry.name.startsWith("META-INF")) {
return@use zis.bufferedReader().readText()
}
entry = zis.nextEntry
}
null
}
} catch (_: Exception) {
null
}
}
// Plain XML
return bytes.decodeToString()
}
@@ -0,0 +1,92 @@
package com.notemusicali.scores
import android.net.Uri
import android.provider.DocumentsContract
actual object ScoreProvider {
actual fun listScores(relativePath: String): List<ScoreEntry> {
val baseDir = ScoreProviderContext.scoresDir ?: return emptyList()
val dir = if (relativePath.isEmpty()) baseDir
else java.io.File(baseDir, relativePath)
if (!dir.exists() || !dir.isDirectory) return emptyList()
return dir.listFiles()
?.filter { it.isDirectory || it.extension.lowercase() in listOf("mxl", "xml", "musicxml") }
?.sortedWith(compareBy<java.io.File> { !it.isDirectory }.thenBy { it.name.lowercase() })
?.map { file ->
ScoreEntry(
name = if (file.isDirectory) file.name else file.nameWithoutExtension,
path = if (relativePath.isEmpty()) file.name
else "$relativePath/${file.name}",
isDirectory = file.isDirectory,
)
}
?: emptyList()
}
actual fun readScoreBytes(path: String): ByteArray? {
val baseDir = ScoreProviderContext.scoresDir ?: return null
val file = java.io.File(baseDir, path)
if (!file.exists()) return null
return try {
file.readBytes()
} catch (_: Exception) {
null
}
}
actual fun listFromUri(treeUri: String, documentId: String): List<ScoreEntry> {
val context = ScoreProviderContext.appContext ?: return emptyList()
val treeUriParsed = Uri.parse(treeUri)
val parentDocId = if (documentId.isEmpty()) {
DocumentsContract.getTreeDocumentId(treeUriParsed)
} else {
documentId
}
val childrenUri = DocumentsContract.buildChildDocumentsUriUsingTree(treeUriParsed, parentDocId)
val results = mutableListOf<ScoreEntry>()
try {
context.contentResolver.query(
childrenUri,
arrayOf(
DocumentsContract.Document.COLUMN_DISPLAY_NAME,
DocumentsContract.Document.COLUMN_MIME_TYPE,
DocumentsContract.Document.COLUMN_DOCUMENT_ID,
),
null, null, null,
)?.use { cursor ->
val nameCol = cursor.getColumnIndexOrThrow(DocumentsContract.Document.COLUMN_DISPLAY_NAME)
val mimeCol = cursor.getColumnIndexOrThrow(DocumentsContract.Document.COLUMN_MIME_TYPE)
val idCol = cursor.getColumnIndexOrThrow(DocumentsContract.Document.COLUMN_DOCUMENT_ID)
while (cursor.moveToNext()) {
val name = cursor.getString(nameCol) ?: continue
val mime = cursor.getString(mimeCol) ?: ""
val docId = cursor.getString(idCol) ?: continue
val isDir = mime == DocumentsContract.Document.MIME_TYPE_DIR
val ext = name.substringAfterLast(".", "").lowercase()
if (isDir || ext in listOf("mxl", "xml", "musicxml")) {
results.add(
ScoreEntry(
name = if (isDir) name else name.substringBeforeLast("."),
path = docId,
isDirectory = isDir,
)
)
}
}
}
} catch (_: Exception) {}
return results.sortedWith(compareBy<ScoreEntry> { !it.isDirectory }.thenBy { it.name.lowercase() })
}
actual fun readFromUri(treeUri: String, documentId: String): ByteArray? {
val context = ScoreProviderContext.appContext ?: return null
val treeUriParsed = Uri.parse(treeUri)
val docUri = DocumentsContract.buildDocumentUriUsingTree(treeUriParsed, documentId)
return try {
context.contentResolver.openInputStream(docUri)?.use { it.readBytes() }
} catch (_: Exception) {
null
}
}
}
@@ -0,0 +1,14 @@
package com.notemusicali.scores
import android.content.Context
import java.io.File
object ScoreProviderContext {
var scoresDir: File? = null
var appContext: Context? = null
fun init(context: Context, externalFilesDir: File?) {
appContext = context.applicationContext
scoresDir = externalFilesDir?.let { File(it, "scores") }
}
}