Add Settings Page on Drawer & Controls Dynamic velocity
This commit is contained in:
parent
89d0b850f8
commit
e2a5d18a20
4 changed files with 481 additions and 148 deletions
|
|
@ -1,6 +1,8 @@
|
|||
package mg.dot.feufaro.midi
|
||||
|
||||
enum class Dynamic(val velocity: Int, val label: String, val factor: Float) {
|
||||
import java.util.prefs.Preferences
|
||||
|
||||
enum class Dynamic(val velocity: Int, val label: String, val defaultFactor: Float) {
|
||||
PPP(16, "ppp", 0.55f),
|
||||
PP (33, "pp", 0.66f),
|
||||
P (49, "p", 0.77f),
|
||||
|
|
@ -9,9 +11,29 @@ enum class Dynamic(val velocity: Int, val label: String, val factor: Float) {
|
|||
F (96, "f", 1.15f),
|
||||
FF (112, "ff", 1.35f),
|
||||
FFF(126, "fff", 1.60f);
|
||||
private val prefs = Preferences.userRoot().node("mg.dot.feufaro")
|
||||
var savedFactor: Float = prefs.getFloat("dynamic_${name.lowercase()}", defaultFactor)
|
||||
set(value) {
|
||||
field = value
|
||||
prefs.putFloat("dynamic_${name.lowercase()}", value)
|
||||
}
|
||||
|
||||
val factor: Float
|
||||
get() = if (isGloballyEnabled) savedFactor else 1.00f
|
||||
|
||||
companion object {
|
||||
private val globalPrefs = Preferences.userRoot().node("mg.dot.feufaro")
|
||||
var isGloballyEnabled: Boolean = globalPrefs.getBoolean("dynamics_enabled", true)
|
||||
set(value) {
|
||||
field = value
|
||||
globalPrefs.putBoolean("dynamics_enabled", value)
|
||||
}
|
||||
|
||||
fun fromVelocity(v: Int): Dynamic =
|
||||
entries.minByOrNull { kotlin.math.abs(it.velocity - v) } ?: MF
|
||||
|
||||
fun resetToDefaults() {
|
||||
entries.forEach { it.savedFactor = it.defaultFactor }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -50,6 +50,7 @@ fun MainScreenWithDrawer(
|
|||
content: @Composable (PaddingValues) -> Unit,
|
||||
) {
|
||||
val drawerState = rememberDrawerState(initialValue = DrawerValue.Closed)
|
||||
var showSettingsDialog by remember { mutableStateOf(false) }
|
||||
val scope = rememberCoroutineScope()
|
||||
|
||||
val items by sharedScreenModel.drawerItems.collectAsState()
|
||||
|
|
@ -175,6 +176,9 @@ fun MainScreenWithDrawer(
|
|||
},
|
||||
onSongSelected = { newSong ->
|
||||
sharedScreenModel.loadNewSong("$midiFile")
|
||||
},
|
||||
onSettingsCheck = {
|
||||
showSettingsDialog = true
|
||||
}
|
||||
)
|
||||
}, content = {
|
||||
|
|
@ -207,6 +211,13 @@ fun MainScreenWithDrawer(
|
|||
}
|
||||
)
|
||||
}
|
||||
if (showSettingsDialog) {
|
||||
Settings(
|
||||
onDismissRequest = {
|
||||
showSettingsDialog = false
|
||||
}
|
||||
)
|
||||
}
|
||||
val favoritePaths by sharedScreenModel.playlistItems.collectAsState()
|
||||
Scaffold(contentWindowInsets = WindowInsets.safeDrawing, topBar = {
|
||||
TopAppBar(
|
||||
|
|
|
|||
393
composeApp/src/commonMain/kotlin/mg/dot/feufaro/ui/Settings.kt
Normal file
393
composeApp/src/commonMain/kotlin/mg/dot/feufaro/ui/Settings.kt
Normal file
|
|
@ -0,0 +1,393 @@
|
|||
package mg.dot.feufaro.ui
|
||||
|
||||
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.RoundedCornerShape
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.KeyboardArrowDown
|
||||
import androidx.compose.material3.*
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.draw.rotate
|
||||
import androidx.compose.ui.graphics.Color
|
||||
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 mg.dot.feufaro.midi.Dynamic
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun Settings(
|
||||
onDismissRequest: () -> Unit
|
||||
) {
|
||||
var isDynamicEnabled by remember { mutableStateOf(Dynamic.isGloballyEnabled) }
|
||||
var refreshTrigger by remember { mutableStateOf(0) }
|
||||
var expandedGeneral by remember { mutableStateOf(false) }
|
||||
var expandedPrint by remember { mutableStateOf(false) }
|
||||
var expandedAudio by remember { mutableStateOf(true) }
|
||||
|
||||
AlertDialog(
|
||||
onDismissRequest = onDismissRequest,
|
||||
title = {
|
||||
Text(
|
||||
text = "Paramètres",
|
||||
fontWeight = FontWeight.Black,
|
||||
fontSize = 22.sp
|
||||
)
|
||||
},
|
||||
text = {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.verticalScroll(rememberScrollState()),
|
||||
verticalArrangement = Arrangement.spacedBy(8.dp)
|
||||
) {
|
||||
HorizontalDivider(color = MaterialTheme.colorScheme.outlineVariant)
|
||||
|
||||
SettingsAccordion(
|
||||
title = "Paramètres Général",
|
||||
isExpanded = expandedGeneral,
|
||||
onToggle = { expandedGeneral = !expandedGeneral }
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier.padding(8.dp),
|
||||
verticalArrangement = Arrangement.spacedBy(10.dp)
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SettingsAccordion(
|
||||
title = "Paramètres Impression",
|
||||
isExpanded = expandedPrint,
|
||||
onToggle = { expandedPrint = !expandedPrint }
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier.padding(8.dp),
|
||||
verticalArrangement = Arrangement.spacedBy(10.dp)
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SettingsAccordion(
|
||||
title = "Paramètres Audio & Nuances",
|
||||
isExpanded = expandedAudio,
|
||||
onToggle = { expandedAudio = !expandedAudio }
|
||||
) {
|
||||
Column(modifier = Modifier.padding(top = 8.dp),
|
||||
verticalArrangement = Arrangement.spacedBy(2.dp)
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.End,
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(10.dp)
|
||||
) {
|
||||
Text(if(isDynamicEnabled) "Désactiver" else "Activer", fontWeight = FontWeight.Bold, fontSize = 15.sp)
|
||||
Switch(
|
||||
checked = isDynamicEnabled,
|
||||
onCheckedChange = { enabled ->
|
||||
isDynamicEnabled = enabled
|
||||
Dynamic.isGloballyEnabled = enabled
|
||||
refreshTrigger++
|
||||
}
|
||||
)
|
||||
|
||||
OutlinedButton(
|
||||
onClick = {
|
||||
Dynamic.resetToDefaults()
|
||||
isDynamicEnabled = true
|
||||
refreshTrigger++
|
||||
},
|
||||
shape = RoundedCornerShape(8.dp),
|
||||
colors = ButtonDefaults.outlinedButtonColors(
|
||||
contentColor = MaterialTheme.colorScheme.error
|
||||
),
|
||||
contentPadding = PaddingValues(horizontal = 16.dp, vertical = 8.dp)
|
||||
) {
|
||||
Text("Réinitialiser", fontSize = 14.sp)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
key(refreshTrigger) {
|
||||
val dynamicEntries = Dynamic.entries
|
||||
val minF = 0.22f
|
||||
val maxF = 2.33f
|
||||
val step = 0.05f
|
||||
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.background(Color(0xFF121212).copy(alpha = 0.6f), RoundedCornerShape(16.dp))
|
||||
.padding(8.dp),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
Column(
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
verticalArrangement = Arrangement.spacedBy(0.dp)
|
||||
) {
|
||||
dynamicEntries.forEachIndexed { index, dynamicItem ->
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(1.dp),
|
||||
modifier = Modifier.padding(vertical = 0.dp)
|
||||
) {
|
||||
// (-)
|
||||
if(index == 0) {
|
||||
FilledIconButton(
|
||||
onClick = {
|
||||
if (isDynamicEnabled) {
|
||||
val delta = - step
|
||||
var insideBounds = true
|
||||
dynamicEntries.forEach { item ->
|
||||
val projectedValue = item.savedFactor + delta
|
||||
if (projectedValue < minF || projectedValue > maxF) {
|
||||
insideBounds = false
|
||||
}
|
||||
}
|
||||
if (insideBounds) {
|
||||
dynamicEntries.forEach { item ->
|
||||
item.savedFactor = (item.savedFactor + delta).coerceIn(minF, maxF)
|
||||
}
|
||||
refreshTrigger++
|
||||
}
|
||||
}
|
||||
},
|
||||
enabled = isDynamicEnabled,
|
||||
colors = IconButtonDefaults.filledIconButtonColors(
|
||||
containerColor = Color(0xFF2C2C2C),
|
||||
contentColor = Color.White
|
||||
),
|
||||
modifier = Modifier.size(32.dp)
|
||||
) {
|
||||
Text("-", fontWeight = FontWeight.Bold, fontSize = 16.sp)
|
||||
}
|
||||
} else {
|
||||
Spacer(modifier = Modifier.width(32.dp))
|
||||
}
|
||||
Text(
|
||||
text = dynamicItem.label.lowercase(),
|
||||
fontSize = 12.sp,
|
||||
fontWeight = FontWeight.Bold,
|
||||
color = if (isDynamicEnabled) Color.White else Color.Gray,
|
||||
textAlign = TextAlign.Center,
|
||||
modifier = Modifier.width(30.dp)
|
||||
)
|
||||
|
||||
Slider(
|
||||
value = dynamicItem.savedFactor,
|
||||
onValueChange = { newValue ->
|
||||
if (isDynamicEnabled) {
|
||||
val oldValue = dynamicItem.savedFactor
|
||||
val delta = newValue - oldValue
|
||||
var insideBounds = true
|
||||
|
||||
dynamicEntries.forEach { item ->
|
||||
val projectedValue = item.savedFactor + delta
|
||||
if (projectedValue < minF || projectedValue > maxF) {
|
||||
insideBounds = false
|
||||
}
|
||||
}
|
||||
|
||||
if (insideBounds) {
|
||||
dynamicEntries.forEach { item ->
|
||||
item.savedFactor = (item.savedFactor + delta).coerceIn(minF, maxF)
|
||||
}
|
||||
refreshTrigger++
|
||||
}
|
||||
}
|
||||
},
|
||||
valueRange = minF..maxF,
|
||||
enabled = isDynamicEnabled,
|
||||
track = { sliderState ->
|
||||
SliderDefaults.Track(
|
||||
sliderState = sliderState,
|
||||
enabled = isDynamicEnabled,
|
||||
colors = SliderDefaults.colors(
|
||||
activeTrackColor = if (isDynamicEnabled) Color.Blue else Color.Gray,
|
||||
inactiveTrackColor = Color.LightGray
|
||||
),
|
||||
modifier = Modifier.height(6.dp)
|
||||
)
|
||||
},
|
||||
thumb = {
|
||||
SliderDefaults.Thumb(
|
||||
interactionSource = remember { MutableInteractionSource() },
|
||||
colors = SliderDefaults.colors(thumbColor = if(isDynamicEnabled) Color(0xFFFF4081) else Color.LightGray),
|
||||
modifier = Modifier.size(12.dp),
|
||||
)
|
||||
},
|
||||
colors = SliderDefaults.colors(
|
||||
activeTrackColor = Color(0xFF7C4DFF),
|
||||
inactiveTrackColor = Color(0xFF2C2C2C)
|
||||
),
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
.padding(horizontal = 8.dp)
|
||||
.height(16.dp)
|
||||
)
|
||||
|
||||
Text(
|
||||
text = String.format("%.2f", if (isDynamicEnabled) dynamicItem.savedFactor else 1.00f),
|
||||
fontSize = 11.sp,
|
||||
fontWeight = FontWeight.Bold,
|
||||
color = if (isDynamicEnabled) Color(0xFFDEFF9A) else Color.DarkGray,
|
||||
textAlign = TextAlign.Center,
|
||||
modifier = Modifier.width(30.dp)
|
||||
)
|
||||
|
||||
// (+)
|
||||
if(index == 0) {
|
||||
FilledIconButton(
|
||||
onClick = {
|
||||
if (isDynamicEnabled) {
|
||||
val delta = step
|
||||
var insideBounds = true
|
||||
dynamicEntries.forEach { item ->
|
||||
val projectedValue = item.savedFactor + delta
|
||||
if (projectedValue < minF || projectedValue > maxF) {
|
||||
insideBounds = false
|
||||
}
|
||||
}
|
||||
if (insideBounds) {
|
||||
dynamicEntries.forEach { item ->
|
||||
item.savedFactor =
|
||||
(item.savedFactor + delta).coerceIn(minF, maxF)
|
||||
}
|
||||
refreshTrigger++
|
||||
}
|
||||
}
|
||||
},
|
||||
enabled = isDynamicEnabled,
|
||||
colors = IconButtonDefaults.filledIconButtonColors(
|
||||
containerColor = Color(0xFF2C2C2C),
|
||||
contentColor = Color.White
|
||||
),
|
||||
modifier = Modifier.size(32.dp)
|
||||
) {
|
||||
Text("+", fontWeight = FontWeight.Bold, fontSize = 16.sp)
|
||||
}
|
||||
} else {
|
||||
Spacer(modifier = Modifier.width(32.dp))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
confirmButton = {
|
||||
TextButton(onClick = onDismissRequest) {
|
||||
Text("Enregistrer", fontWeight = FontWeight.Bold)
|
||||
}
|
||||
},
|
||||
dismissButton = {
|
||||
TextButton(onClick = onDismissRequest) {
|
||||
Text("Annuler")
|
||||
}
|
||||
},
|
||||
containerColor = MaterialTheme.colorScheme.surface,
|
||||
shape = RoundedCornerShape(16.dp)
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun SettingsAccordion(
|
||||
title: String,
|
||||
isExpanded: Boolean,
|
||||
onToggle: () -> Unit,
|
||||
content: @Composable ColumnScope.() -> Unit
|
||||
) {
|
||||
val arrowRotationDegree by animateFloatAsState(
|
||||
targetValue = if (isExpanded) 180f else 0f,
|
||||
animationSpec = tween(durationMillis = 250),
|
||||
label = "ArrowRotation"
|
||||
)
|
||||
|
||||
Card(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.clip(RoundedCornerShape(16.dp)),
|
||||
colors = CardDefaults.cardColors(
|
||||
containerColor = if (isExpanded) {
|
||||
MaterialTheme.colorScheme.surfaceVariant.copy(alpha = 0.5f)
|
||||
} else {
|
||||
MaterialTheme.colorScheme.surfaceVariant.copy(alpha = 0.25f)
|
||||
}
|
||||
),
|
||||
border = BorderStroke(
|
||||
width = 1.dp,
|
||||
color = if (isExpanded) MaterialTheme.colorScheme.primary.copy(alpha = 0.3f) else Color.Transparent
|
||||
),
|
||||
shape = RoundedCornerShape(16.dp)
|
||||
) {
|
||||
Column(modifier = Modifier.fillMaxWidth()) {
|
||||
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.clickable { onToggle() }
|
||||
.padding(horizontal = 16.dp, vertical = 14.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.SpaceBetween
|
||||
) {
|
||||
Text(
|
||||
text = title,
|
||||
fontWeight = if (isExpanded) FontWeight.ExtraBold else FontWeight.SemiBold,
|
||||
fontSize = 15.sp,
|
||||
color = if (isExpanded) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.onSurface
|
||||
)
|
||||
|
||||
Icon(
|
||||
imageVector = Icons.Default.KeyboardArrowDown,
|
||||
contentDescription = null,
|
||||
tint = if (isExpanded) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
modifier = Modifier.rotate(arrowRotationDegree)
|
||||
)
|
||||
}
|
||||
|
||||
AnimatedVisibility(visible = isExpanded) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(start = 16.dp, end = 16.dp, bottom = 16.dp)
|
||||
) {
|
||||
HorizontalDivider(
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant.copy(alpha = 0.1f),
|
||||
modifier = Modifier.padding(bottom = 12.dp)
|
||||
)
|
||||
content()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,15 +1,16 @@
|
|||
package mg.dot.feufaro.ui
|
||||
|
||||
import SharedScreenModel
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
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.*
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.foundation.lazy.itemsIndexed
|
||||
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
|
||||
|
|
@ -26,7 +27,6 @@ import androidx.compose.ui.graphics.Color
|
|||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.launch
|
||||
import mg.dot.feufaro.data.DrawerItem
|
||||
|
|
@ -34,7 +34,7 @@ import mg.dot.feufaro.getPlatform
|
|||
import mg.dot.feufaro.solfa.Solfa
|
||||
import mg.dot.feufaro.viewmodel.SolfaScreenModel
|
||||
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun SimpleDrawerContent(
|
||||
items: List<DrawerItem>,
|
||||
|
|
@ -45,6 +45,7 @@ fun SimpleDrawerContent(
|
|||
scope: CoroutineScope,
|
||||
onScannerButtonClick: () -> Unit,
|
||||
onSongSelected: (String) -> Unit,
|
||||
onSettingsCheck: () -> Unit
|
||||
) {
|
||||
var searchTxt by remember { mutableStateOf("") }
|
||||
|
||||
|
|
@ -76,7 +77,8 @@ fun SimpleDrawerContent(
|
|||
) {
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.SpaceEvenly
|
||||
horizontalArrangement = Arrangement.SpaceEvenly,
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
CustomSwitchItem(
|
||||
checked = editMode,
|
||||
|
|
@ -228,152 +230,57 @@ fun SimpleDrawerContent(
|
|||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(16.dp),
|
||||
horizontalArrangement = Arrangement.SpaceEvenly
|
||||
) {
|
||||
Button(onClick = {
|
||||
scope.launch { drawerState.close() }
|
||||
}) {
|
||||
Text("Scanner")
|
||||
}
|
||||
Button(onClick = {
|
||||
solfaScreenModel.loadCustomFile()
|
||||
scope.launch { drawerState.close() }
|
||||
}) {
|
||||
Text("Importer")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun DrawerAccordionSection(
|
||||
title: String,
|
||||
items: List<DrawerItem>,
|
||||
icon: ImageVector,
|
||||
iconColor: Color,
|
||||
activePath: String,
|
||||
scope: CoroutineScope,
|
||||
solfaScreenModel: SolfaScreenModel,
|
||||
onItemClick: (DrawerItem) -> Unit
|
||||
) {
|
||||
var expanded by remember { mutableStateOf(true) }
|
||||
|
||||
val rotationState by animateFloatAsState(targetValue = if (expanded) 180f else 0f)
|
||||
|
||||
Column(modifier = Modifier.fillMaxWidth()) {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.clickable { expanded = !expanded }
|
||||
.padding(horizontal = 16.dp, vertical = 12.dp),
|
||||
.padding(vertical = 8.dp, horizontal = 16.dp),
|
||||
horizontalArrangement = Arrangement.SpaceEvenly,
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Icon(
|
||||
imageVector = icon,
|
||||
contentDescription = null,
|
||||
tint = iconColor,
|
||||
modifier = Modifier.size(20.dp)
|
||||
)
|
||||
Spacer(Modifier.width(12.dp))
|
||||
Text(
|
||||
text = title.uppercase(),
|
||||
style = MaterialTheme.typography.labelLarge.copy(
|
||||
letterSpacing = 1.sp,
|
||||
fontWeight = FontWeight.Bold
|
||||
),
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
modifier = Modifier.weight(1f)
|
||||
)
|
||||
Surface(
|
||||
color = iconColor.copy(alpha = 0.1f),
|
||||
shape = MaterialTheme.shapes.extraSmall
|
||||
TooltipBox(
|
||||
positionProvider = TooltipDefaults.rememberPlainTooltipPositionProvider(),
|
||||
tooltip = { PlainTooltip { Text("") } },
|
||||
state = rememberTooltipState()
|
||||
) {
|
||||
Text(
|
||||
text = "${items.size}",
|
||||
modifier = Modifier.padding(horizontal = 6.dp, vertical = 2.dp),
|
||||
style = MaterialTheme.typography.labelSmall,
|
||||
color = iconColor
|
||||
)
|
||||
}
|
||||
Spacer(Modifier.width(8.dp))
|
||||
Icon(
|
||||
imageVector = Icons.Default.KeyboardArrowDown,
|
||||
contentDescription = null,
|
||||
modifier = Modifier.rotate(rotationState).size(20.dp)
|
||||
)
|
||||
}
|
||||
|
||||
AnimatedVisibility(visible = expanded) {
|
||||
Column {
|
||||
items.forEach { item ->
|
||||
val isSelected = item.path == activePath
|
||||
NavigationDrawerItem(
|
||||
label = {
|
||||
Column {
|
||||
Text(
|
||||
text = item.title,
|
||||
fontWeight = FontWeight.SemiBold,
|
||||
style = MaterialTheme.typography.bodyMedium
|
||||
)
|
||||
Text(
|
||||
text = item.contentTitle,
|
||||
style = MaterialTheme.typography.labelSmall,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
maxLines = 1
|
||||
)
|
||||
}
|
||||
},
|
||||
selected = isSelected,
|
||||
onClick = { onItemClick(item) },
|
||||
modifier = Modifier.padding(horizontal = 12.dp, vertical = 2.dp),
|
||||
shape = MaterialTheme.shapes.medium,
|
||||
colors = NavigationDrawerItemDefaults.colors(
|
||||
unselectedContainerColor = Color.Transparent
|
||||
)
|
||||
)
|
||||
}
|
||||
IconButton(onClick = {
|
||||
scope.launch { drawerState.close() }
|
||||
}) {
|
||||
Icon(Icons.Default.GraphicEq, contentDescription = null, tint = MaterialTheme.colorScheme.primary)
|
||||
}
|
||||
}
|
||||
|
||||
HorizontalDivider(
|
||||
modifier = Modifier.padding(top = 8.dp),
|
||||
thickness = 0.5.dp,
|
||||
color = MaterialTheme.colorScheme.outlineVariant
|
||||
)
|
||||
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.align(Alignment.CenterHorizontally)
|
||||
.padding(16.dp),
|
||||
contentAlignment = Alignment.Center
|
||||
TooltipBox(
|
||||
positionProvider = TooltipDefaults.rememberPlainTooltipPositionProvider(),
|
||||
tooltip = { PlainTooltip { Text("Importer un fichier") } },
|
||||
state = rememberTooltipState()
|
||||
) {
|
||||
Column(
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
Row (
|
||||
|
||||
) {
|
||||
Spacer(modifier = Modifier.width(10.dp))
|
||||
Button(
|
||||
onClick = {
|
||||
|
||||
}
|
||||
) {
|
||||
Text("Scanner")
|
||||
}
|
||||
Spacer(modifier = Modifier.width(10.dp))
|
||||
Button(
|
||||
onClick = {
|
||||
scope.launch {
|
||||
//drawerState.close()
|
||||
}
|
||||
IconButton(onClick = {
|
||||
solfaScreenModel.loadCustomFile()
|
||||
scope.launch { drawerState.close() }
|
||||
}) {
|
||||
Icon(Icons.Default.FolderOpen, contentDescription = null)
|
||||
}
|
||||
}
|
||||
|
||||
TooltipBox(
|
||||
positionProvider = TooltipDefaults.rememberPlainTooltipPositionProvider(),
|
||||
tooltip = { PlainTooltip { Text("Paramètres") } },
|
||||
state = rememberTooltipState()
|
||||
) {
|
||||
Text("Importer")
|
||||
IconButton(onClick = {
|
||||
onSettingsCheck()
|
||||
scope.launch { drawerState.close() }
|
||||
}) {
|
||||
Icon(Icons.Default.Settings, contentDescription = null)
|
||||
}
|
||||
}
|
||||
|
||||
TooltipBox(
|
||||
positionProvider = TooltipDefaults.rememberPlainTooltipPositionProvider(),
|
||||
tooltip = { PlainTooltip { Text("À propos") } },
|
||||
state = rememberTooltipState()
|
||||
) {
|
||||
IconButton(onClick = {
|
||||
scope.launch { drawerState.close() }
|
||||
}) {
|
||||
Icon(Icons.Default.Info, contentDescription = null)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue