Skip to content

Commit

Permalink
Merge pull request #27 from EchoInMirror/refactor_settings_ui
Browse files Browse the repository at this point in the history
Refactor settings UI
  • Loading branch information
ShirasawaSama authored Dec 10, 2023
2 parents c6070f3 + c4fded9 commit 52f3137
Show file tree
Hide file tree
Showing 5 changed files with 276 additions and 323 deletions.
Original file line number Diff line number Diff line change
@@ -1,13 +1,20 @@
package com.eimsound.daw.components
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Delete
import androidx.compose.material.icons.filled.ExpandMore
import androidx.compose.material3.*
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.input.pointer.PointerIcon
import androidx.compose.ui.input.pointer.pointerHoverIcon
import androidx.compose.ui.text.font.FontStyle
import androidx.compose.ui.text.rememberTextMeasurer
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp

Expand All @@ -16,6 +23,60 @@ private val EXPANDER_PADDING_HORIZONTAL = 16.dp
private val EXPANDER_PADDING_VERTICAL = 8.dp
private val EXPANDER_CARD_GAP = 4.dp
private val LIST_HEIGHT = 36.dp
private val CARD_HEIGHT = 64.dp
private val EXPAND_ICON_SIZE = 20.dp
private val MENU_MAX_WIDTH = 256.dp

@Composable
fun <T> SettingsMenu(
items: Collection<T>?,
selected: T,
toString: (T) -> String = { it.toString() },
onSelect: (T) -> Unit
) {
if (items == null) return
val textMeasurer = rememberTextMeasurer()
val itemsMap = items.associateBy { toString(it) }
val textWidth = (items.maxOfOrNull { textMeasurer.measure(toString(it)).size.width.dp } ?: 0.dp) + EXPANDER_PADDING_HORIZONTAL * 2
val maxWidth = if (textWidth > MENU_MAX_WIDTH) MENU_MAX_WIDTH else textWidth
OutlinedDropdownSelector(
{ itemsMap[it]?.let { selected -> onSelect(selected) } },
itemsMap.keys,
selected = toString(selected),
) {
CustomOutlinedTextField(
toString(selected), { },
Modifier.width(maxWidth).height(LIST_HEIGHT).pointerHoverIcon(PointerIcon.Hand),
readOnly = true,
textStyle = MaterialTheme.typography.labelLarge.copy(LocalContentColor.current),
suffix = {
Icon(Icons.Filled.ExpandMore, "Expand",
Modifier.size(EXPAND_ICON_SIZE).pointerHoverIcon(PointerIcon.Hand).clip(CircleShape)
.clickable { }
)
},
colors = TextFieldDefaults.colors(
unfocusedIndicatorColor = MaterialTheme.colorScheme.outlineVariant,
focusedIndicatorColor = MaterialTheme.colorScheme.outlineVariant,
),
paddingValues = TextFieldDefaults.contentPaddingWithLabel(8.dp, 4.dp, 3.dp, 4.dp)
)
}
}

@Composable
fun SettingsSection(
title: String? = null,
content: @Composable () -> Unit
) {
Column {
if (title != null){
Text(title, style = MaterialTheme.typography.bodyMedium)
Gap(8)
}
content()
}
}

