Compare commits

...

3 commits

8 changed files with 5161 additions and 386 deletions

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,33 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:aapt="http://schemas.android.com/aapt"
android:viewportWidth="256"
android:viewportHeight="256"
android:width="256dp"
android:height="256dp">
<path
android:pathData="M202.2 119.6c-2.1 0 -3.8 1.7 -3.8 3.8V171c0 2.1 1.7 3.8 3.8 3.8c2.1 0 3.8 -1.7 3.8 -3.8v-47.7C206 121.3 204.3 119.6 202.2 119.6z"
android:fillColor="#000000" />
<path
android:pathData="M192.7 117h19c2.1 0 3.8 -1.7 3.8 -3.8V74.4c0 -2.1 -1.7 -3.8 -3.8 -3.8H206V54.9c0 -2.1 -1.7 -3.8 -3.8 -3.8c-2.1 0 -3.8 1.7 -3.8 3.8v15.7h-5.7c-2.1 0 -3.8 1.7 -3.8 3.8v38.8C188.9 115.3 190.6 117 192.7 117zM196.5 78.2h11.4v31.2h-11.4V78.2z"
android:fillColor="#000000" />
<path
android:pathData="M152.7 158.5c-2.1 0 -3.8 1.7 -3.8 3.8v9.3c0 2.1 1.7 3.8 3.8 3.8c2.1 0 3.8 -1.7 3.8 -3.8v-9.3C156.6 160.2 154.9 158.5 152.7 158.5z"
android:fillColor="#000000" />
<path
android:pathData="M143.2 155.9h19c2.1 0 3.8 -1.7 3.8 -3.8v-38.8c0 -2.1 -1.7 -3.8 -3.8 -3.8h-5.7v-54c0 -2.1 -1.7 -3.8 -3.8 -3.8c-2.1 0 -3.8 1.7 -3.8 3.8v54h-5.7c-2.1 0 -3.8 1.7 -3.8 3.8v38.8C139.4 154.2 141.1 155.9 143.2 155.9zM147 117.1h11.4v31.2H147V117.1z"
android:fillColor="#000000" />
<path
android:pathData="M103.3 119.6c-2.1 0 -3.8 1.7 -3.8 3.8V171c0 2.1 1.7 3.8 3.8 3.8c2.1 0 3.8 -1.7 3.8 -3.8v-47.7C107.1 121.3 105.4 119.6 103.3 119.6z"
android:fillColor="#000000" />
<path
android:pathData="M93.7 117h19c2.1 0 3.8 -1.7 3.8 -3.8V74.4c0 -2.1 -1.7 -3.8 -3.8 -3.8H107V54.9c0 -2.1 -1.7 -3.8 -3.8 -3.8c-2.1 0 -3.8 1.7 -3.8 3.8v15.7h-5.7c-2.1 0 -3.8 1.7 -3.8 3.8v38.8C89.9 115.3 91.6 117 93.7 117zM97.5 78.2H109v31.2H97.6L97.5 78.2L97.5 78.2z"
android:fillColor="#000000" />
<path
android:pathData="M53.8 158.5c-2.1 0 -3.8 1.7 -3.8 3.8v9.3c0 2.1 1.7 3.8 3.8 3.8s3.8 -1.7 3.8 -3.8v-9.3C57.6 160.2 55.9 158.5 53.8 158.5z"
android:fillColor="#000000" />
<path
android:pathData="M44.3 155.9h19c2.1 0 3.8 -1.7 3.8 -3.8v-38.8c0 -2.1 -1.7 -3.8 -3.8 -3.8h-5.7v-54c0 -2.1 -1.7 -3.8 -3.8 -3.8S50 53.4 50 55.5v54h-5.7c-2.1 0 -3.8 1.7 -3.8 3.8v38.8C40.4 154.2 42.1 155.9 44.3 155.9zM48.1 117.1h11.4v31.2H48.1V117.1z"
android:fillColor="#000000" />
<path
android:pathData="M242.2 31.1H13.8c-2.1 0 -3.8 1.7 -3.8 3.8v178.6c0 6.3 5.1 11.4 11.4 11.4h213.2c6.3 0 11.4 -5.1 11.4 -11.4V34.9C246 32.8 244.3 31.1 242.2 31.1zM238.4 38.7v149.1H17.6V38.7H238.4zM234.6 217.3H21.4c-2.1 0 -3.8 -1.7 -3.8 -3.8v-18h220.8v18C238.4 215.5 236.7 217.3 234.6 217.3z"
android:fillColor="#000000" />
</vector>

