Renamed all tabs qml, so its easier to distinguish them from services
This commit is contained in:
parent
eac335ab95
commit
39cc72f067
13 changed files with 80 additions and 22 deletions
269
Modules/Settings/Tabs/AudioTab.qml
Normal file
269
Modules/Settings/Tabs/AudioTab.qml
Normal file
|
|
@ -0,0 +1,269 @@
|
|||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
import Quickshell.Services.Pipewire
|
||||
|
||||
import qs.Modules.Settings
|
||||
import qs.Widgets
|
||||
import qs.Services
|
||||
|
||||
ColumnLayout {
|
||||
id: root
|
||||
|
||||
property real localVolume: Audio.volume
|
||||
|
||||
// Connection used to open the pill when volume changes
|
||||
Connections {
|
||||
target: Audio.sink?.audio ? Audio.sink?.audio : null
|
||||
function onVolumeChanged() {
|
||||
localVolume = Audio.volume
|
||||
}
|
||||
}
|
||||
|
||||
spacing: 0
|
||||
|
||||
ScrollView {
|
||||
id: scrollView
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
padding: Style.marginMedium * scaling
|
||||
clip: true
|
||||
ScrollBar.horizontal.policy: ScrollBar.AlwaysOff
|
||||
ScrollBar.vertical.policy: ScrollBar.AsNeeded
|
||||
|
||||
ColumnLayout {
|
||||
width: scrollView.availableWidth
|
||||
spacing: 0
|
||||
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: 0
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
spacing: Style.marginTiny * scaling
|
||||
Layout.fillWidth: true
|
||||
|
||||
NText {
|
||||
text: "Audio"
|
||||
font.pointSize: Style.fontSizeXL * scaling
|
||||
font.weight: Style.fontWeightBold
|
||||
color: Colors.mOnSurface
|
||||
Layout.bottomMargin: Style.marginSmall * scaling
|
||||
}
|
||||
|
||||
// Volume Controls
|
||||
ColumnLayout {
|
||||
spacing: Style.marginSmall * scaling
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: Style.marginSmall * scaling
|
||||
|
||||
// Master Volume
|
||||
ColumnLayout {
|
||||
spacing: Style.marginSmall * scaling
|
||||
Layout.fillWidth: true
|
||||
|
||||
ColumnLayout {
|
||||
spacing: Style.marginTiniest * scaling
|
||||
|
||||
NText {
|
||||
text: "Master Volume"
|
||||
font.weight: Style.fontWeightBold
|
||||
color: Colors.mOnSurface
|
||||
}
|
||||
|
||||
NText {
|
||||
text: "System-wide volume level"
|
||||
font.pointSize: Style.fontSizeSmall * scaling
|
||||
color: Colors.mOnSurface
|
||||
wrapMode: Text.WordWrap
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
}
|
||||
RowLayout {
|
||||
// Pipewire seems a bit finicky, if we spam too many volume changes it breaks easily
|
||||
// Probably because they have some quick fades in and out to avoid clipping
|
||||
// We use a timer to space out the updates, to avoid lock up
|
||||
Timer {
|
||||
interval: 100
|
||||
running: true
|
||||
repeat: true
|
||||
onTriggered: {
|
||||
if (Math.abs(localVolume - Audio.volume) >= 0.01) {
|
||||
Audio.setVolume(localVolume)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NSlider {
|
||||
Layout.fillWidth: true
|
||||
from: 0
|
||||
to: Settings.data.audio.volumeOverdrive ? 2.0 : 1.0
|
||||
value: localVolume
|
||||
stepSize: 0.01
|
||||
onMoved: {
|
||||
localVolume = value
|
||||
}
|
||||
}
|
||||
|
||||
NText {
|
||||
text: Math.floor(Audio.volume * 100) + "%"
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
color: Colors.mOnSurface
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Mute Toggle
|
||||
ColumnLayout {
|
||||
spacing: Style.marginSmall * scaling
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: Style.marginMedium * scaling
|
||||
|
||||
NToggle {
|
||||
label: "Mute Audio"
|
||||
description: "Mute or unmute the default audio output"
|
||||
value: Audio.muted
|
||||
onToggled: function (newValue) {
|
||||
if (Audio.sink && Audio.sink.audio) {
|
||||
Audio.sink.audio.muted = newValue
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NDivider {
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: Style.marginLarge * 2 * scaling
|
||||
Layout.bottomMargin: Style.marginLarge * scaling
|
||||
}
|
||||
|
||||
// Audio Devices
|
||||
ColumnLayout {
|
||||
spacing: Style.marginLarge * scaling
|
||||
Layout.fillWidth: true
|
||||
|
||||
NText {
|
||||
text: "Audio Devices"
|
||||
font.pointSize: Style.fontSizeXL * scaling
|
||||
font.weight: Style.fontWeightBold
|
||||
color: Colors.mOnSurface
|
||||
Layout.bottomMargin: Style.marginSmall * scaling
|
||||
}
|
||||
|
||||
// -------------------------------
|
||||
// Output Devices
|
||||
ButtonGroup {
|
||||
id: sinks
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
spacing: Style.marginTiniest * scaling
|
||||
Layout.fillWidth: true
|
||||
Layout.bottomMargin: Style.marginLarge * scaling
|
||||
|
||||
NText {
|
||||
text: "Output Device"
|
||||
font.pointSize: Style.fontSizeMedium * scaling
|
||||
font.weight: Style.fontWeightBold
|
||||
color: Colors.mOnSurface
|
||||
}
|
||||
|
||||
NText {
|
||||
text: "Select the desired audio output device"
|
||||
font.pointSize: Style.fontSizeSmall * scaling
|
||||
color: Colors.mOnSurface
|
||||
wrapMode: Text.WordWrap
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
Repeater {
|
||||
model: Audio.sinks
|
||||
NRadioButton {
|
||||
required property PwNode modelData
|
||||
ButtonGroup.group: sinks
|
||||
checked: Audio.sink?.id === modelData.id
|
||||
onClicked: Audio.setAudioSink(modelData)
|
||||
text: modelData.description
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------
|
||||
// Input Devices
|
||||
ButtonGroup {
|
||||
id: sources
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
spacing: Style.marginTiniest * scaling
|
||||
Layout.fillWidth: true
|
||||
Layout.bottomMargin: Style.marginLarge * scaling
|
||||
|
||||
NText {
|
||||
text: "Input Device"
|
||||
font.pointSize: Style.fontSizeMedium * scaling
|
||||
font.weight: Style.fontWeightBold
|
||||
color: Colors.mOnSurface
|
||||
}
|
||||
|
||||
NText {
|
||||
text: "Select desired audio input device"
|
||||
font.pointSize: Style.fontSizeSmall * scaling
|
||||
color: Colors.mOnSurface
|
||||
wrapMode: Text.WordWrap
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
Repeater {
|
||||
model: Audio.sources
|
||||
NRadioButton {
|
||||
required property PwNode modelData
|
||||
ButtonGroup.group: sources
|
||||
checked: Audio.source?.id === modelData.id
|
||||
onClicked: Audio.setAudioSource(modelData)
|
||||
text: modelData.description
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Divider
|
||||
NDivider {
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: Style.marginLarge * scaling
|
||||
Layout.bottomMargin: Style.marginMedium * scaling
|
||||
}
|
||||
|
||||
// Audio Visualizer Category
|
||||
ColumnLayout {
|
||||
spacing: Style.marginSmall * scaling
|
||||
Layout.fillWidth: true
|
||||
|
||||
NText {
|
||||
text: "Audio Visualizer"
|
||||
font.pointSize: Style.fontSizeXL * scaling
|
||||
font.weight: Style.fontWeightBold
|
||||
color: Colors.mOnSurface
|
||||
Layout.bottomMargin: Style.marginSmall * scaling
|
||||
}
|
||||
|
||||
// Audio Visualizer section
|
||||
NComboBox {
|
||||
id: audioVisualizerCombo
|
||||
label: "Visualization Type"
|
||||
description: "Choose a visualization type for media playback"
|
||||
optionsKeys: ["none", "linear"]
|
||||
optionsLabels: ["None", "Linear"]
|
||||
currentKey: Settings.data.audio.visualizerType
|
||||
onSelected: function (key) {
|
||||
Settings.data.audio.visualizerType = key
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue