Koin navigation

This commit is contained in:
dotmg 2025-07-09 13:40:23 +02:00
parent 18e7db808a
commit 122d41c9fb
14 changed files with 371 additions and 209 deletions

View file

@ -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 {

View file

@ -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() {

View file

@ -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,116 +54,9 @@ 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) {
"00FFFFFF"

View file

@ -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")}
}
}

View 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
}
}

View file

@ -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")
}
}
}

View file

@ -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
)

View file

@ -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()) }
}

View file

@ -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

View file

@ -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,

View file

@ -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
}

View file

@ -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()
}
}

View file

@ -25,8 +25,7 @@ fun main() = application {
title = "Feufaro",
) {
KoinContext {
val sharedViewModel: SharedViewModel = SharedViewModel()
App(sharedViewModel = sharedViewModel)
App()
}
}
}

View file

@ -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"]