add noctalia and fuzzel
This commit is contained in:
+54
@@ -0,0 +1,54 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
import qs.Commons
|
||||
import qs.Widgets
|
||||
|
||||
ColumnLayout {
|
||||
id: root
|
||||
spacing: 0
|
||||
|
||||
NTabBar {
|
||||
id: subTabBar
|
||||
Layout.fillWidth: true
|
||||
Layout.bottomMargin: Style.marginM
|
||||
distributeEvenly: true
|
||||
currentIndex: tabView.currentIndex
|
||||
|
||||
NTabButton {
|
||||
text: I18n.tr("common.volumes")
|
||||
tabIndex: 0
|
||||
checked: subTabBar.currentIndex === 0
|
||||
}
|
||||
NTabButton {
|
||||
text: I18n.tr("common.devices")
|
||||
tabIndex: 1
|
||||
checked: subTabBar.currentIndex === 1
|
||||
}
|
||||
NTabButton {
|
||||
text: I18n.tr("common.media")
|
||||
tabIndex: 2
|
||||
checked: subTabBar.currentIndex === 2
|
||||
}
|
||||
NTabButton {
|
||||
text: I18n.tr("common.visualizer")
|
||||
tabIndex: 3
|
||||
checked: subTabBar.currentIndex === 3
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: Style.marginL
|
||||
}
|
||||
|
||||
NTabView {
|
||||
id: tabView
|
||||
currentIndex: subTabBar.currentIndex
|
||||
|
||||
VolumesSubTab {}
|
||||
DevicesSubTab {}
|
||||
MediaSubTab {}
|
||||
VisualizerSubTab {}
|
||||
}
|
||||
}
|
||||
+70
@@ -0,0 +1,70 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
import Quickshell.Services.Pipewire
|
||||
import qs.Commons
|
||||
import qs.Services.Media
|
||||
import qs.Widgets
|
||||
|
||||
ColumnLayout {
|
||||
id: root
|
||||
spacing: Style.marginL
|
||||
Layout.fillWidth: true
|
||||
|
||||
// Output Devices
|
||||
ButtonGroup {
|
||||
id: sinks
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
spacing: Style.marginXS
|
||||
Layout.fillWidth: true
|
||||
Layout.bottomMargin: Style.marginL
|
||||
|
||||
NLabel {
|
||||
label: I18n.tr("panels.audio.devices-output-device-label")
|
||||
description: I18n.tr("panels.audio.devices-output-device-description")
|
||||
}
|
||||
|
||||
Repeater {
|
||||
model: AudioService.sinks
|
||||
NRadioButton {
|
||||
ButtonGroup.group: sinks
|
||||
required property PwNode modelData
|
||||
text: modelData.description
|
||||
checked: AudioService.sink?.id === modelData.id
|
||||
onClicked: {
|
||||
AudioService.setAudioSink(modelData);
|
||||
}
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Input Devices
|
||||
ButtonGroup {
|
||||
id: sources
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
spacing: Style.marginXS
|
||||
Layout.fillWidth: true
|
||||
|
||||
NLabel {
|
||||
label: I18n.tr("panels.audio.devices-input-device-label")
|
||||
description: I18n.tr("panels.audio.devices-input-device-description")
|
||||
}
|
||||
|
||||
Repeater {
|
||||
model: AudioService.sources
|
||||
NRadioButton {
|
||||
ButtonGroup.group: sources
|
||||
required property PwNode modelData
|
||||
text: modelData.description
|
||||
checked: AudioService.source?.id === modelData.id
|
||||
onClicked: AudioService.setAudioSource(modelData)
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+104
@@ -0,0 +1,104 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
import qs.Commons
|
||||
import qs.Services.Media
|
||||
import qs.Widgets
|
||||
|
||||
ColumnLayout {
|
||||
id: root
|
||||
spacing: Style.marginL
|
||||
Layout.fillWidth: true
|
||||
|
||||
// Preferred player
|
||||
NTextInput {
|
||||
label: I18n.tr("panels.audio.media-primary-player-label")
|
||||
description: I18n.tr("panels.audio.media-primary-player-description")
|
||||
placeholderText: I18n.tr("panels.audio.media-primary-player-placeholder")
|
||||
text: Settings.data.audio.preferredPlayer
|
||||
defaultValue: Settings.getDefaultValue("audio.preferredPlayer")
|
||||
onTextChanged: {
|
||||
Settings.data.audio.preferredPlayer = text;
|
||||
MediaService.updateCurrentPlayer();
|
||||
}
|
||||
}
|
||||
|
||||
// Blacklist editor
|
||||
ColumnLayout {
|
||||
spacing: Style.marginS
|
||||
Layout.fillWidth: true
|
||||
|
||||
NTextInputButton {
|
||||
id: blacklistInput
|
||||
label: I18n.tr("panels.audio.media-excluded-player-label")
|
||||
description: I18n.tr("panels.audio.media-excluded-player-description")
|
||||
placeholderText: I18n.tr("panels.audio.media-excluded-player-placeholder")
|
||||
buttonIcon: "add"
|
||||
Layout.fillWidth: true
|
||||
onButtonClicked: {
|
||||
const val = (blacklistInput.text || "").trim();
|
||||
if (val !== "") {
|
||||
const arr = (Settings.data.audio.mprisBlacklist || []);
|
||||
if (!arr.find(x => String(x).toLowerCase() === val.toLowerCase())) {
|
||||
Settings.data.audio.mprisBlacklist = [...arr, val];
|
||||
blacklistInput.text = "";
|
||||
MediaService.updateCurrentPlayer();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Current blacklist entries
|
||||
Flow {
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: Style.marginS
|
||||
spacing: Style.marginS
|
||||
|
||||
Repeater {
|
||||
model: Settings.data.audio.mprisBlacklist
|
||||
delegate: Rectangle {
|
||||
required property string modelData
|
||||
property real pad: Style.marginS
|
||||
color: Qt.alpha(Color.mOnSurface, 0.125)
|
||||
border.color: Qt.alpha(Color.mOnSurface, Style.opacityLight)
|
||||
border.width: Style.borderS
|
||||
|
||||
RowLayout {
|
||||
id: chipRow
|
||||
spacing: Style.marginXS
|
||||
anchors.fill: parent
|
||||
anchors.margins: pad
|
||||
|
||||
NText {
|
||||
text: modelData
|
||||
color: Color.mOnSurface
|
||||
pointSize: Style.fontSizeS
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
Layout.leftMargin: Style.marginS
|
||||
}
|
||||
|
||||
NIconButton {
|
||||
icon: "close"
|
||||
baseSize: Style.baseWidgetSize * 0.8
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
Layout.rightMargin: Style.marginXS
|
||||
onClicked: {
|
||||
const arr = (Settings.data.audio.mprisBlacklist || []);
|
||||
const idx = arr.findIndex(x => String(x) === modelData);
|
||||
if (idx >= 0) {
|
||||
arr.splice(idx, 1);
|
||||
Settings.data.audio.mprisBlacklist = arr;
|
||||
MediaService.updateCurrentPlayer();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
implicitWidth: chipRow.implicitWidth + pad * 2
|
||||
implicitHeight: Math.max(chipRow.implicitHeight + pad * 2, Style.baseWidgetSize * 0.8)
|
||||
radius: Style.radiusM
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+97
@@ -0,0 +1,97 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
import qs.Commons
|
||||
import qs.Widgets
|
||||
|
||||
ColumnLayout {
|
||||
id: root
|
||||
spacing: Style.marginL
|
||||
Layout.fillWidth: true
|
||||
|
||||
NComboBox {
|
||||
label: I18n.tr("panels.audio.visualizer-type-label")
|
||||
description: I18n.tr("panels.audio.visualizer-type-description")
|
||||
model: [
|
||||
{
|
||||
"key": "none",
|
||||
"name": I18n.tr("common.none")
|
||||
},
|
||||
{
|
||||
"key": "linear",
|
||||
"name": I18n.tr("options.visualizer-types.linear")
|
||||
},
|
||||
{
|
||||
"key": "mirrored",
|
||||
"name": I18n.tr("options.visualizer-types.mirrored")
|
||||
},
|
||||
{
|
||||
"key": "wave",
|
||||
"name": I18n.tr("options.visualizer-types.wave")
|
||||
}
|
||||
]
|
||||
currentKey: Settings.data.audio.visualizerType
|
||||
defaultValue: Settings.getDefaultValue("audio.visualizerType")
|
||||
onSelected: key => Settings.data.audio.visualizerType = key
|
||||
}
|
||||
|
||||
NToggle {
|
||||
label: I18n.tr("panels.audio.spectrum-mirrored-label")
|
||||
description: I18n.tr("panels.audio.spectrum-mirrored-description")
|
||||
checked: Settings.data.audio.spectrumMirrored
|
||||
defaultValue: Settings.getDefaultValue("audio.spectrumMirrored")
|
||||
onToggled: Settings.data.audio.spectrumMirrored = checked
|
||||
}
|
||||
|
||||
NComboBox {
|
||||
label: I18n.tr("panels.audio.media-frame-rate-label")
|
||||
description: I18n.tr("panels.audio.media-frame-rate-description")
|
||||
model: [
|
||||
{
|
||||
"key": "30",
|
||||
"name": I18n.tr("options.frame-rates-fps", {
|
||||
"fps": "30"
|
||||
})
|
||||
},
|
||||
{
|
||||
"key": "60",
|
||||
"name": I18n.tr("options.frame-rates-fps", {
|
||||
"fps": "60"
|
||||
})
|
||||
},
|
||||
{
|
||||
"key": "100",
|
||||
"name": I18n.tr("options.frame-rates-fps", {
|
||||
"fps": "100"
|
||||
})
|
||||
},
|
||||
{
|
||||
"key": "120",
|
||||
"name": I18n.tr("options.frame-rates-fps", {
|
||||
"fps": "120"
|
||||
})
|
||||
},
|
||||
{
|
||||
"key": "144",
|
||||
"name": I18n.tr("options.frame-rates-fps", {
|
||||
"fps": "144"
|
||||
})
|
||||
},
|
||||
{
|
||||
"key": "165",
|
||||
"name": I18n.tr("options.frame-rates-fps", {
|
||||
"fps": "165"
|
||||
})
|
||||
},
|
||||
{
|
||||
"key": "240",
|
||||
"name": I18n.tr("options.frame-rates-fps", {
|
||||
"fps": "240"
|
||||
})
|
||||
}
|
||||
]
|
||||
currentKey: Settings.data.audio.spectrumFrameRate
|
||||
defaultValue: Settings.getDefaultValue("audio.spectrumFrameRate")
|
||||
onSelected: key => Settings.data.audio.spectrumFrameRate = key
|
||||
}
|
||||
}
|
||||
+196
@@ -0,0 +1,196 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
import Quickshell
|
||||
import qs.Commons
|
||||
import qs.Services.Media
|
||||
import qs.Services.System
|
||||
import qs.Widgets
|
||||
|
||||
ColumnLayout {
|
||||
id: root
|
||||
spacing: Style.marginL
|
||||
Layout.fillWidth: true
|
||||
|
||||
property real localVolume: AudioService.volume
|
||||
|
||||
Connections {
|
||||
target: AudioService
|
||||
function onSinkChanged() {
|
||||
localVolume = AudioService.volume;
|
||||
}
|
||||
function onVolumeChanged() {
|
||||
localVolume = AudioService.volume;
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: AudioService.sink?.audio ? AudioService.sink?.audio : null
|
||||
function onVolumeChanged() {
|
||||
localVolume = AudioService.volume;
|
||||
}
|
||||
}
|
||||
|
||||
// Output Volume
|
||||
ColumnLayout {
|
||||
spacing: Style.marginXXS
|
||||
Layout.fillWidth: true
|
||||
|
||||
NValueSlider {
|
||||
Layout.fillWidth: true
|
||||
label: I18n.tr("panels.osd.types-volume-label")
|
||||
description: I18n.tr("panels.audio.volumes-output-volume-description")
|
||||
from: 0
|
||||
to: Settings.data.audio.volumeOverdrive ? 1.5 : 1.0
|
||||
value: localVolume
|
||||
stepSize: 0.01
|
||||
text: Math.round(AudioService.volume * 100) + "%"
|
||||
onMoved: value => localVolume = value
|
||||
}
|
||||
|
||||
Timer {
|
||||
interval: 100
|
||||
running: true
|
||||
repeat: true
|
||||
onTriggered: {
|
||||
if (!AudioService.isSwitchingSink && Math.abs(localVolume - AudioService.volume) >= 0.01) {
|
||||
AudioService.setVolume(localVolume);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Mute Toggle
|
||||
ColumnLayout {
|
||||
spacing: Style.marginS
|
||||
Layout.fillWidth: true
|
||||
|
||||
NToggle {
|
||||
label: I18n.tr("panels.audio.volumes-mute-output-label")
|
||||
description: I18n.tr("panels.audio.volumes-mute-output-description")
|
||||
checked: AudioService.muted
|
||||
onToggled: checked => AudioService.setOutputMuted(checked)
|
||||
}
|
||||
}
|
||||
|
||||
// Volume Feedback sound Toggle
|
||||
ColumnLayout {
|
||||
spacing: Style.marginS
|
||||
Layout.fillWidth: true
|
||||
|
||||
NToggle {
|
||||
label: I18n.tr("panels.audio.volumes-volume-feedback-label")
|
||||
description: I18n.tr("panels.audio.volumes-volume-feedback-description")
|
||||
checked: Settings.data.audio.volumeFeedback
|
||||
defaultValue: Settings.getDefaultValue("audio.volumeFeedback")
|
||||
onToggled: checked => Settings.data.audio.volumeFeedback = checked
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
enabled: SoundService.multimediaAvailable && Settings.data.audio.volumeFeedback
|
||||
spacing: Style.marginXXS
|
||||
Layout.fillWidth: true
|
||||
|
||||
NLabel {
|
||||
label: I18n.tr("panels.audio.volumes-feedback-sound-file-label")
|
||||
description: I18n.tr("panels.audio.volumes-feedback-sound-file-description")
|
||||
}
|
||||
|
||||
NTextInputButton {
|
||||
enabled: parent.enabled
|
||||
Layout.fillWidth: true
|
||||
placeholderText: I18n.tr("panels.notifications.sounds-files-placeholder")
|
||||
text: Settings.data.audio.volumeFeedbackSoundFile ?? ""
|
||||
buttonIcon: "folder-open"
|
||||
buttonTooltip: I18n.tr("panels.notifications.sounds-files-select-file")
|
||||
onInputTextChanged: text => Settings.data.audio.volumeFeedbackSoundFile = text
|
||||
onButtonClicked: volumeFeedbackFilePicker.open()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NDivider {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
// Input Volume
|
||||
ColumnLayout {
|
||||
spacing: Style.marginXS
|
||||
Layout.fillWidth: true
|
||||
|
||||
NValueSlider {
|
||||
Layout.fillWidth: true
|
||||
label: I18n.tr("panels.osd.types-input-volume-label")
|
||||
description: I18n.tr("panels.audio.volumes-input-volume-description")
|
||||
from: 0
|
||||
to: Settings.data.audio.volumeOverdrive ? 1.5 : 1.0
|
||||
value: AudioService.inputVolume
|
||||
stepSize: 0.01
|
||||
text: Math.round(AudioService.inputVolume * 100) + "%"
|
||||
onMoved: value => AudioService.setInputVolume(value)
|
||||
}
|
||||
}
|
||||
|
||||
// Input Mute Toggle
|
||||
ColumnLayout {
|
||||
spacing: Style.marginS
|
||||
Layout.fillWidth: true
|
||||
|
||||
NToggle {
|
||||
label: I18n.tr("panels.audio.volumes-mute-input-label")
|
||||
description: I18n.tr("panels.audio.volumes-mute-input-description")
|
||||
checked: AudioService.inputMuted
|
||||
onToggled: checked => AudioService.setInputMuted(checked)
|
||||
}
|
||||
}
|
||||
|
||||
// Volume Step Size
|
||||
ColumnLayout {
|
||||
spacing: Style.marginS
|
||||
Layout.fillWidth: true
|
||||
|
||||
NSpinBox {
|
||||
Layout.fillWidth: true
|
||||
label: I18n.tr("panels.audio.volumes-step-size-label")
|
||||
description: I18n.tr("panels.audio.volumes-step-size-description")
|
||||
minimum: 1
|
||||
maximum: 25
|
||||
value: Settings.data.audio.volumeStep
|
||||
stepSize: 1
|
||||
suffix: "%"
|
||||
defaultValue: Settings.getDefaultValue("audio.volumeStep")
|
||||
onValueChanged: Settings.data.audio.volumeStep = value
|
||||
}
|
||||
}
|
||||
|
||||
NDivider {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
// Raise maximum volume above 100%
|
||||
ColumnLayout {
|
||||
spacing: Style.marginS
|
||||
Layout.fillWidth: true
|
||||
|
||||
NToggle {
|
||||
label: I18n.tr("panels.audio.volumes-volume-overdrive-label")
|
||||
description: I18n.tr("panels.audio.volumes-volume-overdrive-description")
|
||||
checked: Settings.data.audio.volumeOverdrive
|
||||
defaultValue: Settings.getDefaultValue("audio.volumeOverdrive")
|
||||
onToggled: checked => Settings.data.audio.volumeOverdrive = checked
|
||||
}
|
||||
}
|
||||
|
||||
NFilePicker {
|
||||
id: volumeFeedbackFilePicker
|
||||
title: I18n.tr("panels.audio.volumes-feedback-sound-file-select-title")
|
||||
selectionMode: "files"
|
||||
initialPath: Quickshell.env("HOME")
|
||||
nameFilters: ["*.wav", "*.mp3", "*.ogg", "*.flac", "*.m4a", "*.aac"]
|
||||
onAccepted: paths => {
|
||||
if (paths.length > 0) {
|
||||
Settings.data.audio.volumeFeedbackSoundFile = paths[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user