View file

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:aapt="http://schemas.android.com/aapt"
android:viewportWidth="512"
android:viewportHeight="512"
android:width="800dp"
android:height="800dp">
<path
android:pathData="M468.826 97.292v103.374h-55.943V48.647h-36.484v152.019h-55.943V0.001h-36.484v200.665h-55.943V0h-36.484v200.666h-55.943V48.647H99.117v152.019H43.174V97.293H6.689V512h498.621V97.292H468.826zM99.117 334.442H43.174v-36.484h55.943V334.442zM135.602 297.958h55.943v36.484h-55.943V297.958zM228.025 475.516H191.54V370.927h36.484V475.516zM228.03 297.958h55.943v36.484H228.03V297.958zM320.452 475.516h-36.484V370.927h36.484V475.516zM376.399 334.442h-55.943v-36.484h55.943V334.442zM468.826 334.442h-55.943v-36.484h55.943V334.442z"
android:fillColor="#000000" />
</vector>

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,33 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:aapt="http://schemas.android.com/aapt"
android:viewportWidth="256"
android:viewportHeight="256"
android:width="256dp"
android:height="256dp">
<path
android:pathData="M202.2 119.6c-2.1 0 -3.8 1.7 -3.8 3.8V171c0 2.1 1.7 3.8 3.8 3.8c2.1 0 3.8 -1.7 3.8 -3.8v-47.7C206 121.3 204.3 119.6 202.2 119.6z"
android:fillColor="#000000" />
<path
android:pathData="M192.7 117h19c2.1 0 3.8 -1.7 3.8 -3.8V74.4c0 -2.1 -1.7 -3.8 -3.8 -3.8H206V54.9c0 -2.1 -1.7 -3.8 -3.8 -3.8c-2.1 0 -3.8 1.7 -3.8 3.8v15.7h-5.7c-2.1 0 -3.8 1.7 -3.8 3.8v38.8C188.9 115.3 190.6 117 192.7 117zM196.5 78.2h11.4v31.2h-11.4V78.2z"
android:fillColor="#000000" />
<path
android:pathData="M152.7 158.5c-2.1 0 -3.8 1.7 -3.8 3.8v9.3c0 2.1 1.7 3.8 3.8 3.8c2.1 0 3.8 -1.7 3.8 -3.8v-9.3C156.6 160.2 154.9 158.5 152.7 158.5z"
android:fillColor="#000000" />
<path
android:pathData="M143.2 155.9h19c2.1 0 3.8 -1.7 3.8 -3.8v-38.8c0 -2.1 -1.7 -3.8 -3.8 -3.8h-5.7v-54c0 -2.1 -1.7 -3.8 -3.8 -3.8c-2.1 0 -3.8 1.7 -3.8 3.8v54h-5.7c-2.1 0 -3.8 1.7 -3.8 3.8v38.8C139.4 154.2 141.1 155.9 143.2 155.9zM147 117.1h11.4v31.2H147V117.1z"
android:fillColor="#000000" />
<path
android:pathData="M103.3 119.6c-2.1 0 -3.8 1.7 -3.8 3.8V171c0 2.1 1.7 3.8 3.8 3.8c2.1 0 3.8 -1.7 3.8 -3.8v-47.7C107.1 121.3 105.4 119.6 103.3 119.6z"
android:fillColor="#000000" />
<path
android:pathData="M93.7 117h19c2.1 0 3.8 -1.7 3.8 -3.8V74.4c0 -2.1 -1.7 -3.8 -3.8 -3.8H107V54.9c0 -2.1 -1.7 -3.8 -3.8 -3.8c-2.1 0 -3.8 1.7 -3.8 3.8v15.7h-5.7c-2.1 0 -3.8 1.7 -3.8 3.8v38.8C89.9 115.3 91.6 117 93.7 117zM97.5 78.2H109v31.2H97.6L97.5 78.2L97.5 78.2z"
android:fillColor="#000000" />
<path
android:pathData="M53.8 158.5c-2.1 0 -3.8 1.7 -3.8 3.8v9.3c0 2.1 1.7 3.8 3.8 3.8s3.8 -1.7 3.8 -3.8v-9.3C57.6 160.2 55.9 158.5 53.8 158.5z"
android:fillColor="#000000" />
<path
android:pathData="M44.3 155.9h19c2.1 0 3.8 -1.7 3.8 -3.8v-38.8c0 -2.1 -1.7 -3.8 -3.8 -3.8h-5.7v-54c0 -2.1 -1.7 -3.8 -3.8 -3.8S50 53.4 50 55.5v54h-5.7c-2.1 0 -3.8 1.7 -3.8 3.8v38.8C40.4 154.2 42.1 155.9 44.3 155.9zM48.1 117.1h11.4v31.2H48.1V117.1z"
android:fillColor="#000000" />
<path
android:pathData="M242.2 31.1H13.8c-2.1 0 -3.8 1.7 -3.8 3.8v178.6c0 6.3 5.1 11.4 11.4 11.4h213.2c6.3 0 11.4 -5.1 11.4 -11.4V34.9C246 32.8 244.3 31.1 242.2 31.1zM238.4 38.7v149.1H17.6V38.7H238.4zM234.6 217.3H21.4c-2.1 0 -3.8 -1.7 -3.8 -3.8v-18h220.8v18C238.4 215.5 236.7 217.3 234.6 217.3z"
android:fillColor="#000000" />
</vector>