@Composable
fun SettingsCard(
Expand All @@ -24,7 +85,7 @@ fun SettingsCard(
) {
Surface(
shape = MaterialTheme.shapes.small,
modifier = Modifier.padding(bottom = EXPANDER_CARD_GAP)
modifier = Modifier.padding(bottom = EXPANDER_CARD_GAP).height(CARD_HEIGHT)
) {
Row(
verticalAlignment = Alignment.CenterVertically,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
package com.eimsound.daw.window.dialogs.settings

import androidx.compose.foundation.layout.*
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.SettingsInputComponent
import androidx.compose.material3.*
import androidx.compose.material3.Icon
import androidx.compose.material3.Switch
import androidx.compose.material3.Text
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.util.fastForEach
import com.eimsound.audioprocessor.AudioPlayerManager
import com.eimsound.daw.Configuration
import com.eimsound.daw.api.EchoInMirror
Expand Down Expand Up @@ -52,113 +54,81 @@ internal object AudioSettings : SettingTab {
@Composable
override fun content() {
Column {
Row(verticalAlignment = Alignment.CenterVertically) {
Text("音频工厂:", Modifier.weight(1f))
Menu({ close ->
AudioPlayerManager.instance.factories.forEach { (name, _) ->
MenuItem({
close()
if (Configuration.audioDeviceFactoryName == name) return@MenuItem
EchoInMirror.player?.close()
Configuration.audioDeviceName = ""
Configuration.audioDeviceFactoryName = name

reopenAudioDevice()
}, Configuration.audioDeviceFactoryName == name, modifier = Modifier.fillMaxWidth()) {
Text(name)
}
SettingsSection("设备与音频设置") {
SettingsCard("音频工厂") {
SettingsMenu(
AudioPlayerManager.instance.factories.keys,
Configuration.audioDeviceFactoryName
) {
if (Configuration.audioDeviceFactoryName == it) return@SettingsMenu
EchoInMirror.player?.close()
Configuration.audioDeviceName = ""
Configuration.audioDeviceFactoryName = it
reopenAudioDevice()
}
}, boxModifier = Modifier.weight(1f)) {
Text(Configuration.audioDeviceFactoryName, Modifier.fillMaxWidth())
}
}
Gap(8)

Row(verticalAlignment = Alignment.CenterVertically) {
Text("音频设备:", Modifier.weight(1f))
Menu({ close ->
SettingsCard("音频设备") {
var playerNames by remember { mutableStateOf(emptyList<String>()) }
LaunchedEffect(Configuration.audioDeviceName) {
playerNames = AudioPlayerManager.instance.factories[Configuration.audioDeviceFactoryName]!!.getPlayers()
}
playerNames.fastForEach { playerName ->
MenuItem({
close()
if (Configuration.audioDeviceName == playerName) return@MenuItem
EchoInMirror.player?.close()
Configuration.audioDeviceName = playerName

reopenAudioDevice()
}, Configuration.audioDeviceName == playerName, modifier = Modifier.fillMaxWidth()) {
Text(playerName)
}
SettingsMenu(
playerNames,
Configuration.audioDeviceName
) {
if (Configuration.audioDeviceName == it) return@SettingsMenu
EchoInMirror.player?.close()
Configuration.audioDeviceName = it
reopenAudioDevice()
}
}, boxModifier = Modifier.weight(1f)) {
Text(Configuration.audioDeviceName, Modifier.fillMaxWidth())
}
}
Gap(8)
Row(verticalAlignment = Alignment.CenterVertically) {
Text("缓冲区大小:", Modifier.weight(1f))
Menu({ close ->
EchoInMirror.player?.availableBufferSizes?.forEach {
MenuItem({
close()
EchoInMirror.player?.close()
SettingsCard("缓冲区大小") {
SettingsMenu(
EchoInMirror.player?.availableBufferSizes?.toList(),
EchoInMirror.currentPosition.bufferSize,
{ "$it 个采样" }
) {
EchoInMirror.player?.close()
// EchoInMirror.currentPosition.setSampleRateAndBufferSize(
// EchoInMirror.currentPosition.sampleRate, it
// )

reopenAudioDevice()
}, EchoInMirror.currentPosition.bufferSize == it, modifier = Modifier.fillMaxWidth()) {
Text("$it 个采样")
}
reopenAudioDevice()
}
}, boxModifier = Modifier.weight(1f)) {
Text("${EchoInMirror.currentPosition.bufferSize} 个采样", Modifier.fillMaxWidth())
}
}

Gap(8)
Row(verticalAlignment = Alignment.CenterVertically) {
Text("采样率:", Modifier.weight(1f))
Menu({ close ->
val sampleRate = EchoInMirror.player?.sampleRate
EchoInMirror.player?.availableSampleRates?.fastForEach {
MenuItem({
close()
EchoInMirror.player?.close()
Configuration.preferredSampleRate = it
SettingsCard("采样率") {
var sampleRate by remember { mutableStateOf(EchoInMirror.currentPosition.sampleRate) }
SettingsMenu(
EchoInMirror.player?.availableSampleRates?.toList(),
sampleRate,
) {
sampleRate = it
EchoInMirror.player?.close()
Configuration.preferredSampleRate = it

reopenAudioDevice()
}, sampleRate == it, modifier = Modifier.fillMaxWidth()) {
Text(it.toString())
}
reopenAudioDevice()
}
}, boxModifier = Modifier.weight(1f)) {
Text(EchoInMirror.player?.sampleRate?.toString() ?: "未知", Modifier.fillMaxWidth())
}
if (SystemUtils.IS_OS_WINDOWS) SettingsCard("后台共享音频设备") {
Switch(
Configuration.stopAudioOutputOnBlur,
{
Configuration.stopAudioOutputOnBlur = it
Configuration.save()
}
)
}
SettingsCard("对超过 0db 的音频进行削波") {
Switch(
Configuration.autoCutOver0db,
{
Configuration.autoCutOver0db = it
Configuration.save()
}
)
}
}

if (SystemUtils.IS_OS_WINDOWS) Row(verticalAlignment = Alignment.CenterVertically) {
Text("后台共享音频设备")
Checkbox(
Configuration.stopAudioOutputOnBlur,
{
Configuration.stopAudioOutputOnBlur = it
Configuration.save()
}
)
}

Row(verticalAlignment = Alignment.CenterVertically) {
Text("对超过 0db 的音频进行削波")
Checkbox(
Configuration.autoCutOver0db,
{
Configuration.autoCutOver0db = it
Configuration.save()
}
)
}

Gap(8)
Latency("输入延迟", EchoInMirror.player?.inputLatency ?: 0)
Latency("输出延迟", EchoInMirror.player?.outputLatency ?: 0)
Gap(8)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import androidx.compose.runtime.Composable
import com.eimsound.daw.Configuration
import com.eimsound.daw.components.Gap
import com.eimsound.daw.components.SettingTab
import com.eimsound.daw.components.SettingsSection
import com.eimsound.daw.components.SettingsCard
import com.eimsound.daw.components.SettingsListManager
import com.eimsound.daw.utils.CurrentWindow
Expand All @@ -30,7 +31,7 @@ internal object FileBrowserSettings : SettingTab {
val window = CurrentWindow.current

Column {
SettingSection("文件浏览器的自定义文件夹") {
SettingsSection("文件浏览器的自定义文件夹") {
SettingsListManager(
Configuration.fileBrowserCustomRoots,
addButtonText = "添加文件夹",
Expand All @@ -48,28 +49,17 @@ internal object FileBrowserSettings : SettingTab {
)
}
Gap(16)
SettingSection("文件浏览器的个性化配置项") {
SettingsSection("文件浏览器的个性化配置项") {
SettingsCard("只显示受支持格式的文件") {
Switch(checked = Configuration.fileBrowserShowSupFormatOnly, onCheckedChange = {
Configuration.fileBrowserShowSupFormatOnly = it
Configuration.save()
})
Switch(
Configuration.fileBrowserShowSupFormatOnly,
{
Configuration.fileBrowserShowSupFormatOnly = it
Configuration.save()
}
)
}
}
}
}
}

@Composable
private fun SettingSection(
title: String? = null,
content: @Composable () -> Unit
){
Column {
if (title != null){
Text(title, style = MaterialTheme.typography.bodyMedium)
Gap(8)
}
content()
}
}
Loading

0 comments on commit 52f3137

Please sign in to comment.