Koin navigation
This commit is contained in:
parent
18e7db808a
commit
122d41c9fb
14 changed files with 371 additions and 209 deletions
|
|
@ -53,6 +53,8 @@ kotlin {
|
|||
implementation(libs.koin.compose)
|
||||
implementation(libs.koin.compose.viewmodel)
|
||||
implementation(libs.koin.compose.viewmodel.navigation)
|
||||
implementation(libs.bundles.voyager)
|
||||
implementation(libs.cafe.voyager.koin)
|
||||
|
||||
}
|
||||
commonTest.dependencies {
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ import androidx.activity.compose.setContent
|
|||
import androidx.activity.enableEdgeToEdge
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import org.koin.androidx.compose.koinViewModel
|
||||
import androidx.core.view.WindowCompat
|
||||
import android.view.WindowManager
|
||||
import androidx.core.view.WindowInsetsCompat
|
||||
|
|
@ -21,8 +20,7 @@ class MainActivity : ComponentActivity() {
|
|||
|
||||
|
||||
setContent {
|
||||
val sharedViewModel: SharedViewModel = koinViewModel()
|
||||
App(sharedViewModel = sharedViewModel)
|
||||
App()
|
||||
}
|
||||
}
|
||||
private fun hideSystemBar() {
|
||||
|
|
|
|||
|
|
@ -1,65 +1,36 @@
|
|||
package mg.dot.feufaro
|
||||
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.gestures.detectTapGestures
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.FlowRow
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import SharedScreenModel
|
||||
import androidx.compose.foundation.layout.RowScope
|
||||
import androidx.compose.foundation.layout.WindowInsets
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.safeContentPadding
|
||||
import androidx.compose.foundation.layout.safeDrawing
|
||||
import androidx.compose.foundation.layout.windowInsetsPadding
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.ButtonDefaults
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.input.pointer.pointerInput
|
||||
import androidx.compose.ui.text.font.FontStyle
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.dp
|
||||
import org.jetbrains.compose.resources.painterResource
|
||||
import org.jetbrains.compose.ui.tooling.preview.Preview
|
||||
import mg.dot.feufaro.musicXML.MusicXML
|
||||
|
||||
import feufaro.composeapp.generated.resources.Res
|
||||
import feufaro.composeapp.generated.resources.compose_multiplatform
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import mg.dot.feufaro.solfa.LazyVerticalGridTUO
|
||||
import mg.dot.feufaro.solfa.Solfa
|
||||
import org.koin.compose.koinInject
|
||||
import androidx.compose.ui.geometry.Offset
|
||||
import androidx.compose.ui.unit.IntOffset
|
||||
import androidx.compose.ui.window.Popup
|
||||
import kotlin.math.roundToInt
|
||||
import cafe.adriel.voyager.navigator.CurrentScreen
|
||||
import cafe.adriel.voyager.navigator.Navigator
|
||||
import mg.dot.feufaro.viewmodel.SolfaScreenModel
|
||||
|
||||
@Composable
|
||||
@Preview
|
||||
fun App(sharedViewModel: SharedViewModel = SharedViewModel()
|
||||
) {
|
||||
fun App() {
|
||||
|
||||
Navigator(screen = ScreenSolfa) {
|
||||
CurrentScreen()
|
||||
}
|
||||
val fileRepository = koinInject<FileRepository>()
|
||||
|
||||
val displayConfigManager = koinInject<DisplayConfigManager>()
|
||||
val currentDisplayConfig by displayConfigManager.displayConfig.collectAsState()
|
||||
// Load Configurations
|
||||
val configScope = CoroutineScope(Dispatchers.Default)
|
||||
var showContextualMenu by remember { mutableStateOf(false)}
|
||||
var menuPosition by remember { mutableStateOf(Offset.Zero)}
|
||||
val sharedScreenModel = koinInject<SharedScreenModel>()
|
||||
val solfaScreenModel = koinInject<SolfaScreenModel>()
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
configScope.launch {
|
||||
|
|
@ -70,12 +41,12 @@ fun App(sharedViewModel: SharedViewModel = SharedViewModel()
|
|||
}
|
||||
}
|
||||
}
|
||||
val solfa = Solfa(sharedViewModel, fileRepository)
|
||||
|
||||
LaunchedEffect(currentDisplayConfig) {
|
||||
if (currentDisplayConfig.playlist.isNotEmpty()) {
|
||||
try {
|
||||
sharedViewModel.setPlaylist(currentDisplayConfig.playlist)
|
||||
solfa.loadNextInPlaylist()
|
||||
sharedScreenModel.setPlaylist(currentDisplayConfig.playlist)
|
||||
solfaScreenModel.loadNextInPlaylist()
|
||||
} catch (e: Exception) {
|
||||
println("Error loading playlist : ${e.message}")
|
||||
}
|
||||
|
|
@ -83,115 +54,8 @@ fun App(sharedViewModel: SharedViewModel = SharedViewModel()
|
|||
}
|
||||
|
||||
val musicXML = MusicXML(fileRepository)
|
||||
// Start App
|
||||
//solfa.parse()
|
||||
MaterialTheme {
|
||||
MaterialTheme {
|
||||
var showContent by remember { mutableStateOf(false) }
|
||||
var gridWidthPx by remember { mutableStateOf(0) }
|
||||
Column(
|
||||
Modifier.fillMaxSize()
|
||||
.pointerInput(Unit) {
|
||||
detectTapGestures(
|
||||
onDoubleTap = {
|
||||
offset ->
|
||||
menuPosition = offset
|
||||
showContextualMenu = true
|
||||
}
|
||||
)
|
||||
},
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
) {
|
||||
if (showContextualMenu) {
|
||||
Popup(
|
||||
alignment = Alignment.TopStart,
|
||||
offset = IntOffset(menuPosition.x.roundToInt(),
|
||||
menuPosition.y.roundToInt()),
|
||||
onDismissRequest = {
|
||||
showContextualMenu = false
|
||||
}
|
||||
) {
|
||||
ContextualMenu(onMenuItemClick = { item ->
|
||||
println("Clicked: $item")
|
||||
showContextualMenu = false
|
||||
})
|
||||
}
|
||||
}
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.weight(1f)
|
||||
.verticalScroll(rememberScrollState())
|
||||
) {
|
||||
val stanza: Int by sharedViewModel.stanza.collectAsState()
|
||||
FlowRow(
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
.windowInsetsPadding(WindowInsets.safeDrawing)
|
||||
.padding(start = 8.dp, end = 8.dp, top = 8.dp),
|
||||
horizontalArrangement = Arrangement.spacedBy(16.dp),
|
||||
verticalArrangement = Arrangement.spacedBy(4.dp)
|
||||
) {
|
||||
val measureString: String by sharedViewModel.measure.collectAsState()
|
||||
val songTitle: String by sharedViewModel.songTitle.collectAsState()
|
||||
val songKey: String by sharedViewModel.songKey.collectAsState()
|
||||
Text(text = songTitle, fontWeight = FontWeight.Bold)
|
||||
Text(
|
||||
text = songKey,
|
||||
modifier = Modifier.background(Color(0xff, 0xea, 0xe7))
|
||||
.padding(horizontal = 4.dp)
|
||||
)
|
||||
Text(text = measureString)
|
||||
Text(text = "Stanza: $stanza")
|
||||
val songAuthor: String by sharedViewModel.songAuthor.collectAsState()
|
||||
val songComposer: String by sharedViewModel.songComposer.collectAsState()
|
||||
val songRhythm: String by sharedViewModel.songRhythm.collectAsState()
|
||||
val nbStanzas: Int by sharedViewModel.nbStanzas.collectAsState()
|
||||
Text(text = songAuthor, fontStyle = FontStyle.Italic)
|
||||
Text(text = songRhythm)
|
||||
Text(text = songComposer)
|
||||
Row() {
|
||||
for (i in 1..nbStanzas) {
|
||||
MGButton(
|
||||
enabled = (i != stanza.toInt()),
|
||||
onClick = {
|
||||
sharedViewModel.setStanza(i.toString())
|
||||
},
|
||||
modifier = Modifier.padding(horizontal = 4.dp)
|
||||
) {
|
||||
Text("$i")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
LazyVerticalGridTUO(
|
||||
sharedViewModel,
|
||||
gridWidthPx = gridWidthPx,
|
||||
onGridWidthMeasured = { width -> gridWidthPx = width }
|
||||
)
|
||||
MGButton(onClick = {
|
||||
//showContent = !showContent
|
||||
|
||||
solfa.loadNextInPlaylist()
|
||||
}, modifier = Modifier.height(40.dp)) {
|
||||
val debugData: String by sharedViewModel.data.collectAsState()
|
||||
Text(debugData)
|
||||
}
|
||||
AnimatedVisibility(showContent) {
|
||||
val greeting = remember { Greeting().greet() }
|
||||
Column(
|
||||
Modifier.fillMaxWidth().height(180.dp),
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
Image(painterResource(Res.drawable.compose_multiplatform), null)
|
||||
Text("Compose: $greeting")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fun String?.toColor(foreGround: Boolean = false): Color {
|
||||
val defaultColor = if (foreGround) {
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import androidx.compose.foundation.layout.Column
|
|||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.automirrored.filled.List
|
||||
import androidx.compose.material.icons.filled.Add
|
||||
import androidx.compose.material.icons.filled.Delete
|
||||
import androidx.compose.material.icons.filled.Edit
|
||||
|
|
@ -26,7 +27,7 @@ fun ContextualMenu (onMenuItemClick: (String) -> Unit){
|
|||
) {
|
||||
MenuItem(icon = Icons.Default.Add, text = "+") { onMenuItemClick("Ajouter")}
|
||||
MenuItem(icon = Icons.Default.Edit, text = "!") { onMenuItemClick("Modifier")}
|
||||
MenuItem(icon = Icons.Default.List, text = "-") { onMenuItemClick("Liste")}
|
||||
MenuItem(icon = Icons.AutoMirrored.Filled.List, text = "-") { onMenuItemClick("Liste")}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
156
composeApp/src/commonMain/kotlin/mg/dot/feufaro/ScreenSolfa.kt
Normal file
156
composeApp/src/commonMain/kotlin/mg/dot/feufaro/ScreenSolfa.kt
Normal file
|
|
@ -0,0 +1,156 @@
|
|||
package mg.dot.feufaro
|
||||
|
||||
import SharedScreenModel
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.gestures.detectTapGestures
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.FlowRow
|
||||
import androidx.compose.foundation.layout.WindowInsets
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.safeDrawing
|
||||
import androidx.compose.foundation.layout.windowInsetsPadding
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.geometry.Offset
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.input.pointer.pointerInput
|
||||
import androidx.compose.ui.text.font.FontStyle
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
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 kotlin.math.roundToInt
|
||||
import cafe.adriel.voyager.core.screen.Screen
|
||||
import cafe.adriel.voyager.koin.koinScreenModel
|
||||
import mg.dot.feufaro.data.GridTUOData
|
||||
import mg.dot.feufaro.viewmodel.SolfaScreenModel
|
||||
import java.io.ObjectStreamException
|
||||
|
||||
object ScreenSolfa : Screen {
|
||||
@Composable
|
||||
override fun Content() {
|
||||
val solfaScreenModel = koinScreenModel<SolfaScreenModel>()
|
||||
var menuPosition by remember { mutableStateOf(Offset.Zero)}
|
||||
var showContextualMenu by remember { mutableStateOf(false)}
|
||||
var gridWidthPx by remember { mutableStateOf(0) }
|
||||
val sharedScreenModel = koinScreenModel<SharedScreenModel>()
|
||||
val tuoList by sharedScreenModel.tuoList.collectAsState()
|
||||
val measure by sharedScreenModel.measure.collectAsState()
|
||||
val stanza by sharedScreenModel.stanza.collectAsState()
|
||||
val gridTUOData = GridTUOData(measure, tuoList, stanza)
|
||||
Column(
|
||||
Modifier.fillMaxSize()
|
||||
.pointerInput(Unit) {
|
||||
detectTapGestures(
|
||||
onDoubleTap = {
|
||||
offset ->
|
||||
menuPosition = offset
|
||||
showContextualMenu = true
|
||||
}
|
||||
)
|
||||
},
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
) {
|
||||
if (showContextualMenu) {
|
||||
Popup(
|
||||
alignment = Alignment.TopStart,
|
||||
offset = IntOffset(menuPosition.x.roundToInt(),
|
||||
menuPosition.y.roundToInt()),
|
||||
onDismissRequest = {
|
||||
showContextualMenu = false
|
||||
}
|
||||
) {
|
||||
ContextualMenu(onMenuItemClick = { item ->
|
||||
println("Clicked: $item")
|
||||
showContextualMenu = false
|
||||
})
|
||||
}
|
||||
}
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.weight(1f)
|
||||
.verticalScroll(rememberScrollState())
|
||||
) {
|
||||
val stanza: Int by sharedScreenModel.stanza.collectAsState()
|
||||
FlowRow(
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
.windowInsetsPadding(WindowInsets.safeDrawing)
|
||||
.padding(start = 8.dp, end = 8.dp, top = 8.dp),
|
||||
horizontalArrangement = Arrangement.spacedBy(16.dp),
|
||||
verticalArrangement = Arrangement.spacedBy(4.dp)
|
||||
) {
|
||||
val measureString: String by sharedScreenModel.measure.collectAsState()
|
||||
val songTitle: String by sharedScreenModel.songTitle.collectAsState()
|
||||
val songKey: String by sharedScreenModel.songKey.collectAsState()
|
||||
Text(text = songTitle, fontWeight = FontWeight.Bold)
|
||||
Text(
|
||||
text = songKey,
|
||||
modifier = Modifier.background(Color(0xff, 0xea, 0xe7))
|
||||
.padding(horizontal = 4.dp)
|
||||
)
|
||||
Text(text = measureString)
|
||||
}
|
||||
LazyVerticalGridTUO(
|
||||
gridTUOData,
|
||||
gridWidthPx = gridWidthPx,
|
||||
onGridWidthMeasured = { width -> gridWidthPx = width }
|
||||
)
|
||||
MGButton(onClick = {
|
||||
//showContent = !showContent
|
||||
|
||||
solfaScreenModel.loadNextInPlaylist()
|
||||
}, modifier = Modifier.height(40.dp)) {
|
||||
val debugData: String by sharedScreenModel.data.collectAsState()
|
||||
Text(debugData)
|
||||
}
|
||||
FlowRow(
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
.windowInsetsPadding(WindowInsets.safeDrawing)
|
||||
.padding(start = 8.dp, end = 8.dp, top = 8.dp),
|
||||
horizontalArrangement = Arrangement.spacedBy(16.dp),
|
||||
verticalArrangement = Arrangement.spacedBy(4.dp)
|
||||
) {
|
||||
val nbStanzas: Int by sharedScreenModel.nbStanzas.collectAsState()
|
||||
for (i in 1..nbStanzas) {
|
||||
MGButton(
|
||||
enabled = (i != stanza.toInt()),
|
||||
onClick = {
|
||||
sharedScreenModel.setStanza(i.toString())
|
||||
},
|
||||
modifier = Modifier.padding(horizontal = 4.dp)
|
||||
) {
|
||||
Text("$i")
|
||||
}
|
||||
}
|
||||
Text(text = "Stanza: $stanza")
|
||||
val songAuthor: String by sharedScreenModel.songAuthor.collectAsState()
|
||||
val songComposer: String by sharedScreenModel.songComposer.collectAsState()
|
||||
val songRhythm: String by sharedScreenModel.songRhythm.collectAsState()
|
||||
Text(text = songAuthor, fontStyle = FontStyle.Italic)
|
||||
Text(text = songRhythm)
|
||||
Text(text = songComposer)
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@Throws(ObjectStreamException::class) // C'est une méthode de sérialisation Java, donc l'exception est nécessaire
|
||||
private fun readResolve(): Any {
|
||||
return this // Toujours retourner l'instance unique de ce singleton
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,83 @@
|
|||
// commonMain/kotlin/mg.dot.feufaro/SongNumberInput.kt
|
||||
package mg.dot.feufaro
|
||||
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.text.KeyboardOptions
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.OutlinedTextField
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.text.input.KeyboardType
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
||||
@Composable
|
||||
fun SongNumberInput(
|
||||
// Callback appelé lorsque le numéro de chant est validé
|
||||
onSongNumberConfirmed: (Int) -> Unit
|
||||
) {
|
||||
// État local pour le texte saisi par l'utilisateur
|
||||
var songNumberText by remember { mutableStateOf("") }
|
||||
// État local pour afficher un message d'erreur
|
||||
var errorMessage by remember { mutableStateOf<String?>(null) }
|
||||
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(16.dp)
|
||||
) {
|
||||
// Champ de texte pour la saisie du numéro de chant
|
||||
OutlinedTextField(
|
||||
value = songNumberText,
|
||||
onValueChange = { newValue ->
|
||||
// N'accepte que les chiffres
|
||||
val filteredValue = newValue.filter { it.isDigit() }
|
||||
// Limite la saisie à 3 chiffres
|
||||
if (filteredValue.length <= 3) {
|
||||
songNumberText = filteredValue
|
||||
errorMessage = null // Réinitialise l'erreur si la saisie redevient valide
|
||||
}
|
||||
},
|
||||
label = { Text("Numéro du chant") },
|
||||
placeholder = { Text("Ex: 123") },
|
||||
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number), // Affiche un clavier numérique
|
||||
isError = errorMessage != null, // Indique visuellement une erreur
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
)
|
||||
|
||||
// Affichage du message d'erreur si présent
|
||||
errorMessage?.let {
|
||||
Text(
|
||||
text = it,
|
||||
color = MaterialTheme.colorScheme.error,
|
||||
style = MaterialTheme.typography.bodySmall,
|
||||
modifier = Modifier.padding(top = 4.dp)
|
||||
)
|
||||
}
|
||||
|
||||
// Bouton de confirmation
|
||||
Button(
|
||||
onClick = {
|
||||
val number = songNumberText.toIntOrNull()
|
||||
if (number == null) {
|
||||
errorMessage = "Veuillez entrer un nombre valide."
|
||||
} else if (songNumberText.length != 3) {
|
||||
errorMessage = "Le numéro doit avoir 3 chiffres."
|
||||
} else if (number < 1 || number > 999) { // Exemple de plage valide si besoin
|
||||
errorMessage = "Le numéro doit être entre 001 et 999."
|
||||
} else {
|
||||
errorMessage = null
|
||||
onSongNumberConfirmed(number) // Appelle le callback avec le numéro validé
|
||||
}
|
||||
},
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(top = 16.dp)
|
||||
) {
|
||||
Text("Confirmer")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
package mg.dot.feufaro.data
|
||||
|
||||
import mg.dot.feufaro.solfa.TimeUnitObject
|
||||
|
||||
data class GridTUOData (
|
||||
val measure: String,
|
||||
val tuoList: List<TimeUnitObject>,
|
||||
val stanza: Int
|
||||
)
|
||||
|
|
@ -1,11 +1,14 @@
|
|||
package mg.dot.feufaro.di
|
||||
|
||||
import PlaylistRepository
|
||||
import SharedScreenModel
|
||||
import mg.dot.feufaro.CommonFileRepository
|
||||
import mg.dot.feufaro.FileRepository
|
||||
import mg.dot.feufaro.SharedViewModel
|
||||
import mg.dot.feufaro.DisplayConfigManager // Importez DisplayConfigManager
|
||||
import mg.dot.feufaro.config.AppConfig
|
||||
import mg.dot.feufaro.musicXML.MusicXML
|
||||
import mg.dot.feufaro.solfa.Solfa
|
||||
import mg.dot.feufaro.viewmodel.SolfaScreenModel
|
||||
import org.koin.dsl.module
|
||||
import org.koin.core.module.dsl.singleOf
|
||||
import org.koin.core.module.Module
|
||||
|
|
@ -18,5 +21,9 @@ val commonModule = module {
|
|||
singleOf(::MusicXML)
|
||||
single<FileRepository> { CommonFileRepository() }
|
||||
single { DisplayConfigManager(fileRepository = get())}
|
||||
viewModel { SharedViewModel() }
|
||||
single { SharedScreenModel(get()) }
|
||||
//viewModel { SharedViewModel() }
|
||||
single { PlaylistRepository() }
|
||||
single { Solfa(get(), get()) }
|
||||
single { SolfaScreenModel(get()) }
|
||||
}
|
||||
|
|
@ -1,15 +1,14 @@
|
|||
package mg.dot.feufaro.solfa
|
||||
|
||||
import SharedScreenModel
|
||||
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.CommonTools
|
||||
import mg.dot.feufaro.SharedViewModel
|
||||
//import mg.dot.feufaro.getOpt
|
||||
|
||||
class Solfa(val sharedViewModel: SharedViewModel, private val fileRepository: FileRepository) {
|
||||
class Solfa(val sharedScreenModel: SharedScreenModel, private val fileRepository: FileRepository) {
|
||||
private val T: MutableList<PTemplate> = mutableListOf()
|
||||
private val N: MutableList<POneVoiceNote> = mutableListOf()
|
||||
private val L: MutableList<POneStanzaLyrics> = mutableListOf()
|
||||
|
|
@ -40,13 +39,13 @@ class Solfa(val sharedViewModel: SharedViewModel, private val fileRepository: Fi
|
|||
private val meta: MutableMap<String, String> = mutableMapOf()
|
||||
private val lyricsComment: MutableList<String> = mutableListOf()
|
||||
suspend fun nextTimeUnitObject() {
|
||||
val lastTUO = sharedViewModel.lastTUO()
|
||||
val lastTUO = sharedScreenModel.lastTUO()
|
||||
nextTIndex++
|
||||
if (nextTIndex == 5) {
|
||||
sharedViewModel.doneTUOList()
|
||||
sharedScreenModel.doneTUOList()
|
||||
}
|
||||
if (T.getOrNull(nextTIndex) == null) {
|
||||
sharedViewModel.doneTUOList()
|
||||
sharedScreenModel.doneTUOList()
|
||||
return
|
||||
}
|
||||
val pTemplate = T[nextTIndex]
|
||||
|
|
@ -89,19 +88,19 @@ class Solfa(val sharedViewModel: SharedViewModel, private val fileRepository: Fi
|
|||
}
|
||||
}
|
||||
withContext(Dispatchers.Main) {
|
||||
sharedViewModel.addTUO(unitObject)
|
||||
sharedScreenModel.addTUO(unitObject)
|
||||
}
|
||||
nextTimeUnitObject()
|
||||
}
|
||||
fun loadSolfa() {
|
||||
val sourceFileName: String = sharedViewModel.currentPlayed()
|
||||
sharedViewModel.reset()
|
||||
val sourceFileName: String = sharedScreenModel.currentPlayed()
|
||||
sharedScreenModel.reset()
|
||||
parse(sourceFileName)
|
||||
}
|
||||
fun loadNextInPlaylist() {
|
||||
val playlist = sharedViewModel.playlist.value
|
||||
val playlist = sharedScreenModel.playlist.value
|
||||
if (playlist.isNotEmpty()) {
|
||||
sharedViewModel.playNext()
|
||||
sharedScreenModel.playNext()
|
||||
loadSolfa()
|
||||
}
|
||||
}
|
||||
|
|
@ -123,8 +122,8 @@ class Solfa(val sharedViewModel: SharedViewModel, private val fileRepository: Fi
|
|||
nextNIndex = -1
|
||||
nextLIndex = -1
|
||||
lyricsComment.clear()
|
||||
sharedViewModel.setStanza("1")
|
||||
sharedViewModel.setNbStanzas(0)
|
||||
sharedScreenModel.setStanza("1")
|
||||
sharedScreenModel.setNbStanzas(0)
|
||||
TimeUnitObject.hasMarker(false)
|
||||
lines.forEach { line ->
|
||||
run {
|
||||
|
|
@ -264,11 +263,11 @@ class Solfa(val sharedViewModel: SharedViewModel, private val fileRepository: Fi
|
|||
val metaChunks: List<String> = value.split(REGEX_PARSE_META)
|
||||
metaChunks.forEach { parseMeta(it) }
|
||||
parseMeta(value)
|
||||
sharedViewModel.setMeasure(meta["m"] ?: "")
|
||||
sharedViewModel.setSongTitle(meta["t"] ?: "")
|
||||
sharedViewModel.setSongAuthor(meta["a"] ?: "")
|
||||
sharedViewModel.setSongComposer(meta["h"] ?: "")
|
||||
sharedViewModel.setSongRhythm(meta["r"] ?: "")
|
||||
sharedScreenModel.setMeasure(meta["m"] ?: "")
|
||||
sharedScreenModel.setSongTitle(meta["t"] ?: "")
|
||||
sharedScreenModel.setSongAuthor(meta["a"] ?: "")
|
||||
sharedScreenModel.setSongComposer(meta["h"] ?: "")
|
||||
sharedScreenModel.setSongRhythm(meta["r"] ?: "")
|
||||
} else if (key == "L") {
|
||||
loadL(index, value)
|
||||
} else if (key == "Y") {
|
||||
|
|
@ -383,7 +382,7 @@ class Solfa(val sharedViewModel: SharedViewModel, private val fileRepository: Fi
|
|||
if ("c" == subKey) {
|
||||
val tonality = line.uppercaseFirstMeta()
|
||||
meta["C"] = tonality
|
||||
sharedViewModel.setSongKey(tonality)
|
||||
sharedScreenModel.setSongKey(tonality)
|
||||
val keyOrigin = CommonTools.tonalityToNumber(tonality)
|
||||
val transposeTo = getOpt("transposeto")
|
||||
val transposeAsIf = getOpt("transposeasif")
|
||||
|
|
@ -463,10 +462,10 @@ class Solfa(val sharedViewModel: SharedViewModel, private val fileRepository: Fi
|
|||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
sharedViewModel.appendData("\nErr: $e")
|
||||
sharedScreenModel.appendData("\nErr: $e")
|
||||
}
|
||||
if (stanzaNumber > sharedViewModel.nbStanzas.value) {
|
||||
sharedViewModel.setNbStanzas(stanzaNumber)
|
||||
if (stanzaNumber > sharedScreenModel.nbStanzas.value) {
|
||||
sharedScreenModel.setNbStanzas(stanzaNumber)
|
||||
}
|
||||
}
|
||||
// loadY is a smart lyrics parser for Malagasy language
|
||||
|
|
|
|||
|
|
@ -12,7 +12,6 @@ import androidx.compose.material3.LocalTextStyle
|
|||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
|
|
@ -29,11 +28,9 @@ import androidx.compose.ui.text.rememberTextMeasurer
|
|||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.TextUnit
|
||||
import androidx.compose.ui.unit.sp
|
||||
import mg.dot.feufaro.SharedViewModel
|
||||
import mg.dot.feufaro.data.GridTUOData
|
||||
import kotlin.math.min
|
||||
|
||||
//import androidx.compose.ui.unit.times
|
||||
|
||||
class TimeUnitObject (val pTemplate: PTemplate, val prevTUO: TimeUnitObject?) {
|
||||
var mutableNoteVersion: Int by mutableStateOf(0)
|
||||
private var lyrics: MutableList<POneStanzaLyrics> = mutableListOf()
|
||||
|
|
@ -334,13 +331,13 @@ fun AutoResizingText(
|
|||
}
|
||||
@Composable
|
||||
fun LazyVerticalGridTUO(
|
||||
viewModel: SharedViewModel,
|
||||
viewModel: GridTUOData,
|
||||
gridWidthPx: Int,
|
||||
onGridWidthMeasured: (Int) -> Unit,
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
val regexMeasure = Regex("(\\d)/\\d").find(viewModel.measure.value)
|
||||
val tuoList by viewModel.tuoList.collectAsState()
|
||||
val regexMeasure = Regex("(\\d)/\\d").find(viewModel.measure)
|
||||
val tuoList = viewModel.tuoList
|
||||
|
||||
Column(
|
||||
modifier = Modifier
|
||||
|
|
@ -368,7 +365,7 @@ fun LazyVerticalGridTUO(
|
|||
GridCells.Fixed(calculatedCols.coerceAtLeast(columnGroup))
|
||||
|
||||
}
|
||||
val currentStanza by viewModel.stanza.collectAsState()
|
||||
val currentStanza = viewModel.stanza
|
||||
|
||||
LazyVerticalGrid(
|
||||
columns = actualColumns,
|
||||
|
|
|
|||
|
|
@ -1,38 +1,51 @@
|
|||
package mg.dot.feufaro
|
||||
|
||||
// commonMain/kotlin/mg/dot/feufaro/viewmodel/SharedScreenModel.kt
|
||||
import cafe.adriel.voyager.core.model.ScreenModel
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import com.rickclephas.kmp.observableviewmodel.ViewModel
|
||||
import com.rickclephas.kmp.observableviewmodel.MutableStateFlow
|
||||
import mg.dot.feufaro.solfa.TimeUnitObject
|
||||
|
||||
open class SharedViewModel(): ViewModel() {
|
||||
private val _data = MutableStateFlow<String>(viewModelScope, "Next ...")
|
||||
// Supposons que vous ayez une autre dépendance, par exemple pour gérer les données de la playlist
|
||||
class PlaylistRepository {
|
||||
private val _playlists = MutableStateFlow(listOf("Playlist par défaut 1", "Playlist par défaut 2"))
|
||||
val playlists: StateFlow<List<String>> = _playlists.asStateFlow()
|
||||
|
||||
fun addPlaylist(name: String) {
|
||||
_playlists.value = _playlists.value + name
|
||||
}
|
||||
}
|
||||
|
||||
class SharedScreenModel(
|
||||
private val playlistRepository: PlaylistRepository // Exemple de dépendance partagée
|
||||
) : ScreenModel {
|
||||
private val _data = MutableStateFlow<String>("Next ...")
|
||||
val data: StateFlow<String> = _data.asStateFlow()
|
||||
private val _measure = MutableStateFlow<String>(viewModelScope, "")
|
||||
private val _measure = MutableStateFlow<String>("")
|
||||
val measure: StateFlow<String> = _measure.asStateFlow()
|
||||
private val _songTitle = MutableStateFlow<String>(viewModelScope, "")
|
||||
private val _songTitle = MutableStateFlow<String>("")
|
||||
val songTitle: StateFlow<String> = _songTitle.asStateFlow()
|
||||
private val _stanza = MutableStateFlow<Int>(viewModelScope, 0)
|
||||
private val _stanza = MutableStateFlow<Int>( 0)
|
||||
val stanza: StateFlow<Int> = _stanza.asStateFlow()
|
||||
private val _songKey = MutableStateFlow<String>(viewModelScope, "")
|
||||
private val _songKey = MutableStateFlow<String>("")
|
||||
val songKey: StateFlow<String> = _songKey.asStateFlow()
|
||||
private val _songAuthor = MutableStateFlow<String>(viewModelScope,"")
|
||||
private val _songAuthor = MutableStateFlow<String>("")
|
||||
val songAuthor: StateFlow<String> = _songAuthor.asStateFlow()
|
||||
private val _songComposer = MutableStateFlow<String>(viewModelScope,"")
|
||||
private val _songComposer = MutableStateFlow<String>("")
|
||||
val songComposer: StateFlow<String> = _songComposer.asStateFlow()
|
||||
private val _songRhythm = MutableStateFlow<String>(viewModelScope,"")
|
||||
private val _songRhythm = MutableStateFlow<String>("")
|
||||
val songRhythm: StateFlow<String> = _songRhythm.asStateFlow()
|
||||
private val _nbStanzas = MutableStateFlow<Int>(viewModelScope,0)
|
||||
private val _nbStanzas = MutableStateFlow<Int>(0)
|
||||
val nbStanzas: StateFlow<Int> = _nbStanzas.asStateFlow()
|
||||
private var _tuoList = MutableStateFlow<List<TimeUnitObject>>(viewModelScope, emptyList())
|
||||
private var _tuoList =
|
||||
MutableStateFlow<List<TimeUnitObject>>(emptyList())
|
||||
val tuoList: StateFlow<List<TimeUnitObject>> = _tuoList.asStateFlow()
|
||||
private var _playlist = MutableStateFlow<List<String>>(viewModelScope, emptyList())
|
||||
private var _playlist =
|
||||
MutableStateFlow<List<String>>(emptyList())
|
||||
val playlist: StateFlow<List<String>> = _playlist.asStateFlow()
|
||||
private var _nextPlayed = MutableStateFlow(viewModelScope, -1)
|
||||
private var _nextPlayed = MutableStateFlow(-1)
|
||||
val nextPlayed: StateFlow<Int> = _nextPlayed.asStateFlow()
|
||||
private val tempTimeUnitObjectList = mutableListOf<TimeUnitObject>()
|
||||
var _hasMarker = MutableStateFlow<Boolean>(viewModelScope, false)
|
||||
var _hasMarker = MutableStateFlow<Boolean>( false)
|
||||
val hasMarker: StateFlow<Boolean> = _hasMarker.asStateFlow()
|
||||
|
||||
fun appendData(otherData: String) {
|
||||
|
|
@ -93,4 +106,18 @@ open class SharedViewModel(): ViewModel() {
|
|||
val playlistIndex = _nextPlayed.value
|
||||
return _playlist.value[playlistIndex]
|
||||
}
|
||||
private val _sharedData = MutableStateFlow("Donnée partagée initiale")
|
||||
val sharedData: StateFlow<String> = _sharedData.asStateFlow()
|
||||
|
||||
val playlists: StateFlow<List<String>> = playlistRepository.playlists
|
||||
|
||||
fun updateSharedData(newData: String) {
|
||||
_sharedData.value = newData
|
||||
}
|
||||
|
||||
fun addNewPlaylist(name: String) {
|
||||
playlistRepository.addPlaylist(name)
|
||||
}
|
||||
|
||||
// Vous pouvez ajouter d'autres fonctions pour interagir avec les données partagées
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
package mg.dot.feufaro.viewmodel
|
||||
|
||||
import cafe.adriel.voyager.core.model.ScreenModel
|
||||
import mg.dot.feufaro.solfa.Solfa
|
||||
|
||||
class SolfaScreenModel (
|
||||
private val solfa: Solfa
|
||||
) : ScreenModel{
|
||||
init {}
|
||||
fun loadNextInPlaylist() {
|
||||
solfa.loadNextInPlaylist()
|
||||
}
|
||||
}
|
||||
|
|
@ -25,8 +25,7 @@ fun main() = application {
|
|||
title = "Feufaro",
|
||||
) {
|
||||
KoinContext {
|
||||
val sharedViewModel: SharedViewModel = SharedViewModel()
|
||||
App(sharedViewModel = sharedViewModel)
|
||||
App()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -21,8 +21,10 @@ core = "0.91.1"
|
|||
kmpObservableviewmodelCore = "1.0.0-BETA-3"
|
||||
kotlinxSerializationJson = "1.8.1"
|
||||
material3 = "1.3.2"
|
||||
voyager = "1.1.0-beta03"
|
||||
|
||||
[libraries]
|
||||
cafe-voyager-koin = { module = "cafe.adriel.voyager:voyager-koin" }
|
||||
koin-compose-viewmodel = { module = "io.insert-koin:koin-compose-viewmodel", version.ref = "koin" }
|
||||
koin-compose-viewmodel-navigation = { module = "io.insert-koin:koin-compose-viewmodel-navigation", version.ref = "koin" }
|
||||
kotlin-test = { module = "org.jetbrains.kotlin:kotlin-test", version.ref = "kotlin" }
|
||||
|
|
@ -43,7 +45,6 @@ koin-compose = { module = "io.insert-koin:koin-compose", version.ref = "koin" }
|
|||
koin-core-viewmodel = { module = "io.insert-koin:koin-core-viewmodel", version.ref = "koin" }
|
||||
koin-android = { module = "io.insert-koin:koin-android", version.ref = "koin" }
|
||||
koin-androidx-compose = { module = "io.insert-koin:koin-androidx-compose", version.ref = "koin" }
|
||||
|
||||
core = { module = "io.github.pdvrieze.xmlutil:core", version.ref = "core" }
|
||||
#core-android = { module = "io.github.pdvrieze.xmlutil:core-android", version.ref = "core" }
|
||||
#core-jdk = { module = "io.github.pdvrieze.xmlutil:core-jdk", version.ref = "core" }
|
||||
|
|
@ -51,6 +52,9 @@ serialization = { module = "io.github.pdvrieze.xmlutil:serialization", version.r
|
|||
kmp-observableviewmodel-core = { module = "com.rickclephas.kmp:kmp-observableviewmodel-core", version.ref = "kmpObservableviewmodelCore" }
|
||||
kotlinx-serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "kotlinxSerializationJson" }
|
||||
androidx-material3 = { module = "androidx.compose.material3:material3", version.ref = "material3" }
|
||||
voyager-navigator = { module = "cafe.adriel.voyager:voyager-navigator", version.ref = "voyager" }
|
||||
voyager-screenmodel = { module = "cafe.adriel.voyager:voyager-screenmodel", version.ref = "voyager" }
|
||||
voyager-koin = { module = "cafe.adriel.voyager:voyager-koin", version.ref = "voyager" }
|
||||
|
||||
[plugins]
|
||||
androidApplication = { id = "com.android.application", version.ref = "agp" }
|
||||
|
|
@ -60,3 +64,6 @@ composeMultiplatform = { id = "org.jetbrains.compose", version.ref = "composeMul
|
|||
composeCompiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }
|
||||
kotlinMultiplatform = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "kotlin" }
|
||||
kotlinSerialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin"}
|
||||
|
||||
[bundles]
|
||||
voyager = ["voyager-navigator", "voyager-screenmodel", "voyager-koin"]
|
||||
Loading…
Add table
Reference in a new issue