Support share button on FAB : export pdf|mid - desktop&android

This commit is contained in:
Hasinjato 2026-08-07 15:43:56 +03:00
parent 92a3a0344d
commit 41fbb204bb
5 changed files with 98 additions and 42 deletions

View file

@ -80,12 +80,6 @@ class AndroidFileRepository(private val context: Context) : FileRepository {
val folder = context.getExternalFilesDir(null)
return "$folder/$shortName"
}
/*override suspend fun readFileBytes(filePath: String): ByteArray = withContext(Dispatchers.IO) {
val folder = context.getExternalFilesDir(null)
val file = File(folder, filePath)
if (!file.exists()) throw IOException("File not found: ${file.absolutePath}")
file.readBytes()
}*/
private fun String.parseSafToRelativePath(): String {
if (!this.startsWith("content://")) return this
@ -129,10 +123,12 @@ class AndroidFileRepository(private val context: Context) : FileRepository {
if (filePath.endsWith(".pdf", ignoreCase = true)) {
openPdfFile(context = context, filePath = filePath)
} else {
val shortDisplayPath = longPathToShort(displayPath)
Toast.makeText(
context.applicationContext,
"Sauvegarde réussie : ${displayPath.substringAfterLast('/')}",
Toast.LENGTH_LONG
"Sauvegarde réussie dans : $shortDisplayPath",
Toast.LENGTH_LONG
).show()
}
}
@ -144,6 +140,15 @@ class AndroidFileRepository(private val context: Context) : FileRepository {
throw e
}
}
private fun longPathToShort(displayPath: String): String {
return if (displayPath.contains("Documents/")) {
"Documents/" + displayPath.substringAfter("Documents/")
} else {
displayPath.substringAfterLast('/')
}
}
override suspend fun getAppPublicFolder(): File {
val publicDocsDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS)
val appDir = File(publicDocsDir, "Feufaro")
@ -162,7 +167,8 @@ class AndroidFileRepository(private val context: Context) : FileRepository {
}
override fun pickSavePath(defaultName: String, title: String): String? {
val file = File(context.filesDir, defaultName)
val publicFolder = getPAppPublicFolder()
val file = File(publicFolder, defaultName)
return file?.absolutePath
}
suspend fun openPdfFile(context: Context, filePath: String) {
@ -182,9 +188,10 @@ class AndroidFileRepository(private val context: Context) : FileRepository {
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
}
val sPath = longPathToShort(filePath)
try {
withContext(Dispatchers.Main) {
Toast.makeText(context.applicationContext, "Fichier sauvegardé avec succès", Toast.LENGTH_LONG).show()
Toast.makeText(context.applicationContext, "Fichier sauvegardé avec succès dans $sPath", Toast.LENGTH_LONG).show()
}
context.startActivity(intent)
} catch (e: Exception) {

View file

@ -3,6 +3,7 @@ package mg.dot.feufaro.midi
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import mg.dot.feufaro.FileRepository
import mg.dot.feufaro.solfa.Transpose
import mg.dot.feufaro.viewmodel.MidiMarkers
@ -37,16 +38,12 @@ class MidiWriterforEXport constructor(private val fileRepository: FileRepositor
}
lastPitch[voiceNumber] = midiNote
}
fun save(filePath: String) {
val parseScope = CoroutineScope(Dispatchers.Default)
parseScope.launch {
sequence.write()
fileRepository.saveFile(filePath, sequence.out.toByteArray())
//val fout = fileRepository.getOutputStream(filePath)
}
suspend fun save(filePath: String) = withContext(Dispatchers.Default) {
sequence.write()
fileRepository.saveLocalFile(filePath, sequence.out.toByteArray())
}
fun addMetaMessage(type: Int, tick: Int, nbData: Int, metaBytes: ByteArray) {
sequence.addMeta(type, tick, nbData, metaBytes.toString())
sequence.addMetaFe(type, tick, nbData, metaBytes)
}
fun setTempoMeta(bpm: Float, tickPosition: Int = 0) {

View file

@ -261,7 +261,7 @@ class Solfa(val sharedScreenModel: SharedScreenModel, private val fileRepository
private val prefs: Settings = provideSettings()
fun generateMidiFile(bpm: Float) {
fun generateMidiFile(bpm: Float, outputPath: String = "whawyd3.mid") {
val parseScope = CoroutineScope(Dispatchers.Default)
parseScope.launch {
val pitchesSorted = pitches.sortedWith(compareBy({ it.tick }, { it.voiceNumber }))
@ -273,8 +273,14 @@ class Solfa(val sharedScreenModel: SharedScreenModel, private val fileRepository
3 to prefs.getInt("voice_instrument", 0),
4 to prefs.getInt("voice_instrument", 0),
)
midiWriter.process(pitchesSorted, sharedScreenModel.getFullMarkers(), initialBpm = bpm, instruments, initialKey = sharedScreenModel.songKey.value)
midiWriter.save("whawyd3.mid")
midiWriter.process(
pitchesSorted,
sharedScreenModel.getFullMarkers(),
initialBpm = bpm,
instruments,
initialKey = sharedScreenModel.songKey.value
)
midiWriter.save(outputPath)
}
}
fun justBuild(sourceFile: String, sourceContent: String) {

View file

@ -88,6 +88,7 @@ fun MainScreenWithDrawer(
val isExpanded by sharedScreenModel.expandedFAB.collectAsState()
val showMidiCtrl by sharedScreenModel.showMidiCtrl.collectAsState()
var isShareExpanded by remember { mutableStateOf(false) }
val isPlay by sharedScreenModel.isPlay.collectAsState()
val isPos by sharedScreenModel.isPos.collectAsState()
@ -732,27 +733,72 @@ fun MainScreenWithDrawer(
enter = fadeIn() + scaleIn() + slideInVertically { it / 2 },
exit = fadeOut() + scaleOut() + slideOutVertically { it / 2 }
) {
MyFAB(
onClick = {
sharedScreenModel.toggleQRCodeVisibility()
sharedScreenModel.setExpandedFAB(false)
},
icon = Icons.Filled.QrCode
)
}
Row(
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(8.dp)
) {
AnimatedVisibility(
visible = isShareExpanded,
enter = fadeIn() + expandHorizontally(),
exit = fadeOut() + shrinkHorizontally()
) {
Row(
horizontalArrangement = Arrangement.spacedBy(8.dp),
verticalAlignment = Alignment.CenterVertically
) {
MyFAB(
onClick = {
sharedScreenModel.toggleQRCodeVisibility()
sharedScreenModel.setExpandedFAB(false)
isShareExpanded = false
},
icon = Icons.Filled.QrCode2
)
MyFAB(
onClick = {
showPrintSettings = !showPrintSettings
isShareExpanded = false
},
icon = Icons.Filled.Print
)
AnimatedVisibility(
visible = isExpanded and !showMidiCtrl,
enter = fadeIn() + scaleIn() + slideInVertically { it / 2 },
exit = fadeOut() + scaleOut() + slideOutVertically { it / 2 }
) {
MyFAB(
onClick = {
showPrintSettings = !showPrintSettings
},
icon = Icons.Filled.Print
)
MyFAB(
onClick = {
isShareExpanded = false
scope.launch {
withContext(Dispatchers.IO) {
try {
val cleanS = songTitle.replace(' ','_')
val exportName = "${cleanS.ifEmpty { "partition" }}.mid"
val savedPath = solfaScreenModel.fileRepository.pickSavePath(
defaultName = exportName,
title = "Enregistrer le fichier MIDI"
)
if (!savedPath.isNullOrEmpty()) {
val bpm = sharedScreenModel.getBpmFlow().value ?: 120f
solfaScreenModel.generateMidiFile(bpm, savedPath)
println("Fichier MIDI enregistré avec succès sous : $savedPath")
}
} catch (e: Exception) {
e.printStackTrace()
}
}
}
},
icon = Icons.Filled.AudioFile
)
}
}
MyFAB(
onClick = { isShareExpanded = !isShareExpanded },
icon = Icons.Filled.Share
)
}
}
AnimatedVisibility(

View file

@ -55,7 +55,7 @@ class SolfaScreenModel(
solfa.createNewSolfa(metadata)
}
}
fun regenMidi(bpm: Float) {
solfa.generateMidiFile(bpm)
fun generateMidiFile(bpm: Float, path: String) {
solfa.generateMidiFile(bpm, path)
}
}