Support share button on FAB : export pdf|mid - desktop&android
This commit is contained in:
parent
92a3a0344d
commit
41fbb204bb
5 changed files with 98 additions and 42 deletions
|
|
@ -80,12 +80,6 @@ class AndroidFileRepository(private val context: Context) : FileRepository {
|
||||||
val folder = context.getExternalFilesDir(null)
|
val folder = context.getExternalFilesDir(null)
|
||||||
return "$folder/$shortName"
|
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 {
|
private fun String.parseSafToRelativePath(): String {
|
||||||
if (!this.startsWith("content://")) return this
|
if (!this.startsWith("content://")) return this
|
||||||
|
|
@ -129,10 +123,12 @@ class AndroidFileRepository(private val context: Context) : FileRepository {
|
||||||
if (filePath.endsWith(".pdf", ignoreCase = true)) {
|
if (filePath.endsWith(".pdf", ignoreCase = true)) {
|
||||||
openPdfFile(context = context, filePath = filePath)
|
openPdfFile(context = context, filePath = filePath)
|
||||||
} else {
|
} else {
|
||||||
|
val shortDisplayPath = longPathToShort(displayPath)
|
||||||
|
|
||||||
Toast.makeText(
|
Toast.makeText(
|
||||||
context.applicationContext,
|
context.applicationContext,
|
||||||
"Sauvegarde réussie : ${displayPath.substringAfterLast('/')}",
|
"Sauvegarde réussie dans : $shortDisplayPath",
|
||||||
Toast.LENGTH_LONG
|
Toast.LENGTH_LONG
|
||||||
).show()
|
).show()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -144,6 +140,15 @@ class AndroidFileRepository(private val context: Context) : FileRepository {
|
||||||
throw e
|
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 {
|
override suspend fun getAppPublicFolder(): File {
|
||||||
val publicDocsDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS)
|
val publicDocsDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS)
|
||||||
val appDir = File(publicDocsDir, "Feufaro")
|
val appDir = File(publicDocsDir, "Feufaro")
|
||||||
|
|
@ -162,7 +167,8 @@ class AndroidFileRepository(private val context: Context) : FileRepository {
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun pickSavePath(defaultName: String, title: String): String? {
|
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
|
return file?.absolutePath
|
||||||
}
|
}
|
||||||
suspend fun openPdfFile(context: Context, filePath: String) {
|
suspend fun openPdfFile(context: Context, filePath: String) {
|
||||||
|
|
@ -182,9 +188,10 @@ class AndroidFileRepository(private val context: Context) : FileRepository {
|
||||||
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val sPath = longPathToShort(filePath)
|
||||||
try {
|
try {
|
||||||
withContext(Dispatchers.Main) {
|
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)
|
context.startActivity(intent)
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ package mg.dot.feufaro.midi
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
import mg.dot.feufaro.FileRepository
|
import mg.dot.feufaro.FileRepository
|
||||||
import mg.dot.feufaro.solfa.Transpose
|
import mg.dot.feufaro.solfa.Transpose
|
||||||
import mg.dot.feufaro.viewmodel.MidiMarkers
|
import mg.dot.feufaro.viewmodel.MidiMarkers
|
||||||
|
|
@ -37,16 +38,12 @@ class MidiWriterforEXport constructor(private val fileRepository: FileRepositor
|
||||||
}
|
}
|
||||||
lastPitch[voiceNumber] = midiNote
|
lastPitch[voiceNumber] = midiNote
|
||||||
}
|
}
|
||||||
fun save(filePath: String) {
|
suspend fun save(filePath: String) = withContext(Dispatchers.Default) {
|
||||||
val parseScope = CoroutineScope(Dispatchers.Default)
|
sequence.write()
|
||||||
parseScope.launch {
|
fileRepository.saveLocalFile(filePath, sequence.out.toByteArray())
|
||||||
sequence.write()
|
|
||||||
fileRepository.saveFile(filePath, sequence.out.toByteArray())
|
|
||||||
//val fout = fileRepository.getOutputStream(filePath)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
fun addMetaMessage(type: Int, tick: Int, nbData: Int, metaBytes: ByteArray) {
|
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) {
|
fun setTempoMeta(bpm: Float, tickPosition: Int = 0) {
|
||||||
|
|
|
||||||
|
|
@ -261,7 +261,7 @@ class Solfa(val sharedScreenModel: SharedScreenModel, private val fileRepository
|
||||||
|
|
||||||
private val prefs: Settings = provideSettings()
|
private val prefs: Settings = provideSettings()
|
||||||
|
|
||||||
fun generateMidiFile(bpm: Float) {
|
fun generateMidiFile(bpm: Float, outputPath: String = "whawyd3.mid") {
|
||||||
val parseScope = CoroutineScope(Dispatchers.Default)
|
val parseScope = CoroutineScope(Dispatchers.Default)
|
||||||
parseScope.launch {
|
parseScope.launch {
|
||||||
val pitchesSorted = pitches.sortedWith(compareBy({ it.tick }, { it.voiceNumber }))
|
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),
|
3 to prefs.getInt("voice_instrument", 0),
|
||||||
4 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.process(
|
||||||
midiWriter.save("whawyd3.mid")
|
pitchesSorted,
|
||||||
|
sharedScreenModel.getFullMarkers(),
|
||||||
|
initialBpm = bpm,
|
||||||
|
instruments,
|
||||||
|
initialKey = sharedScreenModel.songKey.value
|
||||||
|
)
|
||||||
|
midiWriter.save(outputPath)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fun justBuild(sourceFile: String, sourceContent: String) {
|
fun justBuild(sourceFile: String, sourceContent: String) {
|
||||||
|
|
|
||||||
|
|
@ -88,6 +88,7 @@ fun MainScreenWithDrawer(
|
||||||
|
|
||||||
val isExpanded by sharedScreenModel.expandedFAB.collectAsState()
|
val isExpanded by sharedScreenModel.expandedFAB.collectAsState()
|
||||||
val showMidiCtrl by sharedScreenModel.showMidiCtrl.collectAsState()
|
val showMidiCtrl by sharedScreenModel.showMidiCtrl.collectAsState()
|
||||||
|
var isShareExpanded by remember { mutableStateOf(false) }
|
||||||
|
|
||||||
val isPlay by sharedScreenModel.isPlay.collectAsState()
|
val isPlay by sharedScreenModel.isPlay.collectAsState()
|
||||||
val isPos by sharedScreenModel.isPos.collectAsState()
|
val isPos by sharedScreenModel.isPos.collectAsState()
|
||||||
|
|
@ -732,27 +733,72 @@ fun MainScreenWithDrawer(
|
||||||
enter = fadeIn() + scaleIn() + slideInVertically { it / 2 },
|
enter = fadeIn() + scaleIn() + slideInVertically { it / 2 },
|
||||||
exit = fadeOut() + scaleOut() + slideOutVertically { it / 2 }
|
exit = fadeOut() + scaleOut() + slideOutVertically { it / 2 }
|
||||||
) {
|
) {
|
||||||
MyFAB(
|
Row(
|
||||||
onClick = {
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
sharedScreenModel.toggleQRCodeVisibility()
|
horizontalArrangement = Arrangement.spacedBy(8.dp)
|
||||||
sharedScreenModel.setExpandedFAB(false)
|
) {
|
||||||
},
|
AnimatedVisibility(
|
||||||
icon = Icons.Filled.QrCode
|
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(
|
MyFAB(
|
||||||
visible = isExpanded and !showMidiCtrl,
|
onClick = {
|
||||||
enter = fadeIn() + scaleIn() + slideInVertically { it / 2 },
|
isShareExpanded = false
|
||||||
exit = fadeOut() + scaleOut() + slideOutVertically { it / 2 }
|
scope.launch {
|
||||||
) {
|
withContext(Dispatchers.IO) {
|
||||||
MyFAB(
|
try {
|
||||||
onClick = {
|
val cleanS = songTitle.replace(' ','_')
|
||||||
showPrintSettings = !showPrintSettings
|
val exportName = "${cleanS.ifEmpty { "partition" }}.mid"
|
||||||
},
|
|
||||||
icon = Icons.Filled.Print
|
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(
|
AnimatedVisibility(
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,7 @@ class SolfaScreenModel(
|
||||||
solfa.createNewSolfa(metadata)
|
solfa.createNewSolfa(metadata)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fun regenMidi(bpm: Float) {
|
fun generateMidiFile(bpm: Float, path: String) {
|
||||||
solfa.generateMidiFile(bpm)
|
solfa.generateMidiFile(bpm, path)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Loading…
Add table
Reference in a new issue