This commit is contained in:
dotmg 2025-07-09 17:43:24 +02:00
parent 122d41c9fb
commit e120dce2bd
8 changed files with 47 additions and 48 deletions

View file

@ -4,6 +4,6 @@ N1:s,s,-l,t,ds,drs,rm/mfl,fmdmmrl,-r/s,s,-l,t,ds,drs,rm/msfrdt,dmmrd/mfsmfssmdrm
N2:m,m,s,f,f,m,m,s,s,s,s,s,/s,l,f,l,s,s,s,F,F,l,-s,/f,m,s,f,f,m,m,s,s,s,s,s,/T,l,l,l,s,s,s,s,s,f,m,/s,s,ds,s,ds,s,s,s,s,s,/s,dt,t,dt,s,s,s,s,s,s,/m,m,s,f,f,m,m,s,s,s,s,s,/T,l,l,l,s,s,s,s,s,f,m, N2:m,m,s,f,f,m,m,s,s,s,s,s,/s,l,f,l,s,s,s,F,F,l,-s,/f,m,s,f,f,m,m,s,s,s,s,s,/T,l,l,l,s,s,s,s,s,f,m,/s,s,ds,s,ds,s,s,s,s,s,/s,dt,t,dt,s,s,s,s,s,s,/m,m,s,f,f,m,m,s,s,s,s,s,/T,l,l,l,s,s,s,s,s,f,m,
N3:dd-t,s,s,ddt,t,t,d/d7l,l,rdt,/t,d-t,s,s,ddt,t,t,d/ddrfmrmddt,d/drmdrmmddt,dt,/t,drrdrrt,ddt,d/dd-t,s,s,ddt,t,t,d/ddrfmrmddt,d N3:dd-t,s,s,ddt,t,t,d/d7l,l,rdt,/t,d-t,s,s,ddt,t,t,d/ddrfmrmddt,d/drmdrmmddt,dt,/t,drrdrrt,ddt,d/dd-t,s,s,ddt,t,t,d/ddrfmrmddt,d
N4:d,d,m,s,s,d,d,m,s,s,s,d/dfffd,m,d,r,r,F-s,/s,d,m,s,s,d,d,m,s,s,s,d/dfffs,6d,/d7d,m,r,d,s,/s,7fm,m,r,d,/d,d,m,s,s,d,d,m,s,s,s,d/dfffs,s,s,s,s,s,d, N4:d,d,m,s,s,d,d,m,s,s,s,d/dfffd,m,d,r,r,F-s,/s,d,m,s,s,d,d,m,s,s,s,d/dfffs,6d,/d7d,m,r,d,s,/s,7fm,m,r,d,/d,d,m,s,s,d,d,m,s,s,s,d/dfffs,s,s,s,s,s,d,
E1:To God be the glo_ry, great things He has done,/so loved He the world that He gave us His Son,/who yield_ed His life an a_tone_ment for sin,/and o_pened the life gate that all may go in./Praise the Lord, praise the Lord, let the earth hear His voice!/Praise the Lord, praise the Lord, let the peo_ple re_joice!/O come to the Fa_ther through Je_sus the Son, and give Him the glo_ry, great things He has done. E1:To God be the glo_ry, great things He has done,/so loved He the world that He gave us His Son,/who yield_ed His life an a_tone_ment for sin,/and o_pened the life gate that all may go in./${R=}Praise the Lord, praise the Lord, let the earth hear His voice!/Praise the Lord, praise the Lord, let the peo_ple re_joice!/O come to the Fa_ther through Je_sus the Son, and give Him the glo_ry, great things He has done.
E2:O per_fect re_demp_tion, the pur_chase of blood,/to ev'_ry be_lie_ver the pro_mise of God;/the vi_lest of_fen_der who tru_ly be_lieves,/that mo_ment from Je_sus a par_don re_ceives. E2:O per_fect re_demp_tion, the pur_chase of blood,/to ev'_ry be_lie_ver the pro_mise of God;/the vi_lest of_fen_der who tru_ly be_lieves,/that mo_ment from Je_sus a par_don re_ceives.
E3:Great things He has taught us, great things He has done,/and great our re_joi_cing through Je_sus the Son;/but pu_rer, and high_er, and great_er will be/our won_der, our rap_ture, when Je_sus we see. E3:Great things He has taught us, great things He has done,/and great our re_joi_cing through Je_sus the Son;/but pu_rer, and high_er, and great_er will be/our won_der, our rap_ture, when Je_sus we see.

View file