View file

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:aapt="http://schemas.android.com/aapt"
android:viewportWidth="512"
android:viewportHeight="512"
android:width="800dp"
android:height="800dp">
<path
android:pathData="M468.826 97.292v103.374h-55.943V48.647h-36.484v152.019h-55.943V0.001h-36.484v200.665h-55.943V0h-36.484v200.666h-55.943V48.647H99.117v152.019H43.174V97.293H6.689V512h498.621V97.292H468.826zM99.117 334.442H43.174v-36.484h55.943V334.442zM135.602 297.958h55.943v36.484h-55.943V297.958zM228.025 475.516H191.54V370.927h36.484V475.516zM228.03 297.958h55.943v36.484H228.03V297.958zM320.452 475.516h-36.484V370.927h36.484V475.516zM376.399 334.442h-55.943v-36.484h55.943V334.442zM468.826 334.442h-55.943v-36.484h55.943V334.442z"
android:fillColor="#000000" />
</vector>

View file

@ -1,91 +1,31 @@
package mg.dot.feufaro.ui
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.scaleIn
import androidx.compose.animation.scaleOut
import androidx.compose.animation.slideInVertically
import androidx.compose.animation.slideOutVertically
import androidx.compose.foundation.BorderStroke
import androidx.compose.animation.*
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.IntrinsicSize
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
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.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.AvTimer
import androidx.compose.material.icons.filled.Church
import androidx.compose.material.icons.filled.Clear
import androidx.compose.material.icons.filled.ClearAll
import androidx.compose.material.icons.filled.Keyboard
import androidx.compose.material.icons.filled.Loop
import androidx.compose.material.icons.filled.MusicNote
import androidx.compose.material.icons.filled.Pause
import androidx.compose.material.icons.filled.Piano
import androidx.compose.material.icons.filled.PianoOff
import androidx.compose.material.icons.filled.PlayArrow
import androidx.compose.material.icons.filled.Refresh
import androidx.compose.material.icons.filled.SettingsVoice
import androidx.compose.material.icons.filled.Star
import androidx.compose.material.icons.filled.Tonality
import androidx.compose.material.icons.filled.Tune
import androidx.compose.material.icons.automirrored.filled.VolumeUp
import androidx.compose.material.icons.automirrored.filled.VolumeOff
import androidx.compose.material.icons.filled.MoreHoriz
import androidx.compose.material.icons.filled.MoreVert
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.FilledIconToggleButton
import androidx.compose.material3.FilterChip
import androidx.compose.material3.FilterChipDefaults
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedButton
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Slider
import androidx.compose.material3.SliderDefaults
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.produceState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.material.icons.automirrored.filled.KeyboardArrowLeft
import androidx.compose.material.icons.automirrored.filled.KeyboardArrowRight
import androidx.compose.material.icons.filled.*
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.graphics.Color
import androidx.compose.ui.graphics.RectangleShape
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.unit.DpSize
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import feufaro.composeapp.generated.resources.Res
import feufaro.composeapp.generated.resources.ic_mixer_satb
import feufaro.composeapp.generated.resources.ic_organ
import kotlinx.coroutines.delay
import mg.dot.feufaro.getPlatform
import mg.dot.feufaro.midi.MediaPlayer
import org.koin.core.component.getScopeId
import javax.swing.Icon
import org.jetbrains.compose.resources.painterResource
@OptIn(ExperimentalMaterial3Api::class)
@Composable
@ -111,26 +51,47 @@ fun MidiControlPanel(
val voiceStates = mediaPlayer.getVoiceStates()
val labels = listOf("S", "A", "T", "B")
val fullLabels = listOf("Soprano","Alto","Ténor","Basse")
listOf("Soprano", "Alto", "Ténor", "Basse")
var tempo by remember { mutableStateOf(1.0f) }
var currentBpm by remember { mutableStateOf(mediaPlayer.getCurrentBPM()) }
val basseBpm = 120f
var bpmInput by remember { mutableStateOf((basseBpm * tempo).toInt().toString()) }
var isPianoSelected by remember { mutableStateOf(true) }
var showBPMTools by remember { mutableStateOf(false) }
var showInstruTools by remember { mutableStateOf(false) }
var showSATBTools by remember { mutableStateOf(false) }
var showVolumeTools by remember { mutableStateOf(false) }
var expandedCtl by remember { mutableStateOf(false) }
LaunchedEffect(tempo) {
currentBpm = mediaPlayer.getCurrentBPM()
}
fun updateTempoByBpmStep(step: Int) {
val currentBpm = (basseBpm * tempo).toInt()
val newBpm = (currentBpm + step).coerceIn((basseBpm * 0.25f).toInt(), (basseBpm * 1.5f).toInt())
val newFactor = newBpm.toFloat() / basseBpm
tempo = newFactor
mediaPlayer?.setTempo(newFactor)
}
fun updateTempoToBpm(targetBpm: Int) {
val clampedBpm = targetBpm.coerceIn((basseBpm * 0.25f).toInt(), (basseBpm * 1.5f).toInt())
val newFactor = clampedBpm.toFloat() / basseBpm
tempo = newFactor
mediaPlayer?.setTempo(newFactor)
println("tempo : $tempo")
}
Column(
modifier = Modifier.fillMaxWidth()
) {
Row(
modifier = Modifier.fillMaxWidth(),
verticalAlignment = Alignment.Bottom,
horizontalArrangement = Arrangement.Center
) {
Column(
modifier = modifier
.fillMaxWidth()
.fillMaxWidth(if (getPlatform().name.startsWith("Android")) 0.9f else 0.6f)
.padding(16.dp)
.background(color = Color.Gray.copy(alpha = 0.5f), shape = RoundedCornerShape(size = 5.dp)),
horizontalAlignment = Alignment.CenterHorizontally
@ -206,111 +167,106 @@ fun MidiControlPanel(
}
}
AnimatedVisibility(
visible = showInstruTools,
visible = !expandedCtl,
enter = fadeIn() + scaleIn() + slideInVertically { it / 2 },
exit = fadeOut() + scaleOut() + slideOutVertically { it / 2 }
) {
Row (
horizontalArrangement = Arrangement.spacedBy(10.dp)
) {
FilledIconToggleButton(
checked = isPianoSelected,
onCheckedChange = {
isPianoSelected = true;
mediaPlayer.changeInstru(1)
}
){
Icon(imageVector = Icons.Filled.Piano, contentDescription = "Piano")
}
FilledIconToggleButton(
checked = !isPianoSelected,
onCheckedChange = {
isPianoSelected = false;
mediaPlayer.changeInstru(20)
}){
Icon(imageVector = Icons.Filled.PianoOff, contentDescription = "Church Organ")
}
}
}
AnimatedVisibility(
visible = showBPMTools,
enter = fadeIn() + scaleIn() + slideInVertically { it / 2 },
exit = fadeOut() + scaleOut() + slideOutVertically { it / 2 }
) {
Row(
verticalAlignment = Alignment.CenterVertically
){
Column(
horizontalAlignment = Alignment.Start
) {
OutlinedTextField(
value = bpmInput, onValueChange = { newValue ->
if (newValue.all { it.isDigit() } && newValue.length <= 3) {
bpmInput = newValue
}
}, label = { Text("BPM") }, singleLine = true, keyboardOptions = KeyboardOptions(
keyboardType = KeyboardType.Number, imeAction = ImeAction.Done
), keyboardActions = KeyboardActions(
onDone = {
val newBpm = bpmInput.toFloatOrNull() ?: 0f
val newFactor = newBpm / basseBpm
tempo = newFactor
mediaPlayer.setTempo(newFactor)
bpmInput = (basseBpm * newFactor).toInt().toString()
}), modifier = Modifier.width(65.dp))
}
Row {
Column(
horizontalAlignment = Alignment.CenterHorizontally
) {
Slider(value = tempo, onValueChange = {
tempo = it
mediaPlayer?.setTempo(it)
currentBpm = mediaPlayer.getCurrentBPM()
bpmInput = (basseBpm * it).toInt().toString()
}, valueRange = 0.25f..1.5f, modifier = Modifier.width(200.dp), thumb = {
Box(
modifier = Modifier.size(15.dp).background(Color.Magenta, CircleShape)
)
}, track = { sliderState ->
SliderDefaults.Track(
sliderState = sliderState, modifier = Modifier.height(5.dp)
)
})
}
Column(
horizontalAlignment = Alignment.End
Row(
modifier = Modifier
.height(45.dp)
.clip(RoundedCornerShape(12.dp))
.background(Color(0xFF2C3135))
.padding(vertical = 6.dp),
verticalAlignment = Alignment.CenterVertically
) {
IconButton(onClick = {
tempo = 1.0f
mediaPlayer?.setTempo(1.0f)
currentBpm = mediaPlayer.getCurrentBPM()
}) {
Icon(Icons.Default.Refresh, contentDescription = "Reset")
if (tempo >= 0.3) { // limite 40BPM
IconButton(
modifier = Modifier.background(Color(0XFF2C3130)),
onClick = { updateTempoByBpmStep(-10) }) {
Icon(
Icons.AutoMirrored.Filled.KeyboardArrowLeft,
"gauche",
tint = Color.White.copy(0.7f),
modifier = Modifier.size(22.dp)
)
}
}
val currentBpmInt = (basseBpm * tempo).toInt()
Row(
modifier = Modifier.padding(horizontal = 2.dp),
verticalAlignment = Alignment.CenterVertically
) {
val values = listOf(currentBpmInt - 1, currentBpmInt, currentBpmInt + 1)
values.forEach { bpmValue ->
AnimatedContent(
targetState = bpmValue,
transitionSpec = {
if (targetState > initialState) {
slideInHorizontally { it } + fadeIn() togetherWith slideOutHorizontally { -it } + fadeOut()
} else {
slideInHorizontally { -it } + fadeIn() togetherWith slideOutHorizontally { it } + fadeOut()
}
},
modifier = Modifier.padding(horizontal = 4.dp)
) { displayedBpm ->
val isCenter = displayedBpm == currentBpmInt
Text(
text = "$displayedBpm",
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,
modifier = Modifier
.clip(CircleShape)
.clickable(enabled = !isCenter) { updateTempoToBpm(displayedBpm) }
.padding(horizontal = 4.dp)
)
}
}
}
if (tempo <= 1.3) { // limite 156BPM
IconButton(
modifier = Modifier.background(Color(0XFF2C3130)),
onClick = { updateTempoByBpmStep(10) }) {
Icon(
Icons.AutoMirrored.Filled.KeyboardArrowRight,
"droite",
tint = Color.White.copy(0.7f),
modifier = Modifier.size(22.dp)
)
}
}
Text(
text = "bpm",
color = Color.White.copy(0.6f),
fontSize = 12.sp,
modifier = Modifier.padding(end = 8.dp)
)
}
}
}
}
if (!expandedCtl) {
Spacer(modifier = Modifier.height(10.dp))
}
Row(
modifier = Modifier.fillMaxWidth(),
modifier = Modifier.fillMaxWidth().padding(horizontal = 5.dp),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.SpaceAround
) {
Box(contentAlignment = Alignment.CenterStart) {
IconButton(
onClick = {
showBPMTools = !showBPMTools
}
) {
Icon(imageVector = Icons.Default.AvTimer, contentDescription = "Tempo")
}
}
Box( contentAlignment = Alignment.CenterStart) {
Column {
val isAtStart = loopState.first == -1L
val isWaitingForB = loopState.first != -1L && !loopState.third
val isLooping = loopState.third
Button(
OutlinedButton(
onClick = {
when {
isAtStart -> mediaPlayer.setPointA()
@ -326,11 +282,10 @@ fun MidiControlPanel(
else -> Color.LightGray
}
),
contentPadding = PaddingValues(horizontal = 8.dp, vertical = 0.dp),
contentPadding = PaddingValues(horizontal = 2.dp, vertical = 0.dp),
shape = RoundedCornerShape(5.dp),
modifier = Modifier
.height(34.dp)
.padding(horizontal = 4.dp)
) {
Row(
verticalAlignment = Alignment.CenterVertically,
@ -339,67 +294,111 @@ fun MidiControlPanel(
Text(
text = "A",
color = if (isWaitingForB || isLooping) Color.White else Color.Black,
fontWeight = FontWeight.Bold,
fontSize = 18.sp
fontSize = 16.sp
)
Icon(
imageVector = Icons.Default.Loop,
contentDescription = null,
tint = if (isLooping) Color.White else Color.Black,
modifier = Modifier.size(18.dp)
modifier = Modifier.size(16.dp)
)
Text(
text = "B",
color = if (isLooping) Color.White else Color.Black,
fontWeight = FontWeight.Bold,
fontSize = 18.sp
fontSize = 16.sp
)
}
}
}
Box(contentAlignment = Alignment.Center) {
Spacer(modifier = Modifier.weight(1f))
Column {
IconButton(
onClick = {
showSATBTools = !showSATBTools
}) {
Icon(imageVector = Icons.Default.SettingsVoice, contentDescription = "SATB")
}, modifier = Modifier
.size(40.dp)
.clip(CircleShape)
.background(if (showSATBTools) MaterialTheme.colorScheme.primary else Color.Transparent)
) {
Icon(
painter = painterResource(Res.drawable.ic_mixer_satb),
contentDescription = "SATB",
tint = if (showSATBTools) Color.White else Color.Black,
modifier = Modifier.size(35.dp)
)
}
}
Box(contentAlignment = Alignment.Center) {
Spacer(modifier = Modifier.weight(1f))
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)
)
}
}
}
Spacer(modifier = Modifier.weight(1f))
Column(
modifier = Modifier.wrapContentWidth(),
horizontalAlignment = Alignment.CenterHorizontally
) {
IconButton(
onClick = onPlayPauseClick,
modifier = Modifier.size(48.dp)
modifier = Modifier.size(48.dp).background(MaterialTheme.colorScheme.primary, CircleShape)
) {
Icon(
imageVector = if (isPause) Icons.Filled.PlayArrow else Icons.Filled.Pause,
contentDescription = "Pla",
tint = MaterialTheme.colorScheme.primary
tint = Color.White
)
}
}
Box(contentAlignment = Alignment.CenterEnd) {
IconButton(
onClick = {
showInstruTools = !showInstruTools
}
) {
Icon(imageVector = Icons.Default.Tune, contentDescription = "Instru")
}
}
Spacer(modifier = Modifier.weight(1f))
val platform = getPlatform()
if (platform.name.startsWith("Java")) {
ModernVolumeSlider(
volume, onVolumeChange = onVolumeChange
)
}
Spacer(modifier = Modifier.weight(1f))
Row(
modifier = Modifier.wrapContentWidth(),
horizontalArrangement = Arrangement.End,
verticalAlignment = Alignment.CenterVertically
) {
Spacer(modifier = Modifier.width(8.dp))
IconButton(onClick = { expandedCtl = !expandedCtl }) {
IconButton(
onClick = { expandedCtl = !expandedCtl },
modifier = Modifier.size(48.dp)
) {
Icon(
imageVector = if (expandedCtl) Icons.Default.MoreHoriz else Icons.Default.MoreVert,
contentDescription = "More",
@ -410,3 +409,5 @@ fun MidiControlPanel(
}
}
}
}
}

View file

@ -29,6 +29,7 @@ fun ModernVolumeSlider(
volume: Float,
onVolumeChange: (Float) -> Unit
) {
Column {
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier
@ -71,3 +72,4 @@ fun ModernVolumeSlider(
)
}
}
}