Optimize midi control space & modernize volume slider
This commit is contained in:
parent
337f1d9912
commit
da1d130085
2 changed files with 177 additions and 121 deletions
|
|
@ -46,6 +46,8 @@ import androidx.compose.material.icons.filled.Tonality
|
||||||
import androidx.compose.material.icons.filled.Tune
|
import androidx.compose.material.icons.filled.Tune
|
||||||
import androidx.compose.material.icons.automirrored.filled.VolumeUp
|
import androidx.compose.material.icons.automirrored.filled.VolumeUp
|
||||||
import androidx.compose.material.icons.automirrored.filled.VolumeOff
|
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.Button
|
||||||
import androidx.compose.material3.ButtonDefaults
|
import androidx.compose.material3.ButtonDefaults
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
|
|
@ -80,7 +82,9 @@ import androidx.compose.ui.unit.DpSize
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.unit.sp
|
import androidx.compose.ui.unit.sp
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
|
import mg.dot.feufaro.getPlatform
|
||||||
import mg.dot.feufaro.midi.MediaPlayer
|
import mg.dot.feufaro.midi.MediaPlayer
|
||||||
|
import org.koin.core.component.getScopeId
|
||||||
import javax.swing.Icon
|
import javax.swing.Icon
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
|
|
@ -120,7 +124,7 @@ fun MidiControlPanel(
|
||||||
var showInstruTools by remember { mutableStateOf(false) }
|
var showInstruTools by remember { mutableStateOf(false) }
|
||||||
var showSATBTools by remember { mutableStateOf(false) }
|
var showSATBTools by remember { mutableStateOf(false) }
|
||||||
var showVolumeTools by remember { mutableStateOf(false) }
|
var showVolumeTools by remember { mutableStateOf(false) }
|
||||||
|
var expandedCtl by remember { mutableStateOf(false) }
|
||||||
LaunchedEffect(tempo) {
|
LaunchedEffect(tempo) {
|
||||||
currentBpm = mediaPlayer.getCurrentBPM()
|
currentBpm = mediaPlayer.getCurrentBPM()
|
||||||
}
|
}
|
||||||
|
|
@ -131,64 +135,48 @@ fun MidiControlPanel(
|
||||||
.background(color = Color.Gray.copy(alpha = 0.5f), shape = RoundedCornerShape(size = 5.dp)),
|
.background(color = Color.Gray.copy(alpha = 0.5f), shape = RoundedCornerShape(size = 5.dp)),
|
||||||
horizontalAlignment = Alignment.CenterHorizontally
|
horizontalAlignment = Alignment.CenterHorizontally
|
||||||
) {
|
) {
|
||||||
Row (
|
AnimatedVisibility(
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
visible = !expandedCtl
|
||||||
horizontalArrangement = Arrangement.spacedBy(8.dp)
|
|
||||||
) {
|
) {
|
||||||
Text("${currentPos.toInt() / 1000}s", color = Color.White)
|
Row(
|
||||||
Slider(
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
value = currentPos,
|
horizontalArrangement = Arrangement.spacedBy(8.dp)
|
||||||
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),
|
|
||||||
),
|
|
||||||
thumb = {
|
|
||||||
Box (
|
|
||||||
modifier = Modifier
|
|
||||||
.size(15.dp)
|
|
||||||
.background(Color.Gray, CircleShape)
|
|
||||||
)
|
|
||||||
},
|
|
||||||
track = { sliderState ->
|
|
||||||
SliderDefaults.Track(
|
|
||||||
sliderState = sliderState,
|
|
||||||
modifier = Modifier.height(5.dp)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
Text("${momo / 1000}s", color = Color.White)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Row(
|
|
||||||
verticalAlignment = Alignment.CenterVertically
|
|
||||||
){
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
IconButton(
|
|
||||||
onClick = onPlayPauseClick,
|
|
||||||
modifier = Modifier.size(48.dp)
|
|
||||||
) {
|
) {
|
||||||
Icon(
|
Text("${currentPos.toInt() / 1000}s", color = Color.White)
|
||||||
imageVector = if (isPause) Icons.Filled.PlayArrow else Icons.Filled.Pause,
|
Slider(
|
||||||
contentDescription = "Pla",
|
value = currentPos,
|
||||||
tint = MaterialTheme.colorScheme.primary
|
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),
|
||||||
|
),
|
||||||
|
thumb = {
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.size(15.dp)
|
||||||
|
.background(Color.Gray, CircleShape)
|
||||||
|
)
|
||||||
|
},
|
||||||
|
track = { sliderState ->
|
||||||
|
SliderDefaults.Track(
|
||||||
|
sliderState = sliderState,
|
||||||
|
modifier = Modifier.height(5.dp)
|
||||||
|
)
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
Text("${momo / 1000}s", color = Color.White)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
AnimatedVisibility(
|
AnimatedVisibility(
|
||||||
visible = showSATBTools,
|
visible = showSATBTools,
|
||||||
enter = fadeIn() + scaleIn() + slideInVertically { it / 2 },
|
enter = fadeIn() + scaleIn() + slideInVertically { it / 2 },
|
||||||
|
|
@ -302,10 +290,22 @@ fun MidiControlPanel(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Row(
|
Row(
|
||||||
verticalAlignment = Alignment.CenterVertically
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
horizontalArrangement = Arrangement.SpaceAround
|
||||||
){
|
){
|
||||||
Column(horizontalAlignment = Alignment.CenterHorizontally) {
|
Box(contentAlignment = Alignment.CenterStart) {
|
||||||
|
IconButton(
|
||||||
|
onClick = {
|
||||||
|
showBPMTools = !showBPMTools
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
Icon(imageVector = Icons.Default.AvTimer, contentDescription = "Tempo")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Box( contentAlignment = Alignment.CenterStart) {
|
||||||
val isAtStart = loopState.first == -1L
|
val isAtStart = loopState.first == -1L
|
||||||
val isWaitingForB = loopState.first != -1L && !loopState.third
|
val isWaitingForB = loopState.first != -1L && !loopState.third
|
||||||
val isLooping = loopState.third
|
val isLooping = loopState.third
|
||||||
|
|
@ -326,8 +326,15 @@ fun MidiControlPanel(
|
||||||
else -> Color.LightGray
|
else -> Color.LightGray
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
shape = RoundedCornerShape(5.dp) ,
|
contentPadding = PaddingValues(horizontal = 8.dp, vertical = 0.dp),
|
||||||
modifier = Modifier.padding(2.dp)
|
shape = RoundedCornerShape(5.dp) ,
|
||||||
|
modifier = Modifier
|
||||||
|
.height(34.dp)
|
||||||
|
.padding(horizontal = 4.dp)
|
||||||
|
) {
|
||||||
|
Row(
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
horizontalArrangement = Arrangement.spacedBy(4.dp)
|
||||||
) {
|
) {
|
||||||
Text(
|
Text(
|
||||||
text = "A",
|
text = "A",
|
||||||
|
|
@ -349,80 +356,56 @@ fun MidiControlPanel(
|
||||||
fontWeight = FontWeight.Bold,
|
fontWeight = FontWeight.Bold,
|
||||||
fontSize = 18.sp
|
fontSize = 18.sp
|
||||||
)
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Box(contentAlignment = Alignment.Center) {
|
||||||
Column(horizontalAlignment = Alignment.CenterHorizontally) {
|
|
||||||
IconButton(
|
|
||||||
onClick = {
|
|
||||||
showBPMTools = !showBPMTools
|
|
||||||
}) {
|
|
||||||
Icon(imageVector = Icons.Default.AvTimer, contentDescription = "Tempo")
|
|
||||||
}
|
|
||||||
AnimatedVisibility(visible = showBPMTools){
|
|
||||||
Box(
|
|
||||||
modifier = Modifier
|
|
||||||
.width(20.dp)
|
|
||||||
.height(3.dp)
|
|
||||||
.background(MaterialTheme.colorScheme.primary, RoundedCornerShape(2.dp))
|
|
||||||
)}
|
|
||||||
}
|
|
||||||
|
|
||||||
Column(horizontalAlignment = Alignment.CenterHorizontally) {
|
|
||||||
IconButton(
|
|
||||||
onClick = {
|
|
||||||
showInstruTools = !showInstruTools
|
|
||||||
}) {
|
|
||||||
Icon(imageVector = Icons.Default.Tune, contentDescription = "Instru")
|
|
||||||
}
|
|
||||||
AnimatedVisibility(visible = showInstruTools){
|
|
||||||
Box(
|
|
||||||
modifier = Modifier
|
|
||||||
.width(20.dp)
|
|
||||||
.height(3.dp)
|
|
||||||
.background(MaterialTheme.colorScheme.primary, RoundedCornerShape(2.dp))
|
|
||||||
)}
|
|
||||||
}
|
|
||||||
|
|
||||||
Column(horizontalAlignment = Alignment.CenterHorizontally) {
|
|
||||||
IconButton(
|
IconButton(
|
||||||
onClick = {
|
onClick = {
|
||||||
showSATBTools = !showSATBTools
|
showSATBTools = !showSATBTools
|
||||||
}) {
|
}) {
|
||||||
Icon(imageVector = Icons.Default.SettingsVoice, contentDescription = "SATB")
|
Icon(imageVector = Icons.Default.SettingsVoice, contentDescription = "SATB")
|
||||||
}
|
}
|
||||||
AnimatedVisibility(visible = showSATBTools){
|
|
||||||
Box(
|
|
||||||
modifier = Modifier
|
|
||||||
.width(20.dp)
|
|
||||||
.height(3.dp)
|
|
||||||
.background(MaterialTheme.colorScheme.primary, RoundedCornerShape(2.dp))
|
|
||||||
)}
|
|
||||||
}
|
}
|
||||||
|
Box(contentAlignment = Alignment.Center) {
|
||||||
Column(horizontalAlignment = Alignment.CenterHorizontally) {
|
IconButton(
|
||||||
Icon(
|
onClick = onPlayPauseClick,
|
||||||
imageVector = if (volume > 0) Icons.AutoMirrored.Filled.VolumeUp else Icons.AutoMirrored.Filled.VolumeOff,
|
modifier = Modifier.size(48.dp)
|
||||||
contentDescription = null,
|
) {
|
||||||
modifier = Modifier.size(20.dp)
|
Icon(
|
||||||
|
imageVector = if (isPause) Icons.Filled.PlayArrow else Icons.Filled.Pause,
|
||||||
|
contentDescription = "Pla",
|
||||||
|
tint = MaterialTheme.colorScheme.primary
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Box(contentAlignment = Alignment.CenterEnd) {
|
||||||
|
IconButton(
|
||||||
|
onClick = {
|
||||||
|
showInstruTools = !showInstruTools
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
Icon(imageVector = Icons.Default.Tune, contentDescription = "Instru")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val platform = getPlatform()
|
||||||
|
if (platform.name.startsWith("Java")) {
|
||||||
|
ModernVolumeSlider(
|
||||||
|
volume, onVolumeChange = onVolumeChange
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Column(horizontalAlignment = Alignment.CenterHorizontally) {
|
Row(
|
||||||
Slider(
|
horizontalArrangement = Arrangement.End,
|
||||||
value = volume,
|
verticalAlignment = Alignment.CenterVertically
|
||||||
onValueChange = onVolumeChange,
|
) {
|
||||||
valueRange = 0f..1f,
|
Spacer(modifier = Modifier.width(8.dp))
|
||||||
modifier = Modifier.width(100.dp),
|
IconButton(onClick = { expandedCtl = !expandedCtl }) {
|
||||||
thumb = {
|
Icon(
|
||||||
Box(
|
imageVector = if (expandedCtl) Icons.Default.MoreHoriz else Icons.Default.MoreVert,
|
||||||
modifier = Modifier.size(15.dp).background(Color.Blue, CircleShape)
|
contentDescription = "More",
|
||||||
)
|
tint = Color.White
|
||||||
},
|
)
|
||||||
track = { sliderState ->
|
}
|
||||||
SliderDefaults.Track(
|
|
||||||
sliderState = sliderState, modifier = Modifier.height(5.dp)
|
|
||||||
)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,73 @@
|
||||||
|
package mg.dot.feufaro.ui
|
||||||
|
|
||||||
|
import androidx.compose.foundation.background
|
||||||
|
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.VolumeDown
|
||||||
|
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.Slider
|
||||||
|
import androidx.compose.material3.SliderDefaults
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
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.TransformOrigin
|
||||||
|
import androidx.compose.ui.graphics.graphicsLayer
|
||||||
|
import androidx.compose.ui.platform.LocalViewConfiguration
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
|
||||||
|
|
||||||
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
|
@Composable
|
||||||
|
fun ModernVolumeSlider(
|
||||||
|
volume: Float,
|
||||||
|
onVolumeChange: (Float) -> Unit
|
||||||
|
) {
|
||||||
|
Row(
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
modifier = Modifier
|
||||||
|
.height(42.dp)
|
||||||
|
.background(Color.White.copy(alpha = 0.1f), CircleShape)
|
||||||
|
.padding(horizontal = 12.dp, vertical = 4.dp)
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
imageVector = when {
|
||||||
|
volume == 0f -> Icons.AutoMirrored.Filled.VolumeOff
|
||||||
|
volume < 0.5f -> Icons.AutoMirrored.Filled.VolumeDown
|
||||||
|
else -> Icons.AutoMirrored.Filled.VolumeUp
|
||||||
|
},
|
||||||
|
contentDescription = null,
|
||||||
|
tint = if (volume > 0) Color.Black else Color.Gray,
|
||||||
|
modifier = Modifier.size(20.dp)
|
||||||
|
)
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.width(4.dp))
|
||||||
|
|
||||||
|
Slider(
|
||||||
|
value = volume,
|
||||||
|
onValueChange = onVolumeChange,
|
||||||
|
modifier = Modifier.fillMaxWidth(0.30f),
|
||||||
|
colors = SliderDefaults.colors(
|
||||||
|
activeTrackColor = Color(0xFFF59E0B),
|
||||||
|
inactiveTrackColor = Color.White.copy(alpha = 0.2f),
|
||||||
|
thumbColor = Color.Transparent
|
||||||
|
),
|
||||||
|
track = { sliderState ->
|
||||||
|
SliderDefaults.Track(
|
||||||
|
sliderState = sliderState,
|
||||||
|
modifier = Modifier.height(15.dp),
|
||||||
|
thumbTrackGapSize = 0.dp
|
||||||
|
)
|
||||||
|
},
|
||||||
|
thumb = {
|
||||||
|
Box(Modifier.size(0.dp))
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Reference in a new issue