@ -46,7 +46,7 @@ fun App() {
if (currentDisplayConfig.playlist.isNotEmpty()) { if (currentDisplayConfig.playlist.isNotEmpty()) {
try { try {
sharedScreenModel.setPlaylist(currentDisplayConfig.playlist) sharedScreenModel.setPlaylist(currentDisplayConfig.playlist)
solfaScreenModel.loadNextInPlaylist() solfaScreenModel.reload()
} catch (e: Exception) { } catch (e: Exception) {
println("Error loading playlist : ${e.message}") println("Error loading playlist : ${e.message}")
} }

View file

@ -21,6 +21,7 @@ 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
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
@ -46,7 +47,7 @@ object ScreenSolfa : Screen {
val solfaScreenModel = koinScreenModel<SolfaScreenModel>() val solfaScreenModel = koinScreenModel<SolfaScreenModel>()
var menuPosition by remember { mutableStateOf(Offset.Zero)} var menuPosition by remember { mutableStateOf(Offset.Zero)}
var showContextualMenu by remember { mutableStateOf(false)} var showContextualMenu by remember { mutableStateOf(false)}
var gridWidthPx by remember { mutableStateOf(0) } var gridWidthPx by rememberSaveable { mutableStateOf(0) }
val sharedScreenModel = koinScreenModel<SharedScreenModel>() val sharedScreenModel = koinScreenModel<SharedScreenModel>()
val tuoList by sharedScreenModel.tuoList.collectAsState() val tuoList by sharedScreenModel.tuoList.collectAsState()
val measure by sharedScreenModel.measure.collectAsState() val measure by sharedScreenModel.measure.collectAsState()
@ -86,7 +87,6 @@ object ScreenSolfa : Screen {
.weight(1f) .weight(1f)
.verticalScroll(rememberScrollState()) .verticalScroll(rememberScrollState())
) { ) {
val stanza: Int by sharedScreenModel.stanza.collectAsState()
FlowRow( FlowRow(
modifier = Modifier.fillMaxWidth() modifier = Modifier.fillMaxWidth()
.windowInsetsPadding(WindowInsets.safeDrawing) .windowInsetsPadding(WindowInsets.safeDrawing)
@ -130,7 +130,7 @@ object ScreenSolfa : Screen {
MGButton( MGButton(
enabled = (i != stanza.toInt()), enabled = (i != stanza.toInt()),
onClick = { onClick = {
sharedScreenModel.setStanza(i.toString()) sharedScreenModel.setStanza(i)
}, },
modifier = Modifier.padding(horizontal = 4.dp) modifier = Modifier.padding(horizontal = 4.dp)
) { ) {

View file

@ -1,29 +1,21 @@
package mg.dot.feufaro.di package mg.dot.feufaro.di
import PlaylistRepository
import SharedScreenModel 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.DisplayConfigManager // Importez DisplayConfigManager import mg.dot.feufaro.DisplayConfigManager // Importez DisplayConfigManager
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.solfa.Solfa
import mg.dot.feufaro.viewmodel.SolfaScreenModel 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.dsl.viewModel
val commonModule = module { val commonModule = module {
// Déclarez FileRepository comme un singleton.
// L'implémentation concrète (actual) sera résolue par Koin en fonction de la plateforme.
// Pour Android, Koin injectera le Context que vous avez fourni via androidContext().
singleOf(::MusicXML) singleOf(::MusicXML)
single<FileRepository> { CommonFileRepository() } single<FileRepository> { CommonFileRepository() }
single { DisplayConfigManager(fileRepository = get())} single { DisplayConfigManager(fileRepository = get())}
single { SharedScreenModel(get()) } single { SharedScreenModel() }
//viewModel { SharedViewModel() }
single { PlaylistRepository() }
single { Solfa(get(), get()) } single { Solfa(get(), get()) }
single { SolfaScreenModel(get()) } single { SolfaScreenModel(get()) }
} }

View file

@ -2,6 +2,9 @@ package mg.dot.feufaro.solfa
class POneStanzaLyrics { class POneStanzaLyrics {
private val lyrics: MutableList<String> = mutableListOf("") private val lyrics: MutableList<String> = mutableListOf("")
fun getLyrics(stanzaNumber: Int) : String {
return this.lyrics[stanzaNumber]
}
fun setLyrics(stanzaNumber: Int, lyrics: String) { fun setLyrics(stanzaNumber: Int, lyrics: String) {
while (this.lyrics.size <= stanzaNumber) { while (this.lyrics.size <= stanzaNumber) {
this.lyrics.add("") this.lyrics.add("")

View file

@ -13,6 +13,7 @@ class Solfa(val sharedScreenModel: SharedScreenModel, private val fileRepository
private val N: MutableList<POneVoiceNote> = mutableListOf() private val N: MutableList<POneVoiceNote> = mutableListOf()
private val L: MutableList<POneStanzaLyrics> = mutableListOf() private val L: MutableList<POneStanzaLyrics> = mutableListOf()
private val unparsedNote = mutableListOf<String>() private val unparsedNote = mutableListOf<String>()
private var refrainBeginsAt = -1
companion object { companion object {
val REGEX_SHIFT_PAREN_UPWARD = Regex("([^a-yA-Y\\(\\[]+)([\\)\\]])") val REGEX_SHIFT_PAREN_UPWARD = Regex("([^a-yA-Y\\(\\[]+)([\\)\\]])")
val REGEX_SHIFT_PAREN_DOWNWARD = Regex("([\\(\\[])([^a-yA-y\\)\\]]+)") val REGEX_SHIFT_PAREN_DOWNWARD = Regex("([\\(\\[])([^a-yA-y\\)\\]]+)")
@ -23,7 +24,7 @@ class Solfa(val sharedScreenModel: SharedScreenModel, private val fileRepository
val REGEX_TEMPLATE_COMMENT = Regex("(\\$[A-Z]|\\$\\{[^\\}]*\\})") val REGEX_TEMPLATE_COMMENT = Regex("(\\$[A-Z]|\\$\\{[^\\}]*\\})")
val REGEX_REPETITION = Regex("([zdrmfslt-](?>[',]*))([1-9][0-9]*)") val REGEX_REPETITION = Regex("([zdrmfslt-](?>[',]*))([1-9][0-9]*)")
val REGEX_PARSE_META = Regex("\\|(?=[a-z]:)") val REGEX_PARSE_META = Regex("\\|(?=[a-z]:)")
val REGEX_LYRICS_COMMENT = Regex("\\$\\{([^\\}]*)\\}") val REGEX_LYRICS_COMMENT = Regex("\\$\\{([^\\}]:[^\\}]*)\\}")
val REGEX_LYRICS_REPETITION = Regex("_(\\d)") val REGEX_LYRICS_REPETITION = Regex("_(\\d)")
val REGEX_VOWELS_STAGE1 = Regex("[aeiouyàéỳ,;\\.\\-:!](?![ aeiouyàéỳ,;\\.\\-:!])", RegexOption.IGNORE_CASE) val REGEX_VOWELS_STAGE1 = Regex("[aeiouyàéỳ,;\\.\\-:!](?![ aeiouyàéỳ,;\\.\\-:!])", RegexOption.IGNORE_CASE)
val REGEX_VOWELS_STAGE2 = Regex("([aeiouyàéỳ,;\\.\\-:!])__", RegexOption.IGNORE_CASE) val REGEX_VOWELS_STAGE2 = Regex("([aeiouyàéỳ,;\\.\\-:!])__", RegexOption.IGNORE_CASE)
@ -122,7 +123,9 @@ class Solfa(val sharedScreenModel: SharedScreenModel, private val fileRepository
nextNIndex = -1 nextNIndex = -1
nextLIndex = -1 nextLIndex = -1
lyricsComment.clear() lyricsComment.clear()
sharedScreenModel.setStanza("1") if (sharedScreenModel.stanza.value == 0) {
sharedScreenModel.setStanza(1)
}
sharedScreenModel.setNbStanzas(0) sharedScreenModel.setNbStanzas(0)
TimeUnitObject.hasMarker(false) TimeUnitObject.hasMarker(false)
lines.forEach { line -> lines.forEach { line ->
@ -449,11 +452,16 @@ class Solfa(val sharedScreenModel: SharedScreenModel, private val fileRepository
arrayLyrics.forEachIndexed { i, lyricsItem -> arrayLyrics.forEachIndexed { i, lyricsItem ->
addLyricsItem(stanzaNumber, i, lyricsItem) addLyricsItem(stanzaNumber, i, lyricsItem)
} }
if (refrainBeginsAt > 0 && stanzaNumber > 1) {
copyRefrainToStanza(stanzaNumber)
}
if (lyricsComment.isNotEmpty()) { if (lyricsComment.isNotEmpty()) {
val lyricsIterator = lyricsComment.iterator() val lyricsIterator = lyricsComment.iterator()
while (lyricsIterator.hasNext()) { while (lyricsIterator.hasNext()) {
val item = lyricsIterator.next() val item = lyricsIterator.next()
if (item.substring(0, 4) == "\${D:") { // ${D:xxx} lyrics of DC and DSs
if (item.substring(0, 4) == $$"${D:") {
item.replace(REGEX_LYRICS_COMMENT, "$1").addHyphens().split(Regex("[_/]")).drop(1).forEachIndexed { i, xval -> item.replace(REGEX_LYRICS_COMMENT, "$1").addHyphens().split(Regex("[_/]")).drop(1).forEachIndexed { i, xval ->
appendLyricsItem(stanzaNumber, i, xval) appendLyricsItem(stanzaNumber, i, xval)
} }
@ -502,11 +510,28 @@ class Solfa(val sharedScreenModel: SharedScreenModel, private val fileRepository
lyricsComment.addAll(matchResult) lyricsComment.addAll(matchResult)
} }
} }
private fun defineRefrainFrom(tuoNumber: Int) {
refrainBeginsAt = tuoNumber
}
private fun copyRefrainToStanza(stanzaNumber: Int) {
for (i in refrainBeginsAt..L.size-1) {
L[i].setLyrics(stanzaNumber, L[i].getLyrics(1))
}
}
private fun addLyricsItem(stanzaNumber: Int, i: Int, lyricsItem: String) { private fun addLyricsItem(stanzaNumber: Int, i: Int, lyricsItem: String) {
while (L.size <= i) { while (L.size <= i) {
L.add(POneStanzaLyrics()) L.add(POneStanzaLyrics())
} }
L[i].setLyrics(stanzaNumber, lyricsItem) val strippedLyrics =
if (lyricsItem.contains($$"${R=}")) {
if (stanzaNumber == 1) {
defineRefrainFrom(i)
}
lyricsItem.replace($$"${R=}", "")
} else {
lyricsItem
}
L[i].setLyrics(stanzaNumber, strippedLyrics)
} }
private fun appendLyricsItem(stanzaNumber: Int, i: Int, lyricsItem: String) { private fun appendLyricsItem(stanzaNumber: Int, i: Int, lyricsItem: String) {
if (L.size > i) { if (L.size > i) {

View file

@ -5,19 +5,7 @@ import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.asStateFlow
import mg.dot.feufaro.solfa.TimeUnitObject import mg.dot.feufaro.solfa.TimeUnitObject
// Supposons que vous ayez une autre dépendance, par exemple pour gérer les données de la playlist class SharedScreenModel() : ScreenModel {
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 ...") private val _data = MutableStateFlow<String>("Next ...")
val data: StateFlow<String> = _data.asStateFlow() val data: StateFlow<String> = _data.asStateFlow()
private val _measure = MutableStateFlow<String>("") private val _measure = MutableStateFlow<String>("")
@ -42,7 +30,7 @@ class SharedScreenModel(
private var _playlist = private var _playlist =
MutableStateFlow<List<String>>(emptyList()) MutableStateFlow<List<String>>(emptyList())
val playlist: StateFlow<List<String>> = _playlist.asStateFlow() val playlist: StateFlow<List<String>> = _playlist.asStateFlow()
private var _nextPlayed = MutableStateFlow(-1) private var _nextPlayed = MutableStateFlow(0)
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>( false) var _hasMarker = MutableStateFlow<Boolean>( false)
@ -69,9 +57,9 @@ class SharedScreenModel(
fun setSongTitle(theTitle: String) { fun setSongTitle(theTitle: String) {
_songTitle.value = theTitle _songTitle.value = theTitle
} }
fun setStanza(theStanza: String) { fun setStanza(theStanza: Int) {
try { try {
_stanza.value = theStanza.toInt() _stanza.value = theStanza
} catch(e: NumberFormatException) { } catch(e: NumberFormatException) {
_stanza.value = 0 _stanza.value = 0
} }
@ -101,23 +89,11 @@ class SharedScreenModel(
fun playNext() { fun playNext() {
val nextIndex = (_nextPlayed.value + 1) % _playlist.value.size val nextIndex = (_nextPlayed.value + 1) % _playlist.value.size
_nextPlayed.value = nextIndex _nextPlayed.value = nextIndex
setStanza(1)
} }
fun currentPlayed(): String { fun currentPlayed(): String {
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
} }

View file

@ -10,4 +10,7 @@ class SolfaScreenModel (
fun loadNextInPlaylist() { fun loadNextInPlaylist() {
solfa.loadNextInPlaylist() solfa.loadNextInPlaylist()
} }
fun reload() {
solfa.loadSolfa()
}
} }