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)
|
||||||
implementation(libs.koin.compose.viewmodel)
|
implementation(libs.koin.compose.viewmodel)
|
||||||
implementation(libs.koin.compose.viewmodel.navigation)
|
implementation(libs.koin.compose.viewmodel.navigation)
|
||||||
|
implementation(libs.bundles.voyager)
|
||||||
|
implementation(libs.cafe.voyager.koin)
|
||||||
|
|
||||||
}
|
}
|
||||||
commonTest.dependencies {
|
commonTest.dependencies {
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,6 @@ 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 org.koin.androidx.compose.koinViewModel
|
|
||||||
import androidx.core.view.WindowCompat
|
import androidx.core.view.WindowCompat
|
||||||
import android.view.WindowManager
|
import android.view.WindowManager
|
||||||
import androidx.core.view.WindowInsetsCompat
|
import androidx.core.view.WindowInsetsCompat
|
||||||
|
|
@ -21,8 +20,7 @@ class MainActivity : ComponentActivity() {
|
||||||
|
|
||||||
|
|
||||||
setContent {
|
setContent {
|
||||||
val sharedViewModel: SharedViewModel = koinViewModel()
|
App()
|
||||||
App(sharedViewModel = sharedViewModel)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private fun hideSystemBar() {
|
private fun hideSystemBar() {
|
||||||
|
|
|
||||||
|
|
@ -1,65 +1,36 @@
|
||||||
package mg.dot.feufaro
|
package mg.dot.feufaro
|
||||||
|
|
||||||
import androidx.compose.animation.AnimatedVisibility
|
import SharedScreenModel
|
||||||
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 androidx.compose.foundation.layout.RowScope
|
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.Button
|
||||||
import androidx.compose.material3.ButtonDefaults
|
import androidx.compose.material3.ButtonDefaults
|
||||||
import androidx.compose.material3.MaterialTheme
|
|
||||||
import androidx.compose.material3.Text
|
|
||||||
import androidx.compose.runtime.*
|
import androidx.compose.runtime.*
|
||||||
import androidx.compose.ui.Alignment
|
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.graphics.Color
|
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 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.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import mg.dot.feufaro.solfa.LazyVerticalGridTUO
|
|
||||||
import mg.dot.feufaro.solfa.Solfa
|
|
||||||
import org.koin.compose.koinInject
|
import org.koin.compose.koinInject
|
||||||
import androidx.compose.ui.geometry.Offset
|
import androidx.compose.ui.geometry.Offset
|
||||||
import androidx.compose.ui.unit.IntOffset
|
import cafe.adriel.voyager.navigator.CurrentScreen
|
||||||
import androidx.compose.ui.window.Popup
|
import cafe.adriel.voyager.navigator.Navigator
|
||||||
import kotlin.math.roundToInt
|
import mg.dot.feufaro.viewmodel.SolfaScreenModel
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
@Preview
|
fun App() {
|
||||||
fun App(sharedViewModel: SharedViewModel = SharedViewModel()
|
|
||||||
) {
|
Navigator(screen = ScreenSolfa) {
|
||||||
|
CurrentScreen()
|
||||||
|
}
|
||||||
val fileRepository = koinInject<FileRepository>()
|
val fileRepository = koinInject<FileRepository>()
|
||||||
|
|
||||||
val displayConfigManager = koinInject<DisplayConfigManager>()
|
val displayConfigManager = koinInject<DisplayConfigManager>()
|
||||||
val currentDisplayConfig by displayConfigManager.displayConfig.collectAsState()
|
val currentDisplayConfig by displayConfigManager.displayConfig.collectAsState()
|
||||||
// Load Configurations
|
// Load Configurations
|
||||||
val configScope = CoroutineScope(Dispatchers.Default)
|
val configScope = CoroutineScope(Dispatchers.Default)
|
||||||
var showContextualMenu by remember { mutableStateOf(false)}
|
val sharedScreenModel = koinInject<SharedScreenModel>()
|
||||||
var menuPosition by remember { mutableStateOf(Offset.Zero)}
|
val solfaScreenModel = koinInject<SolfaScreenModel>()
|
||||||
|
|
||||||
LaunchedEffect(Unit) {
|
LaunchedEffect(Unit) {
|
||||||
configScope.launch {
|
configScope.launch {
|
||||||
|
|
@ -70,12 +41,12 @@ fun App(sharedViewModel: SharedViewModel = SharedViewModel()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val solfa = Solfa(sharedViewModel, fileRepository)
|
|
||||||
LaunchedEffect(currentDisplayConfig) {
|
LaunchedEffect(currentDisplayConfig) {
|
||||||
if (currentDisplayConfig.playlist.isNotEmpty()) {
|
if (currentDisplayConfig.playlist.isNotEmpty()) {
|
||||||
try {
|
try {
|
||||||
sharedViewModel.setPlaylist(currentDisplayConfig.playlist)
|
sharedScreenModel.setPlaylist(currentDisplayConfig.playlist)
|
||||||
solfa.loadNextInPlaylist()
|
solfaScreenModel.loadNextInPlaylist()
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
println("Error loading playlist : ${e.message}")
|
println("Error loading playlist : ${e.message}")
|
||||||
}
|
}
|
||||||
|
|
@ -83,115 +54,8 @@ fun App(sharedViewModel: SharedViewModel = SharedViewModel()
|
||||||
}
|
}
|
||||||
|
|
||||||
val musicXML = MusicXML(fileRepository)
|
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 {
|
fun String?.toColor(foreGround: Boolean = false): Color {
|
||||||
val defaultColor = if (foreGround) {
|
val defaultColor = if (foreGround) {
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
import androidx.compose.material.icons.Icons
|
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.Add
|
||||||
import androidx.compose.material.icons.filled.Delete
|
import androidx.compose.material.icons.filled.Delete
|
||||||
import androidx.compose.material.icons.filled.Edit
|
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.Add, text = "+") { onMenuItemClick("Ajouter")}
|
||||||
MenuItem(icon = Icons.Default.Edit, text = "!") { onMenuItemClick("Modifier")}
|
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
|
package mg.dot.feufaro.di
|
||||||
|
|
||||||
|
import PlaylistRepository
|
||||||
|
import SharedScreenModel
|
||||||
import mg.dot.feufaro.CommonFileRepository
|
import mg.dot.feufaro.CommonFileRepository
|
||||||
import mg.dot.feufaro.FileRepository
|
import mg.dot.feufaro.FileRepository
|
||||||
import mg.dot.feufaro.SharedViewModel
|
|
||||||
import mg.dot.feufaro.DisplayConfigManager // Importez DisplayConfigManager
|
import mg.dot.feufaro.DisplayConfigManager // Importez DisplayConfigManager
|
||||||
import mg.dot.feufaro.config.AppConfig
|
import mg.dot.feufaro.config.AppConfig
|
||||||
import mg.dot.feufaro.musicXML.MusicXML
|
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.dsl.module
|
||||||
import org.koin.core.module.dsl.singleOf
|
import org.koin.core.module.dsl.singleOf
|
||||||
import org.koin.core.module.Module
|
import org.koin.core.module.Module
|
||||||
|
|
@ -18,5 +21,9 @@ val commonModule = module {
|
||||||
singleOf(::MusicXML)
|
singleOf(::MusicXML)
|
||||||
single<FileRepository> { CommonFileRepository() }
|
single<FileRepository> { CommonFileRepository() }
|
||||||
single { DisplayConfigManager(fileRepository = get())}
|
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
|
package mg.dot.feufaro.solfa
|
||||||
|
|
||||||
|
import SharedScreenModel
|
||||||
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 kotlinx.coroutines.withContext
|
||||||
import mg.dot.feufaro.FileRepository
|
import mg.dot.feufaro.FileRepository
|
||||||
import mg.dot.feufaro.CommonTools
|
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 T: MutableList<PTemplate> = mutableListOf()
|
||||||
private val N: MutableList<POneVoiceNote> = mutableListOf()
|
private val N: MutableList<POneVoiceNote> = mutableListOf()
|
||||||
private val L: MutableList<POneStanzaLyrics> = 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 meta: MutableMap<String, String> = mutableMapOf()
|
||||||
private val lyricsComment: MutableList<String> = mutableListOf()
|
private val lyricsComment: MutableList<String> = mutableListOf()
|
||||||
suspend fun nextTimeUnitObject() {
|
suspend fun nextTimeUnitObject() {
|
||||||
val lastTUO = sharedViewModel.lastTUO()
|
val lastTUO = sharedScreenModel.lastTUO()
|
||||||
nextTIndex++
|
nextTIndex++
|
||||||
if (nextTIndex == 5) {
|
if (nextTIndex == 5) {
|
||||||
sharedViewModel.doneTUOList()
|
sharedScreenModel.doneTUOList()
|
||||||
}
|
}
|
||||||
if (T.getOrNull(nextTIndex) == null) {
|
if (T.getOrNull(nextTIndex) == null) {
|
||||||
sharedViewModel.doneTUOList()
|
sharedScreenModel.doneTUOList()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
val pTemplate = T[nextTIndex]
|
val pTemplate = T[nextTIndex]
|
||||||
|
|
@ -89,19 +88,19 @@ class Solfa(val sharedViewModel: SharedViewModel, private val fileRepository: Fi
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
withContext(Dispatchers.Main) {
|
withContext(Dispatchers.Main) {
|
||||||
sharedViewModel.addTUO(unitObject)
|
sharedScreenModel.addTUO(unitObject)
|
||||||
}
|
}
|
||||||
nextTimeUnitObject()
|
nextTimeUnitObject()
|
||||||
}
|
}
|
||||||
fun loadSolfa() {
|
fun loadSolfa() {
|
||||||
val sourceFileName: String = sharedViewModel.currentPlayed()
|
val sourceFileName: String = sharedScreenModel.currentPlayed()
|
||||||
sharedViewModel.reset()
|
sharedScreenModel.reset()
|
||||||
parse(sourceFileName)
|
parse(sourceFileName)
|
||||||
}
|
}
|
||||||
fun loadNextInPlaylist() {
|
fun loadNextInPlaylist() {
|
||||||
val playlist = sharedViewModel.playlist.value
|
val playlist = sharedScreenModel.playlist.value
|
||||||
if (playlist.isNotEmpty()) {
|
if (playlist.isNotEmpty()) {
|
||||||
sharedViewModel.playNext()
|
sharedScreenModel.playNext()
|
||||||
loadSolfa()
|
loadSolfa()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -123,8 +122,8 @@ class Solfa(val sharedViewModel: SharedViewModel, private val fileRepository: Fi
|
||||||
nextNIndex = -1
|
nextNIndex = -1
|
||||||
nextLIndex = -1
|
nextLIndex = -1
|
||||||
lyricsComment.clear()
|
lyricsComment.clear()
|
||||||
sharedViewModel.setStanza("1")
|
sharedScreenModel.setStanza("1")
|
||||||
sharedViewModel.setNbStanzas(0)
|
sharedScreenModel.setNbStanzas(0)
|
||||||
TimeUnitObject.hasMarker(false)
|
TimeUnitObject.hasMarker(false)
|
||||||
lines.forEach { line ->
|
lines.forEach { line ->
|
||||||
run {
|
run {
|
||||||
|
|
@ -264,11 +263,11 @@ class Solfa(val sharedViewModel: SharedViewModel, private val fileRepository: Fi
|
||||||
val metaChunks: List<String> = value.split(REGEX_PARSE_META)
|
val metaChunks: List<String> = value.split(REGEX_PARSE_META)
|
||||||
metaChunks.forEach { parseMeta(it) }
|
metaChunks.forEach { parseMeta(it) }
|
||||||
parseMeta(value)
|
parseMeta(value)
|
||||||
sharedViewModel.setMeasure(meta["m"] ?: "")
|
sharedScreenModel.setMeasure(meta["m"] ?: "")
|
||||||
sharedViewModel.setSongTitle(meta["t"] ?: "")
|
sharedScreenModel.setSongTitle(meta["t"] ?: "")
|
||||||
sharedViewModel.setSongAuthor(meta["a"] ?: "")
|
sharedScreenModel.setSongAuthor(meta["a"] ?: "")
|
||||||
sharedViewModel.setSongComposer(meta["h"] ?: "")
|
sharedScreenModel.setSongComposer(meta["h"] ?: "")
|
||||||
sharedViewModel.setSongRhythm(meta["r"] ?: "")
|
sharedScreenModel.setSongRhythm(meta["r"] ?: "")
|
||||||
} else if (key == "L") {
|
} else if (key == "L") {
|
||||||
loadL(index, value)
|
loadL(index, value)
|
||||||
} else if (key == "Y") {
|
} else if (key == "Y") {
|
||||||
|
|
@ -383,7 +382,7 @@ class Solfa(val sharedViewModel: SharedViewModel, private val fileRepository: Fi
|
||||||
if ("c" == subKey) {
|
if ("c" == subKey) {
|
||||||
val tonality = line.uppercaseFirstMeta()
|
val tonality = line.uppercaseFirstMeta()
|
||||||
meta["C"] = tonality
|
meta["C"] = tonality
|
||||||
sharedViewModel.setSongKey(tonality)
|
sharedScreenModel.setSongKey(tonality)
|
||||||
val keyOrigin = CommonTools.tonalityToNumber(tonality)
|
val keyOrigin = CommonTools.tonalityToNumber(tonality)
|
||||||
val transposeTo = getOpt("transposeto")
|
val transposeTo = getOpt("transposeto")
|
||||||
val transposeAsIf = getOpt("transposeasif")
|
val transposeAsIf = getOpt("transposeasif")
|
||||||
|
|
@ -463,10 +462,10 @@ class Solfa(val sharedViewModel: SharedViewModel, private val fileRepository: Fi
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
sharedViewModel.appendData("\nErr: $e")
|
sharedScreenModel.appendData("\nErr: $e")
|
||||||
}
|
}
|
||||||
if (stanzaNumber > sharedViewModel.nbStanzas.value) {
|
if (stanzaNumber > sharedScreenModel.nbStanzas.value) {
|
||||||
sharedViewModel.setNbStanzas(stanzaNumber)
|
sharedScreenModel.setNbStanzas(stanzaNumber)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// loadY is a smart lyrics parser for Malagasy language
|
// 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.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.collectAsState
|
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
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.text.style.TextOverflow
|
||||||
import androidx.compose.ui.unit.TextUnit
|
import androidx.compose.ui.unit.TextUnit
|
||||||
import androidx.compose.ui.unit.sp
|
import androidx.compose.ui.unit.sp
|
||||||
import mg.dot.feufaro.SharedViewModel
|
import mg.dot.feufaro.data.GridTUOData
|
||||||
import kotlin.math.min
|
import kotlin.math.min
|
||||||
|
|
||||||
//import androidx.compose.ui.unit.times
|
|
||||||
|
|
||||||
class TimeUnitObject (val pTemplate: PTemplate, val prevTUO: TimeUnitObject?) {
|
class TimeUnitObject (val pTemplate: PTemplate, val prevTUO: TimeUnitObject?) {
|
||||||
var mutableNoteVersion: Int by mutableStateOf(0)
|
var mutableNoteVersion: Int by mutableStateOf(0)
|
||||||
private var lyrics: MutableList<POneStanzaLyrics> = mutableListOf()
|
private var lyrics: MutableList<POneStanzaLyrics> = mutableListOf()
|
||||||
|
|
@ -334,13 +331,13 @@ fun AutoResizingText(
|
||||||
}
|
}
|
||||||
@Composable
|
@Composable
|
||||||
fun LazyVerticalGridTUO(
|
fun LazyVerticalGridTUO(
|
||||||
viewModel: SharedViewModel,
|
viewModel: GridTUOData,
|
||||||
gridWidthPx: Int,
|
gridWidthPx: Int,
|
||||||
onGridWidthMeasured: (Int) -> Unit,
|
onGridWidthMeasured: (Int) -> Unit,
|
||||||
modifier: Modifier = Modifier
|
modifier: Modifier = Modifier
|
||||||
) {
|
) {
|
||||||
val regexMeasure = Regex("(\\d)/\\d").find(viewModel.measure.value)
|
val regexMeasure = Regex("(\\d)/\\d").find(viewModel.measure)
|
||||||
val tuoList by viewModel.tuoList.collectAsState()
|
val tuoList = viewModel.tuoList
|
||||||
|
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
|
|
@ -368,7 +365,7 @@ fun LazyVerticalGridTUO(
|
||||||
GridCells.Fixed(calculatedCols.coerceAtLeast(columnGroup))
|
GridCells.Fixed(calculatedCols.coerceAtLeast(columnGroup))
|
||||||
|
|
||||||
}
|
}
|
||||||
val currentStanza by viewModel.stanza.collectAsState()
|
val currentStanza = viewModel.stanza
|
||||||
|
|
||||||
LazyVerticalGrid(
|
LazyVerticalGrid(
|
||||||
columns = actualColumns,
|
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.StateFlow
|
||||||
import kotlinx.coroutines.flow.asStateFlow
|
import kotlinx.coroutines.flow.asStateFlow
|
||||||
import com.rickclephas.kmp.observableviewmodel.ViewModel
|
|
||||||
import com.rickclephas.kmp.observableviewmodel.MutableStateFlow
|
|
||||||
import mg.dot.feufaro.solfa.TimeUnitObject
|
import mg.dot.feufaro.solfa.TimeUnitObject
|
||||||
|
|
||||||
open class SharedViewModel(): ViewModel() {
|
// Supposons que vous ayez une autre dépendance, par exemple pour gérer les données de la playlist
|
||||||
private val _data = MutableStateFlow<String>(viewModelScope, "Next ...")
|
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()
|
val data: StateFlow<String> = _data.asStateFlow()
|
||||||
private val _measure = MutableStateFlow<String>(viewModelScope, "")
|
private val _measure = MutableStateFlow<String>("")
|
||||||
val measure: StateFlow<String> = _measure.asStateFlow()
|
val measure: StateFlow<String> = _measure.asStateFlow()
|
||||||
private val _songTitle = MutableStateFlow<String>(viewModelScope, "")
|
private val _songTitle = MutableStateFlow<String>("")
|
||||||
val songTitle: StateFlow<String> = _songTitle.asStateFlow()
|
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()
|
val stanza: StateFlow<Int> = _stanza.asStateFlow()
|
||||||
private val _songKey = MutableStateFlow<String>(viewModelScope, "")
|
private val _songKey = MutableStateFlow<String>("")
|
||||||
val songKey: StateFlow<String> = _songKey.asStateFlow()
|
val songKey: StateFlow<String> = _songKey.asStateFlow()
|
||||||
private val _songAuthor = MutableStateFlow<String>(viewModelScope,"")
|
private val _songAuthor = MutableStateFlow<String>("")
|
||||||
val songAuthor: StateFlow<String> = _songAuthor.asStateFlow()
|
val songAuthor: StateFlow<String> = _songAuthor.asStateFlow()
|
||||||
private val _songComposer = MutableStateFlow<String>(viewModelScope,"")
|
private val _songComposer = MutableStateFlow<String>("")
|
||||||
val songComposer: StateFlow<String> = _songComposer.asStateFlow()
|
val songComposer: StateFlow<String> = _songComposer.asStateFlow()
|
||||||
private val _songRhythm = MutableStateFlow<String>(viewModelScope,"")
|
private val _songRhythm = MutableStateFlow<String>("")
|
||||||
val songRhythm: StateFlow<String> = _songRhythm.asStateFlow()
|
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()
|
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()
|
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()
|
val playlist: StateFlow<List<String>> = _playlist.asStateFlow()
|
||||||
private var _nextPlayed = MutableStateFlow(viewModelScope, -1)
|
private var _nextPlayed = MutableStateFlow(-1)
|
||||||
val nextPlayed: StateFlow<Int> = _nextPlayed.asStateFlow()
|
val nextPlayed: StateFlow<Int> = _nextPlayed.asStateFlow()
|
||||||
private val tempTimeUnitObjectList = mutableListOf<TimeUnitObject>()
|
private val tempTimeUnitObjectList = mutableListOf<TimeUnitObject>()
|
||||||
var _hasMarker = MutableStateFlow<Boolean>(viewModelScope, false)
|
var _hasMarker = MutableStateFlow<Boolean>( false)
|
||||||
val hasMarker: StateFlow<Boolean> = _hasMarker.asStateFlow()
|
val hasMarker: StateFlow<Boolean> = _hasMarker.asStateFlow()
|
||||||
|
|
||||||
fun appendData(otherData: String) {
|
fun appendData(otherData: String) {
|
||||||
|
|
@ -93,4 +106,18 @@ open class SharedViewModel(): ViewModel() {
|
||||||
val playlistIndex = _nextPlayed.value
|
val playlistIndex = _nextPlayed.value
|
||||||
return _playlist.value[playlistIndex]
|
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",
|
title = "Feufaro",
|
||||||
) {
|
) {
|
||||||
KoinContext {
|
KoinContext {
|
||||||
val sharedViewModel: SharedViewModel = SharedViewModel()
|
App()
|
||||||
App(sharedViewModel = sharedViewModel)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -21,8 +21,10 @@ core = "0.91.1"
|
||||||
kmpObservableviewmodelCore = "1.0.0-BETA-3"
|
kmpObservableviewmodelCore = "1.0.0-BETA-3"
|
||||||
kotlinxSerializationJson = "1.8.1"
|
kotlinxSerializationJson = "1.8.1"
|
||||||
material3 = "1.3.2"
|
material3 = "1.3.2"
|
||||||
|
voyager = "1.1.0-beta03"
|
||||||
|
|
||||||
[libraries]
|
[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 = { 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" }
|
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" }
|
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-core-viewmodel = { module = "io.insert-koin:koin-core-viewmodel", version.ref = "koin" }
|
||||||
koin-android = { module = "io.insert-koin:koin-android", 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" }
|
koin-androidx-compose = { module = "io.insert-koin:koin-androidx-compose", version.ref = "koin" }
|
||||||
|
|
||||||
core = { module = "io.github.pdvrieze.xmlutil:core", version.ref = "core" }
|
core = { module = "io.github.pdvrieze.xmlutil:core", version.ref = "core" }
|
||||||
#core-android = { module = "io.github.pdvrieze.xmlutil:core-android", 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" }
|
#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" }
|
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" }
|
kotlinx-serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "kotlinxSerializationJson" }
|
||||||
androidx-material3 = { module = "androidx.compose.material3:material3", version.ref = "material3" }
|
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]
|
[plugins]
|
||||||
androidApplication = { id = "com.android.application", version.ref = "agp" }
|
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" }
|
composeCompiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }
|
||||||
kotlinMultiplatform = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "kotlin" }
|
kotlinMultiplatform = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "kotlin" }
|
||||||
kotlinSerialization = { id = "org.jetbrains.kotlin.plugin.serialization", 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