QR Share
This commit is contained in:
parent
27aabc139d
commit
581bf42b32
20 changed files with 1544 additions and 192 deletions
|
|
@ -13,6 +13,13 @@ plugins {
|
|||
}
|
||||
|
||||
kotlin {
|
||||
linuxX64 {
|
||||
binaries {
|
||||
executable {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
androidTarget {
|
||||
@OptIn(ExperimentalKotlinGradlePluginApi::class)
|
||||
compilerOptions {
|
||||
|
|
@ -22,6 +29,19 @@ kotlin {
|
|||
|
||||
jvm("desktop")
|
||||
|
||||
afterEvaluate {
|
||||
afterEvaluate {
|
||||
tasks.configureEach {
|
||||
if (
|
||||
name.startsWith("compile")
|
||||
&& name.endsWith("KotlinMetadata")
|
||||
) {
|
||||
println("disabling $name")
|
||||
enabled = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
sourceSets {
|
||||
val desktopMain by getting
|
||||
|
||||
|
|
@ -30,7 +50,11 @@ kotlin {
|
|||
implementation(libs.androidx.activity.compose)
|
||||
implementation(libs.koin.android) // Koin Android-specific extensions
|
||||
implementation(libs.koin.androidx.compose)
|
||||
|
||||
implementation("com.google.zxing:core:3.5.4")
|
||||
implementation("androidx.camera:camera-view:1.5.2")
|
||||
implementation("androidx.camera:camera-core:1.5.2")
|
||||
implementation("androidx.camera:camera-camera2:1.5.2")
|
||||
implementation("androidx.camera:camera-lifecycle:1.5.2")
|
||||
}
|
||||
commonMain.dependencies {
|
||||
implementation(compose.components.resources)
|
||||
|
|
@ -57,6 +81,9 @@ kotlin {
|
|||
implementation(libs.cafe.voyager.koin)
|
||||
implementation(libs.androidx.material.icons.extended)
|
||||
implementation(kotlin("stdlib-jdk8"))
|
||||
implementation(compose.desktop.currentOs)
|
||||
//implementation("org.jetbrains.compose.foundation:foundation-desktop")
|
||||
|
||||
//implementation(libs.ktmidi)
|
||||
}
|
||||
commonTest.dependencies {
|
||||
|
|
@ -65,6 +92,8 @@ kotlin {
|
|||
desktopMain.dependencies {
|
||||
implementation(compose.desktop.currentOs)
|
||||
implementation(libs.kotlinx.coroutinesSwing)
|
||||
implementation("com.google.zxing:core:3.5.4")
|
||||
implementation("com.google.zxing:javase:3.5.4")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,293 @@
|
|||
package mg.dot.feufaro.data
|
||||
|
||||
private val LISTE_FICHIERS_SOLFA = listOf(
|
||||
"480.txt",
|
||||
"ews-10.txt",
|
||||
"ews-11.txt",
|
||||
"ews-12.txt",
|
||||
"ews-13.txt",
|
||||
"ews-14.txt",
|
||||
"ews-15.txt",
|
||||
"ews-16.txt",
|
||||
"ews-179.txt",
|
||||
"ews-17.txt",
|
||||
"ews-18.txt",
|
||||
"ews-190.txt",
|
||||
"ews-19.txt",
|
||||
"ews-1.txt",
|
||||
"ews-20.txt",
|
||||
"ews-21.txt",
|
||||
"ews-22.txt",
|
||||
"ews-23.txt",
|
||||
"ews-24.txt",
|
||||
"ews-25-1.txt",
|
||||
"ews-25-2.txt",
|
||||
"ews-26-1.txt",
|
||||
"ews-26-2.txt",
|
||||
"ews-27.txt",
|
||||
"ews-28.txt",
|
||||
"ews-29.txt",
|
||||
"ews-2.txt",
|
||||
"ews-30-1.txt",
|
||||
"ews-30-2.txt",
|
||||
"ews-31.txt",
|
||||
"ews-32.txt",
|
||||
"ews-33.txt",
|
||||
"ews-34.txt",
|
||||
"ews-351-1.txt",
|
||||
"ews-35.txt",
|
||||
"ews-36.txt",
|
||||
"ews-37.txt",
|
||||
"ews-38.txt",
|
||||
"ews-39.txt",
|
||||
"ews-3.txt",
|
||||
"ews-40.txt",
|
||||
"ews-41.txt",
|
||||
"ews-42.txt",
|
||||
"ews-43.txt",
|
||||
"ews-443.txt",
|
||||
"ews-44.txt",
|
||||
"ews-456.txt",
|
||||
"ews-45.txt",
|
||||
"ews-46.txt",
|
||||
"ews-47.txt",
|
||||
"ews-4.txt",
|
||||
"ews-5.txt",
|
||||
"ews-66.txt",
|
||||
"ews-6.txt",
|
||||
"ews-7.txt",
|
||||
"ews-89.txt",
|
||||
"ews-8.txt",
|
||||
"ews-999.txt",
|
||||
"ews-9.txt",
|
||||
"ff-33.txt",
|
||||
"ff-43.txt",
|
||||
"ff-7.txt",
|
||||
"ff-8.txt",
|
||||
"ff-9.txt",
|
||||
"ffmp-16.txt",
|
||||
"ffpm-100.txt",
|
||||
"ffpm-101.txt",
|
||||
"ffpm-103.txt",
|
||||
"ffpm-105.txt",
|
||||
"ffpm-106.txt",
|
||||
"ffpm-110.txt",
|
||||
"ffpm-111.txt",
|
||||
"ffpm-118.txt",
|
||||
"ffpm-12-1.txt",
|
||||
"ffpm-12-2.txt",
|
||||
"ffpm-123.txt",
|
||||
"ffpm-126.txt",
|
||||
"ffpm-127.txt",
|
||||
"ffpm-129.txt",
|
||||
"ffpm-1-2.txt",
|
||||
"ffpm-131.txt",
|
||||
"ffpm-132.txt",
|
||||
"ffpm-133.txt",
|
||||
"ffpm-134.txt",
|
||||
"ffpm-136.txt",
|
||||
"ffpm-137.txt",
|
||||
"ffpm-140-1.txt",
|
||||
"ffpm-140-2.txt",
|
||||
"ffpm-141.txt",
|
||||
"ffpm-14.txt",
|
||||
"ffpm-153.txt",
|
||||
"ffpm-154.txt",
|
||||
"ffpm-155.txt",
|
||||
"ffpm-157.txt",
|
||||
"ffpm-160.txt",
|
||||
"ffpm-161.txt",
|
||||
"ffpm-163.txt",
|
||||
"ffpm-164.txt",
|
||||
"ffpm-165.txt",
|
||||
"ffpm-166-new.txt",
|
||||
"ffpm-166.txt",
|
||||
"ffpm-16.txt",
|
||||
"ffpm-170.txt",
|
||||
"ffpm-172-1.txt",
|
||||
"ffpm-172-2.txt",
|
||||
"ffpm-175.txt",
|
||||
"ffpm-178.txt",
|
||||
"ffpm-179.txt",
|
||||
"ffpm-17.txt",
|
||||
"ffpm-180.txt",
|
||||
"ffpm-189.txt",
|
||||
"ffpm-190.txt",
|
||||
"ffpm-191.txt",
|
||||
"ffpm-192.txt",
|
||||
"ffpm-194.txt",
|
||||
"ffpm-195-1.txt",
|
||||
"ffpm-195-2.txt",
|
||||
"ffpm-198.txt",
|
||||
"ffpm-199.txt",
|
||||
"ffpm-19.txt",
|
||||
"ffpm-202.txt",
|
||||
"ffpm-203.txt",
|
||||
"ffpm-204.txt",
|
||||
"ffpm-209.txt",
|
||||
"ffpm-20.txt",
|
||||
"ffpm-210.txt",
|
||||
"ffpm-211.txt",
|
||||
"ffpm-212.txt",
|
||||
"ffpm-213.txt",
|
||||
"ffpm-214.txt",
|
||||
"ffpm-21.txt",
|
||||
"ffpm-220.txt",
|
||||
"ffpm-221.txt",
|
||||
"ffpm-222.txt",
|
||||
"ffpm-223.txt",
|
||||
"ffpm-224.txt",
|
||||
"ffpm-225.txt",
|
||||
"ffpm-229.txt",
|
||||
"ffpm-232.txt",
|
||||
"ffpm-233.txt",
|
||||
"ffpm-236.txt",
|
||||
"ffpm-237.txt",
|
||||
"ffpm-238-1.txt",
|
||||
"ffpm-238-2.txt",
|
||||
"ffpm-239-1.txt",
|
||||
"ffpm-239-2.txt",
|
||||
"ffpm-249.txt",
|
||||
"ffpm-250-1.txt",
|
||||
"ffpm-250-2.txt",
|
||||
"ffpm-251.txt",
|
||||
"ffpm-253.txt",
|
||||
"ffpm-254.txt",
|
||||
"ffpm-255.txt",
|
||||
"ffpm-256.txt",
|
||||
"ffpm-257-1.txt",
|
||||
"ffpm-257-2.txt",
|
||||
"ffpm-259.txt",
|
||||
"ffpm-260.txt",
|
||||
"ffpm-263.txt",
|
||||
"ffpm-269.txt",
|
||||
"ffpm-270.txt",
|
||||
"ffpm-271.txt",
|
||||
"ffpm-272.txt",
|
||||
"ffpm-273.txt",
|
||||
"ffpm-274.txt",
|
||||
"ffpm-276.txt",
|
||||
"ffpm-279.txt",
|
||||
"ffpm-281.txt",
|
||||
"ffpm-297.txt",
|
||||
"ffpm-307.txt",
|
||||
"ffpm-310.txt",
|
||||
"ffpm-311.txt",
|
||||
"ffpm-315.txt",
|
||||
"ffpm-321.txt",
|
||||
"ffpm-32.txt",
|
||||
"ffpm-332.txt",
|
||||
"ffpm-33.txt",
|
||||
"ffpm-352.txt",
|
||||
"ffpm-353-1.txt",
|
||||
"ffpm-353-2.txt",
|
||||
"ffpm-357.txt",
|
||||
"ffpm-358.txt",
|
||||
"ffpm-35.txt",
|
||||
"ffpm-367.txt",
|
||||
"ffpm-381-1.txt",
|
||||
"ffpm-381-2.txt",
|
||||
"ffpm-38.txt",
|
||||
"ffpm-392.txt",
|
||||
"ffpm-408-1.txt",
|
||||
"ffpm-408-2.txt",
|
||||
"ffpm-413.txt",
|
||||
"ffpm-4-1.txt",
|
||||
"ffpm-42-1.txt",
|
||||
"ffpm-42-2.txt",
|
||||
"ffpm-428.txt",
|
||||
"ffpm-4-2.txt",
|
||||
"ffpm-43.txt",
|
||||
"ffpm-440-1.txt",
|
||||
"ffpm-444-1.txt",
|
||||
"ffpm-444-2.txt",
|
||||
"ffpm-449.txt",
|
||||
"ffpm-44.txt",
|
||||
"ffpm-46.txt",
|
||||
"ffpm-47.txt",
|
||||
"ffpm-483.txt",
|
||||
"ffpm-489.txt",
|
||||
"ffpm-490.txt",
|
||||
"ffpm-49-1.txt",
|
||||
"ffpm-49-2.txt",
|
||||
"ffpm-501.txt",
|
||||
"ffpm-503.txt",
|
||||
"ffpm-5-1.txt",
|
||||
"ffpm-51.txt",
|
||||
"ffpm-5-2.txt",
|
||||
"ffpm-52.txt",
|
||||
"ffpm-539.txt",
|
||||
"ffpm-546.txt",
|
||||
"ffpm-549.txt",
|
||||
"ffpm-54.txt",
|
||||
"ffpm-558.txt",
|
||||
"ffpm-55.txt",
|
||||
"ffpm-563.txt",
|
||||
"ffpm-564.txt",
|
||||
"ffpm-56-new.txt",
|
||||
"ffpm-56.txt",
|
||||
"ffpm-57-new.txt",
|
||||
"ffpm-57.txt",
|
||||
"ffpm-58.txt",
|
||||
"ffpm-603-1.txt",
|
||||
"ffpm-603-2.txt",
|
||||
"ffpm-610.txt",
|
||||
"ffpm-611-1.txt",
|
||||
"ffpm-611-2.txt",
|
||||
"ffpm-616.txt",
|
||||
"ffpm-61.txt",
|
||||
"ffpm-626.txt",
|
||||
"ffpm-636.txt",
|
||||
"ffpm-640.txt",
|
||||
"ffpm-642-1.txt",
|
||||
"ffpm-642-2.txt",
|
||||
"ffpm-653.txt",
|
||||
"ffpm-674.txt",
|
||||
"ffpm-69.txt",
|
||||
"ffpm-6.txt",
|
||||
"ffpm-705-2.txt",
|
||||
"ffpm-71.txt",
|
||||
"ffpm-725.txt",
|
||||
"ffpm-726-1.txt",
|
||||
"ffpm-726-2.txt",
|
||||
"ffpm-729.txt",
|
||||
"ffpm-72.txt",
|
||||
"ffpm-733.txt",
|
||||
"ffpm-734.txt",
|
||||
"ffpm-735.txt",
|
||||
"ffpm-737.txt",
|
||||
"ffpm-750.txt",
|
||||
"ffpm-75.txt",
|
||||
"ffpm-760.txt",
|
||||
"ffpm-79-1.txt",
|
||||
"ffpm-79-2.txt",
|
||||
"ffpm-796.txt",
|
||||
"ffpm-799.txt",
|
||||
"ffpm-7.txt",
|
||||
"ffpm-82-1.txt",
|
||||
"ffpm-82-2.txt",
|
||||
"ffpm-825.txt",
|
||||
"ffpm-87.txt",
|
||||
"ffpm-89.txt",
|
||||
"ffpm-8.txt",
|
||||
"ffpm-91.txt",
|
||||
"ffpm-93.txt",
|
||||
"ffpm-94.txt",
|
||||
"ffpm-97-1.txt",
|
||||
"ffpm-97-2.txt",
|
||||
"ffpm-9.txt"
|
||||
)
|
||||
|
||||
private const val ASSET_PREFIX = "assets://"
|
||||
|
||||
actual fun getDrawerItems(): List<DrawerItem> {
|
||||
return LISTE_FICHIERS_SOLFA.mapIndexed { index, fileName ->
|
||||
val titleWithoutExtension = fileName.removeSuffix(".txt")
|
||||
|
||||
DrawerItem(
|
||||
id = index + 1,
|
||||
title = titleWithoutExtension,
|
||||
path = ASSET_PREFIX + fileName
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
package mg.dot.feufaro.midi
|
||||
|
||||
import android.media.midi.*
|
||||
import mg.dot.feufaro.FileRepository
|
||||
|
||||
actual class MidiWriterKotlin actual constructor(private val fileRepository: FileRepository) {
|
||||
private val midiEvents = mutableListOf<String>()
|
||||
actual fun addNote( voiceNumber: Int, note: Int, velocity: Int, tick: Long) {
|
||||
// TODO: Implémentation Android pour ajouter des notes
|
||||
midiEvents.add("Note: $note on tick $tick")
|
||||
}
|
||||
|
||||
actual fun save(filePath: String) {
|
||||
// TODO: Implémentation Android pour écrire le fichier MIDI
|
||||
println("Sauvegarde MIDI sur Android (Non implémenté complètement)")
|
||||
}
|
||||
|
||||
actual fun addMetaMessage(type: Int, tick: Int, nbData: Int, metaByteString: String) {
|
||||
// TODO: Implémentation Android pour ajouter des Meta Messages
|
||||
}
|
||||
|
||||
actual fun process(pitches: List<MidiPitch>) {
|
||||
// TODO: Implémentation Android pour traiter les pitches
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
package mg.dot.feufaro.ui
|
||||
|
||||
import androidx.compose.ui.graphics.ImageBitmap
|
||||
import androidx.compose.ui.graphics.asImageBitmap
|
||||
import com.google.zxing.BarcodeFormat
|
||||
import com.google.zxing.qrcode.QRCodeWriter
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.Color
|
||||
import java.io.IOException
|
||||
|
||||
|
||||
actual fun generateQRCode(content: String, size: Int): ImageBitmap? {
|
||||
if (content.isNullOrBlank()) return null
|
||||
|
||||
return try {
|
||||
val bitMatrix = QRCodeWriter().encode(content, BarcodeFormat.QR_CODE, size, size)
|
||||
val bitmap = Bitmap.createBitmap(size, size, Bitmap.Config.RGB_565)
|
||||
|
||||
for (x in 0 until size) {
|
||||
for (y in 0 until size) {
|
||||
bitmap.setPixel(x, y, if (bitMatrix[x, y]) Color.BLACK else Color.WHITE)
|
||||
}
|
||||
}
|
||||
return bitmap.asImageBitmap()
|
||||
|
||||
} catch (e: Exception) {
|
||||
println("Erreur de génération du QR Code Android: ${e.message}")
|
||||
null
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
package mg.dot.feufaro.ui
|
||||
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.lazy.LazyListState
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
|
||||
@Composable
|
||||
actual fun ScrollableDrawerContent(
|
||||
modifier: Modifier,
|
||||
lazyListState: LazyListState,
|
||||
content: @Composable () -> Unit
|
||||
) {
|
||||
Box(modifier = modifier) {
|
||||
content()
|
||||
}
|
||||
}
|
||||
|
|
@ -37,6 +37,7 @@ import androidx.compose.ui.unit.IntOffset
|
|||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.window.Popup
|
||||
import mg.dot.feufaro.solfa.LazyVerticalGridTUO
|
||||
import mg.dot.feufaro.ui.MainScreenWithDrawer
|
||||
import kotlin.math.roundToInt
|
||||
import cafe.adriel.voyager.core.screen.Screen
|
||||
import cafe.adriel.voyager.koin.koinScreenModel
|
||||
|
|
@ -61,8 +62,31 @@ object ScreenSolfa : Screen {
|
|||
val coroutineScope = rememberCoroutineScope()
|
||||
val scrollState = rememberScrollState()
|
||||
|
||||
var isScanning by remember { mutableStateOf(false) }
|
||||
var qrCodeResult by remember { mutableStateOf("Aucun code scanné") }
|
||||
|
||||
/* if (isScanning) {
|
||||
ScannerScreen(
|
||||
onScanComplete = { result ->
|
||||
qrCodeResult = result
|
||||
isScanning = false
|
||||
},
|
||||
onClose = {
|
||||
isScanning = false
|
||||
}
|
||||
)
|
||||
} else {*/
|
||||
|
||||
MainScreenWithDrawer(
|
||||
solfaScreenModel,
|
||||
sharedScreenModel,
|
||||
qrCodeResult = qrCodeResult,
|
||||
onScannerButtonClick = {
|
||||
isScanning = true
|
||||
}
|
||||
) { paddingValues ->
|
||||
Box(
|
||||
Modifier.fillMaxSize()
|
||||
Modifier.fillMaxSize().padding(paddingValues)
|
||||
) {
|
||||
Column(
|
||||
Modifier
|
||||
|
|
@ -191,6 +215,7 @@ object ScreenSolfa : Screen {
|
|||
) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Throws(ObjectStreamException::class) // C'est une méthode de sérialisation Java, donc l'exception est nécessaire
|
||||
private fun readResolve(): Any {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,9 @@
|
|||
package mg.dot.feufaro.data
|
||||
|
||||
data class DrawerItem(
|
||||
val id: Int,
|
||||
val title: String,
|
||||
val path: String
|
||||
)
|
||||
|
||||
expect fun getDrawerItems(): List<DrawerItem>
|
||||
|
|
@ -1,71 +1,10 @@
|
|||
package mg.dot.feufaro.midi
|
||||
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import mg.dot.feufaro.FileRepository
|
||||
import javax.sound.midi.*
|
||||
|
||||
class MidiWriterKotlin (private val fileRepository: FileRepository) {
|
||||
private val sequence = Sequence(Sequence.PPQ, 60)
|
||||
private val track = sequence.createTrack()
|
||||
private var tick: Long = 0
|
||||
private var nextTick: MutableList<Int> = mutableListOf()
|
||||
private val noteOn = ShortMessage()
|
||||
private val noteOff = ShortMessage()
|
||||
private val lastPitch : MutableList<Int> = mutableListOf()
|
||||
private val useChord : Boolean = true
|
||||
fun addNote( voiceNumber: Int, note: Int, velocity: Int, tick: Long) {
|
||||
var channel: Int = voiceNumber - 1
|
||||
if (useChord) {
|
||||
channel = channel / 2
|
||||
}
|
||||
var note = note
|
||||
if (voiceNumber == 3 || voiceNumber == 4) {
|
||||
note -= 12
|
||||
}
|
||||
if (lastPitch.size > voiceNumber && lastPitch[voiceNumber] > 0) {
|
||||
noteOff.setMessage(ShortMessage.NOTE_OFF, channel, lastPitch[voiceNumber], 0)
|
||||
val n2 = noteOff.clone() as MidiMessage
|
||||
track.add(MidiEvent(n2, tick))
|
||||
}
|
||||
var velocity = velocity
|
||||
if (note <= 0) {
|
||||
note = 40
|
||||
velocity = 0
|
||||
}
|
||||
noteOn.setMessage(ShortMessage.NOTE_ON, channel, note, velocity)
|
||||
val n1: MidiMessage = noteOn.clone() as MidiMessage
|
||||
track.add(MidiEvent(n1, tick))
|
||||
while(lastPitch.size <= voiceNumber) {
|
||||
lastPitch.add(0)
|
||||
}
|
||||
lastPitch[voiceNumber] = note
|
||||
}
|
||||
fun save(filePath: String) {
|
||||
val parseScope = CoroutineScope(Dispatchers.Default)
|
||||
parseScope.launch {
|
||||
val out = fileRepository.getOutputStream(filePath)
|
||||
MidiSystem.write(sequence, 1, out)
|
||||
out.close()
|
||||
}
|
||||
}
|
||||
fun addMetaMessage(type: Int, tick: Int, nbData: Int, metaByteString: String) {
|
||||
val byteArray = metaByteString.toByteArray()
|
||||
val metaMessage = MetaMessage(type, byteArray, nbData)
|
||||
track.add(MidiEvent(metaMessage, tick.toLong()))
|
||||
}
|
||||
fun process(pitches: List<MidiPitch>) {
|
||||
val lastTick = 0
|
||||
nextTick.clear()
|
||||
// addMetaMessage(0x59, 4, 2, 2,0)
|
||||
tick = 0
|
||||
pitches.forEach {
|
||||
if (it.metaType > 0) {
|
||||
addMetaMessage(it.metaType, it.tick, it.metaByteSize, it.metaBytes)
|
||||
} else if (it.pitch != "") {
|
||||
addNote(it.voiceNumber, it.pitch.toInt(), 100, it.tick.toLong())
|
||||
}
|
||||
}
|
||||
}
|
||||
expect class MidiWriterKotlin(fileRepository: FileRepository) {
|
||||
fun addNote( voiceNumber: Int, note: Int, velocity: Int, tick: Long)
|
||||
fun save(filePath: String)
|
||||
fun addMetaMessage(type: Int, tick: Int, nbData: Int, metaByteString: String)
|
||||
fun process(pitches: List<MidiPitch>)
|
||||
}
|
||||
|
|
@ -2,10 +2,12 @@ package mg.dot.feufaro.solfa
|
|||
|
||||
import SharedScreenModel
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.SupervisorJob
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import mg.dot.feufaro.FileRepository
|
||||
import mg.dot.feufaro.getConfigDirectoryPath
|
||||
import mg.dot.feufaro.launchFilePicker
|
||||
import mg.dot.feufaro.midi.MidiPitch
|
||||
import mg.dot.feufaro.midi.MidiWriterKotlin
|
||||
|
|
@ -144,7 +146,11 @@ class Solfa(val sharedScreenModel: SharedScreenModel, private val fileRepository
|
|||
}
|
||||
|
||||
fun loadFile() {
|
||||
println("Load btn clicked")
|
||||
val screenModelScope= CoroutineScope(SupervisorJob() + Dispatchers.Main.immediate)
|
||||
screenModelScope.launch {
|
||||
val initialPath = fileRepository.readLastDirectoryPath()
|
||||
val homedir = getConfigDirectoryPath();
|
||||
|
||||
launchFilePicker(
|
||||
mimeTypes = arrayOf("text/plain"),
|
||||
onFileSelected = { path ->
|
||||
|
|
@ -152,6 +158,9 @@ class Solfa(val sharedScreenModel: SharedScreenModel, private val fileRepository
|
|||
println("fichier $path");
|
||||
sharedScreenModel.reset()
|
||||
parse(path)
|
||||
screenModelScope.launch {
|
||||
fileRepository.saveLastDirectoryPath(path)
|
||||
}
|
||||
//loadSolfa()
|
||||
} else {
|
||||
println("Pas de dichier")
|
||||
|
|
@ -159,6 +168,7 @@ class Solfa(val sharedScreenModel: SharedScreenModel, private val fileRepository
|
|||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun parse(sourceFile: String) {
|
||||
currentFile = sourceFile
|
||||
|
|
@ -170,6 +180,8 @@ class Solfa(val sharedScreenModel: SharedScreenModel, private val fileRepository
|
|||
println("Opening $sourceFile raised exception {${e.message}")
|
||||
emptyList()
|
||||
}
|
||||
val contentString = fileRepository.readFileLines(sourceFile).joinToString("\n")
|
||||
sharedScreenModel.setFileContent(contentString, sourceFile)
|
||||
T.clear()
|
||||
N.clear()
|
||||
L.clear()
|
||||
|
|
|
|||
373
composeApp/src/commonMain/kotlin/mg/dot/feufaro/ui/DrawerUI.kt
Normal file
373
composeApp/src/commonMain/kotlin/mg/dot/feufaro/ui/DrawerUI.kt
Normal file
|
|
@ -0,0 +1,373 @@
|
|||
package mg.dot.feufaro.ui
|
||||
|
||||
import SharedScreenModel
|
||||
import androidx.compose.animation.AnimatedContent
|
||||
import androidx.compose.animation.ExperimentalSharedTransitionApi
|
||||
import androidx.compose.foundation.*
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.itemsIndexed
|
||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.*
|
||||
import androidx.compose.material3.*
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.alpha
|
||||
import androidx.compose.ui.focus.FocusRequester
|
||||
import androidx.compose.ui.focus.focusRequester
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import kotlinx.coroutines.*
|
||||
import mg.dot.feufaro.data.DrawerItem
|
||||
import mg.dot.feufaro.data.getDrawerItems
|
||||
import mg.dot.feufaro.getPlatform
|
||||
import mg.dot.feufaro.solfa.Solfa
|
||||
import mg.dot.feufaro.viewmodel.SolfaScreenModel
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun MainScreenWithDrawer(
|
||||
solfaScreenModel: SolfaScreenModel,
|
||||
sharedScreenModel: SharedScreenModel,
|
||||
qrCodeResult: String,
|
||||
onScannerButtonClick: () -> Unit,
|
||||
content: @Composable (PaddingValues) -> Unit,
|
||||
) {
|
||||
val drawerState = rememberDrawerState(initialValue = DrawerValue.Closed)
|
||||
val scope = rememberCoroutineScope()
|
||||
|
||||
val items = getDrawerItems()
|
||||
|
||||
val songTitle = sharedScreenModel.songTitle.collectAsState().value
|
||||
val filteredSongs by sharedScreenModel.filteredSongs.collectAsState()
|
||||
val songKey = sharedScreenModel.songKey.collectAsState().value
|
||||
val measure = sharedScreenModel.measure.collectAsState().value
|
||||
|
||||
val scrollState = rememberScrollState()
|
||||
val currentActivePath = Solfa.currentFile
|
||||
var textInput = sharedScreenModel.searchTitle.collectAsState().value
|
||||
|
||||
var isSearchActive by remember { mutableStateOf(false) }
|
||||
val focusRequester = remember { FocusRequester() }
|
||||
|
||||
LaunchedEffect(isSearchActive) {
|
||||
if (isSearchActive) {
|
||||
focusRequester.requestFocus()
|
||||
}
|
||||
}
|
||||
ModalNavigationDrawer(
|
||||
drawerState = drawerState,
|
||||
drawerContent = {
|
||||
SimpleDrawerContent(
|
||||
items, solfaScreenModel, sharedScreenModel, currentActivePath, drawerState, scope,
|
||||
onScannerButtonClick = {
|
||||
scope.launch { drawerState.close() }
|
||||
onScannerButtonClick()
|
||||
}
|
||||
)
|
||||
},
|
||||
content = {
|
||||
Scaffold(
|
||||
contentWindowInsets = WindowInsets(0, 0, 0, 0),
|
||||
topBar = {
|
||||
TopAppBar(
|
||||
modifier = Modifier
|
||||
.height(55.dp)
|
||||
.windowInsetsPadding(WindowInsets.statusBars),
|
||||
title = {
|
||||
Column (
|
||||
modifier= Modifier
|
||||
.fillMaxSize()
|
||||
.verticalScroll(scrollState)
|
||||
) {
|
||||
AnimatedContent(
|
||||
targetState = isSearchActive,
|
||||
label = "Search Transition"
|
||||
) {
|
||||
targetIsActive ->
|
||||
if(targetIsActive) {
|
||||
TextField(
|
||||
value = textInput,
|
||||
onValueChange = { newValue ->
|
||||
textInput = newValue
|
||||
sharedScreenModel.updateSearchTxt(newValue)
|
||||
},
|
||||
placeholder = {
|
||||
Text("Rechercher...")
|
||||
},
|
||||
leadingIcon = {
|
||||
Icon(
|
||||
imageVector = Icons.Default.Search,
|
||||
contentDescription = "Icône de recherche",
|
||||
tint = MaterialTheme.colorScheme.onSurfaceVariant
|
||||
)
|
||||
},
|
||||
textStyle = MaterialTheme.typography.titleLarge.copy(
|
||||
fontSize = 17.sp,
|
||||
fontWeight = FontWeight.Bold,
|
||||
color = MaterialTheme.colorScheme.onSurface
|
||||
),
|
||||
modifier = Modifier
|
||||
.focusRequester(focusRequester)
|
||||
.fillMaxWidth()
|
||||
)
|
||||
} else {
|
||||
Text(songTitle,
|
||||
modifier = Modifier.weight(1f, fill = true),
|
||||
maxLines = 1,
|
||||
softWrap = false,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
navigationIcon = {
|
||||
IconButton(onClick = {
|
||||
scope.launch { drawerState.open() }
|
||||
}) {
|
||||
Icon(Icons.Filled.Menu, contentDescription = "Ouvrir Menu")
|
||||
}
|
||||
},
|
||||
actions = {
|
||||
if (isSearchActive) {
|
||||
IconButton(onClick = {
|
||||
textInput = ""
|
||||
isSearchActive = false
|
||||
}) {
|
||||
Icon(Icons.Default.Close, contentDescription = "Annuler la recherche")
|
||||
}
|
||||
} else {
|
||||
Text(
|
||||
text = measure,
|
||||
modifier = Modifier.weight(1f, fill = false),
|
||||
fontSize = 20.sp,
|
||||
maxLines = 2,
|
||||
softWrap = false,
|
||||
overflow = TextOverflow.Ellipsis
|
||||
)
|
||||
Spacer(Modifier.width(8.dp))
|
||||
Text(
|
||||
text = songKey,
|
||||
fontSize = 25.sp,
|
||||
fontWeight = FontWeight.Black,
|
||||
)
|
||||
Spacer(Modifier.width(8.dp))
|
||||
IconButton(onClick = {
|
||||
isSearchActive = true
|
||||
}) {
|
||||
Icon(Icons.Default.Search, contentDescription = "Rechercher")
|
||||
}
|
||||
}
|
||||
|
||||
},
|
||||
colors = TopAppBarColors(
|
||||
containerColor = MaterialTheme.colorScheme.primary,
|
||||
titleContentColor = MaterialTheme.colorScheme.onPrimary,
|
||||
actionIconContentColor = MaterialTheme.colorScheme.onPrimary,
|
||||
navigationIconContentColor = MaterialTheme.colorScheme.onPrimary,
|
||||
scrolledContainerColor = MaterialTheme.colorScheme.onPrimary,
|
||||
)
|
||||
)
|
||||
},
|
||||
floatingActionButton = {
|
||||
FloatingActionButton (
|
||||
onClick = {
|
||||
sharedScreenModel.toggleQRCodeVisibility()
|
||||
},
|
||||
modifier = Modifier.alpha(0.5f)
|
||||
) {
|
||||
Icon(
|
||||
imageVector = Icons.Filled.Share,
|
||||
contentDescription = "Partager",
|
||||
tint = Color.Blue
|
||||
)
|
||||
}
|
||||
}
|
||||
) {
|
||||
paddingValues ->
|
||||
|
||||
Box(modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.padding(paddingValues)
|
||||
.windowInsetsPadding(WindowInsets.ime)
|
||||
){
|
||||
content(PaddingValues(0.dp))
|
||||
if (sharedScreenModel.isQRCodeVisible.value) {
|
||||
QRDisplay(sharedScreenModel = sharedScreenModel)
|
||||
} else {
|
||||
if (filteredSongs.isNotEmpty()) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth(0.65f)
|
||||
.heightIn(max = 350.dp)
|
||||
.align(Alignment.TopCenter)
|
||||
.background(MaterialTheme.colorScheme.surface)
|
||||
.border(1.dp, MaterialTheme.colorScheme.outlineVariant, shape = MaterialTheme.shapes.medium)
|
||||
){
|
||||
if (filteredSongs.isNotEmpty()) {
|
||||
LazyColumn(Modifier.fillMaxSize()) {
|
||||
itemsIndexed(filteredSongs){ index, item ->
|
||||
ListItem(
|
||||
headlineContent = { Text(item.title) },
|
||||
supportingContent = { Text(item.path, maxLines = 1) },
|
||||
modifier = Modifier.clickable {
|
||||
sharedScreenModel.updateSearchTxt("")
|
||||
sharedScreenModel.reset()
|
||||
solfaScreenModel.loadFromFile(item.path)
|
||||
isSearchActive = false
|
||||
}
|
||||
)
|
||||
HorizontalDivider()
|
||||
}
|
||||
}
|
||||
} else if (songTitle.trim().isNotEmpty() && songTitle != sharedScreenModel.songTitle.value) {
|
||||
Text(
|
||||
text = "Aucune chanson trouvée pour \"$songTitle\"",
|
||||
modifier = Modifier.padding(16.dp)
|
||||
)
|
||||
} else {
|
||||
content(paddingValues)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun SimpleDrawerContent(
|
||||
items: List<DrawerItem>,
|
||||
solfaScreenModel: SolfaScreenModel,
|
||||
sharedScreenModel: SharedScreenModel,
|
||||
activePath: String = Solfa.currentFile,
|
||||
drawerState: DrawerState,
|
||||
scope: CoroutineScope,
|
||||
onScannerButtonClick: () -> Unit
|
||||
) {
|
||||
var searchTxt by remember { mutableStateOf("") }
|
||||
|
||||
val context = getPlatform()
|
||||
|
||||
|
||||
ModalDrawerSheet(
|
||||
modifier = Modifier.width(300.dp)
|
||||
) {
|
||||
Box (
|
||||
modifier = Modifier.fillMaxSize()
|
||||
)
|
||||
{
|
||||
val lazyListState = rememberLazyListState()
|
||||
ScrollableDrawerContent(
|
||||
lazyListState = lazyListState,
|
||||
modifier = Modifier.fillMaxSize()
|
||||
) {
|
||||
LazyColumn(
|
||||
state = lazyListState,
|
||||
){
|
||||
stickyHeader {
|
||||
Surface(
|
||||
color = MaterialTheme.colorScheme.surfaceContainerHigh,
|
||||
modifier = Modifier.fillParentMaxWidth()
|
||||
) {
|
||||
Text(
|
||||
"Liste des solfa disponibles",
|
||||
style = MaterialTheme.typography.titleLarge
|
||||
)
|
||||
}
|
||||
}
|
||||
itemsIndexed(items){ index, item ->
|
||||
val isSelected = item.path == activePath
|
||||
val title = item.title
|
||||
var isFfpm = false
|
||||
var isEws = false
|
||||
var isFF = false
|
||||
|
||||
if (title.startsWith("ffpm")) {
|
||||
isFfpm = true
|
||||
} else if(title.startsWith("ews")) {
|
||||
isEws = true
|
||||
} else {
|
||||
isFF = true
|
||||
}
|
||||
NavigationDrawerItem(
|
||||
label = {
|
||||
Text(item.title)
|
||||
},
|
||||
icon = {
|
||||
val isIcon = when {
|
||||
isFfpm -> Icons.Filled.MenuBook
|
||||
isEws -> Icons.Filled.MusicNote
|
||||
isFF -> Icons.Filled.Book
|
||||
else -> Icons.Filled.Menu
|
||||
}
|
||||
Icon(
|
||||
isIcon,
|
||||
contentDescription = "",
|
||||
tint = Color.Blue
|
||||
)
|
||||
},
|
||||
badge = {
|
||||
Icon(
|
||||
Icons.Filled.Menu,
|
||||
contentDescription = ""
|
||||
)
|
||||
},
|
||||
selected = if(isSelected){ true } else { false },
|
||||
onClick = {
|
||||
scope.launch {
|
||||
drawerState.close()
|
||||
}
|
||||
sharedScreenModel.reset()
|
||||
solfaScreenModel.loadFromFile(item.path)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.align(Alignment.BottomCenter)
|
||||
.padding(16.dp),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
Column(
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
Row (
|
||||
|
||||
) {
|
||||
Spacer(modifier = Modifier.width(10.dp))
|
||||
Button(
|
||||
onClick = {
|
||||
onScannerButtonClick()
|
||||
}
|
||||
) {
|
||||
Text("Scanner")
|
||||
}
|
||||
Spacer(modifier = Modifier.width(10.dp))
|
||||
Button(
|
||||
onClick = {
|
||||
scope.launch {
|
||||
drawerState.close()
|
||||
}
|
||||
solfaScreenModel.loadCustomFile()
|
||||
}
|
||||
) {
|
||||
Text("Importer")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
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.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.shadow
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
||||
@Composable
|
||||
fun QRDisplay(sharedScreenModel: SharedScreenModel) {
|
||||
|
||||
val content by sharedScreenModel.fileContent
|
||||
|
||||
val qrCodeImage = remember(content) {
|
||||
if (content != null) {
|
||||
generateQRCode(content!!, size = 800)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
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 ceci: ")
|
||||
if (qrCodeImage != null) {
|
||||
Image(
|
||||
bitmap = qrCodeImage,
|
||||
contentDescription = "Code QR du fichier actif",
|
||||
modifier = Modifier.size(400.dp)
|
||||
)
|
||||
} else {
|
||||
Text("Chargement du Code QR ou contenu vide...", modifier = Modifier.padding(16.dp))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
package mg.dot.feufaro.ui
|
||||
|
||||
import androidx.compose.ui.graphics.ImageBitmap
|
||||
|
||||
expect fun generateQRCode(content: String, size: Int): ImageBitmap?
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
package mg.dot.feufaro.ui
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.foundation.lazy.LazyListState
|
||||
|
||||
@Composable
|
||||
expect fun ScrollableDrawerContent(
|
||||
modifier: Modifier,
|
||||
lazyListState: LazyListState,
|
||||
content: @Composable () -> Unit
|
||||
)
|
||||
|
|
@ -1,9 +1,18 @@
|
|||
// commonMain/kotlin/mg/dot/feufaro/viewmodel/SharedScreenModel.kt
|
||||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import cafe.adriel.voyager.core.model.ScreenModel
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.flow.mapLatest
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import mg.dot.feufaro.data.DrawerItem
|
||||
import mg.dot.feufaro.solfa.TimeUnitObject
|
||||
import mg.dot.feufaro.data.getDrawerItems
|
||||
|
||||
class SharedScreenModel() : ScreenModel {
|
||||
private val _nextLabel = MutableStateFlow<String>("Next ...")
|
||||
|
|
@ -44,7 +53,44 @@ class SharedScreenModel() : ScreenModel {
|
|||
var _hasMarker = MutableStateFlow<Boolean>(false)
|
||||
val hasMarker: StateFlow<Boolean> = _hasMarker.asStateFlow()
|
||||
|
||||
fun appendData(otherData: String) {
|
||||
private val _searchTitle = MutableStateFlow<String>("")
|
||||
val searchTitle: StateFlow<String> = _searchTitle.asStateFlow()
|
||||
|
||||
@OptIn
|
||||
val filteredSongs: StateFlow<List<DrawerItem>> = searchTitle
|
||||
.mapLatest { currentTitle ->
|
||||
val searchTxt = if (currentTitle == "") "" else currentTitle.trim()
|
||||
return@mapLatest if(searchTxt.isEmpty()) {
|
||||
emptyList()
|
||||
} else {
|
||||
getDrawerItems().filter { item ->
|
||||
item.title.contains(searchTxt, ignoreCase = true)
|
||||
}
|
||||
}
|
||||
}.stateIn (
|
||||
scope = CoroutineScope(Dispatchers.Default),
|
||||
started = SharingStarted.WhileSubscribed(5000),
|
||||
initialValue = emptyList()
|
||||
)
|
||||
private val _fileContent = mutableStateOf<String?>(null)
|
||||
val fileContent: State<String?> = _fileContent
|
||||
|
||||
private val _isQRCodeVisible = mutableStateOf(false)
|
||||
val isQRCodeVisible: State<Boolean> = _isQRCodeVisible
|
||||
|
||||
private val _activeFilePath = mutableStateOf("")
|
||||
val activeFilePath: State<String> = _activeFilePath
|
||||
|
||||
fun setFileContent(content: String?, path: String) {
|
||||
_fileContent.value = content
|
||||
_activeFilePath.value = path
|
||||
}
|
||||
fun toggleQRCodeVisibility() {
|
||||
_isQRCodeVisible.value = !_isQRCodeVisible.value
|
||||
}
|
||||
fun updateSearchTxt(searchValue: String) {
|
||||
_searchTitle.value = searchValue
|
||||
} fun appendData(otherData: String) {
|
||||
_nextLabel.value += otherData
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -19,4 +19,7 @@ class SolfaScreenModel(
|
|||
fun loadCustomFile() {
|
||||
solfa.loadFile()
|
||||
}
|
||||
fun loadFromFile(path: String) {
|
||||
solfa.parse(path)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,281 @@
|
|||
package mg.dot.feufaro.data
|
||||
|
||||
actual fun getDrawerItems(): List<DrawerItem> {
|
||||
return listOf(
|
||||
DrawerItem(1, "480", "assets://480.txt"),
|
||||
DrawerItem(2, "ews-10", "assets://ews-10.txt"),
|
||||
DrawerItem(3, "ews-11", "assets://ews-11.txt"),
|
||||
DrawerItem(4, "ews-12", "assets://ews-12.txt"),
|
||||
DrawerItem(5, "ews-13", "assets://ews-13.txt"),
|
||||
DrawerItem(6, "ews-14", "assets://ews-14.txt"),
|
||||
DrawerItem(7, "ews-15", "assets://ews-15.txt"),
|
||||
DrawerItem(8, "ews-16", "assets://ews-16.txt"),
|
||||
DrawerItem(9, "ews-179", "assets://ews-179.txt"),
|
||||
DrawerItem(10, "ews-17", "assets://ews-17.txt"),
|
||||
DrawerItem(11, "ews-18", "assets://ews-18.txt"),
|
||||
DrawerItem(12, "ews-190", "assets://ews-190.txt"),
|
||||
DrawerItem(13, "ews-19", "assets://ews-19.txt"),
|
||||
DrawerItem(14, "ews-1", "assets://ews-1.txt"),
|
||||
DrawerItem(15, "ews-20", "assets://ews-20.txt"),
|
||||
DrawerItem(16, "ews-21", "assets://ews-21.txt"),
|
||||
DrawerItem(17, "ews-22", "assets://ews-22.txt"),
|
||||
DrawerItem(18, "ews-23", "assets://ews-23.txt"),
|
||||
DrawerItem(19, "ews-24", "assets://ews-24.txt"),
|
||||
DrawerItem(20, "ews-25-1", "assets://ews-25-1.txt"),
|
||||
DrawerItem(21, "ews-25-2", "assets://ews-25-2.txt"),
|
||||
DrawerItem(22, "ews-26-1", "assets://ews-26-1.txt"),
|
||||
DrawerItem(23, "ews-26-2", "assets://ews-26-2.txt"),
|
||||
DrawerItem(24, "ews-27", "assets://ews-27.txt"),
|
||||
DrawerItem(25, "ews-28", "assets://ews-28.txt"),
|
||||
DrawerItem(26, "ews-29", "assets://ews-29.txt"),
|
||||
DrawerItem(27, "ews-2", "assets://ews-2.txt"),
|
||||
DrawerItem(28, "ews-30-1", "assets://ews-30-1.txt"),
|
||||
DrawerItem(29, "ews-30-2", "assets://ews-30-2.txt"),
|
||||
DrawerItem(30, "ews-31", "assets://ews-31.txt"),
|
||||
DrawerItem(31, "ews-32", "assets://ews-32.txt"),
|
||||
DrawerItem(32, "ews-33", "assets://ews-33.txt"),
|
||||
DrawerItem(33, "ews-34", "assets://ews-34.txt"),
|
||||
DrawerItem(34, "ews-351-1", "assets://ews-351-1.txt"),
|
||||
DrawerItem(35, "ews-35", "assets://ews-35.txt"),
|
||||
DrawerItem(36, "ews-36", "assets://ews-36.txt"),
|
||||
DrawerItem(37, "ews-37", "assets://ews-37.txt"),
|
||||
DrawerItem(38, "ews-38", "assets://ews-38.txt"),
|
||||
DrawerItem(39, "ews-39", "assets://ews-39.txt"),
|
||||
DrawerItem(40, "ews-3", "assets://ews-3.txt"),
|
||||
DrawerItem(41, "ews-40", "assets://ews-40.txt"),
|
||||
DrawerItem(42, "ews-41", "assets://ews-41.txt"),
|
||||
DrawerItem(43, "ews-42", "assets://ews-42.txt"),
|
||||
DrawerItem(44, "ews-43", "assets://ews-43.txt"),
|
||||
DrawerItem(45, "ews-443", "assets://ews-443.txt"),
|
||||
DrawerItem(46, "ews-44", "assets://ews-44.txt"),
|
||||
DrawerItem(47, "ews-456", "assets://ews-456.txt"),
|
||||
DrawerItem(48, "ews-45", "assets://ews-45.txt"),
|
||||
DrawerItem(49, "ews-46", "assets://ews-46.txt"),
|
||||
DrawerItem(50, "ews-47", "assets://ews-47.txt"),
|
||||
DrawerItem(51, "ews-4", "assets://ews-4.txt"),
|
||||
DrawerItem(52, "ews-5", "assets://ews-5.txt"),
|
||||
DrawerItem(53, "ews-66", "assets://ews-66.txt"),
|
||||
DrawerItem(54, "ews-6", "assets://ews-6.txt"),
|
||||
DrawerItem(55, "ews-7", "assets://ews-7.txt"),
|
||||
DrawerItem(56, "ews-89", "assets://ews-89.txt"),
|
||||
DrawerItem(57, "ews-8", "assets://ews-8.txt"),
|
||||
DrawerItem(58, "ews-999", "assets://ews-999.txt"),
|
||||
DrawerItem(59, "ews-9", "assets://ews-9.txt"),
|
||||
DrawerItem(60, "ff-33", "assets://ff-33.txt"),
|
||||
DrawerItem(61, "ff-43", "assets://ff-43.txt"),
|
||||
DrawerItem(62, "ff-7", "assets://ff-7.txt"),
|
||||
DrawerItem(63, "ff-8", "assets://ff-8.txt"),
|
||||
DrawerItem(64, "ff-9", "assets://ff-9.txt"),
|
||||
DrawerItem(65, "ffmp-16", "assets://ffmp-16.txt"),
|
||||
DrawerItem(66, "ffpm-100", "assets://ffpm-100.txt"),
|
||||
DrawerItem(67, "ffpm-101", "assets://ffpm-101.txt"),
|
||||
DrawerItem(68, "ffpm-103", "assets://ffpm-103.txt"),
|
||||
DrawerItem(69, "ffpm-105", "assets://ffpm-105.txt"),
|
||||
DrawerItem(70, "ffpm-106", "assets://ffpm-106.txt"),
|
||||
DrawerItem(71, "ffpm-110", "assets://ffpm-110.txt"),
|
||||
DrawerItem(72, "ffpm-111", "assets://ffpm-111.txt"),
|
||||
DrawerItem(73, "ffpm-118", "assets://ffpm-118.txt"),
|
||||
DrawerItem(74, "ffpm-12-1", "assets://ffpm-12-1.txt"),
|
||||
DrawerItem(75, "ffpm-12-2", "assets://ffpm-12-2.txt"),
|
||||
DrawerItem(76, "ffpm-123", "assets://ffpm-123.txt"),
|
||||
DrawerItem(77, "ffpm-126", "assets://ffpm-126.txt"),
|
||||
DrawerItem(78, "ffpm-127", "assets://ffpm-127.txt"),
|
||||
DrawerItem(79, "ffpm-129", "assets://ffpm-129.txt"),
|
||||
DrawerItem(80, "ffpm-1-2", "assets://ffpm-1-2.txt"),
|
||||
DrawerItem(81, "ffpm-131", "assets://ffpm-131.txt"),
|
||||
DrawerItem(82, "ffpm-132", "assets://ffpm-132.txt"),
|
||||
DrawerItem(83, "ffpm-133", "assets://ffpm-133.txt"),
|
||||
DrawerItem(84, "ffpm-134", "assets://ffpm-134.txt"),
|
||||
DrawerItem(85, "ffpm-136", "assets://ffpm-136.txt"),
|
||||
DrawerItem(86, "ffpm-137", "assets://ffpm-137.txt"),
|
||||
DrawerItem(87, "ffpm-140-1", "assets://ffpm-140-1.txt"),
|
||||
DrawerItem(88, "ffpm-140-2", "assets://ffpm-140-2.txt"),
|
||||
DrawerItem(89, "ffpm-141", "assets://ffpm-141.txt"),
|
||||
DrawerItem(90, "ffpm-14", "assets://ffpm-14.txt"),
|
||||
DrawerItem(91, "ffpm-153", "assets://ffpm-153.txt"),
|
||||
DrawerItem(92, "ffpm-154", "assets://ffpm-154.txt"),
|
||||
DrawerItem(93, "ffpm-155", "assets://ffpm-155.txt"),
|
||||
DrawerItem(94, "ffpm-157", "assets://ffpm-157.txt"),
|
||||
DrawerItem(95, "ffpm-160", "assets://ffpm-160.txt"),
|
||||
DrawerItem(96, "ffpm-161", "assets://ffpm-161.txt"),
|
||||
DrawerItem(97, "ffpm-163", "assets://ffpm-163.txt"),
|
||||
DrawerItem(98, "ffpm-164", "assets://ffpm-164.txt"),
|
||||
DrawerItem(99, "ffpm-165", "assets://ffpm-165.txt"),
|
||||
DrawerItem(100, "ffpm-166-new", "assets://ffpm-166-new.txt"),
|
||||
DrawerItem(101, "ffpm-166", "assets://ffpm-166.txt"),
|
||||
DrawerItem(102, "ffpm-16", "assets://ffpm-16.txt"),
|
||||
DrawerItem(103, "ffpm-170", "assets://ffpm-170.txt"),
|
||||
DrawerItem(104, "ffpm-172-1", "assets://ffpm-172-1.txt"),
|
||||
DrawerItem(105, "ffpm-172-2", "assets://ffpm-172-2.txt"),
|
||||
DrawerItem(106, "ffpm-175", "assets://ffpm-175.txt"),
|
||||
DrawerItem(107, "ffpm-178", "assets://ffpm-178.txt"),
|
||||
DrawerItem(108, "ffpm-179", "assets://ffpm-179.txt"),
|
||||
DrawerItem(109, "ffpm-17", "assets://ffpm-17.txt"),
|
||||
DrawerItem(110, "ffpm-180", "assets://ffpm-180.txt"),
|
||||
DrawerItem(111, "ffpm-189", "assets://ffpm-189.txt"),
|
||||
DrawerItem(112, "ffpm-190", "assets://ffpm-190.txt"),
|
||||
DrawerItem(113, "ffpm-191", "assets://ffpm-191.txt"),
|
||||
DrawerItem(114, "ffpm-192", "assets://ffpm-192.txt"),
|
||||
DrawerItem(115, "ffpm-194", "assets://ffpm-194.txt"),
|
||||
DrawerItem(116, "ffpm-195-1", "assets://ffpm-195-1.txt"),
|
||||
DrawerItem(117, "ffpm-195-2", "assets://ffpm-195-2.txt"),
|
||||
DrawerItem(118, "ffpm-198", "assets://ffpm-198.txt"),
|
||||
DrawerItem(119, "ffpm-199", "assets://ffpm-199.txt"),
|
||||
DrawerItem(120, "ffpm-19", "assets://ffpm-19.txt"),
|
||||
DrawerItem(121, "ffpm-202", "assets://ffpm-202.txt"),
|
||||
DrawerItem(122, "ffpm-203", "assets://ffpm-203.txt"),
|
||||
DrawerItem(123, "ffpm-204", "assets://ffpm-204.txt"),
|
||||
DrawerItem(124, "ffpm-209", "assets://ffpm-209.txt"),
|
||||
DrawerItem(125, "ffpm-20", "assets://ffpm-20.txt"),
|
||||
DrawerItem(126, "ffpm-210", "assets://ffpm-210.txt"),
|
||||
DrawerItem(127, "ffpm-211", "assets://ffpm-211.txt"),
|
||||
DrawerItem(128, "ffpm-212", "assets://ffpm-212.txt"),
|
||||
DrawerItem(129, "ffpm-213", "assets://ffpm-213.txt"),
|
||||
DrawerItem(130, "ffpm-214", "assets://ffpm-214.txt"),
|
||||
DrawerItem(131, "ffpm-21", "assets://ffpm-21.txt"),
|
||||
DrawerItem(132, "ffpm-220", "assets://ffpm-220.txt"),
|
||||
DrawerItem(133, "ffpm-221", "assets://ffpm-221.txt"),
|
||||
DrawerItem(134, "ffpm-222", "assets://ffpm-222.txt"),
|
||||
DrawerItem(135, "ffpm-223", "assets://ffpm-223.txt"),
|
||||
DrawerItem(136, "ffpm-224", "assets://ffpm-224.txt"),
|
||||
DrawerItem(137, "ffpm-225", "assets://ffpm-225.txt"),
|
||||
DrawerItem(138, "ffpm-229", "assets://ffpm-229.txt"),
|
||||
DrawerItem(139, "ffpm-232", "assets://ffpm-232.txt"),
|
||||
DrawerItem(140, "ffpm-233", "assets://ffpm-233.txt"),
|
||||
DrawerItem(141, "ffpm-236", "assets://ffpm-236.txt"),
|
||||
DrawerItem(142, "ffpm-237", "assets://ffpm-237.txt"),
|
||||
DrawerItem(143, "ffpm-238-1", "assets://ffpm-238-1.txt"),
|
||||
DrawerItem(144, "ffpm-238-2", "assets://ffpm-238-2.txt"),
|
||||
DrawerItem(145, "ffpm-239-1", "assets://ffpm-239-1.txt"),
|
||||
DrawerItem(146, "ffpm-239-2", "assets://ffpm-239-2.txt"),
|
||||
DrawerItem(147, "ffpm-249", "assets://ffpm-249.txt"),
|
||||
DrawerItem(148, "ffpm-250-1", "assets://ffpm-250-1.txt"),
|
||||
DrawerItem(149, "ffpm-250-2", "assets://ffpm-250-2.txt"),
|
||||
DrawerItem(150, "ffpm-251", "assets://ffpm-251.txt"),
|
||||
DrawerItem(151, "ffpm-253", "assets://ffpm-253.txt"),
|
||||
DrawerItem(152, "ffpm-254", "assets://ffpm-254.txt"),
|
||||
DrawerItem(153, "ffpm-255", "assets://ffpm-255.txt"),
|
||||
DrawerItem(154, "ffpm-256", "assets://ffpm-256.txt"),
|
||||
DrawerItem(155, "ffpm-257-1", "assets://ffpm-257-1.txt"),
|
||||
DrawerItem(156, "ffpm-257-2", "assets://ffpm-257-2.txt"),
|
||||
DrawerItem(157, "ffpm-259", "assets://ffpm-259.txt"),
|
||||
DrawerItem(158, "ffpm-260", "assets://ffpm-260.txt"),
|
||||
DrawerItem(159, "ffpm-263", "assets://ffpm-263.txt"),
|
||||
DrawerItem(160, "ffpm-269", "assets://ffpm-269.txt"),
|
||||
DrawerItem(161, "ffpm-270", "assets://ffpm-270.txt"),
|
||||
DrawerItem(162, "ffpm-271", "assets://ffpm-271.txt"),
|
||||
DrawerItem(163, "ffpm-272", "assets://ffpm-272.txt"),
|
||||
DrawerItem(164, "ffpm-273", "assets://ffpm-273.txt"),
|
||||
DrawerItem(165, "ffpm-274", "assets://ffpm-274.txt"),
|
||||
DrawerItem(166, "ffpm-276", "assets://ffpm-276.txt"),
|
||||
DrawerItem(167, "ffpm-279", "assets://ffpm-279.txt"),
|
||||
DrawerItem(168, "ffpm-281", "assets://ffpm-281.txt"),
|
||||
DrawerItem(169, "ffpm-297", "assets://ffpm-297.txt"),
|
||||
DrawerItem(170, "ffpm-307", "assets://ffpm-307.txt"),
|
||||
DrawerItem(171, "ffpm-310", "assets://ffpm-310.txt"),
|
||||
DrawerItem(172, "ffpm-311", "assets://ffpm-311.txt"),
|
||||
DrawerItem(173, "ffpm-315", "assets://ffpm-315.txt"),
|
||||
DrawerItem(174, "ffpm-321", "assets://ffpm-321.txt"),
|
||||
DrawerItem(175, "ffpm-32", "assets://ffpm-32.txt"),
|
||||
DrawerItem(176, "ffpm-332", "assets://ffpm-332.txt"),
|
||||
DrawerItem(177, "ffpm-33", "assets://ffpm-33.txt"),
|
||||
DrawerItem(178, "ffpm-352", "assets://ffpm-352.txt"),
|
||||
DrawerItem(179, "ffpm-353-1", "assets://ffpm-353-1.txt"),
|
||||
DrawerItem(180, "ffpm-353-2", "assets://ffpm-353-2.txt"),
|
||||
DrawerItem(181, "ffpm-357", "assets://ffpm-357.txt"),
|
||||
DrawerItem(182, "ffpm-358", "assets://ffpm-358.txt"),
|
||||
DrawerItem(183, "ffpm-35", "assets://ffpm-35.txt"),
|
||||
DrawerItem(184, "ffpm-367", "assets://ffpm-367.txt"),
|
||||
DrawerItem(185, "ffpm-381-1", "assets://ffpm-381-1.txt"),
|
||||
DrawerItem(186, "ffpm-381-2", "assets://ffpm-381-2.txt"),
|
||||
DrawerItem(187, "ffpm-38", "assets://ffpm-38.txt"),
|
||||
DrawerItem(188, "ffpm-392", "assets://ffpm-392.txt"),
|
||||
DrawerItem(189, "ffpm-408-1", "assets://ffpm-408-1.txt"),
|
||||
DrawerItem(190, "ffpm-408-2", "assets://ffpm-408-2.txt"),
|
||||
DrawerItem(191, "ffpm-413", "assets://ffpm-413.txt"),
|
||||
DrawerItem(192, "ffpm-4-1", "assets://ffpm-4-1.txt"),
|
||||
DrawerItem(193, "ffpm-42-1", "assets://ffpm-42-1.txt"),
|
||||
DrawerItem(194, "ffpm-42-2", "assets://ffpm-42-2.txt"),
|
||||
DrawerItem(195, "ffpm-428", "assets://ffpm-428.txt"),
|
||||
DrawerItem(196, "ffpm-4-2", "assets://ffpm-4-2.txt"),
|
||||
DrawerItem(197, "ffpm-43", "assets://ffpm-43.txt"),
|
||||
DrawerItem(198, "ffpm-440-1", "assets://ffpm-440-1.txt"),
|
||||
DrawerItem(199, "ffpm-444-1", "assets://ffpm-444-1.txt"),
|
||||
DrawerItem(200, "ffpm-444-2", "assets://ffpm-444-2.txt"),
|
||||
DrawerItem(201, "ffpm-449", "assets://ffpm-449.txt"),
|
||||
DrawerItem(202, "ffpm-44", "assets://ffpm-44.txt"),
|
||||
DrawerItem(203, "ffpm-46", "assets://ffpm-46.txt"),
|
||||
DrawerItem(204, "ffpm-47", "assets://ffpm-47.txt"),
|
||||
DrawerItem(205, "ffpm-483", "assets://ffpm-483.txt"),
|
||||
DrawerItem(206, "ffpm-489", "assets://ffpm-489.txt"),
|
||||
DrawerItem(207, "ffpm-490", "assets://ffpm-490.txt"),
|
||||
DrawerItem(208, "ffpm-49-1", "assets://ffpm-49-1.txt"),
|
||||
DrawerItem(209, "ffpm-49-2", "assets://ffpm-49-2.txt"),
|
||||
DrawerItem(210, "ffpm-501", "assets://ffpm-501.txt"),
|
||||
DrawerItem(211, "ffpm-503", "assets://ffpm-503.txt"),
|
||||
DrawerItem(212, "ffpm-5-1", "assets://ffpm-5-1.txt"),
|
||||
DrawerItem(213, "ffpm-51", "assets://ffpm-51.txt"),
|
||||
DrawerItem(214, "ffpm-5-2", "assets://ffpm-5-2.txt"),
|
||||
DrawerItem(215, "ffpm-52", "assets://ffpm-52.txt"),
|
||||
DrawerItem(216, "ffpm-539", "assets://ffpm-539.txt"),
|
||||
DrawerItem(217, "ffpm-546", "assets://ffpm-546.txt"),
|
||||
DrawerItem(218, "ffpm-549", "assets://ffpm-549.txt"),
|
||||
DrawerItem(219, "ffpm-54", "assets://ffpm-54.txt"),
|
||||
DrawerItem(220, "ffpm-558", "assets://ffpm-558.txt"),
|
||||
DrawerItem(221, "ffpm-55", "assets://ffpm-55.txt"),
|
||||
DrawerItem(222, "ffpm-563", "assets://ffpm-563.txt"),
|
||||
DrawerItem(223, "ffpm-564", "assets://ffpm-564.txt"),
|
||||
DrawerItem(224, "ffpm-56-new", "assets://ffpm-56-new.txt"),
|
||||
DrawerItem(225, "ffpm-56", "assets://ffpm-56.txt"),
|
||||
DrawerItem(226, "ffpm-57-new", "assets://ffpm-57-new.txt"),
|
||||
DrawerItem(227, "ffpm-57", "assets://ffpm-57.txt"),
|
||||
DrawerItem(228, "ffpm-58", "assets://ffpm-58.txt"),
|
||||
DrawerItem(229, "ffpm-603-1", "assets://ffpm-603-1.txt"),
|
||||
DrawerItem(230, "ffpm-603-2", "assets://ffpm-603-2.txt"),
|
||||
DrawerItem(231, "ffpm-610", "assets://ffpm-610.txt"),
|
||||
DrawerItem(232, "ffpm-611-1", "assets://ffpm-611-1.txt"),
|
||||
DrawerItem(233, "ffpm-611-2", "assets://ffpm-611-2.txt"),
|
||||
DrawerItem(234, "ffpm-616", "assets://ffpm-616.txt"),
|
||||
DrawerItem(235, "ffpm-61", "assets://ffpm-61.txt"),
|
||||
DrawerItem(236, "ffpm-626", "assets://ffpm-626.txt"),
|
||||
DrawerItem(237, "ffpm-636", "assets://ffpm-636.txt"),
|
||||
DrawerItem(238, "ffpm-640", "assets://ffpm-640.txt"),
|
||||
DrawerItem(239, "ffpm-642-1", "assets://ffpm-642-1.txt"),
|
||||
DrawerItem(240, "ffpm-642-2", "assets://ffpm-642-2.txt"),
|
||||
DrawerItem(241, "ffpm-653", "assets://ffpm-653.txt"),
|
||||
DrawerItem(242, "ffpm-674", "assets://ffpm-674.txt"),
|
||||
DrawerItem(243, "ffpm-69", "assets://ffpm-69.txt"),
|
||||
DrawerItem(244, "ffpm-6", "assets://ffpm-6.txt"),
|
||||
DrawerItem(245, "ffpm-705-2", "assets://ffpm-705-2.txt"),
|
||||
DrawerItem(246, "ffpm-71", "assets://ffpm-71.txt"),
|
||||
DrawerItem(247, "ffpm-725", "assets://ffpm-725.txt"),
|
||||
DrawerItem(248, "ffpm-726-1", "assets://ffpm-726-1.txt"),
|
||||
DrawerItem(249, "ffpm-726-2", "assets://ffpm-726-2.txt"),
|
||||
DrawerItem(250, "ffpm-729", "assets://ffpm-729.txt"),
|
||||
DrawerItem(251, "ffpm-72", "assets://ffpm-72.txt"),
|
||||
DrawerItem(252, "ffpm-733", "assets://ffpm-733.txt"),
|
||||
DrawerItem(253, "ffpm-734", "assets://ffpm-734.txt"),
|
||||
DrawerItem(254, "ffpm-735", "assets://ffpm-735.txt"),
|
||||
DrawerItem(255, "ffpm-737", "assets://ffpm-737.txt"),
|
||||
DrawerItem(256, "ffpm-750", "assets://ffpm-750.txt"),
|
||||
DrawerItem(257, "ffpm-75", "assets://ffpm-75.txt"),
|
||||
DrawerItem(258, "ffpm-760", "assets://ffpm-760.txt"),
|
||||
DrawerItem(259, "ffpm-79-1", "assets://ffpm-79-1.txt"),
|
||||
DrawerItem(260, "ffpm-79-2", "assets://ffpm-79-2.txt"),
|
||||
DrawerItem(261, "ffpm-796", "assets://ffpm-796.txt"),
|
||||
DrawerItem(262, "ffpm-799", "assets://ffpm-799.txt"),
|
||||
DrawerItem(263, "ffpm-7", "assets://ffpm-7.txt"),
|
||||
DrawerItem(264, "ffpm-82-1", "assets://ffpm-82-1.txt"),
|
||||
DrawerItem(265, "ffpm-82-2", "assets://ffpm-82-2.txt"),
|
||||
DrawerItem(266, "ffpm-825", "assets://ffpm-825.txt"),
|
||||
DrawerItem(267, "ffpm-87", "assets://ffpm-87.txt"),
|
||||
DrawerItem(268, "ffpm-89", "assets://ffpm-89.txt"),
|
||||
DrawerItem(269, "ffpm-8", "assets://ffpm-8.txt"),
|
||||
DrawerItem(270, "ffpm-91", "assets://ffpm-91.txt"),
|
||||
DrawerItem(271, "ffpm-93", "assets://ffpm-93.txt"),
|
||||
DrawerItem(272, "ffpm-94", "assets://ffpm-94.txt"),
|
||||
DrawerItem(273, "ffpm-97-1", "assets://ffpm-97-1.txt"),
|
||||
DrawerItem(274, "ffpm-97-2", "assets://ffpm-97-2.txt"),
|
||||
DrawerItem(275, "ffpm-9", "assets://ffpm-9.txt")
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
package mg.dot.feufaro.midi
|
||||
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import mg.dot.feufaro.FileRepository
|
||||
import javax.sound.midi.*
|
||||
|
||||
class `MidiWriterKotlin-1` (private val fileRepository: FileRepository) {
|
||||
private val sequence = Sequence(Sequence.PPQ, 60)
|
||||
private val track = sequence.createTrack()
|
||||
private var tick: Long = 0
|
||||
private var nextTick: MutableList<Int> = mutableListOf()
|
||||
private val noteOn = ShortMessage()
|
||||
private val noteOff = ShortMessage()
|
||||
private val lastPitch : MutableList<Int> = mutableListOf()
|
||||
private val useChord : Boolean = true
|
||||
fun addNote( voiceNumber: Int, note: Int, velocity: Int, tick: Long) {
|
||||
var channel: Int = voiceNumber - 1
|
||||
if (useChord) {
|
||||
channel = channel / 2
|
||||
}
|
||||
var note = note
|
||||
if (voiceNumber == 3 || voiceNumber == 4) {
|
||||
note -= 12
|
||||
}
|
||||
if (lastPitch.size > voiceNumber && lastPitch[voiceNumber] > 0) {
|
||||
noteOff.setMessage(ShortMessage.NOTE_OFF, channel, lastPitch[voiceNumber], 0)
|
||||
val n2 = noteOff.clone() as MidiMessage
|
||||
track.add(MidiEvent(n2, tick))
|
||||
}
|
||||
var velocity = velocity
|
||||
if (note <= 0) {
|
||||
note = 40
|
||||
velocity = 0
|
||||
}
|
||||
noteOn.setMessage(ShortMessage.NOTE_ON, channel, note, velocity)
|
||||
val n1: MidiMessage = noteOn.clone() as MidiMessage
|
||||
track.add(MidiEvent(n1, tick))
|
||||
while(lastPitch.size <= voiceNumber) {
|
||||
lastPitch.add(0)
|
||||
}
|
||||
lastPitch[voiceNumber] = note
|
||||
}
|
||||
fun save(filePath: String) {
|
||||
val parseScope = CoroutineScope(Dispatchers.Default)
|
||||
parseScope.launch {
|
||||
val out = fileRepository.getOutputStream(filePath)
|
||||
MidiSystem.write(sequence, 1, out)
|
||||
out.close()
|
||||
}
|
||||
}
|
||||
fun addMetaMessage(type: Int, tick: Int, nbData: Int, metaByteString: String) {
|
||||
val byteArray = metaByteString.toByteArray()
|
||||
val metaMessage = MetaMessage(type, byteArray, nbData)
|
||||
track.add(MidiEvent(metaMessage, tick.toLong()))
|
||||
}
|
||||
fun process(pitches: List<MidiPitch>) {
|
||||
val lastTick = 0
|
||||
nextTick.clear()
|
||||
// addMetaMessage(0x59, 4, 2, 2,0)
|
||||
tick = 0
|
||||
pitches.forEach {
|
||||
if (it.metaType > 0) {
|
||||
addMetaMessage(it.metaType, it.tick, it.metaByteSize, it.metaBytes)
|
||||
} else if (it.pitch != "") {
|
||||
addNote(it.voiceNumber, it.pitch.toInt(), 100, it.tick.toLong())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
package mg.dot.feufaro.midi
|
||||
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import mg.dot.feufaro.FileRepository
|
||||
import javax.sound.midi.*
|
||||
|
||||
actual class MidiWriterKotlin actual constructor(private val fileRepository: FileRepository) {
|
||||
private val sequence = Sequence(Sequence.PPQ, 60)
|
||||
private val track = sequence.createTrack()
|
||||
private var tick: Long = 0
|
||||
//private var nextTick: MidiPitch<Int> = mutableListOf()
|
||||
private var nextTick: MutableList<MidiPitch> = mutableListOf()
|
||||
private val noteOn = ShortMessage()
|
||||
private val noteOff = ShortMessage()
|
||||
private val lastPitch : MutableList<Int> = mutableListOf()
|
||||
private val useChord : Boolean = true
|
||||
actual fun addNote( voiceNumber: Int, note: Int, velocity: Int, tick: Long) {
|
||||
var channel: Int = voiceNumber - 1
|
||||
if (useChord) {
|
||||
channel = channel / 2
|
||||
}
|
||||
var note = note
|
||||
if (voiceNumber == 3 || voiceNumber == 4) {
|
||||
note -= 12
|
||||
}
|
||||
if (lastPitch.size > voiceNumber && lastPitch[voiceNumber] > 0) {
|
||||
noteOff.setMessage(ShortMessage.NOTE_OFF, channel, lastPitch[voiceNumber], 0)
|
||||
val n2 = noteOff.clone() as MidiMessage
|
||||
track.add(MidiEvent(n2, tick))
|
||||
}
|
||||
var velocity = velocity
|
||||
if (note <= 0) {
|
||||
note = 40
|
||||
velocity = 0
|
||||
}
|
||||
noteOn.setMessage(ShortMessage.NOTE_ON, channel, note, velocity)
|
||||
val n1: MidiMessage = noteOn.clone() as MidiMessage
|
||||
track.add(MidiEvent(n1, tick))
|
||||
while(lastPitch.size <= voiceNumber) {
|
||||
lastPitch.add(0)
|
||||
}
|
||||
lastPitch[voiceNumber] = note
|
||||
}
|
||||
actual fun save(filePath: String) {
|
||||
val parseScope = CoroutineScope(Dispatchers.Default)
|
||||
parseScope.launch {
|
||||
val out = fileRepository.getOutputStream(filePath)
|
||||
MidiSystem.write(sequence, 1, out)
|
||||
out.close()
|
||||
}
|
||||
}
|
||||
actual fun addMetaMessage(type: Int, tick: Int, nbData: Int, metaByteString: String) {
|
||||
val byteArray = metaByteString.toByteArray()
|
||||
val metaMessage = MetaMessage(type, byteArray, nbData)
|
||||
track.add(MidiEvent(metaMessage, tick.toLong()))
|
||||
}
|
||||
actual fun process(pitches: List<MidiPitch>) {
|
||||
val lastTick = 0
|
||||
nextTick.clear()
|
||||
// addMetaMessage(0x59, 4, 2, 2,0)
|
||||
tick = 0
|
||||
pitches.forEach {
|
||||
if (it.metaType > 0) {
|
||||
addMetaMessage(it.metaType, it.tick, it.metaByteSize, it.metaBytes)
|
||||
} else if (it.pitch != "") {
|
||||
addNote(it.voiceNumber, it.pitch.toInt(), 100, it.tick.toLong())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
package mg.dot.feufaro.ui
|
||||
|
||||
import androidx.compose.ui.graphics.ImageBitmap
|
||||
import androidx.compose.ui.graphics.toComposeImageBitmap
|
||||
import com.google.zxing.BarcodeFormat
|
||||
import com.google.zxing.client.j2se.MatrixToImageWriter
|
||||
import com.google.zxing.qrcode.QRCodeWriter
|
||||
|
||||
actual fun generateQRCode(content: String, size: Int): ImageBitmap? {
|
||||
return try {
|
||||
val writer = QRCodeWriter()
|
||||
val bitMatrix = writer.encode(content, BarcodeFormat.QR_CODE, size, size)
|
||||
|
||||
val image = MatrixToImageWriter.toBufferedImage(bitMatrix)
|
||||
|
||||
image.toComposeImageBitmap()
|
||||
|
||||
} catch (e: Exception) {
|
||||
println("Erreur QR Code Desktop: ${e.message}")
|
||||
null
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
package mg.dot.feufaro.ui
|
||||
|
||||
import androidx.compose.foundation.*
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.lazy.LazyListState
|
||||
|
||||
@Composable
|
||||
actual fun ScrollableDrawerContent(
|
||||
modifier: Modifier,
|
||||
lazyListState: LazyListState,
|
||||
content: @Composable () -> Unit
|
||||
) {
|
||||
val scrollState = rememberScrollState()
|
||||
|
||||
Box(modifier = modifier) {
|
||||
content()
|
||||
|
||||
VerticalScrollbar(
|
||||
modifier = Modifier.align(Alignment.CenterEnd).fillMaxHeight().width(8.dp),
|
||||
adapter = rememberScrollbarAdapter(lazyListState)
|
||||
)
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue