Improve ui/ux and dynamic theme & fontsize controls on Settings
This commit is contained in:
parent
e91bc7d08e
commit
4070315b94
15 changed files with 942 additions and 421 deletions
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"themeMode": "DARK",
|
||||
"fontSize": 18.5,
|
||||
"themeMode": "LIGHT",
|
||||
"fontSize": 14,
|
||||
"playlist": [
|
||||
"assets://a.txt",
|
||||
"assets://ffpm-617.txt",
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import SharedScreenModel
|
|||
import androidx.compose.foundation.layout.RowScope
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.ButtonDefaults
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
|
|
@ -14,33 +15,26 @@ import kotlinx.coroutines.launch
|
|||
import org.koin.compose.koinInject
|
||||
import cafe.adriel.voyager.navigator.CurrentScreen
|
||||
import cafe.adriel.voyager.navigator.Navigator
|
||||
import mg.dot.feufaro.ui.FeufaroTheme
|
||||
import mg.dot.feufaro.viewmodel.SolfaScreenModel
|
||||
|
||||
@Composable
|
||||
fun App() {
|
||||
|
||||
val displayConfigManager = koinInject<DisplayConfigManager>()
|
||||
val currentDisplayConfig by displayConfigManager.displayConfig.collectAsState()
|
||||
|
||||
FeufaroTheme(themeModeSelected = currentDisplayConfig.themeMode, userFontSize = currentDisplayConfig.fontSize) {
|
||||
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)
|
||||
val sharedScreenModel = koinInject<SharedScreenModel>()
|
||||
val solfaScreenModel = koinInject<SolfaScreenModel>()
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
configScope.launch {
|
||||
try {
|
||||
displayConfigManager.loadConfigFromFile("assets://config.json")
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LaunchedEffect(currentDisplayConfig) {
|
||||
if (currentDisplayConfig.playlist.isNotEmpty()) {
|
||||
if (DeepLinkHandler.hasConsumedDeepLink) {
|
||||
|
|
@ -94,10 +88,10 @@ fun MGButton(
|
|||
val displayConfigManager = koinInject<DisplayConfigManager>()
|
||||
val currentDisplayConfig by displayConfigManager.displayConfig.collectAsState()
|
||||
val buttonColors = ButtonDefaults.buttonColors(
|
||||
containerColor = currentDisplayConfig.buttonContainerColorHex.toColor(),
|
||||
disabledContainerColor = currentDisplayConfig.buttonDisabledContainerColorHex.toColor(),
|
||||
contentColor = currentDisplayConfig.buttonDisabledContentColorHex.toColor(),
|
||||
disabledContentColor = currentDisplayConfig.buttonDisabledContentColorHex.toColor()
|
||||
containerColor = MaterialTheme.colorScheme.error,
|
||||
contentColor = MaterialTheme.colorScheme.onError,
|
||||
disabledContainerColor = MaterialTheme.colorScheme.error.copy(alpha = 0.6f),
|
||||
disabledContentColor = MaterialTheme.colorScheme.onError.copy(alpha = 0.7f)
|
||||
)
|
||||
Button(
|
||||
onClick = onClick,
|
||||
|
|
|
|||
|
|
@ -1,14 +1,16 @@
|
|||
package mg.dot.feufaro
|
||||
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.json.Json
|
||||
import mg.dot.feufaro.config.AppConfigJson
|
||||
import mg.dot.feufaro.config.DisplayConfig
|
||||
import kotlinx.serialization.json.Json
|
||||
import kotlin.String
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
import java.util.prefs.Preferences
|
||||
|
||||
@Serializable
|
||||
data class AppConfigJson(
|
||||
|
|
@ -36,20 +38,29 @@ class DisplayConfigManager(
|
|||
private val fileRepository: FileRepository
|
||||
)
|
||||
{
|
||||
private val _displayConfig = MutableStateFlow(
|
||||
DisplayConfig(
|
||||
themeMode = "SYSTEM",
|
||||
fontSize = 16f,
|
||||
playlist = listOf(),
|
||||
buttonContainerColorHex = "#FF000000",
|
||||
buttonContentColorHex = "#FFFFFFFF",
|
||||
buttonDisabledContainerColorHex = "#FF888888",
|
||||
buttonDisabledContentColorHex = "#FFAA6666"
|
||||
|
||||
),
|
||||
)
|
||||
private val prefs = Preferences.userRoot().node("mg.dot.feufaro")
|
||||
private val _displayConfig = MutableStateFlow(DisplayConfig())
|
||||
val displayConfig: StateFlow<DisplayConfig> = _displayConfig.asStateFlow()
|
||||
private val configScope = CoroutineScope(Dispatchers.Default)
|
||||
|
||||
init {
|
||||
loadInitialConfig()
|
||||
}
|
||||
|
||||
private fun loadInitialConfig() {
|
||||
configScope.launch {
|
||||
loadConfigFromFile("assets://config.json")
|
||||
|
||||
val jsonConfig = _displayConfig.value
|
||||
val finalTheme = prefs.get("themeMode", jsonConfig.themeMode)
|
||||
val finalFontSize = prefs.getFloat("fontSize", jsonConfig.fontSize)
|
||||
|
||||
_displayConfig.value = jsonConfig.copy(
|
||||
themeMode = finalTheme,
|
||||
fontSize = finalFontSize
|
||||
)
|
||||
}
|
||||
}
|
||||
suspend fun loadConfigFromFile(filePath: String) {
|
||||
try {
|
||||
val jsonString = fileRepository.readFileContent(filePath)
|
||||
|
|
@ -61,5 +72,29 @@ class DisplayConfigManager(
|
|||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
|
||||
fun updateThemeMode(themeMode: String) {
|
||||
prefs.put("themeMode", themeMode)
|
||||
prefs.flush()
|
||||
_displayConfig.value = _displayConfig.value.copy(themeMode = themeMode)
|
||||
}
|
||||
|
||||
fun updateFontSize(fontSize: Float) {
|
||||
prefs.putFloat("fontSize", fontSize)
|
||||
prefs.flush()
|
||||
_displayConfig.value = _displayConfig.value.copy(fontSize = fontSize)
|
||||
}
|
||||
|
||||
fun resetToDefault() {
|
||||
try {
|
||||
prefs.remove("themeMode")
|
||||
prefs.remove("fontSize")
|
||||
prefs.flush()
|
||||
|
||||
loadInitialConfig()
|
||||
} catch (e: Exception) {
|
||||
println("Erreur lors de la réinitialisation : ${e.message}")
|
||||
}
|
||||
}
|
||||
// NOUVELLE MÉTHODE : Pour basculer le mode débogage
|
||||
}
|
||||
|
|
@ -11,6 +11,7 @@ import androidx.compose.material.icons.filled.Check
|
|||
import androidx.compose.material.icons.filled.Edit
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconToggleButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.runtime.saveable.rememberSaveable
|
||||
|
|
@ -151,14 +152,15 @@ object ScreenSolfa : Screen {
|
|||
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 = songTitle, style = MaterialTheme.typography.bodyLarge, fontWeight = FontWeight.Bold)
|
||||
Text(
|
||||
text = songKey,
|
||||
modifier = Modifier.background(Color(0xff, 0xea, 0xe7))
|
||||
style = MaterialTheme.typography.bodyLarge,
|
||||
modifier = Modifier.background(MaterialTheme.colorScheme.tertiary.copy(alpha = 0.1f))
|
||||
.padding(horizontal = 4.dp)
|
||||
)
|
||||
Text(text = measureString)
|
||||
Text(text = "Stanza: $stanza")
|
||||
Text(text = measureString, style = MaterialTheme.typography.bodyLarge)
|
||||
Text(text = "Stanza: $stanza", style = MaterialTheme.typography.bodyLarge)
|
||||
//ScreenTranspose.Content()
|
||||
}
|
||||
LazyVerticalGridTUO(
|
||||
|
|
|
|||
|
|
@ -4,12 +4,12 @@ import kotlinx.serialization.Serializable
|
|||
|
||||
@Serializable
|
||||
data class DisplayConfig (
|
||||
val themeMode: String,
|
||||
val fontSize: Float,
|
||||
val playlist: List<String>,
|
||||
val buttonContainerColorHex: String,
|
||||
val buttonContentColorHex: String ,
|
||||
val buttonDisabledContainerColorHex: String,
|
||||
val buttonDisabledContentColorHex: String ,
|
||||
val themeMode: String = "LIGHT",
|
||||
val fontSize: Float = 14f,
|
||||
val playlist: List<String> = emptyList(),
|
||||
val buttonContainerColorHex: String = "#737EFC",
|
||||
val buttonContentColorHex: String = "#FFFFFF",
|
||||
val buttonDisabledContainerColorHex: String = "#CCCCCC",
|
||||
val buttonDisabledContentColorHex: String = "#888888"
|
||||
|
||||
)
|
||||
|
|
@ -91,10 +91,16 @@ fun TUODetailDialog(
|
|||
if (existing.isEmpty() && canAdd) add("_") else add(existing)
|
||||
}
|
||||
}
|
||||
val lyricsLines = result
|
||||
.flatMap { it.split("\n") }
|
||||
.map { it.trim() }
|
||||
.toMutableList()
|
||||
val lyricsLines = remember(editState.lyricsByStanza) {
|
||||
mutableStateListOf<String>().apply {
|
||||
addAll(editState.lyricsByStanza.values.toList())
|
||||
}
|
||||
}
|
||||
val editedLyricsMap = remember {
|
||||
mutableStateMapOf<Int, String>().apply {
|
||||
putAll(editState.lyricsByStanza)
|
||||
}
|
||||
}
|
||||
|
||||
var canAddMark = mutableStateOf(false)
|
||||
Popup(
|
||||
|
|
@ -111,7 +117,7 @@ fun TUODetailDialog(
|
|||
.widthIn(max=125.dp)
|
||||
.heightIn(max = 400.dp),
|
||||
shape = MaterialTheme.shapes.small,
|
||||
color = Color(0xFF2D2D2D).copy(0.75f),
|
||||
color = MaterialTheme.colorScheme.onSecondaryContainer.copy(0.75f),
|
||||
) {
|
||||
Column(modifier = Modifier.padding(horizontal = 10.dp, vertical = 5.dp).fillMaxWidth()) {
|
||||
Row (
|
||||
|
|
@ -269,7 +275,7 @@ fun TUODetailDialog(
|
|||
}) {
|
||||
Text(
|
||||
text = "/",
|
||||
color = Color.Cyan,
|
||||
color = MaterialTheme.colorScheme.secondary.copy(alpha = 1.5f),
|
||||
fontSize = 18.sp,
|
||||
fontWeight = FontWeight.Bold,
|
||||
textAlign = TextAlign.Center
|
||||
|
|
@ -283,7 +289,7 @@ fun TUODetailDialog(
|
|||
}) {
|
||||
Icon(
|
||||
imageVector = Icons.Default.Add,
|
||||
tint = Color.Cyan,
|
||||
tint = MaterialTheme.colorScheme.secondary.copy(alpha = 1.5f),
|
||||
contentDescription = null
|
||||
)
|
||||
}
|
||||
|
|
@ -297,7 +303,7 @@ fun TUODetailDialog(
|
|||
MyTextEditField(
|
||||
value = templateFragment,
|
||||
customFontSize = 14.sp,
|
||||
color = Color.Yellow,
|
||||
color = MaterialTheme.colorScheme.tertiary.copy(alpha = 1.5f),
|
||||
customPadding = 8.dp,
|
||||
customBrush = SolidColor(Color.White),
|
||||
isEditable = false,
|
||||
|
|
@ -313,7 +319,7 @@ fun TUODetailDialog(
|
|||
MyTextEditField(
|
||||
value = marker,
|
||||
customFontSize = 14.sp,
|
||||
color = Color.Yellow,
|
||||
color = MaterialTheme.colorScheme.tertiary.copy(alpha = 1.5f),
|
||||
customPadding = 8.dp,
|
||||
customBrush = SolidColor(Color.White),
|
||||
isEditable = isEditable,
|
||||
|
|
@ -342,7 +348,7 @@ fun TUODetailDialog(
|
|||
}) {
|
||||
Icon(
|
||||
imageVector = Icons.Default.Add,
|
||||
tint = Color.Green,
|
||||
tint = MaterialTheme.colorScheme.secondary.copy(alpha = 1.5f),
|
||||
contentDescription = null
|
||||
)
|
||||
}
|
||||
|
|
@ -366,7 +372,7 @@ fun TUODetailDialog(
|
|||
.fillMaxWidth()
|
||||
.padding(bottom = 12.dp),
|
||||
shape = RoundedCornerShape(8.dp),
|
||||
color = if (firstValidation.isValid) Color(0xFF10B981) else Color(0xFFF59E0B),
|
||||
color = if (firstValidation.isValid) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.tertiary.copy(alpha = 1.5f),
|
||||
shadowElevation = 2.dp
|
||||
) {
|
||||
Row(
|
||||
|
|
@ -414,6 +420,14 @@ fun TUODetailDialog(
|
|||
|
||||
// --- SECTION LYRICS ---
|
||||
lyricsLines.forEachIndexed { index, line ->
|
||||
val displayedLine = line
|
||||
LaunchedEffect(displayedLine) {
|
||||
if (displayedLine != line) {
|
||||
lyricsLines[index] = displayedLine
|
||||
val updatedLyricsMap = editState.lyricsByStanza.toMutableMap()
|
||||
updatedLyricsMap[index + 1] = displayedLine
|
||||
}
|
||||
}
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
modifier = Modifier.padding(vertical = 2.dp)
|
||||
|
|
@ -421,19 +435,48 @@ fun TUODetailDialog(
|
|||
Column(
|
||||
modifier = Modifier.fillMaxWidth(0.8f)
|
||||
) {
|
||||
|
||||
val isLyricsValid = validateLyricsInput(line, templateFragment)
|
||||
val tooltipState2 = rememberTooltipState(isPersistent = false)
|
||||
Row(
|
||||
) {
|
||||
TooltipBox(
|
||||
positionProvider = TooltipDefaults.rememberPlainTooltipPositionProvider(),
|
||||
tooltip = {
|
||||
if (!isLyricsValid) {
|
||||
PlainTooltip(
|
||||
containerColor = Color(0XFF34EB71),
|
||||
contentColor = Color.White
|
||||
) {
|
||||
Text("Veuillez suivre ce format: $templateFragment")
|
||||
}
|
||||
}
|
||||
},
|
||||
state = tooltipState2
|
||||
) {
|
||||
MyTextEditField(
|
||||
value = line,
|
||||
value = displayedLine,
|
||||
customFontSize = 13.sp,
|
||||
color = Color.White,
|
||||
customPadding = 8.dp,
|
||||
customBrush = SolidColor(Color.White),
|
||||
isEditable = isEditable,
|
||||
isAddable = canAdd,
|
||||
isWarn = !isLyricsValid,
|
||||
funTransform = { input -> transformLyricsInput(input, templateFragment) },
|
||||
onValueChng = { newValue ->
|
||||
lyricsLines[index] = newValue
|
||||
val trimmedValue = newValue.trimStart()
|
||||
val dataToSave = if (trimmedValue.endsWith(" ")) trimmedValue else "$trimmedValue "
|
||||
lyricsLines[index] = trimmedValue
|
||||
val updatedLyricsMap = editState.lyricsByStanza.toMutableMap()
|
||||
editedLyricsMap[index + 1] = dataToSave
|
||||
|
||||
val updatedState = editState.copy(lyricsByStanza = updatedLyricsMap)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isEditable || canAdd) {
|
||||
IconButton(
|
||||
onClick = {
|
||||
|
|
@ -443,7 +486,7 @@ fun TUODetailDialog(
|
|||
}) {
|
||||
Icon(
|
||||
imageVector = if (index == 0) Icons.Default.Add else Icons.Default.Clear,
|
||||
tint = if (index == 0) Color.Green else Color.Red,
|
||||
tint = if (index == 0) MaterialTheme.colorScheme.secondary.copy(alpha = 1.5f) else MaterialTheme.colorScheme.tertiary.copy(alpha = 1.5f),
|
||||
contentDescription = null
|
||||
)
|
||||
}
|
||||
|
|
@ -467,12 +510,17 @@ fun TUODetailDialog(
|
|||
if (isEditable || canAdd) {
|
||||
IconButton(
|
||||
onClick = {
|
||||
val finalLyricsMap = editState.lyricsByStanza.toMutableMap()
|
||||
finalLyricsMap.putAll(editedLyricsMap)
|
||||
if (!finalLyricsMap.containsKey(currentStanza)) {
|
||||
finalLyricsMap[currentStanza] = lyricsLines.getOrNull(0)?.trim() ?: ""
|
||||
}
|
||||
val state = TUOEditState(
|
||||
tuoIndex = globalIndex,
|
||||
notesByVoice = notes.toMap(),
|
||||
originalNotes = originalNotes.toMap(),
|
||||
originalLyricsByStanza = originalLyricsByStz.toMutableMap(),
|
||||
lyricsByStanza = mutableMapOf(currentStanza to lyricsLines.joinToString(" ")),
|
||||
lyricsByStanza = finalLyricsMap,
|
||||
templateFragment = templateFragment,
|
||||
marker = if(marker.isEmpty()) "_" else marker,
|
||||
originalSep = initialSep,
|
||||
|
|
@ -485,7 +533,7 @@ fun TUODetailDialog(
|
|||
Icon(
|
||||
Icons.Default.Build,
|
||||
contentDescription = null,
|
||||
tint = Color.Green
|
||||
tint = MaterialTheme.colorScheme.secondary.copy(alpha = 1.5f)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -494,6 +542,102 @@ fun TUODetailDialog(
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun unpackLyrics(lyrics: String): String {
|
||||
val comments = Solfa.REGEX_COMMENT.findAll(lyrics)
|
||||
val commentsIterator = comments.iterator()
|
||||
val loadedLyrics = lyrics
|
||||
.replace(Solfa.REGEX_LYRICS_REPETITION) { matchResult ->
|
||||
val repeating = matchResult.destructured.match.groupValues[1]
|
||||
"_".repeat(repeating.toString().toInt())
|
||||
}
|
||||
.replace(Regex("(?<![\\?:,\\.; ])_"), "-_")
|
||||
.replace(Regex("_-(?=_)"), "_")
|
||||
.replace(" -_", "_")
|
||||
.replace("--_", "-_")
|
||||
.replace(Regex("_$"), "")
|
||||
|
||||
val lyricsFinal = Solfa.REGEX_COMMENT.replace(loadedLyrics) { matchResult ->
|
||||
commentsIterator.next().value
|
||||
}
|
||||
return lyricsFinal
|
||||
}
|
||||
private fun smartYLyrics(lyrics: String): String {
|
||||
val comments = Solfa.REGEX_COMMENT.findAll(lyrics)
|
||||
val commentsIterator = comments.iterator()
|
||||
val loadedLyrics = lyrics
|
||||
.replace(Solfa.REGEX_VOWELS_STAGE1, "$0_")
|
||||
.replace(Solfa.REGEX_VOWELS_STAGE2, "$1_")
|
||||
.replace(Solfa.REGEX_VOWELS_STAGE3, "$1_")
|
||||
.replace(" ", " _")
|
||||
.replace("_\\ _", " ")
|
||||
.replace("_\\", "")
|
||||
.replace("_0", "")
|
||||
.replace(Solfa.REGEX_MALAGASY_MN, "$1$2_$3")
|
||||
.replace(Solfa.REGEX_MALAGASY_MN_STAGE2, "$1-_")
|
||||
.replace("_n'", "n'_")
|
||||
val lyricsFinal = Solfa.REGEX_COMMENT.replace(loadedLyrics) { matchResult ->
|
||||
commentsIterator.next().value
|
||||
}
|
||||
return unpackLyrics(lyricsFinal)
|
||||
}
|
||||
public fun transformLyricsInput(input: String, template: String): String {
|
||||
val templateCount = template.count { it.isLetter() && it.lowercaseChar() != 'z' }
|
||||
|
||||
val processed = smartYLyrics(input)
|
||||
val currentSyllables = processed.split("_").filter { it.isNotEmpty() }
|
||||
val currentCount = currentSyllables.size
|
||||
|
||||
// println("\n\n\tDEBUG [Start] Input: '$input' | TemplateCount: $templateCount | Found: $currentCount ${currentSyllables.joinToString("|")}")
|
||||
// println("DEBUG [Segments]: $currentSyllables")
|
||||
|
||||
val rawResult = if (currentCount <= templateCount) {
|
||||
// println("DEBUG [Status]: Pas de fusion nécessaire.")
|
||||
input
|
||||
} else {
|
||||
val parts = currentSyllables.toMutableList()
|
||||
val excess = currentCount - templateCount
|
||||
// println("DEBUG [Fusion]: Besoin de fusionner $excess fois.")
|
||||
|
||||
for (i in 0 until excess) {
|
||||
val idx = parts.size - 2/* - i*/
|
||||
if (idx >= 0) {
|
||||
// println("DEBUG [Loop $i]: Fusion de l'index $idx avec ${idx + 1}")
|
||||
// println("DEBUG [Avant]: '${parts[idx]}' et '${parts[idx + 1]}'")
|
||||
val part1 = parts[idx].trimEnd()
|
||||
val part2 = parts[idx + 1].trimStart()
|
||||
val cleanPart1 = part1.replace("-", "")
|
||||
val lastChar = if (cleanPart1.isNotEmpty()) cleanPart1.last() else ' '
|
||||
|
||||
val endsWithVowel = "aeiouyòàéìỳAEIOUY".contains(lastChar)
|
||||
val isVowelConsonantPair = endsWithVowel && part2.length == 1 && !"aeiouyòàéìỳAEIOUY".contains(part2.first())
|
||||
|
||||
if (part2.isNotEmpty()) {
|
||||
if (isVowelConsonantPair) {
|
||||
parts[idx] = part1 + part2
|
||||
} else {
|
||||
parts[idx] = part1 + "\\ " + part2
|
||||
}
|
||||
} else {
|
||||
parts[idx] = part1 + "\\"
|
||||
}
|
||||
parts.removeAt(idx + 1)
|
||||
}
|
||||
// println("DEBUG [Après]: Résultat index $idx -> '${parts}'")
|
||||
}
|
||||
|
||||
val result = parts.joinToString("")
|
||||
// println("DEBUG [Final]: '$result'")
|
||||
result
|
||||
}
|
||||
val REGEX_MALAGASY_MN_OUTPUT = Regex("-([mn])")
|
||||
val correctedResult = rawResult.replace(REGEX_MALAGASY_MN_OUTPUT, "$1-")
|
||||
|
||||
if (correctedResult != rawResult) {
|
||||
// println("DEBUG [Correction MN]: '$rawResult' -> '$correctedResult'")
|
||||
}
|
||||
return correctedResult
|
||||
}
|
||||
private fun transformMusicalInput(input: String): String {
|
||||
return input.lowercase()
|
||||
.replace(";", "• ,")
|
||||
|
|
@ -585,7 +729,7 @@ fun MyTextEditField(
|
|||
.background(Color.Black.copy(alpha = 0.3f), RoundedCornerShape(4.dp))
|
||||
.border(
|
||||
if (isWarn!!) 1.dp else 0.dp,
|
||||
if (isWarn!!) Color(0xFFF59E0B) else Color.Transparent,
|
||||
if (isWarn!!) MaterialTheme.colorScheme.tertiary.copy(alpha = 1.5f) else Color.Transparent,
|
||||
shape = RoundedCornerShape(4.dp)
|
||||
)
|
||||
.padding(customPadding),
|
||||
|
|
|
|||
|
|
@ -268,11 +268,11 @@ fun TimeUnitComposable(
|
|||
parentFocusRequester: FocusRequester? = null,
|
||||
transpositionInterval: Int
|
||||
) {
|
||||
val col = if (tuo.getNum() % 2 == 0) Color(0xff, 0xfa, 0xf7) else Color(0xfb, 0xf3, 0xff)
|
||||
val col = if (tuo.getNum() % 2 == 0) MaterialTheme.colorScheme.tertiary.copy(alpha = 0.05f) else MaterialTheme.colorScheme.error.copy(alpha = 0.05f)
|
||||
val currentDensity = LocalDensity.current
|
||||
|
||||
val animatedColor by animateColorAsState(
|
||||
targetValue = if (gridActive) Color.Cyan.copy(alpha = 0.5f) else col,
|
||||
targetValue = if (gridActive) MaterialTheme.colorScheme.secondary.copy(alpha = 1f) else col,
|
||||
animationSpec = tween(durationMillis = 100) // Très court pour rester réactif
|
||||
)
|
||||
val focusRequesters = remember { List(4) { FocusRequester() } }
|
||||
|
|
@ -449,7 +449,7 @@ fun TimeUnitComposable(
|
|||
fontSize = 10.sp,
|
||||
baselineShift = BaselineShift.Superscript,
|
||||
//fontStyle = FontStyle.Italic,
|
||||
color = FEUFAROO_KEY_CHANGE_COLOR
|
||||
color = MaterialTheme.colorScheme.primary
|
||||
)) {
|
||||
append(text+" ")
|
||||
}
|
||||
|
|
@ -459,6 +459,7 @@ fun TimeUnitComposable(
|
|||
}
|
||||
Text(
|
||||
text = annotatedText,
|
||||
style = MaterialTheme.typography.bodyLarge,
|
||||
onTextLayout = { result ->
|
||||
textLayoutResult = result
|
||||
}
|
||||
|
|
@ -768,8 +769,8 @@ fun LazyVerticalGridTUO(
|
|||
fontStyle = fontStyle,
|
||||
fontWeight = fontWeight,
|
||||
style = TextStyle(
|
||||
color = Color.Black,
|
||||
fontSize = 17.sp
|
||||
color = MaterialTheme.colorScheme.onSecondaryContainer,
|
||||
fontSize = MaterialTheme.typography.titleMedium.fontSize
|
||||
)
|
||||
)
|
||||
}
|
||||
|
|
@ -792,11 +793,11 @@ fun LazyVerticalGridTUO(
|
|||
.width(gridWidthDp / gridColumnCount)
|
||||
.border(
|
||||
width = if (isSelectedByKeyboard && editMode) 2.dp else 0.dp,
|
||||
color = if (isSelectedByKeyboard && editMode) Color(0xFF9C27B0) else Color.Transparent,
|
||||
color = if (isSelectedByKeyboard && editMode) MaterialTheme.colorScheme.error else Color.Transparent,
|
||||
shape = RoundedCornerShape(4.dp)
|
||||
)
|
||||
.background(
|
||||
if (isHovered) Color.Black.copy(alpha = 0.05f) else Color.Transparent,
|
||||
if (isHovered) MaterialTheme.colorScheme.onSecondary.copy(alpha = 0.05f) else Color.Transparent,
|
||||
RoundedCornerShape(4.dp)
|
||||
)
|
||||
.combinedClickable(
|
||||
|
|
@ -994,18 +995,18 @@ fun LazyVerticalGridTUO(
|
|||
text = dynamicSpaceSyl,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(end = 4.dp)/*.border(1.dp, Color.Yellow, RectangleShape)*/
|
||||
.padding(end = 4.dp)
|
||||
.wrapContentSize(unbounded = true, align = alignmentText),
|
||||
softWrap = false,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Visible,
|
||||
style = TextStyle(
|
||||
color = when {
|
||||
(isTooLong) -> Color(0XFF121212)
|
||||
(index == 0) -> Color.Black
|
||||
else -> Color(0XFF3B3A39)
|
||||
(isTooLong) -> MaterialTheme.colorScheme.onBackground
|
||||
(index == 0) -> MaterialTheme.colorScheme.onBackground
|
||||
else -> MaterialTheme.colorScheme.onBackground
|
||||
},
|
||||
fontSize = 16.sp,
|
||||
fontSize = MaterialTheme.typography.titleMedium.fontSize,
|
||||
),
|
||||
onTextLayout = { txtLayoutRes ->
|
||||
textWidth = with(density) { txtLayoutRes.size.width.toDp() }
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@ package mg.dot.feufaro.ui
|
|||
|
||||
import SharedScreenModel
|
||||
import androidx.compose.animation.*
|
||||
import androidx.compose.animation.core.animateDpAsState
|
||||
import androidx.compose.animation.core.animateFloatAsState
|
||||
import androidx.compose.foundation.*
|
||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
import androidx.compose.foundation.layout.*
|
||||
|
|
@ -24,7 +26,10 @@ import androidx.compose.ui.focus.FocusRequester
|
|||
import androidx.compose.ui.focus.focusRequester
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.SolidColor
|
||||
import androidx.compose.ui.graphics.graphicsLayer
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.input.pointer.PointerEventType
|
||||
import androidx.compose.ui.input.pointer.pointerInput
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.input.VisualTransformation
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
|
|
@ -169,6 +174,8 @@ fun MainScreenWithDrawer(
|
|||
}
|
||||
}
|
||||
|
||||
val isQrVisible = sharedScreenModel.isQRCodeVisible.value
|
||||
|
||||
ModalNavigationDrawer(drawerState = drawerState, drawerContent = {
|
||||
SimpleDrawerContent(
|
||||
items,
|
||||
|
|
@ -350,17 +357,20 @@ fun MainScreenWithDrawer(
|
|||
maxLines = 1,
|
||||
softWrap = false,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
style = MaterialTheme.typography.headlineLarge
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}, navigationIcon = {
|
||||
if(!isQrVisible) {
|
||||
IconButton(onClick = {
|
||||
scope.launch { drawerState.open() }
|
||||
}) {
|
||||
Icon(Icons.Filled.Menu, contentDescription = "Ouvrir Menu")
|
||||
}
|
||||
}
|
||||
}, actions = {
|
||||
var tempInterval by remember(fileContent) { mutableStateOf(0) }
|
||||
var isEyeVisible by remember { mutableStateOf(false) }
|
||||
|
|
@ -382,7 +392,7 @@ fun MainScreenWithDrawer(
|
|||
) {
|
||||
Text(
|
||||
text = tempUiKey,
|
||||
fontSize = 25.sp,
|
||||
style = MaterialTheme.typography.displaySmall,
|
||||
fontWeight = FontWeight.Black,
|
||||
textAlign = TextAlign.Center,
|
||||
color = if (isCurrentlyTransposed && !isPendingChange) Color(0xFFFFD700) else Color.White,
|
||||
|
|
@ -441,7 +451,7 @@ fun MainScreenWithDrawer(
|
|||
}
|
||||
|
||||
val centralIcon = if (isPendingChange) Icons.Filled.Check else Icons.Filled.SwapHoriz
|
||||
val centralTint = if (isPendingChange) Color(0xFFFFD700) else Color.White
|
||||
val centralTint = if (isPendingChange) MaterialTheme.colorScheme.tertiary else Color.White
|
||||
val tooltipText = if (isPendingChange) "Transposer en $tempUiKey" else if (isCurrentlyTransposed) "Revenir en $songKey" else "Transposer"
|
||||
|
||||
TooltipBox(
|
||||
|
|
@ -522,11 +532,9 @@ fun MainScreenWithDrawer(
|
|||
},
|
||||
modifier = Modifier.fillMaxWidth().height(36.dp),
|
||||
shape = RoundedCornerShape(8.dp),
|
||||
border = BorderStroke(1.dp, Color(0xFFFFD700).copy(alpha = 0.5f)),
|
||||
border = BorderStroke(1.dp, MaterialTheme.colorScheme.tertiary.copy(alpha = 0.5f)),
|
||||
colors = ButtonDefaults.outlinedButtonColors(
|
||||
contentColor = Color(
|
||||
0xFFFFD700
|
||||
)
|
||||
contentColor = MaterialTheme.colorScheme.tertiary
|
||||
)
|
||||
) {
|
||||
Text(
|
||||
|
|
@ -571,7 +579,6 @@ fun MainScreenWithDrawer(
|
|||
}
|
||||
}
|
||||
},
|
||||
containerColor = Color(0x20000000),
|
||||
icon = Icons.AutoMirrored.Default.Undo
|
||||
)
|
||||
}
|
||||
|
|
@ -593,7 +600,6 @@ fun MainScreenWithDrawer(
|
|||
}
|
||||
}
|
||||
},
|
||||
containerColor = Color(0x20000000),
|
||||
icon = Icons.Filled.SaveAs
|
||||
)
|
||||
}
|
||||
|
|
@ -607,11 +613,10 @@ fun MainScreenWithDrawer(
|
|||
onClick = {
|
||||
sharedScreenModel.toggleEditorMode(false)
|
||||
},
|
||||
containerColor = Color(0x20000000),
|
||||
icon = Icons.Default.Close
|
||||
)
|
||||
}
|
||||
} else {
|
||||
} else if(!isQrVisible) {
|
||||
AnimatedVisibility(
|
||||
visible = isExpanded and !showMidiCtrl,
|
||||
enter = fadeIn() + scaleIn() + slideInVertically { it / 2 },
|
||||
|
|
@ -623,7 +628,6 @@ fun MainScreenWithDrawer(
|
|||
onClick = {
|
||||
sharedScreenModel.descGridCount(1)
|
||||
},
|
||||
containerColor = Color(0x15000000),
|
||||
size = 30.dp,
|
||||
icon = Icons.Default.Remove
|
||||
)
|
||||
|
|
@ -633,7 +637,6 @@ fun MainScreenWithDrawer(
|
|||
onClick = {
|
||||
sharedScreenModel.addGridCount(1)
|
||||
},
|
||||
containerColor = Color(0x15000000),
|
||||
size = 30.dp,
|
||||
icon = Icons.Default.Add
|
||||
)
|
||||
|
|
@ -650,7 +653,6 @@ fun MainScreenWithDrawer(
|
|||
sharedScreenModel.toggleQRCodeVisibility()
|
||||
sharedScreenModel.setExpandedFAB(false)
|
||||
},
|
||||
containerColor = Color(0x15000000),
|
||||
icon = Icons.Filled.QrCode
|
||||
)
|
||||
}
|
||||
|
|
@ -665,7 +667,6 @@ fun MainScreenWithDrawer(
|
|||
onClick = {
|
||||
showPrintSettings = !showPrintSettings
|
||||
},
|
||||
containerColor = Color(0x15000000),
|
||||
icon = Icons.Filled.Print
|
||||
)
|
||||
}
|
||||
|
|
@ -679,7 +680,6 @@ fun MainScreenWithDrawer(
|
|||
onClick = {
|
||||
sharedScreenModel.setMidiCtrl(!showMidiCtrl)
|
||||
},
|
||||
containerColor = Color(0x15000000),
|
||||
icon = if (showMidiCtrl) Icons.Filled.StopCircle else Icons.Filled.PlayCircle
|
||||
)
|
||||
}
|
||||
|
|
@ -690,7 +690,6 @@ fun MainScreenWithDrawer(
|
|||
refreshTrigeer++
|
||||
sharedScreenModel.loadNewSong("$midiFile")
|
||||
},
|
||||
containerColor = if (isExpanded) Color(0x25000000) else Color.Transparent,
|
||||
icon = if (isExpanded) Icons.Filled.Close else Icons.Filled.Menu
|
||||
)
|
||||
}
|
||||
|
|
@ -748,17 +747,42 @@ fun MainScreenWithDrawer(
|
|||
/*.windowInsetsPadding(currentInsets.union(WindowInsets.ime))*/
|
||||
) {
|
||||
content(PaddingValues(0.dp))
|
||||
if (sharedScreenModel.isQRCodeVisible.value) {
|
||||
|
||||
AnimatedVisibility(
|
||||
visible = isQrVisible,
|
||||
enter = slideInVertically(
|
||||
initialOffsetY = { fullHeight -> fullHeight }
|
||||
) + fadeIn(),
|
||||
exit = slideOutVertically(
|
||||
targetOffsetY = { fullHeight -> fullHeight }
|
||||
) + fadeOut()
|
||||
) {
|
||||
QRDisplay(
|
||||
sharedScreenModel = sharedScreenModel,
|
||||
fileRepository = solfaScreenModel.fileRepository
|
||||
)
|
||||
}
|
||||
|
||||
var isHovered by remember { mutableStateOf(false) }
|
||||
val offsetX by animateDpAsState(targetValue = if (isHovered || isSearchActive) 0.dp else 15.dp)
|
||||
|
||||
AnimatedVisibility(
|
||||
visible = !isEditMode,
|
||||
visible = !isEditMode && !isQrVisible,
|
||||
modifier = Modifier
|
||||
.align(Alignment.TopEnd)
|
||||
.padding(16.dp)
|
||||
.padding(top = 15.dp)
|
||||
.offset(x = offsetX)
|
||||
.pointerInput(Unit) {
|
||||
awaitPointerEventScope {
|
||||
while (true) {
|
||||
val event = awaitPointerEvent()
|
||||
when (event.type) {
|
||||
PointerEventType.Enter -> isHovered = true
|
||||
PointerEventType.Exit -> isHovered = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
) {
|
||||
IconButton(
|
||||
onClick = {
|
||||
|
|
@ -778,14 +802,14 @@ fun MainScreenWithDrawer(
|
|||
.size(55.dp)
|
||||
.alpha(0.6f)
|
||||
.background(
|
||||
color = Color.Blue,
|
||||
color = MaterialTheme.colorScheme.tertiary,
|
||||
shape = CircleShape
|
||||
)
|
||||
) {
|
||||
Icon(
|
||||
imageVector = if (isSearchActive) Icons.Default.Close else Icons.Default.Search,
|
||||
contentDescription = null,
|
||||
tint = Color.White
|
||||
tint = MaterialTheme.colorScheme.onTertiary
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -884,20 +908,19 @@ fun MainScreenWithDrawer(
|
|||
@Composable
|
||||
private fun MyFAB(
|
||||
onClick: () -> Unit,
|
||||
containerColor: Color,
|
||||
size: Dp ?= 55.dp,
|
||||
icon: ImageVector
|
||||
) {
|
||||
FloatingActionButton(
|
||||
onClick = onClick,
|
||||
modifier = Modifier.size(size!!),
|
||||
containerColor = containerColor,
|
||||
containerColor = MaterialTheme.colorScheme.onSecondary.copy(alpha = 0.1f),
|
||||
elevation = FloatingActionButtonDefaults.elevation(0.dp, 0.dp, 0.dp, 0.dp)
|
||||
) {
|
||||
Icon(
|
||||
imageVector = icon,
|
||||
contentDescription = null,
|
||||
tint = Color.Blue.copy(alpha = 0.75f)
|
||||
tint = MaterialTheme.colorScheme.primary
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ import androidx.compose.ui.Alignment
|
|||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.draw.paint
|
||||
import androidx.compose.ui.draw.shadow
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.RectangleShape
|
||||
import androidx.compose.ui.graphics.TransformOrigin
|
||||
|
|
@ -121,8 +122,25 @@ fun MidiControlPanel(
|
|||
) {
|
||||
Column(
|
||||
modifier = modifier
|
||||
.padding(24.dp)
|
||||
.fillMaxWidth(if (platform.startsWith("Android")) 1f else 0.6f)
|
||||
.background(color = Color.Gray.copy(alpha = 0.5f), shape = RoundedCornerShape(size = 5.dp)),
|
||||
.background(
|
||||
color = MaterialTheme.colorScheme.onSecondary.copy(alpha = 0.12f),
|
||||
shape = RoundedCornerShape(24.dp)
|
||||
)
|
||||
.border(
|
||||
width = 1.dp,
|
||||
color = MaterialTheme.colorScheme.tertiary.copy(alpha = 0.8f),
|
||||
shape = RoundedCornerShape(24.dp)
|
||||
)
|
||||
.shadow(
|
||||
elevation = 40.dp,
|
||||
shape = RoundedCornerShape(24.dp),
|
||||
clip = false,
|
||||
ambientColor = Color.Black.copy(alpha = 0.1f),
|
||||
spotColor = Color.Black.copy(alpha = 0.3f)
|
||||
),
|
||||
/*.background(color = Color.Gray.copy(alpha = 0.5f), shape = RoundedCornerShape(size = 5.dp)),*/
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
AnimatedVisibility(
|
||||
|
|
@ -130,40 +148,43 @@ fun MidiControlPanel(
|
|||
) {
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(8.dp)
|
||||
horizontalArrangement = Arrangement.spacedBy(12.dp)
|
||||
) {
|
||||
Text("${currentPos.toInt() / 1000}s", color = Color.White)
|
||||
Text("${currentPos.toInt() / 1000}s", color = MaterialTheme.colorScheme.onSecondary, fontSize = MaterialTheme.typography.titleSmall.fontSize)
|
||||
Slider(
|
||||
value = currentPos,
|
||||
onValueChange = onSeek,
|
||||
valueRange = 0f..(if (duration > 0) duration else 1f),
|
||||
modifier = Modifier.weight(1f),
|
||||
colors = SliderDefaults.colors(
|
||||
thumbColor = Color.Red,
|
||||
activeTrackColor = Color.Green,
|
||||
inactiveTrackColor = Color.Gray,
|
||||
inactiveTickColor = Color(0xffb0BEC5),
|
||||
disabledThumbColor = Color(0xff78909C),
|
||||
disabledActiveTickColor = Color(0xff757575),
|
||||
disabledActiveTrackColor = Color(0xffBDBDBD),
|
||||
disabledInactiveTickColor = Color(0xff616161),
|
||||
disabledInactiveTrackColor = Color(0xffBCAAA4),
|
||||
activeTrackColor = MaterialTheme.colorScheme.primary,
|
||||
inactiveTrackColor = Color.White.copy(alpha = 0.2f),
|
||||
thumbColor = MaterialTheme.colorScheme.secondary,
|
||||
disabledThumbColor = Color.Gray,
|
||||
disabledActiveTrackColor = Color.Gray.copy(alpha = 0.5f)
|
||||
),
|
||||
thumb = {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.size(15.dp)
|
||||
.background(Color.Gray, CircleShape)
|
||||
.size(12.dp)
|
||||
.background(MaterialTheme.colorScheme.secondary, CircleShape)
|
||||
.shadow(4.dp, CircleShape)
|
||||
)
|
||||
},
|
||||
track = { sliderState ->
|
||||
SliderDefaults.Track(
|
||||
sliderState = sliderState,
|
||||
modifier = Modifier.height(5.dp)
|
||||
modifier = Modifier.height(6.dp).clip(CircleShape),
|
||||
colors = SliderDefaults.colors(
|
||||
activeTrackColor = MaterialTheme.colorScheme.primary,
|
||||
inactiveTrackColor = MaterialTheme.colorScheme.onSecondary.copy(alpha = 0.6f)
|
||||
),
|
||||
drawStopIndicator = null,
|
||||
thumbTrackGapSize = 2.dp,
|
||||
)
|
||||
}
|
||||
)
|
||||
Text("${momo / 1000}s", color = Color.White)
|
||||
Text("${momo / 1000}s", color = MaterialTheme.colorScheme.onSecondary, fontSize = MaterialTheme.typography.titleSmall.fontSize)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -279,11 +300,16 @@ fun MidiControlPanel(
|
|||
modifier = Modifier.padding(horizontal = 2.dp)
|
||||
) { displayedBpm ->
|
||||
val isCenter = displayedBpm == currentBpmInt
|
||||
// 1. On prépare le style de manière propre en dehors du Text
|
||||
val bpmTextStyle = if (isCenter) {
|
||||
MaterialTheme.typography.titleLarge.copy(fontWeight = FontWeight.Bold)
|
||||
} else {
|
||||
MaterialTheme.typography.bodyLarge.copy(fontWeight = FontWeight.Normal)
|
||||
}
|
||||
Text(
|
||||
text = "$displayedBpm",
|
||||
text = displayedBpm.toString(),
|
||||
color = if (isCenter) Color.White else Color.Gray.copy(alpha = 0.4f),
|
||||
fontSize = if (isCenter) 22.sp else 14.sp,
|
||||
fontWeight = if (isCenter) FontWeight.Bold else FontWeight.Normal,
|
||||
style = bpmTextStyle,
|
||||
modifier = Modifier
|
||||
.clip(CircleShape)
|
||||
.clickable(enabled = !isCenter) { updateTempoToBpm(displayedBpm) }
|
||||
|
|
@ -308,7 +334,7 @@ fun MidiControlPanel(
|
|||
Text(
|
||||
text = "bpm",
|
||||
color = Color.White.copy(0.6f),
|
||||
fontSize = 12.sp,
|
||||
fontSize = MaterialTheme.typography.bodyMedium.fontSize,
|
||||
modifier = Modifier.padding(end = 8.dp)
|
||||
)
|
||||
}
|
||||
|
|
@ -340,8 +366,8 @@ fun MidiControlPanel(
|
|||
},
|
||||
colors = ButtonDefaults.buttonColors(
|
||||
containerColor = when {
|
||||
(isWaitingForB || isLooping) -> Color.Red
|
||||
else -> Color.LightGray
|
||||
(isWaitingForB || isLooping) -> MaterialTheme.colorScheme.error
|
||||
else -> MaterialTheme.colorScheme.onError
|
||||
}
|
||||
),
|
||||
contentPadding = PaddingValues(horizontal = 2.dp, vertical = 0.dp),
|
||||
|
|
@ -356,7 +382,7 @@ fun MidiControlPanel(
|
|||
Text(
|
||||
text = "A",
|
||||
color = if (isWaitingForB || isLooping) Color.White else Color.Black,
|
||||
fontSize = 16.sp
|
||||
fontSize = MaterialTheme.typography.titleLarge.fontSize
|
||||
)
|
||||
|
||||
Icon(
|
||||
|
|
@ -369,7 +395,7 @@ fun MidiControlPanel(
|
|||
Text(
|
||||
text = "B",
|
||||
color = if (isLooping) Color.White else Color.Black,
|
||||
fontSize = 16.sp
|
||||
fontSize = MaterialTheme.typography.titleLarge.fontSize
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -388,106 +414,60 @@ fun MidiControlPanel(
|
|||
Icon(
|
||||
painter = painterResource(Res.drawable.ic_mixer_satb),
|
||||
contentDescription = "SATB",
|
||||
tint = if (showSATBTools) Color.White else Color.Black,
|
||||
tint = if (showSATBTools) MaterialTheme.colorScheme.background else MaterialTheme.colorScheme.onSecondary,
|
||||
modifier = Modifier.size(35.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
|
||||
val playPauseButton = @Composable {
|
||||
IconButton(
|
||||
onClick = onPlayPauseClick,
|
||||
modifier = Modifier
|
||||
.size(48.dp)
|
||||
.background(MaterialTheme.colorScheme.primary, CircleShape)
|
||||
) {
|
||||
Icon(
|
||||
imageVector = if (isPause) Icons.Filled.PlayArrow else Icons.Filled.Pause,
|
||||
contentDescription = "Play/Pause",
|
||||
tint = Color.White
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
val instrumentButton = @Composable {
|
||||
IconButton(
|
||||
onClick = {
|
||||
isPianoSelected = !isPianoSelected
|
||||
mediaPlayer?.changeInstru(if (isPianoSelected) 1 else 20)
|
||||
}
|
||||
) {
|
||||
if (isPianoSelected) {
|
||||
Icon(
|
||||
imageVector = Icons.Default.Piano,
|
||||
contentDescription = "Piano",
|
||||
tint = MaterialTheme.colorScheme.onSecondary
|
||||
)
|
||||
} else {
|
||||
Icon(
|
||||
painter = painterResource(Res.drawable.ic_organ),
|
||||
contentDescription = "Orgue",
|
||||
tint = MaterialTheme.colorScheme.onSecondary,
|
||||
modifier = Modifier.size(25.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (platform.startsWith("Android")) {
|
||||
Column(
|
||||
modifier = Modifier.wrapContentWidth(),
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
IconButton(
|
||||
onClick = onPlayPauseClick,
|
||||
modifier = Modifier.size(48.dp).background(MaterialTheme.colorScheme.primary, CircleShape)
|
||||
) {
|
||||
Icon(
|
||||
imageVector = if (isPause) Icons.Filled.PlayArrow else Icons.Filled.Pause,
|
||||
contentDescription = "Pla",
|
||||
tint = Color.White
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
playPauseButton()
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
|
||||
Column {
|
||||
IconButton(
|
||||
onClick = {
|
||||
isPianoSelected = !isPianoSelected
|
||||
if (isPianoSelected) {
|
||||
mediaPlayer?.changeInstru(1)
|
||||
instrumentButton()
|
||||
} else {
|
||||
mediaPlayer?.changeInstru(20)
|
||||
}
|
||||
|
||||
}
|
||||
) {
|
||||
if (isPianoSelected) {
|
||||
Icon(
|
||||
Icons.Default.Piano,
|
||||
contentDescription = "Piano",
|
||||
tint = Color.Black
|
||||
)
|
||||
} else {
|
||||
Icon(
|
||||
painter = painterResource(Res.drawable.ic_organ),
|
||||
contentDescription = "Orgue",
|
||||
tint = Color.Black,
|
||||
modifier = Modifier.size(25.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Column {
|
||||
IconButton(
|
||||
onClick = {
|
||||
isPianoSelected = !isPianoSelected
|
||||
if (isPianoSelected) {
|
||||
mediaPlayer?.changeInstru(1)
|
||||
} else {
|
||||
mediaPlayer?.changeInstru(20)
|
||||
}
|
||||
|
||||
}
|
||||
) {
|
||||
if (isPianoSelected) {
|
||||
Icon(
|
||||
Icons.Default.Piano,
|
||||
contentDescription = "Piano",
|
||||
tint = Color.Black
|
||||
)
|
||||
} else {
|
||||
Icon(
|
||||
painter = painterResource(Res.drawable.ic_organ),
|
||||
contentDescription = "Orgue",
|
||||
tint = Color.Black,
|
||||
modifier = Modifier.size(25.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
instrumentButton()
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
Column(
|
||||
modifier = Modifier.wrapContentWidth(),
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
IconButton(
|
||||
onClick = onPlayPauseClick,
|
||||
modifier = Modifier.size(48.dp).background(MaterialTheme.colorScheme.primary, CircleShape)
|
||||
) {
|
||||
Icon(
|
||||
imageVector = if (isPause) Icons.Filled.PlayArrow else Icons.Filled.Pause,
|
||||
contentDescription = "Pla",
|
||||
tint = Color.White
|
||||
)
|
||||
}
|
||||
}
|
||||
playPauseButton()
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -512,7 +492,7 @@ fun MidiControlPanel(
|
|||
Icon(
|
||||
imageVector = if (expandedCtl) Icons.Default.MoreHoriz else Icons.Default.MoreVert,
|
||||
contentDescription = "More",
|
||||
tint = Color.White
|
||||
tint = MaterialTheme.colorScheme.onSecondary
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import androidx.compose.material.icons.automirrored.filled.VolumeOff
|
|||
import androidx.compose.material.icons.automirrored.filled.VolumeUp
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Slider
|
||||
import androidx.compose.material3.SliderDefaults
|
||||
import androidx.compose.runtime.Composable
|
||||
|
|
@ -34,7 +35,7 @@ fun ModernVolumeSlider(
|
|||
verticalAlignment = Alignment.CenterVertically,
|
||||
modifier = Modifier
|
||||
.height(42.dp)
|
||||
.background(Color.White.copy(alpha = 0.1f), CircleShape)
|
||||
.background(MaterialTheme.colorScheme.onSecondary.copy(alpha = 0.1f), CircleShape)
|
||||
.padding(horizontal = 12.dp, vertical = 4.dp)
|
||||
) {
|
||||
Icon(
|
||||
|
|
@ -44,7 +45,7 @@ fun ModernVolumeSlider(
|
|||
else -> Icons.AutoMirrored.Filled.VolumeUp
|
||||
},
|
||||
contentDescription = null,
|
||||
tint = if (volume > 0) Color.Black else Color.Gray,
|
||||
tint = if (volume > 0) MaterialTheme.colorScheme.onSecondary else Color.Gray,
|
||||
modifier = Modifier.size(20.dp)
|
||||
)
|
||||
|
||||
|
|
@ -55,8 +56,8 @@ fun ModernVolumeSlider(
|
|||
onValueChange = onVolumeChange,
|
||||
modifier = Modifier.fillMaxWidth(0.30f),
|
||||
colors = SliderDefaults.colors(
|
||||
activeTrackColor = Color(0xFFF59E0B),
|
||||
inactiveTrackColor = Color.White.copy(alpha = 0.2f),
|
||||
activeTrackColor = MaterialTheme.colorScheme.primary,
|
||||
inactiveTrackColor = MaterialTheme.colorScheme.onSecondary.copy(alpha = 0.6f),
|
||||
thumbColor = Color.Transparent
|
||||
),
|
||||
track = { sliderState ->
|
||||
|
|
|
|||
|
|
@ -5,12 +5,16 @@ import androidx.compose.foundation.Image
|
|||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.Card
|
||||
import androidx.compose.material3.CardDefaults
|
||||
import androidx.compose.material3.CircularProgressIndicator
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.OutlinedButton
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextButton
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.produceState
|
||||
|
|
@ -26,6 +30,7 @@ import androidx.compose.ui.unit.sp
|
|||
import feufaro.composeapp.generated.resources.Res
|
||||
import feufaro.composeapp.generated.resources.compose_multiplatform
|
||||
import mg.dot.feufaro.FileRepository
|
||||
import mg.dot.feufaro.MGButton
|
||||
import mg.dot.feufaro.solfa.ColorPrefixA
|
||||
import mg.dot.feufaro.solfa.ColorPrefixB
|
||||
import mg.dot.feufaro.solfa.ColorValue
|
||||
|
|
@ -62,48 +67,59 @@ fun QRDisplay(sharedScreenModel: SharedScreenModel, fileRepository: FileReposito
|
|||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.background(Color.Black.copy(alpha = 0.6f)) // Assombrissement moderne
|
||||
.clickable { sharedScreenModel.toggleQRCodeVisibility() } // Fermer au clic
|
||||
.imePadding()
|
||||
.systemBarsPadding(),
|
||||
contentAlignment = Alignment.Center
|
||||
.background(Color.Black.copy(alpha = 0.4f))
|
||||
.clickable { sharedScreenModel.toggleQRCodeVisibility() },
|
||||
contentAlignment = Alignment.BottomCenter
|
||||
) {
|
||||
BoxWithConstraints(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
contentAlignment = Alignment.BottomCenter
|
||||
) {
|
||||
val screenHeight = maxHeight
|
||||
Card(
|
||||
modifier = Modifier
|
||||
.width(400.dp)
|
||||
.wrapContentHeight()
|
||||
.shadow(24.dp, shape = RoundedCornerShape(28.dp)),
|
||||
shape = RoundedCornerShape(28.dp),
|
||||
.fillMaxWidth()
|
||||
.widthIn(max = 450.dp)
|
||||
.height(screenHeight * 0.85f)
|
||||
.clickable(enabled = false) {}
|
||||
.shadow(16.dp, shape = RoundedCornerShape(topStart = 32.dp, topEnd = 32.dp)),
|
||||
shape = RoundedCornerShape(topStart = 32.dp, topEnd = 32.dp),
|
||||
colors = CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.surface)
|
||||
) {
|
||||
Column(
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
modifier = Modifier.padding(24.dp)
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 24.dp)
|
||||
.padding(top = 12.dp, bottom = 32.dp)
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.size(width = 40.dp, height = 4.dp)
|
||||
.clip(CircleShape)
|
||||
.background(MaterialTheme.colorScheme.onSurfaceVariant.copy(alpha = 0.3f))
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(12.dp))
|
||||
Text(
|
||||
text = "Partager la partition",
|
||||
text = "Scanner ce QR Code",
|
||||
style = MaterialTheme.typography.titleLarge.copy(
|
||||
fontWeight = FontWeight.Bold,
|
||||
letterSpacing = 0.5.sp
|
||||
fontSize = 22.sp
|
||||
)
|
||||
)
|
||||
|
||||
Text(
|
||||
text = "Scannez pour ouvrir instantanément",
|
||||
style = MaterialTheme.typography.bodyMedium.copy(
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant
|
||||
),
|
||||
modifier = Modifier.padding(top = 4.dp, bottom = 24.dp)
|
||||
)
|
||||
Spacer(modifier = Modifier.height(5.dp))
|
||||
|
||||
if (qrCodeImage != null) {
|
||||
Box(
|
||||
contentAlignment = Alignment.Center,
|
||||
modifier = Modifier
|
||||
.size(350.dp)
|
||||
.clip(RoundedCornerShape(16.dp))
|
||||
.background(Color.White)
|
||||
.padding(5.dp)
|
||||
.weight(10f)
|
||||
.fillMaxHeight(1f)
|
||||
.aspectRatio(1f)
|
||||
.clip(RoundedCornerShape(24.dp))
|
||||
.padding(12.dp)
|
||||
) {
|
||||
Image(
|
||||
bitmap = qrCodeImage!!,
|
||||
|
|
@ -113,7 +129,8 @@ fun QRDisplay(sharedScreenModel: SharedScreenModel, fileRepository: FileReposito
|
|||
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.size(54.dp)
|
||||
.fillMaxHeight(0.18f)
|
||||
.aspectRatio(1f)
|
||||
.background(Color.White, shape = RoundedCornerShape(12.dp))
|
||||
.padding(4.dp),
|
||||
contentAlignment = Alignment.Center
|
||||
|
|
@ -143,15 +160,36 @@ fun QRDisplay(sharedScreenModel: SharedScreenModel, fileRepository: FileReposito
|
|||
Text(
|
||||
text = "Génération du QR Code...",
|
||||
style = MaterialTheme.typography.bodyMedium.copy(
|
||||
color = ColorValue,
|
||||
fontWeight = FontWeight.Medium
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant.copy(alpha = 0.7f)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
Spacer(modifier = Modifier.height(2.dp))
|
||||
|
||||
Spacer(modifier = Modifier.height(12.dp))
|
||||
Text(
|
||||
text = "Partager et charger rapidement cette partition",
|
||||
style = MaterialTheme.typography.bodyMedium.copy(
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant.copy(alpha = 0.6f),
|
||||
letterSpacing = 0.2.sp
|
||||
)
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(2.dp))
|
||||
Button(
|
||||
onClick = { sharedScreenModel.toggleQRCodeVisibility() },
|
||||
modifier = Modifier
|
||||
.width(450.dp),
|
||||
|
||||
) {
|
||||
Text(
|
||||
text = "Fermer",
|
||||
fontWeight = FontWeight.Bold,
|
||||
fontSize = 16.sp
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,14 +1,19 @@
|
|||
package mg.dot.feufaro.ui
|
||||
|
||||
import SharedScreenModel
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.animation.core.animateFloatAsState
|
||||
import androidx.compose.animation.core.tween
|
||||
import androidx.compose.foundation.*
|
||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.automirrored.filled.Undo
|
||||
import androidx.compose.material.icons.filled.DarkMode
|
||||
import androidx.compose.material.icons.filled.KeyboardArrowDown
|
||||
import androidx.compose.material.icons.filled.LightMode
|
||||
import androidx.compose.material3.*
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Alignment
|
||||
|
|
@ -20,10 +25,12 @@ import androidx.compose.ui.text.font.FontWeight
|
|||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import SharedScreenModel
|
||||
import androidx.compose.material.icons.automirrored.filled.Undo
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import mg.dot.feufaro.DisplayConfigManager
|
||||
import mg.dot.feufaro.getPlatform
|
||||
import mg.dot.feufaro.midi.Dynamic
|
||||
import org.koin.compose.koinInject
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
|
|
@ -39,6 +46,22 @@ fun Settings(
|
|||
val isFullScreenEnabled by sharedScreenModel.isFullScreen.collectAsState()
|
||||
val platform = getPlatform()
|
||||
val isAndroid = platform.name.startsWith("Android")
|
||||
|
||||
// Load Configurations
|
||||
val displayConfigManager = koinInject<DisplayConfigManager>()
|
||||
val currentDisplayConfig by displayConfigManager.displayConfig.collectAsState()
|
||||
|
||||
val currentTheme = currentDisplayConfig.themeMode
|
||||
val isDarkModeActive = currentTheme == "DARK"
|
||||
val configScope = CoroutineScope(Dispatchers.Default)
|
||||
|
||||
var tempDarkMode by remember(currentDisplayConfig.themeMode) {
|
||||
mutableStateOf(currentDisplayConfig.themeMode == "DARK")
|
||||
}
|
||||
var tempFontSize by remember(currentDisplayConfig.fontSize) {
|
||||
mutableStateOf(currentDisplayConfig.fontSize)
|
||||
}
|
||||
|
||||
AlertDialog(
|
||||
onDismissRequest = onDismissRequest,
|
||||
title = {
|
||||
|
|
@ -63,8 +86,8 @@ fun Settings(
|
|||
onToggle = { expandedGeneral = !expandedGeneral }
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier.padding(8.dp),
|
||||
verticalArrangement = Arrangement.spacedBy(10.dp)
|
||||
modifier = Modifier.padding(16.dp),
|
||||
verticalArrangement = Arrangement.spacedBy(8.dp)
|
||||
) {
|
||||
if(isAndroid) {
|
||||
Row(
|
||||
|
|
@ -81,6 +104,109 @@ fun Settings(
|
|||
)
|
||||
}
|
||||
}
|
||||
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(vertical = 4.dp),
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Text(
|
||||
text = "Thème Sombre",
|
||||
style = MaterialTheme.typography.bodyLarge,
|
||||
color = MaterialTheme.colorScheme.onSurface
|
||||
)
|
||||
|
||||
Switch(
|
||||
checked = tempDarkMode,
|
||||
onCheckedChange = { checked ->
|
||||
val newMode = if (checked) "DARK" else "LIGHT"
|
||||
displayConfigManager.updateThemeMode(newMode)
|
||||
},
|
||||
thumbContent = {
|
||||
Icon(
|
||||
imageVector = if (tempDarkMode) Icons.Default.DarkMode else Icons.Default.LightMode,
|
||||
contentDescription = null,
|
||||
tint = MaterialTheme.colorScheme.onSecondary
|
||||
)
|
||||
},
|
||||
colors = SwitchDefaults.colors(
|
||||
checkedThumbColor = MaterialTheme.colorScheme.primary,
|
||||
checkedTrackColor = MaterialTheme.colorScheme.primary.copy(alpha = 0.4f),
|
||||
uncheckedThumbColor = MaterialTheme.colorScheme.error,
|
||||
uncheckedTrackColor = MaterialTheme.colorScheme.error.copy(alpha = 0.2f),
|
||||
checkedBorderColor = Color.Transparent,
|
||||
uncheckedBorderColor = Color.Transparent,
|
||||
checkedIconColor = Color.White,
|
||||
uncheckedIconColor = MaterialTheme.colorScheme.onTertiary,
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
HorizontalDivider(color = MaterialTheme.colorScheme.surfaceVariant.copy(alpha = 0.5f))
|
||||
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(vertical = 4.dp),
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Text(
|
||||
text = "Taille de la police",
|
||||
style = MaterialTheme.typography.bodyLarge,
|
||||
color = MaterialTheme.colorScheme.onSurface
|
||||
)
|
||||
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(15.dp)
|
||||
) {
|
||||
IconButton(
|
||||
onClick = {
|
||||
if (currentDisplayConfig.fontSize > 8f) {
|
||||
displayConfigManager.updateFontSize(currentDisplayConfig.fontSize - 0.5f)
|
||||
}
|
||||
},
|
||||
modifier = Modifier.size(25.dp).background(MaterialTheme.colorScheme.primary, CircleShape)
|
||||
) {
|
||||
Text("-", fontWeight = FontWeight.Bold, style = MaterialTheme.typography.titleLarge, color = Color.White)
|
||||
}
|
||||
|
||||
OutlinedTextField(
|
||||
value = tempFontSize.toString(),
|
||||
onValueChange = {},
|
||||
readOnly = true,
|
||||
textStyle = MaterialTheme.typography.titleMedium.copy(textAlign = TextAlign.Center),
|
||||
modifier = Modifier.width(80.dp),
|
||||
shape = RoundedCornerShape(12.dp)
|
||||
)
|
||||
|
||||
IconButton(
|
||||
onClick = {
|
||||
if (currentDisplayConfig.fontSize < 30f) {
|
||||
displayConfigManager.updateFontSize(currentDisplayConfig.fontSize + 0.5f)
|
||||
}
|
||||
},
|
||||
modifier = Modifier.size(25.dp).background(MaterialTheme.colorScheme.primary, CircleShape)
|
||||
) {
|
||||
Text("+", fontWeight = FontWeight.Bold, style = MaterialTheme.typography.titleLarge, color = Color.White)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
OutlinedButton(
|
||||
onClick = { displayConfigManager.resetToDefault() },
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
shape = RoundedCornerShape(12.dp),
|
||||
colors = ButtonDefaults.outlinedButtonColors(
|
||||
contentColor = MaterialTheme.colorScheme.error
|
||||
)
|
||||
) {
|
||||
Text("Réinitialiser", style = MaterialTheme.typography.labelLarge)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -145,7 +271,7 @@ fun Settings(
|
|||
Icon(
|
||||
imageVector = Icons.AutoMirrored.Default.Undo,
|
||||
contentDescription = null,
|
||||
tint = Color.Red
|
||||
tint = MaterialTheme.colorScheme.error
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ package mg.dot.feufaro.ui
|
|||
|
||||
import SharedScreenModel
|
||||
import androidx.compose.animation.core.animateFloatAsState
|
||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.*
|
||||
|
|
@ -13,9 +12,8 @@ import androidx.compose.foundation.lazy.rememberLazyListState
|
|||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.automirrored.filled.EventNote
|
||||
import androidx.compose.material.icons.automirrored.filled.Note
|
||||
import androidx.compose.material.icons.automirrored.filled.StarHalf
|
||||
import androidx.compose.material.icons.automirrored.filled.ListAlt
|
||||
import androidx.compose.material.icons.automirrored.filled.PlaylistPlay
|
||||
import androidx.compose.material.icons.filled.*
|
||||
import androidx.compose.material3.*
|
||||
import androidx.compose.runtime.*
|
||||
|
|
@ -25,7 +23,6 @@ import androidx.compose.ui.draw.rotate
|
|||
import androidx.compose.ui.draw.scale
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.text.TextStyle
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
|
|
@ -87,23 +84,28 @@ fun SimpleDrawerContent(
|
|||
onCheckedChange = { newState ->
|
||||
sharedScreenModel.toggleEditorMode(newState)
|
||||
},
|
||||
label = "Mode Edit",
|
||||
color = MaterialTheme.colorScheme.primary
|
||||
thumbIcon = Icons.Default.Edit,
|
||||
label = "Mode Edit"
|
||||
)
|
||||
|
||||
CustomSwitchItem(
|
||||
checked = state1,
|
||||
onCheckedChange = { state1 = it },
|
||||
thumbIcon = Icons.Default.MusicNote,
|
||||
label = "Analyse chords",
|
||||
color = Color(0xFFE57373)
|
||||
)
|
||||
|
||||
CustomSwitchItem(
|
||||
checked = state2,
|
||||
onCheckedChange = { state2 = it },
|
||||
label = "Titre 3",
|
||||
color = Color(0xFFBFBF11)
|
||||
)
|
||||
Column(
|
||||
modifier = Modifier.padding(5.dp),
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
IconButton(
|
||||
onClick = { },
|
||||
modifier = Modifier.background(Color(0xFF81C784), shape = CircleShape).size(40.dp)
|
||||
) {
|
||||
Icon(Icons.Default.Add, contentDescription = null, tint = Color.White)
|
||||
}
|
||||
Text("Ajouter", style = MaterialTheme.typography.labelSmall)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -123,8 +125,7 @@ fun SimpleDrawerContent(
|
|||
stickyHeader {
|
||||
DrawerHeaderSticky(
|
||||
title = "Solfa disponibles",
|
||||
icon = Icons.AutoMirrored.Filled.Note,
|
||||
color = MaterialTheme.colorScheme.primary,
|
||||
icon = Icons.AutoMirrored.Filled.ListAlt,
|
||||
isExpanded = internalExpanded,
|
||||
onToggle = { internalExpanded = !internalExpanded },
|
||||
count = internalList.size
|
||||
|
|
@ -134,11 +135,29 @@ fun SimpleDrawerContent(
|
|||
if (internalExpanded) {
|
||||
items(internalList) { item ->
|
||||
val isSelected = item.path == activePath
|
||||
val favoriteLists by sharedScreenModel.playlistItems.collectAsState()
|
||||
val isFavorite = favoriteLists.contains(item)
|
||||
|
||||
NavigationDrawerItem(
|
||||
icon = {
|
||||
Text("\uD834\uDD1E", fontSize = 18.sp)
|
||||
Text("\uD834\uDD1E", fontSize = 22.sp)
|
||||
},
|
||||
label = { DrawerItemLabel(item) },
|
||||
badge = {
|
||||
IconButton(
|
||||
onClick = {
|
||||
sharedScreenModel.toggleFavorite(item.path)
|
||||
},
|
||||
modifier = Modifier.size(32.dp)
|
||||
) {
|
||||
Icon(
|
||||
imageVector = Icons.Default.PlaylistAddCircle,
|
||||
contentDescription = null,
|
||||
tint = if (!isFavorite) Color.LightGray else Color(0xFFFFD700),
|
||||
modifier = Modifier.size(18.dp)
|
||||
)
|
||||
}
|
||||
},
|
||||
label = { DrawerItemLabel(item, sharedScreenModel) },
|
||||
selected = isSelected,
|
||||
onClick = {
|
||||
scope.launch { drawerState.close() }
|
||||
|
|
@ -149,8 +168,8 @@ fun SimpleDrawerContent(
|
|||
shape = RoundedCornerShape(5.dp),
|
||||
modifier = Modifier.padding(horizontal = 12.dp, vertical = 2.dp),
|
||||
colors = NavigationDrawerItemDefaults.colors(
|
||||
selectedContainerColor = Color(0, 157, 255).copy(alpha = 0.1f),
|
||||
selectedTextColor = Color(0, 157, 255)
|
||||
selectedContainerColor = MaterialTheme.colorScheme.primary.copy(alpha = 0.12f),
|
||||
selectedTextColor = MaterialTheme.colorScheme.primary
|
||||
)
|
||||
)
|
||||
}
|
||||
|
|
@ -159,8 +178,7 @@ fun SimpleDrawerContent(
|
|||
stickyHeader {
|
||||
DrawerHeaderSticky(
|
||||
title = "Personnel",
|
||||
icon = Icons.AutoMirrored.Filled.EventNote,
|
||||
color = MaterialTheme.colorScheme.tertiary,
|
||||
icon = Icons.Default.LibraryMusic,
|
||||
isExpanded = externalExpanded,
|
||||
onToggle = { externalExpanded = !externalExpanded },
|
||||
count = externalList.size
|
||||
|
|
@ -170,12 +188,30 @@ fun SimpleDrawerContent(
|
|||
if (externalExpanded) {
|
||||
items(externalList) { item ->
|
||||
val isSelected = item.path == activePath
|
||||
val favoriteLists by sharedScreenModel.playlistItems.collectAsState()
|
||||
val isFavorite = favoriteLists.contains(item)
|
||||
|
||||
if (item.path != "") {
|
||||
NavigationDrawerItem(
|
||||
icon = {
|
||||
Text("♬", fontSize = 18.sp)
|
||||
Text("♬", fontSize = 20.sp)
|
||||
},
|
||||
label = { DrawerItemLabel(item) },
|
||||
badge = {
|
||||
IconButton(
|
||||
onClick = {
|
||||
sharedScreenModel.toggleFavorite(item.path)
|
||||
},
|
||||
modifier = Modifier.size(32.dp)
|
||||
) {
|
||||
Icon(
|
||||
imageVector = Icons.Default.PlaylistAddCircle,
|
||||
contentDescription = null,
|
||||
tint = if (!isFavorite) Color.LightGray else Color(0xFFFFD700),
|
||||
modifier = Modifier.size(18.dp)
|
||||
)
|
||||
}
|
||||
},
|
||||
label = { DrawerItemLabel(item, sharedScreenModel) },
|
||||
selected = isSelected,
|
||||
onClick = {
|
||||
scope.launch { drawerState.close() }
|
||||
|
|
@ -186,8 +222,8 @@ fun SimpleDrawerContent(
|
|||
shape = RoundedCornerShape(5.dp),
|
||||
modifier = Modifier.padding(horizontal = 12.dp, vertical = 2.dp),
|
||||
colors = NavigationDrawerItemDefaults.colors(
|
||||
selectedContainerColor = Color.Blue.copy(alpha = 0.1f),
|
||||
selectedTextColor = Color.Blue
|
||||
selectedContainerColor = MaterialTheme.colorScheme.secondary.copy(alpha = 0.5f),
|
||||
selectedTextColor = MaterialTheme.colorScheme.onSecondary
|
||||
)
|
||||
)
|
||||
}
|
||||
|
|
@ -197,8 +233,7 @@ fun SimpleDrawerContent(
|
|||
stickyHeader {
|
||||
DrawerHeaderSticky(
|
||||
title = "Playlist",
|
||||
icon = Icons.AutoMirrored.Filled.StarHalf,
|
||||
color = MaterialTheme.colorScheme.tertiary,
|
||||
icon = Icons.AutoMirrored.Filled.PlaylistPlay,
|
||||
isExpanded = playListExpanded,
|
||||
onToggle = { playListExpanded = !playListExpanded },
|
||||
count = playList.size
|
||||
|
|
@ -211,8 +246,36 @@ fun SimpleDrawerContent(
|
|||
val isSelected = item.path == activePath
|
||||
|
||||
NavigationDrawerItem(
|
||||
icon = {
|
||||
Text("♯", fontSize = 22.sp)
|
||||
},
|
||||
label = {
|
||||
DrawerFavorisItemLabel(item, index, isSelected, sharedScreenModel)
|
||||
DrawerItemLabel(item)
|
||||
},
|
||||
badge = {
|
||||
if (index > 0) {
|
||||
IconButton(
|
||||
onClick = { sharedScreenModel.moveToTop(index) },
|
||||
modifier = Modifier.size(30.dp)
|
||||
) {
|
||||
Icon(
|
||||
imageVector = Icons.Default.VerticalAlignTop,
|
||||
contentDescription = null,
|
||||
modifier = Modifier.size(16.dp),
|
||||
tint = MaterialTheme.colorScheme.onSecondary
|
||||
)
|
||||
}
|
||||
}
|
||||
IconButton(
|
||||
onClick = { sharedScreenModel.toggleFavorite(item.path) },
|
||||
modifier = Modifier.size(30.dp)
|
||||
) {
|
||||
Icon(
|
||||
imageVector = Icons.Default.Star,
|
||||
contentDescription = null,
|
||||
tint = if (isSelected) MaterialTheme.colorScheme.background else MaterialTheme.colorScheme.tertiary
|
||||
)
|
||||
}
|
||||
},
|
||||
selected = isSelected,
|
||||
onClick = {
|
||||
|
|
@ -221,11 +284,11 @@ fun SimpleDrawerContent(
|
|||
solfaScreenModel.loadFromFile(item.path)
|
||||
onSongSelected(midi)
|
||||
},
|
||||
shape = RoundedCornerShape(5.dp),
|
||||
modifier = Modifier.padding(horizontal = 12.dp, vertical = 2.dp),
|
||||
colors = NavigationDrawerItemDefaults.colors(
|
||||
selectedContainerColor = Color(0xFFFFD700).copy(alpha = 0.3f),
|
||||
selectedTextColor = Color(0xFF665500),
|
||||
selectedIconColor = Color(0xFF665500)
|
||||
selectedContainerColor = MaterialTheme.colorScheme.tertiary.copy(alpha = 0.5f),
|
||||
selectedTextColor = MaterialTheme.colorScheme.onTertiary,
|
||||
)
|
||||
)
|
||||
}
|
||||
|
|
@ -250,7 +313,7 @@ fun SimpleDrawerContent(
|
|||
IconButton(onClick = {
|
||||
scope.launch { drawerState.close() }
|
||||
}) {
|
||||
Icon(Icons.Default.GraphicEq, contentDescription = null, tint = MaterialTheme.colorScheme.primary)
|
||||
Icon(Icons.Default.GraphicEq, contentDescription = null, tint = MaterialTheme.colorScheme.onSecondary)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -263,7 +326,7 @@ fun SimpleDrawerContent(
|
|||
solfaScreenModel.loadCustomFile()
|
||||
scope.launch { drawerState.close() }
|
||||
}) {
|
||||
Icon(Icons.Default.FolderOpen, contentDescription = null)
|
||||
Icon(Icons.Default.FolderOpen, contentDescription = null, tint = MaterialTheme.colorScheme.onSecondary)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -276,7 +339,7 @@ fun SimpleDrawerContent(
|
|||
onSettingsCheck()
|
||||
scope.launch { drawerState.close() }
|
||||
}) {
|
||||
Icon(Icons.Default.Settings, contentDescription = null)
|
||||
Icon(Icons.Default.Settings, contentDescription = null, tint = MaterialTheme.colorScheme.onSecondary)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -288,7 +351,7 @@ fun SimpleDrawerContent(
|
|||
IconButton(onClick = {
|
||||
scope.launch { drawerState.close() }
|
||||
}) {
|
||||
Icon(Icons.Default.Info, contentDescription = null)
|
||||
Icon(Icons.Default.Info, contentDescription = null, tint = MaterialTheme.colorScheme.onSecondary)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -300,7 +363,6 @@ fun SimpleDrawerContent(
|
|||
fun DrawerHeaderSticky(
|
||||
title: String,
|
||||
icon: ImageVector,
|
||||
color: Color,
|
||||
isExpanded: Boolean,
|
||||
onToggle: () -> Unit,
|
||||
count: Int
|
||||
|
|
@ -315,23 +377,23 @@ fun DrawerHeaderSticky(
|
|||
modifier = Modifier.padding(16.dp),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Icon(icon, contentDescription = null, tint = color, modifier = Modifier.size(20.dp))
|
||||
Icon(icon, contentDescription = null, tint = MaterialTheme.colorScheme.primary, modifier = Modifier.size(20.dp))
|
||||
Spacer(Modifier.width(12.dp))
|
||||
Text(
|
||||
text = "$title".uppercase(),
|
||||
text = title.uppercase(),
|
||||
modifier = Modifier.weight(1f),
|
||||
style = MaterialTheme.typography.labelLarge.copy(fontWeight = FontWeight.Bold),
|
||||
color = color
|
||||
style = MaterialTheme.typography.titleSmall.copy(fontWeight = FontWeight.Bold),
|
||||
color = MaterialTheme.colorScheme.primary
|
||||
)
|
||||
Surface(
|
||||
color = Color.Green.copy(alpha = 0.1f),
|
||||
color = MaterialTheme.colorScheme.error.copy(alpha = 0.1f),
|
||||
shape = MaterialTheme.shapes.extraSmall
|
||||
) {
|
||||
Text(
|
||||
text = "${count}",
|
||||
text = count.toString() ,
|
||||
modifier = Modifier.padding(horizontal = 6.dp, vertical = 2.dp),
|
||||
style = MaterialTheme.typography.labelSmall,
|
||||
color = Color.Green
|
||||
color = MaterialTheme.colorScheme.error
|
||||
)
|
||||
}
|
||||
Icon(
|
||||
|
|
@ -344,94 +406,25 @@ fun DrawerHeaderSticky(
|
|||
}
|
||||
|
||||
@Composable
|
||||
fun DrawerItemLabel(item: DrawerItem, sharedScreenModel: SharedScreenModel) {
|
||||
val favoriteLists by sharedScreenModel.playlistItems.collectAsState()
|
||||
val isFavorite = favoriteLists.contains(item)
|
||||
fun DrawerItemLabel(item: DrawerItem) {
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.SpaceBetween
|
||||
) {
|
||||
Column(modifier = Modifier.weight(1f)) {
|
||||
Text(text = item.title, fontWeight = FontWeight.SemiBold, style = MaterialTheme.typography.bodyMedium)
|
||||
Text(text = item.title, fontWeight = FontWeight.SemiBold, style = MaterialTheme.typography.titleSmall)
|
||||
Text(text = item.contentTitle, style = MaterialTheme.typography.labelSmall, maxLines = 1)
|
||||
}
|
||||
|
||||
Row {
|
||||
IconButton(
|
||||
onClick = {
|
||||
sharedScreenModel.toggleFavorite(item.path)
|
||||
},
|
||||
modifier = Modifier.size(32.dp)
|
||||
) {
|
||||
Icon(
|
||||
imageVector = Icons.Default.PlaylistAddCircle,
|
||||
contentDescription = null,
|
||||
tint = if (!isFavorite) Color.LightGray else Color(0xFFFFD700),
|
||||
modifier = Modifier.size(18.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun DrawerFavorisItemLabel(item: DrawerItem, index: Int, isSelected: Boolean, sharedScreenModel: SharedScreenModel) {
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Icon(
|
||||
imageVector = Icons.Default.Reorder,
|
||||
contentDescription = null,
|
||||
modifier = Modifier.padding(end = 8.dp).size(18.dp),
|
||||
tint = Color.Gray.copy(alpha = 0.5f)
|
||||
)
|
||||
Column(modifier = Modifier.weight(1f)) {
|
||||
Text(
|
||||
text = item.title,
|
||||
fontWeight = FontWeight.Bold,
|
||||
style = MaterialTheme.typography.bodyMedium
|
||||
)
|
||||
Text(
|
||||
text = item.contentTitle,
|
||||
style = MaterialTheme.typography.labelSmall,
|
||||
maxLines = 1
|
||||
)
|
||||
}
|
||||
|
||||
if (index > 0) {
|
||||
IconButton(
|
||||
onClick = { sharedScreenModel.moveToTop(index) },
|
||||
modifier = Modifier.size(30.dp)
|
||||
) {
|
||||
Icon(
|
||||
imageVector = Icons.Default.VerticalAlignTop,
|
||||
contentDescription = null,
|
||||
modifier = Modifier.size(16.dp),
|
||||
tint = if (isSelected) Color.White else Color.Gray
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
IconButton(
|
||||
onClick = { sharedScreenModel.toggleFavorite(item.path) },
|
||||
modifier = Modifier.size(30.dp)
|
||||
) {
|
||||
Icon(
|
||||
imageVector = Icons.Default.Star,
|
||||
contentDescription = null,
|
||||
tint = if (isSelected) Color.White else Color(0xFFFFD700)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@Composable
|
||||
fun CustomSwitchItem(
|
||||
checked: Boolean,
|
||||
onCheckedChange: (Boolean) -> Unit,
|
||||
label: String,
|
||||
color: Color
|
||||
thumbIcon: ImageVector
|
||||
) {
|
||||
Column(
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
|
|
@ -440,11 +433,20 @@ fun CustomSwitchItem(
|
|||
checked = checked,
|
||||
onCheckedChange = onCheckedChange,
|
||||
colors = SwitchDefaults.colors(
|
||||
checkedThumbColor = Color.White,
|
||||
checkedTrackColor = color,
|
||||
uncheckedTrackColor = color.copy(alpha = 0.3f)
|
||||
checkedThumbColor = MaterialTheme.colorScheme.error,
|
||||
checkedTrackColor = MaterialTheme.colorScheme.error.copy(alpha = 0.5f),
|
||||
uncheckedThumbColor = MaterialTheme.colorScheme.onBackground.copy(alpha = 0.4f),
|
||||
uncheckedTrackColor = MaterialTheme.colorScheme.onBackground.copy(alpha = 0.1f),
|
||||
uncheckedBorderColor = MaterialTheme.colorScheme.error.copy(alpha = 0.2f),
|
||||
),
|
||||
modifier = Modifier.scale(0.7f)
|
||||
modifier = Modifier.scale(0.8f),
|
||||
thumbContent = {
|
||||
Icon(
|
||||
imageVector = if (checked) thumbIcon else Icons.Default.Visibility,
|
||||
contentDescription = null,
|
||||
modifier = Modifier.size(SwitchDefaults.IconSize)
|
||||
)
|
||||
}
|
||||
)
|
||||
Text(
|
||||
text = label,
|
||||
|
|
|
|||
161
composeApp/src/commonMain/kotlin/mg/dot/feufaro/ui/Theme.kt
Normal file
161
composeApp/src/commonMain/kotlin/mg/dot/feufaro/ui/Theme.kt
Normal file
|
|
@ -0,0 +1,161 @@
|
|||
package mg.dot.feufaro.ui
|
||||
|
||||
import androidx.compose.foundation.isSystemInDarkTheme
|
||||
import androidx.compose.material3.ColorScheme
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Typography
|
||||
import androidx.compose.material3.darkColorScheme
|
||||
import androidx.compose.material3.lightColorScheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.text.TextStyle
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.sp
|
||||
|
||||
object ThemeDefaults {
|
||||
val PrimaryBlue = Color(0xFF5061FF)
|
||||
val AccentYellow = Color(0xFFFFFA54)
|
||||
val AccentGreen = Color(0xFF3EFF96)
|
||||
val AccentPink = Color(0xFFFF4FA8)
|
||||
|
||||
val LightBackground = Color(0xFFF9F9FB)
|
||||
val DarkBackground = Color(0xFF121214)
|
||||
|
||||
|
||||
fun getSelectedThemeColors(themeModeStr: String): Pair<ColorScheme, ColorScheme> {
|
||||
return when (themeModeStr.uppercase()) {
|
||||
"SYSTEM", "DARK", "LIGHT" -> Pair(
|
||||
lightColorScheme(
|
||||
primary = PrimaryBlue.copy(alpha = 0.85f),
|
||||
onPrimary = LightBackground,
|
||||
|
||||
secondary = AccentGreen.copy(alpha = 0.85f),
|
||||
onSecondary = DarkBackground,
|
||||
secondaryContainer = AccentGreen.copy(alpha = 0.85f),
|
||||
onSecondaryContainer = DarkBackground,
|
||||
|
||||
tertiary = AccentYellow.copy(alpha = 0.85f),
|
||||
onTertiary = DarkBackground,
|
||||
|
||||
error = AccentPink.copy(alpha = 0.85f),
|
||||
onError = LightBackground,
|
||||
|
||||
background = LightBackground,
|
||||
surface = LightBackground
|
||||
),
|
||||
darkColorScheme(
|
||||
primary = PrimaryBlue,
|
||||
onPrimary = LightBackground,
|
||||
|
||||
secondary = AccentGreen,
|
||||
onSecondary = LightBackground,
|
||||
secondaryContainer = AccentGreen,
|
||||
onSecondaryContainer = DarkBackground,
|
||||
|
||||
tertiary = AccentYellow,
|
||||
onTertiary = DarkBackground,
|
||||
|
||||
error = AccentPink,
|
||||
onError = LightBackground,
|
||||
|
||||
background = DarkBackground,
|
||||
surface = Color(0xFF1E1E24),
|
||||
onBackground = LightBackground,
|
||||
onSurface = LightBackground
|
||||
)
|
||||
)
|
||||
else -> Pair(
|
||||
lightColorScheme(primary = PrimaryBlue, background = LightBackground),
|
||||
darkColorScheme(primary = PrimaryBlue, background = DarkBackground)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun FeufaroTheme(
|
||||
themeModeSelected: String,
|
||||
userFontSize: Float,
|
||||
content: @Composable () -> Unit
|
||||
) {
|
||||
val (lightScheme, darkScheme) = ThemeDefaults.getSelectedThemeColors(themeModeSelected)
|
||||
val useDarkTheme = when (themeModeSelected.uppercase()) {
|
||||
"DARK" -> true
|
||||
"LIGHT" -> false
|
||||
else -> isSystemInDarkTheme()
|
||||
}
|
||||
|
||||
val colorScheme = if (useDarkTheme) darkScheme else lightScheme
|
||||
|
||||
val baseSize = userFontSize
|
||||
|
||||
val customTypography = Typography(
|
||||
displayLarge = TextStyle(
|
||||
fontSize = (baseSize * 2.4f).sp,
|
||||
letterSpacing = (-1).sp
|
||||
),
|
||||
displayMedium = TextStyle(
|
||||
fontSize = (baseSize * 2.0f).sp,
|
||||
letterSpacing = (-0.5).sp
|
||||
),
|
||||
displaySmall = TextStyle(
|
||||
fontSize = (baseSize * 1.7f).sp
|
||||
),
|
||||
|
||||
headlineLarge = TextStyle(
|
||||
fontSize = (baseSize * 1.5f).sp,
|
||||
letterSpacing = 0.sp
|
||||
),
|
||||
headlineMedium = TextStyle(
|
||||
fontSize = (baseSize * 1.35f).sp
|
||||
),
|
||||
headlineSmall = TextStyle(
|
||||
fontSize = (baseSize * 1.2f).sp
|
||||
),
|
||||
|
||||
titleLarge = TextStyle(
|
||||
fontSize = (baseSize + 4f).sp,
|
||||
letterSpacing = 0.15.sp
|
||||
),
|
||||
titleMedium = TextStyle(
|
||||
fontSize = (baseSize + 2f).sp,
|
||||
letterSpacing = 0.1.sp
|
||||
),
|
||||
titleSmall = TextStyle(
|
||||
fontSize = baseSize.sp,
|
||||
letterSpacing = 0.1.sp
|
||||
),
|
||||
|
||||
bodyLarge = TextStyle(
|
||||
fontSize = baseSize.sp,
|
||||
letterSpacing = 0.25.sp
|
||||
),
|
||||
bodyMedium = TextStyle(
|
||||
fontSize = (baseSize - 1.5f).sp,
|
||||
letterSpacing = 0.25.sp
|
||||
),
|
||||
bodySmall = TextStyle(
|
||||
fontSize = (baseSize - 3f).sp,
|
||||
letterSpacing = 0.4.sp
|
||||
),
|
||||
|
||||
labelLarge = TextStyle(
|
||||
fontSize = (baseSize - 0.5f).sp,
|
||||
letterSpacing = 0.1.sp
|
||||
),
|
||||
labelMedium = TextStyle(
|
||||
fontSize = (baseSize - 2.5f).sp,
|
||||
letterSpacing = 0.5.sp
|
||||
),
|
||||
labelSmall = TextStyle(
|
||||
fontSize = (baseSize - 4f).sp,
|
||||
letterSpacing = 0.5.sp
|
||||
)
|
||||
)
|
||||
|
||||
MaterialTheme(
|
||||
colorScheme = colorScheme,
|
||||
typography = customTypography,
|
||||
content = content
|
||||
)
|
||||
}
|
||||
|
|
@ -1,17 +1,19 @@
|
|||
package mg.dot.feufaro.ui
|
||||
|
||||
import androidx.compose.foundation.ScrollState
|
||||
import androidx.compose.foundation.ScrollbarStyle
|
||||
import androidx.compose.foundation.VerticalScrollbar
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.fillMaxHeight
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.rememberScrollbarAdapter
|
||||
import androidx.compose.foundation.lazy.LazyListState
|
||||
import androidx.compose.foundation.rememberScrollbarAdapter
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
||||
@Composable
|
||||
actual fun MyVerticalScrollbar (
|
||||
|
|
@ -29,10 +31,22 @@ actual fun MyVerticalScrollbar (
|
|||
else -> null
|
||||
}
|
||||
|
||||
val scrollbarUnhoverColor = MaterialTheme.colorScheme.secondary.copy(alpha = 0.85f)
|
||||
val scrollbarHoverColor = MaterialTheme.colorScheme.secondary
|
||||
val scrollbarBackground = MaterialTheme.colorScheme.onSecondary.copy(alpha = 0.25f)
|
||||
|
||||
if (adapter != null) {
|
||||
VerticalScrollbar(
|
||||
adapter = adapter,
|
||||
modifier = modifier.fillMaxHeight(0.5f).background(Color.Green.copy(0.75f))
|
||||
modifier = modifier.fillMaxHeight(0.5f).background(scrollbarBackground),
|
||||
style = ScrollbarStyle(
|
||||
minimalHeight = 16.dp,
|
||||
thickness = 8.dp,
|
||||
shape = RoundedCornerShape(4.dp),
|
||||
hoverDurationMillis = 250,
|
||||
unhoverColor = scrollbarUnhoverColor,
|
||||
hoverColor = scrollbarHoverColor
|
||||
)
|
||||
)
|
||||
//content()
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue