Generate PDF partition - desktop&android
This commit is contained in:
parent
fa28916eca
commit
e0b98c5758
22 changed files with 2981 additions and 10 deletions
|
|
@ -53,6 +53,7 @@ kotlin {
|
||||||
implementation(libs.koin.androidx.compose)
|
implementation(libs.koin.androidx.compose)
|
||||||
implementation("com.google.zxing:core:3.5.4")
|
implementation("com.google.zxing:core:3.5.4")
|
||||||
implementation("com.github.billthefarmer:mididriver:1.25")
|
implementation("com.github.billthefarmer:mididriver:1.25")
|
||||||
|
implementation("com.tom-roush:pdfbox-android:2.0.27.0")
|
||||||
}
|
}
|
||||||
commonMain.dependencies {
|
commonMain.dependencies {
|
||||||
// implementation(compose.components.resources)
|
// implementation(compose.components.resources)
|
||||||
|
|
@ -86,6 +87,7 @@ kotlin {
|
||||||
implementation(libs.kotlinx.coroutinesSwing)
|
implementation(libs.kotlinx.coroutinesSwing)
|
||||||
implementation("com.google.zxing:core:3.5.4")
|
implementation("com.google.zxing:core:3.5.4")
|
||||||
implementation("com.google.zxing:javase:3.5.4")
|
implementation("com.google.zxing:javase:3.5.4")
|
||||||
|
implementation("org.apache.pdfbox:pdfbox:3.0.7")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
targets.all {
|
targets.all {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,9 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
|
||||||
|
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||||
|
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
|
||||||
|
android:maxSdkVersion="28" />
|
||||||
<application
|
<application
|
||||||
android:name=".AndroidApp"
|
android:name=".AndroidApp"
|
||||||
android:allowBackup="true"
|
android:allowBackup="true"
|
||||||
|
|
@ -18,6 +21,15 @@
|
||||||
<category android:name="android.intent.category.LAUNCHER" />
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
|
<provider
|
||||||
|
android:name="androidx.core.content.FileProvider"
|
||||||
|
android:authorities="mg.dot.feufaro.fileprovider"
|
||||||
|
android:exported="false"
|
||||||
|
android:grantUriPermissions="true">
|
||||||
|
<meta-data
|
||||||
|
android:name="android.support.FILE_PROVIDER_PATHS"
|
||||||
|
android:resource="@xml/file_paths" />
|
||||||
|
</provider>
|
||||||
</application>
|
</application>
|
||||||
|
|
||||||
</manifest>
|
</manifest>
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
package mg.dot.feufaro
|
package mg.dot.feufaro
|
||||||
|
|
||||||
import android.app.Application
|
import android.app.Application
|
||||||
|
import com.tom_roush.pdfbox.android.PDFBoxResourceLoader
|
||||||
import org.koin.core.context.GlobalContext.startKoin
|
import org.koin.core.context.GlobalContext.startKoin
|
||||||
import mg.dot.feufaro.di.commonModule // Importez votre module commun
|
import mg.dot.feufaro.di.commonModule // Importez votre module commun
|
||||||
import org.koin.android.ext.koin.androidContext
|
import org.koin.android.ext.koin.androidContext
|
||||||
|
|
@ -12,6 +13,7 @@ import mg.dot.feufaro.di.platformModule
|
||||||
class AndroidApp: Application() {
|
class AndroidApp: Application() {
|
||||||
override fun onCreate() {
|
override fun onCreate() {
|
||||||
super.onCreate()
|
super.onCreate()
|
||||||
|
PDFBoxResourceLoader.init(this)
|
||||||
startKoin {
|
startKoin {
|
||||||
// Log Koin messages (INFO pour le développement, ERROR pour la production)
|
// Log Koin messages (INFO pour le développement, ERROR pour la production)
|
||||||
androidLogger(Level.INFO)
|
androidLogger(Level.INFO)
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,11 @@
|
||||||
package mg.dot.feufaro
|
package mg.dot.feufaro
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
|
import android.os.Environment
|
||||||
|
import android.widget.Toast
|
||||||
|
import androidx.core.content.FileProvider
|
||||||
import feufaro.composeapp.generated.resources.Res
|
import feufaro.composeapp.generated.resources.Res
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
|
|
@ -62,10 +66,10 @@ class AndroidFileRepository(private val context: Context) : FileRepository {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getFileName(shortName: String): String {
|
/*override fun getFileName(shortName: String): String {
|
||||||
val folder = context.getExternalFilesDir(null)
|
val folder = context.getExternalFilesDir(null)
|
||||||
return "$folder/$shortName"
|
return "$folder/$shortName"
|
||||||
}
|
}*/
|
||||||
// Dans androidMain / AndroidFileRepository.kt
|
// Dans androidMain / AndroidFileRepository.kt
|
||||||
/*override suspend fun readFileBytes(filePath: String): ByteArray = withContext(Dispatchers.IO) {
|
/*override suspend fun readFileBytes(filePath: String): ByteArray = withContext(Dispatchers.IO) {
|
||||||
val folder = context.getExternalFilesDir(null)
|
val folder = context.getExternalFilesDir(null)
|
||||||
|
|
@ -73,5 +77,59 @@ class AndroidFileRepository(private val context: Context) : FileRepository {
|
||||||
if (!file.exists()) throw IOException("File not found: ${file.absolutePath}")
|
if (!file.exists()) throw IOException("File not found: ${file.absolutePath}")
|
||||||
file.readBytes()
|
file.readBytes()
|
||||||
}*/
|
}*/
|
||||||
|
override suspend fun saveLocalFile(filePath: String, data: ByteArray) {
|
||||||
|
val cleanPath = if (filePath.contains("/storage/emulated/0/")) {
|
||||||
|
filePath.substring(filePath.indexOf("/storage/emulated/0/"))
|
||||||
|
} else {
|
||||||
|
filePath
|
||||||
|
}
|
||||||
|
|
||||||
|
val file = File(cleanPath)
|
||||||
|
try {
|
||||||
|
file.parentFile?.mkdirs()
|
||||||
|
file.writeBytes(data)
|
||||||
|
println("Fichier sauvegardé avec succès dans : ${file.absolutePath}")
|
||||||
|
openPdfFile(context = context, filePath = file.absolutePath)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
|
throw e
|
||||||
|
}
|
||||||
|
}
|
||||||
|
override fun getFileName(shortName: String): String {
|
||||||
|
return File(context.filesDir, shortName).absolutePath
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun pickSavePath(defaultName: String): String? {
|
||||||
|
val downloadDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)
|
||||||
|
return File(downloadDir, defaultName).absolutePath
|
||||||
|
}
|
||||||
|
suspend fun openPdfFile(context: Context, filePath: String) {
|
||||||
|
val file = File(filePath)
|
||||||
|
if (!file.exists()) return
|
||||||
|
|
||||||
|
// 1. Transformer le File en Uri sécurisée
|
||||||
|
val uri: Uri = FileProvider.getUriForFile(
|
||||||
|
context,
|
||||||
|
"mg.dot.feufaro.fileprovider",
|
||||||
|
file
|
||||||
|
)
|
||||||
|
|
||||||
|
// uvrir un PDF
|
||||||
|
val intent = Intent(Intent.ACTION_VIEW).apply {
|
||||||
|
setDataAndType(uri, "application/pdf")
|
||||||
|
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) // Important !
|
||||||
|
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
withContext(Dispatchers.Main) {
|
||||||
|
Toast.makeText(context.applicationContext, "Fichier sauvegardé avec succès", Toast.LENGTH_LONG).show()
|
||||||
|
}
|
||||||
|
context.startActivity(intent)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
withContext(Dispatchers.Main) {
|
||||||
|
Toast.makeText(context.applicationContext, "Aucun lecteur PDF trouvé", Toast.LENGTH_SHORT).show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,19 +1,26 @@
|
||||||
package mg.dot.feufaro
|
package mg.dot.feufaro
|
||||||
|
|
||||||
|
import android.Manifest
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.view.WindowManager
|
||||||
import androidx.activity.ComponentActivity
|
import androidx.activity.ComponentActivity
|
||||||
import androidx.activity.compose.setContent
|
import androidx.activity.compose.setContent
|
||||||
import androidx.activity.enableEdgeToEdge
|
import androidx.activity.enableEdgeToEdge
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
|
import androidx.core.app.ActivityCompat
|
||||||
import androidx.core.view.WindowCompat
|
import androidx.core.view.WindowCompat
|
||||||
import android.view.WindowManager
|
|
||||||
import androidx.core.view.WindowInsetsCompat
|
import androidx.core.view.WindowInsetsCompat
|
||||||
import androidx.core.view.WindowInsetsControllerCompat
|
import androidx.core.view.WindowInsetsControllerCompat
|
||||||
import org.koin.androidx.compose.KoinAndroidContext
|
import org.koin.androidx.compose.KoinAndroidContext
|
||||||
|
|
||||||
class MainActivity : ComponentActivity() {
|
class MainActivity : ComponentActivity() {
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
ActivityCompat.requestPermissions(
|
||||||
|
this,
|
||||||
|
arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE),
|
||||||
|
1
|
||||||
|
)
|
||||||
enableEdgeToEdge()
|
enableEdgeToEdge()
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
setFilePickerActivity(this)
|
setFilePickerActivity(this)
|
||||||
|
|
|
||||||
1041
composeApp/src/androidMain/kotlin/mg/dot/feufaro/pdf/PdfExport.kt
Normal file
1041
composeApp/src/androidMain/kotlin/mg/dot/feufaro/pdf/PdfExport.kt
Normal file
File diff suppressed because it is too large
Load diff
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -15,8 +15,10 @@ interface FileRepository {
|
||||||
suspend fun getOutputStream(filePath: String): OutputStream
|
suspend fun getOutputStream(filePath: String): OutputStream
|
||||||
//Lire le dernier dossier d'importation
|
//Lire le dernier dossier d'importation
|
||||||
suspend fun saveFile(filePath: String, data: ByteArray)
|
suspend fun saveFile(filePath: String, data: ByteArray)
|
||||||
|
suspend fun saveLocalFile(filePath: String, data: ByteArray)
|
||||||
fun getFileName(shortName: String) : String
|
fun getFileName(shortName: String) : String
|
||||||
// suspend fun readFileBytes(filePath: String): ByteArray
|
// suspend fun readFileBytes(filePath: String): ByteArray
|
||||||
|
fun pickSavePath(defaultName: String): String?
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is just a regular class that implements the common 'FileRepository' interface.
|
// This is just a regular class that implements the common 'FileRepository' interface.
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ val commonModule = module {
|
||||||
single { SharedScreenModel(fileRepository = get()) }
|
single { SharedScreenModel(fileRepository = get()) }
|
||||||
|
|
||||||
single { Solfa(get(), get()) }
|
single { Solfa(get(), get()) }
|
||||||
single { SolfaScreenModel(get()) }
|
single { SolfaScreenModel(get(), get()) }
|
||||||
single { MusicXML(get()) }
|
single { MusicXML(get()) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
package mg.dot.feufaro.pdf
|
||||||
|
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import mg.dot.feufaro.FileRepository
|
||||||
|
import mg.dot.feufaro.data.GridTUOData
|
||||||
|
|
||||||
|
expect fun rememberPdfExportAction(
|
||||||
|
scope: CoroutineScope,
|
||||||
|
fileRepository: FileRepository,
|
||||||
|
gridData: GridTUOData,
|
||||||
|
songTitle: String,
|
||||||
|
measure: String,
|
||||||
|
stanza: Int,
|
||||||
|
nbStanza: Int,
|
||||||
|
songKey: String,
|
||||||
|
songAut: String,
|
||||||
|
songComp: String,
|
||||||
|
songRythm: String
|
||||||
|
): () -> Unit
|
||||||
|
|
@ -746,6 +746,15 @@ class Solfa(val sharedScreenModel: SharedScreenModel, private val fileRepository
|
||||||
val override = O.getOrElse(overrideNumber) { null }
|
val override = O.getOrElse(overrideNumber) { null }
|
||||||
override?.forEachIndexed { index, value ->
|
override?.forEachIndexed { index, value ->
|
||||||
val matchResult = Regex("v(\\d+):(.*)").find(value)
|
val matchResult = Regex("v(\\d+):(.*)").find(value)
|
||||||
|
// 1. Extraire le numéro de voix (ex: "2")
|
||||||
|
val voiceNum = matchResult?.groupValues?.get(1) ?: ""
|
||||||
|
val prefix = if (voiceNum.isNotEmpty()) {
|
||||||
|
// .map transforme chaque caractère '3', '4' en "3.", "4."
|
||||||
|
// .joinToString("") les colle ensemble -> "3.4."
|
||||||
|
voiceNum.map { "$it." }.joinToString("")
|
||||||
|
} else {
|
||||||
|
""
|
||||||
|
}
|
||||||
val overrideString = when (smartLyricsType) {
|
val overrideString = when (smartLyricsType) {
|
||||||
"E" -> smartELyrics(matchResult?.groupValues[2] ?: value)
|
"E" -> smartELyrics(matchResult?.groupValues[2] ?: value)
|
||||||
"Y" -> smartYLyrics(matchResult?.groupValues[2] ?: value)
|
"Y" -> smartYLyrics(matchResult?.groupValues[2] ?: value)
|
||||||
|
|
@ -753,7 +762,11 @@ class Solfa(val sharedScreenModel: SharedScreenModel, private val fileRepository
|
||||||
}
|
}
|
||||||
for (iN in (1..9)) {
|
for (iN in (1..9)) {
|
||||||
if (matchResult?.groupValues[1]?.contains(iN.digitToChar()) ?: false) {
|
if (matchResult?.groupValues[1]?.contains(iN.digitToChar()) ?: false) {
|
||||||
val overrideSyllabus = overrideString.split(Regex("[_/]")).iterator()
|
val overrideSyllabus = overrideString.split(Regex("[_/]"))
|
||||||
|
.map { syllable ->
|
||||||
|
if (syllable.isNotBlank()) "$prefix$syllable" else syllable
|
||||||
|
}
|
||||||
|
.iterator()
|
||||||
overrideIterator[iN] = overrideSyllabus
|
overrideIterator[iN] = overrideSyllabus
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -755,6 +755,12 @@ fun LazyVerticalGridTUO(
|
||||||
horizontalArrangement = Arrangement.Start
|
horizontalArrangement = Arrangement.Start
|
||||||
) {
|
) {
|
||||||
val columnWidthDp = gridWidthDp / gridColumnCount
|
val columnWidthDp = gridWidthDp / gridColumnCount
|
||||||
|
val REGEX_CLEAN_PREFIX = Regex("(\\d+\\.)+")
|
||||||
|
val cleanAllTemps = allTemps.map { column ->
|
||||||
|
column.map { syllable ->
|
||||||
|
syllable.replace(REGEX_CLEAN_PREFIX, "").trim()
|
||||||
|
}
|
||||||
|
}
|
||||||
allTemps.forEachIndexed { syls_i, syllables ->
|
allTemps.forEachIndexed { syls_i, syllables ->
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
|
|
@ -763,7 +769,9 @@ fun LazyVerticalGridTUO(
|
||||||
val noteWidth = columnWidthDp
|
val noteWidth = columnWidthDp
|
||||||
val density = LocalDensity.current
|
val density = LocalDensity.current
|
||||||
syllables.joinToString { " " }
|
syllables.joinToString { " " }
|
||||||
syllables.mapIndexed { index, syl ->
|
|
||||||
|
val cleanSyllables = cleanAllTemps[syls_i]
|
||||||
|
cleanSyllables.forEachIndexed { index, syl ->
|
||||||
var textWidth by remember { mutableStateOf(0.dp) }
|
var textWidth by remember { mutableStateOf(0.dp) }
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -777,7 +785,7 @@ fun LazyVerticalGridTUO(
|
||||||
val isTooLong = textWidthDp > containerWidthDp
|
val isTooLong = textWidthDp > containerWidthDp
|
||||||
|
|
||||||
val spacer = makeSpaceBetweenSyllables(textMeasurer, columnWidthDp)
|
val spacer = makeSpaceBetweenSyllables(textMeasurer, columnWidthDp)
|
||||||
val (dynamicSpaceSyl, alignmentText) = spacer(syl, allTemps, syls_i, index)
|
val (dynamicSpaceSyl, alignmentText) = spacer(syl, cleanAllTemps, syls_i, index)
|
||||||
Text(
|
Text(
|
||||||
text = dynamicSpaceSyl,
|
text = dynamicSpaceSyl,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
|
|
|
||||||
|
|
@ -22,9 +22,11 @@ import androidx.compose.ui.text.font.FontWeight
|
||||||
import androidx.compose.ui.text.style.TextOverflow
|
import androidx.compose.ui.text.style.TextOverflow
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.unit.sp
|
import androidx.compose.ui.unit.sp
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import mg.dot.feufaro.data.getDrawerItems
|
import mg.dot.feufaro.data.getDrawerItems
|
||||||
|
import mg.dot.feufaro.pdf.rememberPdfExportAction
|
||||||
import mg.dot.feufaro.solfa.Solfa
|
import mg.dot.feufaro.solfa.Solfa
|
||||||
import mg.dot.feufaro.viewmodel.SolfaScreenModel
|
import mg.dot.feufaro.viewmodel.SolfaScreenModel
|
||||||
|
|
||||||
|
|
@ -47,6 +49,11 @@ fun MainScreenWithDrawer(
|
||||||
val filteredSongs by sharedScreenModel.filteredSongs.collectAsState()
|
val filteredSongs by sharedScreenModel.filteredSongs.collectAsState()
|
||||||
val songKey = sharedScreenModel.songKey.collectAsState().value
|
val songKey = sharedScreenModel.songKey.collectAsState().value
|
||||||
val measure = sharedScreenModel.measure.collectAsState().value
|
val measure = sharedScreenModel.measure.collectAsState().value
|
||||||
|
val stanza = sharedScreenModel.stanza.collectAsState().value
|
||||||
|
val nbStanzas = sharedScreenModel.nbStanzas.collectAsState().value
|
||||||
|
val songAuthor = sharedScreenModel.songAuthor.collectAsState().value
|
||||||
|
val songComposer = sharedScreenModel.songComposer.collectAsState().value
|
||||||
|
val songRhythm = sharedScreenModel.songRhythm.collectAsState().value
|
||||||
|
|
||||||
val scrollState = rememberScrollState()
|
val scrollState = rememberScrollState()
|
||||||
val currentActivePath = Solfa.currentFile
|
val currentActivePath = Solfa.currentFile
|
||||||
|
|
@ -103,6 +110,20 @@ LaunchedEffect(isPlay, isPos) {
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}, content = {
|
}, content = {
|
||||||
|
val scope = rememberCoroutineScope()
|
||||||
|
val pdfExportAction: () -> Unit = rememberPdfExportAction(
|
||||||
|
scope = scope,
|
||||||
|
fileRepository = solfaScreenModel.fileRepository,
|
||||||
|
gridData = sharedScreenModel.currentGridData,
|
||||||
|
songTitle = songTitle,
|
||||||
|
measure = measure,
|
||||||
|
stanza = stanza,
|
||||||
|
nbStanza = nbStanzas,
|
||||||
|
songKey = songKey,
|
||||||
|
songAut = songAuthor,
|
||||||
|
songComp = songComposer,
|
||||||
|
songRythm = songRhythm
|
||||||
|
)
|
||||||
Scaffold(contentWindowInsets = WindowInsets(0, 0, 0, 0), topBar = {
|
Scaffold(contentWindowInsets = WindowInsets(0, 0, 0, 0), topBar = {
|
||||||
TopAppBar(
|
TopAppBar(
|
||||||
modifier = Modifier.height(55.dp).windowInsetsPadding(WindowInsets.statusBars), title = {
|
modifier = Modifier.height(55.dp).windowInsetsPadding(WindowInsets.statusBars), title = {
|
||||||
|
|
@ -176,7 +197,9 @@ LaunchedEffect(isPlay, isPos) {
|
||||||
exit = fadeOut() + scaleOut() + slideOutVertically { it / 2 }
|
exit = fadeOut() + scaleOut() + slideOutVertically { it / 2 }
|
||||||
) {
|
) {
|
||||||
FloatingActionButton(
|
FloatingActionButton(
|
||||||
onClick = {}, modifier = Modifier.alpha(0.45f)
|
onClick = {
|
||||||
|
pdfExportAction()
|
||||||
|
}, modifier = Modifier.alpha(0.45f)
|
||||||
) {
|
) {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = Icons.Filled.Print,
|
imageVector = Icons.Filled.Print,
|
||||||
|
|
@ -243,12 +266,12 @@ LaunchedEffect(isPlay, isPos) {
|
||||||
delay(100)
|
delay(100)
|
||||||
sharedScreenModel.setDragging(false)
|
sharedScreenModel.setDragging(false)
|
||||||
}
|
}
|
||||||
println("DrawerUI:335: mihetsika $newPos")
|
//println("DrawerUI:335: mihetsika $newPos")
|
||||||
},
|
},
|
||||||
mediaPlayer = player,
|
mediaPlayer = player,
|
||||||
onVolumeChange = { newVolume ->
|
onVolumeChange = { newVolume ->
|
||||||
sharedScreenModel.setVolume(newVolume)
|
sharedScreenModel.setVolume(newVolume)
|
||||||
println("Changement volume $newVolume -l $volumelevel")
|
// println("Changement volume $newVolume -l $volumelevel")
|
||||||
},
|
},
|
||||||
onVoiceVolumeChange = { index, volume ->
|
onVoiceVolumeChange = { index, volume ->
|
||||||
player?.updateVoiceVolume(index, volume)
|
player?.updateVoiceVolume(index, volume)
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ import kotlinx.coroutines.flow.mapLatest
|
||||||
import kotlinx.coroutines.flow.stateIn
|
import kotlinx.coroutines.flow.stateIn
|
||||||
import mg.dot.feufaro.FileRepository
|
import mg.dot.feufaro.FileRepository
|
||||||
import mg.dot.feufaro.data.DrawerItem
|
import mg.dot.feufaro.data.DrawerItem
|
||||||
|
import mg.dot.feufaro.data.GridTUOData
|
||||||
import mg.dot.feufaro.data.getDrawerItems
|
import mg.dot.feufaro.data.getDrawerItems
|
||||||
import mg.dot.feufaro.solfa.TimeUnitObject
|
import mg.dot.feufaro.solfa.TimeUnitObject
|
||||||
import mg.dot.feufaro.midi.FMediaPlayer
|
import mg.dot.feufaro.midi.FMediaPlayer
|
||||||
|
|
@ -163,6 +164,12 @@ class SharedScreenModel(private val fileRepository: FileRepository) : ScreenMode
|
||||||
private val _activeIndex = MutableStateFlow(-1)
|
private val _activeIndex = MutableStateFlow(-1)
|
||||||
val activeIndex: StateFlow<Int> = _activeIndex.asStateFlow()
|
val activeIndex: StateFlow<Int> = _activeIndex.asStateFlow()
|
||||||
|
|
||||||
|
val currentGridData: GridTUOData
|
||||||
|
get() = GridTUOData(
|
||||||
|
tuoList = _tuoList.value,
|
||||||
|
measure = _measure.value,
|
||||||
|
stanza = _stanza.value
|
||||||
|
)
|
||||||
fun updateActiveIndex(currentPosMs: Long) {
|
fun updateActiveIndex(currentPosMs: Long) {
|
||||||
val currentPosMicros = currentPosMs * 1000
|
val currentPosMicros = currentPosMs * 1000
|
||||||
val index = _tuoTimestamps.value.indexOfLast { it <= currentPosMicros }
|
val index = _tuoTimestamps.value.indexOfLast { it <= currentPosMicros }
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,11 @@
|
||||||
package mg.dot.feufaro.viewmodel
|
package mg.dot.feufaro.viewmodel
|
||||||
|
|
||||||
import cafe.adriel.voyager.core.model.ScreenModel
|
import cafe.adriel.voyager.core.model.ScreenModel
|
||||||
|
import mg.dot.feufaro.FileRepository
|
||||||
import mg.dot.feufaro.solfa.Solfa
|
import mg.dot.feufaro.solfa.Solfa
|
||||||
|
|
||||||
class SolfaScreenModel(
|
class SolfaScreenModel(
|
||||||
|
val fileRepository: FileRepository,
|
||||||
private val solfa: Solfa
|
private val solfa: Solfa
|
||||||
) : ScreenModel {
|
) : ScreenModel {
|
||||||
init {}
|
init {}
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,8 @@ import feufaro.composeapp.generated.resources.Res
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import mg.dot.feufaro.FileRepository
|
import mg.dot.feufaro.FileRepository
|
||||||
|
import java.awt.FileDialog
|
||||||
|
import java.awt.Frame
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.FileOutputStream
|
import java.io.FileOutputStream
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
|
|
@ -46,9 +48,29 @@ class DesktopFileRepository : FileRepository { // IMPORTS AND IMPLEMENTS THE com
|
||||||
val file = File("$userHome/$filePath")
|
val file = File("$userHome/$filePath")
|
||||||
file.writeBytes(data) // Extension Kotlin très efficace
|
file.writeBytes(data) // Extension Kotlin très efficace
|
||||||
}
|
}
|
||||||
|
override suspend fun saveLocalFile(filePath: String, data: ByteArray) {
|
||||||
|
val file = if (filePath.startsWith("/")) {
|
||||||
|
File(filePath) // chemin absolu → utilisé directement
|
||||||
|
} else {
|
||||||
|
File(System.getProperty("user.home"), filePath) // chemin relatif → préfixé
|
||||||
|
}
|
||||||
|
file.parentFile?.mkdirs() // crée les dossiers parents si nécessaire
|
||||||
|
file.writeBytes(data) // Extension Kotlin très efficace
|
||||||
|
}
|
||||||
|
|
||||||
override fun getFileName(shortName: String): String {
|
override fun getFileName(shortName: String): String {
|
||||||
val userHome = System.getProperty("user.home")
|
val userHome = System.getProperty("user.home")
|
||||||
return "$userHome/$shortName"
|
return "$userHome/$shortName"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun pickSavePath(defaultName: String): String? {
|
||||||
|
val dialog = FileDialog(null as Frame?, "Exporter en PDF", FileDialog.SAVE)
|
||||||
|
dialog.directory = System.getProperty("user.home")
|
||||||
|
dialog.file = defaultName
|
||||||
|
dialog.isVisible = true
|
||||||
|
|
||||||
|
return if (dialog.directory != null && dialog.file != null) {
|
||||||
|
File(dialog.directory, dialog.file).absolutePath
|
||||||
|
} else null
|
||||||
|
}
|
||||||
}
|
}
|
||||||
1752
composeApp/src/desktopMain/kotlin/mg/dot/feufaro/pdf/PdfExport.kt
Normal file
1752
composeApp/src/desktopMain/kotlin/mg/dot/feufaro/pdf/PdfExport.kt
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -13,6 +13,7 @@ dependencyResolutionManagement {
|
||||||
repositories {
|
repositories {
|
||||||
google()
|
google()
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
|
maven { url = uri("https://jitpack.io") }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue