mirror of
https://github.com/zoriya/noctalia-shell.git
synced 2026-08-15 18:43:59 +00:00
Merge branch 'quick-settings'
This commit is contained in:
@@ -77,7 +77,7 @@ Item {
|
||||
// Error handling
|
||||
onWidgetIdChanged: {
|
||||
if (widgetId && !BarWidgetRegistry.hasWidget(widgetId)) {
|
||||
Logger.warn("BarWidgetLoader", "Widget not found in bar registry:", widgetId)
|
||||
Logger.warn("BarWidgetLoader", "Widget not found in registry:", widgetId)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import qs.Widgets
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
property ShellScreen screen
|
||||
property real scaling: 1.0
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ import qs.Widgets
|
||||
NIconButton {
|
||||
id: root
|
||||
|
||||
property ShellScreen screen
|
||||
property real scaling: 1.0
|
||||
|
||||
baseSize: Style.capsuleHeight
|
||||
|
||||
@@ -9,6 +9,7 @@ import qs.Services
|
||||
NIconButton {
|
||||
id: root
|
||||
|
||||
property ShellScreen screen
|
||||
property real scaling: 1.0
|
||||
|
||||
// Widget properties passed from Bar.qml for per-instance settings
|
||||
|
||||
@@ -11,8 +11,7 @@ import qs.Modules.Bar.Extras
|
||||
Item {
|
||||
id: root
|
||||
|
||||
// Widget properties passed from Bar.qml
|
||||
property var screen
|
||||
property ShellScreen screen
|
||||
property real scaling: 1.0
|
||||
|
||||
// Widget properties passed from Bar.qml for per-instance settings
|
||||
|
||||
@@ -6,6 +6,7 @@ import qs.Services
|
||||
NIconButton {
|
||||
id: root
|
||||
|
||||
property ShellScreen screen
|
||||
property real scaling: 1.0
|
||||
|
||||
icon: "dark-mode"
|
||||
|
||||
@@ -8,6 +8,7 @@ import qs.Widgets
|
||||
NIconButton {
|
||||
id: root
|
||||
|
||||
property ShellScreen screen
|
||||
property real scaling: 1.0
|
||||
|
||||
baseSize: Style.capsuleHeight
|
||||
|
||||
@@ -11,6 +11,7 @@ import qs.Widgets
|
||||
NIconButton {
|
||||
id: root
|
||||
|
||||
property ShellScreen screen
|
||||
property real scaling: 1.0
|
||||
|
||||
compact: (Settings.data.bar.density === "compact")
|
||||
|
||||
@@ -10,6 +10,7 @@ import qs.Widgets
|
||||
NIconButton {
|
||||
id: root
|
||||
|
||||
property ShellScreen screen
|
||||
property real scaling: 1.0
|
||||
|
||||
// Widget properties passed from Bar.qml for per-instance settings
|
||||
|
||||
@@ -9,6 +9,7 @@ import qs.Widgets
|
||||
NIconButton {
|
||||
id: root
|
||||
|
||||
property ShellScreen screen
|
||||
property real scaling: 1.0
|
||||
|
||||
baseSize: Style.capsuleHeight
|
||||
|
||||
@@ -7,6 +7,7 @@ import qs.Widgets
|
||||
NIconButton {
|
||||
id: root
|
||||
|
||||
property ShellScreen screen
|
||||
property real scaling: 1.0
|
||||
|
||||
icon: "camera-video"
|
||||
|
||||
@@ -8,6 +8,7 @@ import qs.Widgets
|
||||
NIconButton {
|
||||
id: root
|
||||
|
||||
property ShellScreen screen
|
||||
property real scaling: 1.0
|
||||
|
||||
compact: (Settings.data.bar.density === "compact")
|
||||
|
||||
@@ -8,8 +8,7 @@ import qs.Widgets
|
||||
Item {
|
||||
id: root
|
||||
|
||||
// Widget properties passed from Bar.qml
|
||||
property var screen
|
||||
property ShellScreen screen
|
||||
property real scaling: 1.0
|
||||
|
||||
// Widget properties passed from Bar.qml for per-instance settings
|
||||
|
||||
@@ -8,6 +8,7 @@ import qs.Widgets
|
||||
NIconButton {
|
||||
id: root
|
||||
|
||||
property ShellScreen screen
|
||||
property real scaling: 1.0
|
||||
|
||||
baseSize: Style.capsuleHeight
|
||||
|
||||
@@ -10,6 +10,7 @@ import qs.Widgets
|
||||
NIconButton {
|
||||
id: root
|
||||
|
||||
property ShellScreen screen
|
||||
property real scaling: 1.0
|
||||
|
||||
compact: (Settings.data.bar.density === "compact")
|
||||
|
||||
@@ -84,7 +84,7 @@ NBox {
|
||||
anchors.fill: parent
|
||||
values: CavaService.values
|
||||
fillColor: Color.mPrimary
|
||||
opacity: MediaService.trackArtUrl !== "" ? 0.4 : 0.8
|
||||
opacity: MediaService.trackArtUrl !== "" ? 0.5 : 0.8
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,7 +94,7 @@ NBox {
|
||||
anchors.fill: parent
|
||||
values: CavaService.values
|
||||
fillColor: Color.mPrimary
|
||||
opacity: MediaService.trackArtUrl !== "" ? 0.4 : 0.8
|
||||
opacity: MediaService.trackArtUrl !== "" ? 0.5 : 0.8
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,7 +104,7 @@ NBox {
|
||||
anchors.fill: parent
|
||||
values: CavaService.values
|
||||
fillColor: Color.mPrimary
|
||||
opacity: MediaService.trackArtUrl !== "" ? 0.4 : 0.8
|
||||
opacity: MediaService.trackArtUrl !== "" ? 0.5 : 0.8
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,14 +9,11 @@ import qs.Widgets
|
||||
NBox {
|
||||
id: root
|
||||
|
||||
GridLayout {
|
||||
RowLayout {
|
||||
id: content
|
||||
anchors.fill: parent
|
||||
anchors.margins: Style.marginXS * scaling
|
||||
columns: 2
|
||||
rows: 2
|
||||
columnSpacing: Style.marginS * scaling
|
||||
rowSpacing: Style.marginS * scaling
|
||||
spacing: Style.marginS * scaling
|
||||
|
||||
NCircleStat {
|
||||
value: SystemStatService.cpuUsage
|
||||
|
||||
@@ -4,9 +4,9 @@ import QtQuick.Layouts
|
||||
import Quickshell
|
||||
import Quickshell.Io
|
||||
import Quickshell.Widgets
|
||||
import Quickshell.Services.UPower
|
||||
import qs.Modules.Settings
|
||||
import qs.Modules.ControlCenter
|
||||
import qs.Modules.ControlCenter.Extras
|
||||
import qs.Commons
|
||||
import qs.Services
|
||||
import qs.Widgets
|
||||
@@ -17,7 +17,6 @@ NBox {
|
||||
|
||||
property string uptimeText: "--"
|
||||
property real spacing: Style.marginS * scaling
|
||||
readonly property bool hasPP: PowerProfileService.available
|
||||
|
||||
ColumnLayout {
|
||||
anchors.fill: parent
|
||||
@@ -32,7 +31,7 @@ NBox {
|
||||
|
||||
NImageCircled {
|
||||
width: Style.baseWidgetSize * 1.25 * scaling
|
||||
height: Style.baseWidgetSize * 1.25 * scaling
|
||||
height: width
|
||||
imagePath: Settings.data.general.avatarImage
|
||||
fallbackIcon: "person"
|
||||
borderColor: Color.mPrimary
|
||||
@@ -53,7 +52,7 @@ NBox {
|
||||
text: I18n.tr("system.uptime", {
|
||||
"uptime": uptimeText
|
||||
})
|
||||
pointSize: Style.fontSizeS * scaling
|
||||
pointSize: Style.fontSizeXS * scaling
|
||||
color: Color.mOnSurfaceVariant
|
||||
}
|
||||
}
|
||||
@@ -97,205 +96,33 @@ NBox {
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
id: utilitiesRow
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
Layout.topMargin: Style.marginM * scaling
|
||||
Layout.bottomMargin: Style.marginM * scaling
|
||||
NDivider {
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: Style.marginS * scaling
|
||||
Layout.bottomMargin: Style.marginS * scaling
|
||||
}
|
||||
|
||||
// Left group - Media & Display
|
||||
Rectangle {
|
||||
color: Color.mSurface
|
||||
radius: Style.radiusM * scaling
|
||||
Layout.preferredHeight: Style.baseWidgetSize * 1.2 * scaling
|
||||
Layout.preferredWidth: childrenRect.width + (Style.marginS * scaling * 2)
|
||||
GridLayout {
|
||||
id: grid
|
||||
Layout.fillWidth: true
|
||||
columns: (Settings.data.controlCenter.quickSettingsStyle === "compact") ? 4 : 3
|
||||
columnSpacing: Style.marginS * scaling
|
||||
rowSpacing: Style.marginS * scaling
|
||||
|
||||
RowLayout {
|
||||
anchors.centerIn: parent
|
||||
spacing: Style.marginM * scaling
|
||||
|
||||
// Screen Recorder
|
||||
NIconButton {
|
||||
baseSize: Style.baseWidgetSize * 0.9
|
||||
icon: "camera-video"
|
||||
visible: ProgramCheckerService.gpuScreenRecorderAvailable
|
||||
tooltipText: ScreenRecorderService.isRecording ? I18n.tr("tooltips.stop-screen-recording") : I18n.tr("tooltips.start-screen-recording")
|
||||
colorBg: ScreenRecorderService.isRecording ? Color.mPrimary : Color.mSurfaceVariant
|
||||
colorFg: ScreenRecorderService.isRecording ? Color.mOnPrimary : Color.mPrimary
|
||||
onClicked: {
|
||||
ScreenRecorderService.toggleRecording()
|
||||
if (!ScreenRecorderService.isRecording) {
|
||||
var panel = PanelService.getPanel("controlCenterPanel")
|
||||
panel?.close()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Wallpaper
|
||||
NIconButton {
|
||||
baseSize: Style.baseWidgetSize * 0.9
|
||||
visible: Settings.data.wallpaper.enabled
|
||||
icon: "wallpaper-selector"
|
||||
tooltipText: I18n.tr("tooltips.wallpaper-selector")
|
||||
onClicked: PanelService.getPanel("wallpaperPanel")?.toggle(this)
|
||||
onRightClicked: WallpaperService.setRandomWallpaper()
|
||||
}
|
||||
|
||||
// Night Light
|
||||
NIconButton {
|
||||
baseSize: Style.baseWidgetSize * 0.9
|
||||
visible: ProgramCheckerService.wlsunsetAvailable
|
||||
colorBg: Settings.data.nightLight.forced ? Color.mPrimary : Color.transparent
|
||||
colorFg: Settings.data.nightLight.forced ? Color.mOnPrimary : Color.mPrimary
|
||||
icon: Settings.data.nightLight.enabled ? (Settings.data.nightLight.forced ? "nightlight-forced" : "nightlight-on") : "nightlight-off"
|
||||
tooltipText: Settings.data.nightLight.enabled ? (Settings.data.nightLight.forced ? I18n.tr("tooltips.night-light-forced") : I18n.tr("tooltips.night-light-enabled")) : I18n.tr("tooltips.night-light-disabled")
|
||||
onClicked: {
|
||||
if (!Settings.data.nightLight.enabled) {
|
||||
Settings.data.nightLight.enabled = true
|
||||
Settings.data.nightLight.forced = false
|
||||
} else if (Settings.data.nightLight.enabled && !Settings.data.nightLight.forced) {
|
||||
Settings.data.nightLight.forced = true
|
||||
} else {
|
||||
Settings.data.nightLight.enabled = false
|
||||
Settings.data.nightLight.forced = false
|
||||
}
|
||||
}
|
||||
|
||||
onRightClicked: {
|
||||
var settingsPanel = PanelService.getPanel("settingsPanel")
|
||||
settingsPanel.requestedTab = SettingsPanel.Tab.Display
|
||||
settingsPanel.open()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Spacer
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
// Center group - Network & Caffeine
|
||||
Rectangle {
|
||||
color: Color.mSurface
|
||||
radius: Style.radiusM * scaling
|
||||
Layout.preferredHeight: Style.baseWidgetSize * 1.2 * scaling
|
||||
Layout.preferredWidth: childrenRect.width + (Style.marginS * scaling * 2)
|
||||
|
||||
RowLayout {
|
||||
anchors.centerIn: parent
|
||||
spacing: Style.marginM * scaling
|
||||
|
||||
// Wifi
|
||||
NIconButton {
|
||||
id: wifiButton
|
||||
baseSize: Style.baseWidgetSize * 0.9
|
||||
tooltipText: I18n.tr("tooltips.manage-wifi")
|
||||
icon: {
|
||||
try {
|
||||
if (NetworkService.ethernetConnected) {
|
||||
return "ethernet"
|
||||
}
|
||||
let connected = false
|
||||
let signalStrength = 0
|
||||
for (const net in NetworkService.networks) {
|
||||
if (NetworkService.networks[net].connected) {
|
||||
connected = true
|
||||
signalStrength = NetworkService.networks[net].signal
|
||||
break
|
||||
}
|
||||
}
|
||||
return connected ? NetworkService.signalIcon(signalStrength) : "wifi-off"
|
||||
} catch (error) {
|
||||
Logger.error("Wi-Fi", "Error getting icon:", error)
|
||||
return "signal_wifi_bad"
|
||||
}
|
||||
}
|
||||
onClicked: PanelService.getPanel("wifiPanel")?.toggle(this)
|
||||
onRightClicked: PanelService.getPanel("wifiPanel")?.toggle(this)
|
||||
}
|
||||
|
||||
// Bluetooth
|
||||
NIconButton {
|
||||
baseSize: Style.baseWidgetSize * 0.9
|
||||
tooltipText: I18n.tr("tooltips.bluetooth-devices")
|
||||
icon: BluetoothService.enabled ? "bluetooth" : "bluetooth-off"
|
||||
onClicked: PanelService.getPanel("bluetoothPanel")?.toggle(this)
|
||||
onRightClicked: PanelService.getPanel("bluetoothPanel")?.toggle(this)
|
||||
}
|
||||
|
||||
// Caffeine (Keep Awake)
|
||||
NIconButton {
|
||||
baseSize: Style.baseWidgetSize * 0.9
|
||||
icon: IdleInhibitorService.isInhibited ? "keep-awake-on" : "keep-awake-off"
|
||||
tooltipText: IdleInhibitorService.isInhibited ? I18n.tr("tooltips.disable-keep-awake") : I18n.tr("tooltips.enable-keep-awake")
|
||||
colorBg: IdleInhibitorService.isInhibited ? Color.mPrimary : Color.mSurfaceVariant
|
||||
colorFg: IdleInhibitorService.isInhibited ? Color.mOnPrimary : Color.mPrimary
|
||||
onClicked: {
|
||||
IdleInhibitorService.manualToggle()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Spacer
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
// Right group - Power Profiles
|
||||
Rectangle {
|
||||
color: Color.mSurface
|
||||
radius: Style.radiusM * scaling
|
||||
Layout.preferredHeight: Style.baseWidgetSize * 1.2 * scaling
|
||||
Layout.preferredWidth: childrenRect.width + (Style.marginS * scaling * 2)
|
||||
|
||||
RowLayout {
|
||||
anchors.centerIn: parent
|
||||
spacing: Style.marginM * scaling
|
||||
|
||||
// Performance
|
||||
NIconButton {
|
||||
baseSize: Style.baseWidgetSize * 0.9
|
||||
icon: PowerProfileService.getIcon(PowerProfile.Performance)
|
||||
tooltipText: I18n.tr("tooltips.set-power-profile", {
|
||||
"profile": PowerProfileService.getName(PowerProfile.Performance)
|
||||
})
|
||||
enabled: hasPP
|
||||
opacity: enabled ? Style.opacityFull : Style.opacityMedium
|
||||
colorBg: (enabled && PowerProfileService.profile === PowerProfile.Performance) ? Color.mPrimary : Color.mSurfaceVariant
|
||||
colorFg: (enabled && PowerProfileService.profile === PowerProfile.Performance) ? Color.mOnPrimary : Color.mPrimary
|
||||
onClicked: PowerProfileService.setProfile(PowerProfile.Performance)
|
||||
}
|
||||
|
||||
// Balanced
|
||||
NIconButton {
|
||||
baseSize: Style.baseWidgetSize * 0.9
|
||||
icon: PowerProfileService.getIcon(PowerProfile.Balanced)
|
||||
tooltipText: I18n.tr("tooltips.set-power-profile", {
|
||||
"profile": PowerProfileService.getName(PowerProfile.Balanced)
|
||||
})
|
||||
enabled: hasPP
|
||||
opacity: enabled ? Style.opacityFull : Style.opacityMedium
|
||||
colorBg: (enabled && PowerProfileService.profile === PowerProfile.Balanced) ? Color.mPrimary : Color.mSurfaceVariant
|
||||
colorFg: (enabled && PowerProfileService.profile === PowerProfile.Balanced) ? Color.mOnPrimary : Color.mPrimary
|
||||
onClicked: PowerProfileService.setProfile(PowerProfile.Balanced)
|
||||
}
|
||||
|
||||
// Eco
|
||||
NIconButton {
|
||||
baseSize: Style.baseWidgetSize * 0.9
|
||||
icon: PowerProfileService.getIcon(PowerProfile.PowerSaver)
|
||||
tooltipText: I18n.tr("tooltips.set-power-profile", {
|
||||
"profile": PowerProfileService.getName(PowerProfile.PowerSaver)
|
||||
})
|
||||
enabled: hasPP
|
||||
opacity: enabled ? Style.opacityFull : Style.opacityMedium
|
||||
colorBg: (enabled && PowerProfileService.profile === PowerProfile.PowerSaver) ? Color.mPrimary : Color.mSurfaceVariant
|
||||
colorFg: (enabled && PowerProfileService.profile === PowerProfile.PowerSaver) ? Color.mOnPrimary : Color.mPrimary
|
||||
onClicked: PowerProfileService.setProfile(PowerProfile.PowerSaver)
|
||||
Repeater {
|
||||
model: Settings.data.controlCenter.widgets.quickSettings
|
||||
delegate: ControlCenterWidgetLoader {
|
||||
Layout.fillWidth: true
|
||||
widgetId: (modelData.id !== undefined ? modelData.id : "")
|
||||
widgetProps: {
|
||||
"screen": root.modelData || null,
|
||||
"scaling": ScalingService.getScreenScale(screen),
|
||||
"widgetId": modelData.id,
|
||||
"section": "quickSettings",
|
||||
"sectionWidgetIndex": index,
|
||||
"sectionWidgetsCount": Settings.data.controlCenter.widgets.quickSettings.length
|
||||
}
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,130 +0,0 @@
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import Quickshell
|
||||
import qs.Commons
|
||||
import qs.Services
|
||||
import qs.Widgets
|
||||
|
||||
// Weather overview card (placeholder data)
|
||||
NBox {
|
||||
id: root
|
||||
|
||||
readonly property bool weatherReady: (LocationService.data.weather !== null)
|
||||
|
||||
ColumnLayout {
|
||||
id: content
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.top: parent.top
|
||||
anchors.margins: Style.marginM * scaling
|
||||
spacing: Style.marginM * scaling
|
||||
clip: true
|
||||
|
||||
RowLayout {
|
||||
spacing: Style.marginS * scaling
|
||||
NIcon {
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
icon: weatherReady ? LocationService.weatherSymbolFromCode(LocationService.data.weather.current_weather.weathercode) : ""
|
||||
pointSize: Style.fontSizeXXXL * 1.75 * scaling
|
||||
color: Color.mPrimary
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
spacing: Style.marginXXS * scaling
|
||||
NText {
|
||||
text: {
|
||||
// Ensure the name is not too long if one had to specify the country
|
||||
const chunks = Settings.data.location.name.split(",")
|
||||
return chunks[0]
|
||||
}
|
||||
pointSize: Style.fontSizeL * scaling
|
||||
font.weight: Style.fontWeightBold
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
NText {
|
||||
visible: weatherReady
|
||||
text: {
|
||||
if (!weatherReady) {
|
||||
return ""
|
||||
}
|
||||
var temp = LocationService.data.weather.current_weather.temperature
|
||||
var suffix = "C"
|
||||
if (Settings.data.location.useFahrenheit) {
|
||||
temp = LocationService.celsiusToFahrenheit(temp)
|
||||
var suffix = "F"
|
||||
}
|
||||
temp = Math.round(temp)
|
||||
return `${temp}°${suffix}`
|
||||
}
|
||||
pointSize: Style.fontSizeXL * scaling
|
||||
font.weight: Style.fontWeightBold
|
||||
}
|
||||
|
||||
NText {
|
||||
text: weatherReady ? `(${LocationService.data.weather.timezone_abbreviation})` : ""
|
||||
pointSize: Style.fontSizeXS * scaling
|
||||
color: Color.mOnSurfaceVariant
|
||||
visible: LocationService.data.weather
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NDivider {
|
||||
visible: weatherReady
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
visible: weatherReady
|
||||
Layout.fillWidth: true
|
||||
Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter
|
||||
spacing: Style.marginL * scaling
|
||||
Repeater {
|
||||
model: weatherReady ? LocationService.data.weather.daily.time : []
|
||||
delegate: ColumnLayout {
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
spacing: Style.marginS * scaling
|
||||
NText {
|
||||
text: {
|
||||
var weatherDate = new Date(LocationService.data.weather.daily.time[index].replace(/-/g, "/"))
|
||||
return Qt.locale().toString(weatherDate, "ddd")
|
||||
}
|
||||
color: Color.mOnSurface
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
}
|
||||
NIcon {
|
||||
Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter
|
||||
icon: LocationService.weatherSymbolFromCode(LocationService.data.weather.daily.weathercode[index])
|
||||
pointSize: Style.fontSizeXXL * 1.6 * scaling
|
||||
color: Color.mPrimary
|
||||
}
|
||||
NText {
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
text: {
|
||||
var max = LocationService.data.weather.daily.temperature_2m_max[index]
|
||||
var min = LocationService.data.weather.daily.temperature_2m_min[index]
|
||||
if (Settings.data.location.useFahrenheit) {
|
||||
max = LocationService.celsiusToFahrenheit(max)
|
||||
min = LocationService.celsiusToFahrenheit(min)
|
||||
}
|
||||
max = Math.round(max)
|
||||
min = Math.round(min)
|
||||
return `${max}°/${min}°`
|
||||
}
|
||||
pointSize: Style.fontSizeXS * scaling
|
||||
color: Color.mOnSurfaceVariant
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
visible: !weatherReady
|
||||
Layout.fillWidth: true
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
NBusyIndicator {}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10,10 +10,28 @@ import qs.Widgets
|
||||
NPanel {
|
||||
id: root
|
||||
|
||||
preferredWidth: 480
|
||||
preferredHeight: 580
|
||||
preferredWidth: 400
|
||||
preferredHeight: topHeight + midHeight + bottomHeight + Math.round(Style.marginL * 4)
|
||||
panelKeyboardFocus: true
|
||||
|
||||
readonly property int topHeight: {
|
||||
const columns = (Settings.data.controlCenter.quickSettingsStyle === "compact") ? 4 : 3
|
||||
const rowsCount = Math.ceil(Settings.data.controlCenter.widgets.quickSettings.length / columns)
|
||||
|
||||
var buttonHeight
|
||||
if (Settings.data.controlCenter.quickSettingsStyle === "classic") {
|
||||
buttonHeight = Style.baseWidgetSize
|
||||
} else if (Settings.data.controlCenter.quickSettingsStyle === "compact") {
|
||||
buttonHeight = Style.baseWidgetSize * 0.8 // Smaller for compact
|
||||
} else {
|
||||
buttonHeight = 56
|
||||
}
|
||||
|
||||
return (rowsCount * buttonHeight) + 120
|
||||
}
|
||||
readonly property int midHeight: 220
|
||||
readonly property int bottomHeight: 80
|
||||
|
||||
// Positioning
|
||||
readonly property string controlCenterPosition: Settings.data.controlCenter.position
|
||||
panelAnchorHorizontalCenter: controlCenterPosition !== "close_to_bar_button" && controlCenterPosition.endsWith("_center")
|
||||
@@ -37,33 +55,21 @@ NPanel {
|
||||
|
||||
// Top Card: profile + utilities
|
||||
TopCard {
|
||||
id: topCard
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: Math.max(124 * scaling)
|
||||
Layout.preferredHeight: topHeight * scaling
|
||||
}
|
||||
|
||||
// Weather
|
||||
WeatherCard {
|
||||
// Media card
|
||||
MediaCard {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: Math.max(196 * scaling)
|
||||
Layout.preferredHeight: midHeight * scaling
|
||||
}
|
||||
|
||||
// Media + stats column
|
||||
RowLayout {
|
||||
// System monitors combined in one card
|
||||
SystemMonitorCard {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: Math.max(196 * scaling)
|
||||
spacing: content.cardSpacing
|
||||
|
||||
// Media card
|
||||
MediaCard {
|
||||
Layout.preferredWidth: Math.max(270 * scaling)
|
||||
Layout.fillHeight: true
|
||||
}
|
||||
|
||||
// System monitors combined in one card
|
||||
SystemMonitorCard {
|
||||
Layout.preferredWidth: Math.max(160 * scaling)
|
||||
Layout.preferredHeight: Math.max(196 * scaling)
|
||||
}
|
||||
Layout.preferredHeight: bottomHeight * scaling
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
import QtQuick
|
||||
import Quickshell
|
||||
import qs.Services
|
||||
import qs.Commons
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
property string widgetId: ""
|
||||
property var widgetProps: ({})
|
||||
property string screenName: widgetProps && widgetProps.screen ? widgetProps.screen.name : ""
|
||||
property string section: widgetProps && widgetProps.section || ""
|
||||
property int sectionIndex: widgetProps && widgetProps.sectionWidgetIndex || 0
|
||||
|
||||
// Don't reserve space unless the loaded widget is really visible
|
||||
implicitWidth: getImplicitSize(loader.item, "implicitWidth")
|
||||
implicitHeight: getImplicitSize(loader.item, "implicitHeight")
|
||||
|
||||
Connections {
|
||||
target: ScalingService
|
||||
enabled: loader.item && (loader.item.screen !== undefined)
|
||||
function onScaleChanged(aScreenName, scale) {
|
||||
if (loader.item && loader.item.screen && aScreenName === screenName) {
|
||||
loader.item['scaling'] = scale
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getImplicitSize(item, prop) {
|
||||
return (item && item.visible) ? item[prop] : 0
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: loader
|
||||
anchors.fill: parent
|
||||
active: widgetId !== ""
|
||||
asynchronous: false
|
||||
sourceComponent: {
|
||||
if (!active) {
|
||||
return null
|
||||
}
|
||||
return ControlCenterWidgetRegistry.getWidget(widgetId)
|
||||
}
|
||||
|
||||
onLoaded: {
|
||||
if (item && widgetProps) {
|
||||
// Apply properties to loaded widget
|
||||
for (var prop in widgetProps) {
|
||||
if (item.hasOwnProperty(prop)) {
|
||||
item[prop] = widgetProps[prop]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (item.hasOwnProperty("onLoaded")) {
|
||||
item.onLoaded()
|
||||
}
|
||||
|
||||
//Logger.log("ControlCenterWidgetLoader", "Loaded", widgetId, "on screen", item.screen.name)
|
||||
}
|
||||
|
||||
Component.onDestruction: {
|
||||
// Explicitly clear references
|
||||
widgetProps = null
|
||||
}
|
||||
}
|
||||
|
||||
// Error handling
|
||||
onWidgetIdChanged: {
|
||||
if (widgetId && !ControlCenterWidgetRegistry.hasWidget(widgetId)) {
|
||||
Logger.warn("ControlCenterWidgetLoader", "Widget not found in registry:", widgetId)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
import QtQuick.Layouts
|
||||
import Quickshell
|
||||
import qs.Commons
|
||||
import qs.Services
|
||||
import qs.Widgets
|
||||
|
||||
NQuickSetting {
|
||||
property ShellScreen screen
|
||||
property real scaling: 1.0
|
||||
|
||||
text: I18n.tr("quickSettings.bluetooth.label.enabled")
|
||||
icon: BluetoothService.enabled ? "bluetooth" : "bluetooth-off"
|
||||
tooltipText: I18n.tr("quickSettings.bluetooth.tooltip.action")
|
||||
style: Settings.data.controlCenter.quickSettingsStyle || "modern"
|
||||
onClicked: PanelService.getPanel("bluetoothPanel")?.toggle(this)
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
import QtQuick.Layouts
|
||||
import Quickshell
|
||||
import qs.Commons
|
||||
import qs.Services
|
||||
import qs.Widgets
|
||||
|
||||
NQuickSetting {
|
||||
property ShellScreen screen
|
||||
property real scaling: 1.0
|
||||
|
||||
text: I18n.tr("quickSettings.keepAwake.label.enabled")
|
||||
icon: IdleInhibitorService.isInhibited ? "keep-awake-on" : "keep-awake-off"
|
||||
hot: IdleInhibitorService.isInhibited
|
||||
tooltipText: I18n.tr("quickSettings.keepAwake.tooltip.action")
|
||||
style: Settings.data.controlCenter.quickSettingsStyle || "modern"
|
||||
|
||||
onClicked: IdleInhibitorService.manualToggle()
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
import QtQuick.Layouts
|
||||
import Quickshell
|
||||
import qs.Commons
|
||||
import qs.Services
|
||||
import qs.Widgets
|
||||
|
||||
NQuickSetting {
|
||||
property ShellScreen screen
|
||||
property real scaling: 1.0
|
||||
|
||||
enabled: ProgramCheckerService.wlsunsetAvailable
|
||||
text: I18n.tr("quickSettings.nightLight.label.enabled")
|
||||
icon: Settings.data.nightLight.enabled ? (Settings.data.nightLight.forced ? "nightlight-forced" : "nightlight-on") : "nightlight-off"
|
||||
hot: !Settings.data.nightLight.enabled || Settings.data.nightLight.forced
|
||||
style: Settings.data.controlCenter.quickSettingsStyle || "modern"
|
||||
tooltipText: I18n.tr("quickSettings.nightLight.tooltip.action")
|
||||
|
||||
onClicked: {
|
||||
if (!Settings.data.nightLight.enabled) {
|
||||
Settings.data.nightLight.enabled = true
|
||||
Settings.data.nightLight.forced = false
|
||||
} else if (Settings.data.nightLight.enabled && !Settings.data.nightLight.forced) {
|
||||
Settings.data.nightLight.forced = true
|
||||
} else {
|
||||
Settings.data.nightLight.enabled = false
|
||||
Settings.data.nightLight.forced = false
|
||||
}
|
||||
}
|
||||
|
||||
onRightClicked: {
|
||||
var settingsPanel = PanelService.getPanel("settingsPanel")
|
||||
settingsPanel.requestedTab = SettingsPanel.Tab.Display
|
||||
settingsPanel.open()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
import QtQuick.Layouts
|
||||
import Quickshell
|
||||
import qs.Commons
|
||||
import qs.Services
|
||||
import qs.Widgets
|
||||
|
||||
NQuickSetting {
|
||||
property ShellScreen screen
|
||||
property real scaling: 1.0
|
||||
|
||||
text: Settings.data.notifications.doNotDisturb ? I18n.tr("quickSettings.notifications.label.disabled") : I18n.tr("quickSettings.notifications.label.enabled")
|
||||
icon: Settings.data.notifications.doNotDisturb ? "bell-off" : "bell"
|
||||
hot: Settings.data.notifications.doNotDisturb
|
||||
tooltipText: I18n.tr("quickSettings.notifications.tooltip.action")
|
||||
style: Settings.data.controlCenter.quickSettingsStyle || "modern"
|
||||
|
||||
onClicked: PanelService.getPanel("notificationHistoryPanel")?.toggle(this)
|
||||
onRightClicked: Settings.data.notifications.doNotDisturb = !Settings.data.notifications.doNotDisturb
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
import QtQuick.Layouts
|
||||
import Quickshell
|
||||
import Quickshell.Services.UPower
|
||||
import qs.Commons
|
||||
import qs.Services
|
||||
import qs.Widgets
|
||||
|
||||
// Performance
|
||||
NQuickSetting {
|
||||
property ShellScreen screen
|
||||
property real scaling: 1.0
|
||||
readonly property bool hasPP: PowerProfileService.available
|
||||
|
||||
enabled: hasPP
|
||||
text: hasPP ? PowerProfileService.getName() : I18n.tr("quickSettings.powerProfile.label.unavailable")
|
||||
icon: PowerProfileService.getIcon()
|
||||
hot: !PowerProfileService.isDefault()
|
||||
tooltipText: I18n.tr("quickSettings.powerProfile.tooltip.action")
|
||||
style: Settings.data.controlCenter.quickSettingsStyle || "modern"
|
||||
|
||||
onClicked: {
|
||||
PowerProfileService.cycleProfile()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
import QtQuick.Layouts
|
||||
import Quickshell
|
||||
import qs.Commons
|
||||
import qs.Services
|
||||
import qs.Widgets
|
||||
|
||||
NQuickSetting {
|
||||
property ShellScreen screen
|
||||
property real scaling: 1.0
|
||||
|
||||
enabled: ProgramCheckerService.gpuScreenRecorderAvailable
|
||||
icon: "camera-video"
|
||||
text: ScreenRecorderService.isRecording ? I18n.tr("quickSettings.screenRecorder.label.recording") : I18n.tr("quickSettings.screenRecorder.label.stopped")
|
||||
hot: ScreenRecorderService.isRecording
|
||||
tooltipText: I18n.tr("quickSettings.screenRecorder.tooltip.action")
|
||||
style: Settings.data.controlCenter.quickSettingsStyle || "modern"
|
||||
|
||||
// Force hover state when recording to get hover colors
|
||||
property bool originalHovered: hovered
|
||||
hovered: ScreenRecorderService.isRecording || originalHovered
|
||||
|
||||
onClicked: {
|
||||
ScreenRecorderService.toggleRecording()
|
||||
if (!ScreenRecorderService.isRecording) {
|
||||
var panel = PanelService.getPanel("controlCenterPanel")
|
||||
panel?.close()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
import QtQuick.Layouts
|
||||
import Quickshell
|
||||
import qs.Commons
|
||||
import qs.Services
|
||||
import qs.Widgets
|
||||
|
||||
NQuickSetting {
|
||||
property ShellScreen screen
|
||||
property real scaling: 1.0
|
||||
|
||||
enabled: Settings.data.wallpaper.enabled
|
||||
icon: "wallpaper-selector"
|
||||
text: I18n.tr("quickSettings.wallpaperSelector.label")
|
||||
tooltipText: I18n.tr("quickSettings.wallpaperSelector.tooltip.action")
|
||||
style: Settings.data.controlCenter.quickSettingsStyle || "modern"
|
||||
|
||||
onClicked: PanelService.getPanel("wallpaperPanel")?.toggle(this)
|
||||
onRightClicked: WallpaperService.setRandomWallpaper()
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
import QtQuick.Layouts
|
||||
import Quickshell
|
||||
import qs.Commons
|
||||
import qs.Services
|
||||
import qs.Widgets
|
||||
|
||||
NQuickSetting {
|
||||
property ShellScreen screen
|
||||
property real scaling: 1.0
|
||||
|
||||
icon: {
|
||||
try {
|
||||
if (NetworkService.ethernetConnected) {
|
||||
return "ethernet"
|
||||
}
|
||||
let connected = false
|
||||
let signalStrength = 0
|
||||
for (const net in NetworkService.networks) {
|
||||
if (NetworkService.networks[net].connected) {
|
||||
connected = true
|
||||
signalStrength = NetworkService.networks[net].signal
|
||||
break
|
||||
}
|
||||
}
|
||||
return connected ? NetworkService.signalIcon(signalStrength) : "wifi-off"
|
||||
} catch (error) {
|
||||
Logger.error("Wi-Fi", "Error getting icon:", error)
|
||||
return "signal_wifi_bad"
|
||||
}
|
||||
}
|
||||
|
||||
text: {
|
||||
if (NetworkService.ethernetConnected) {
|
||||
return I18n.tr("quickSettings.wifi.label.ethernet")
|
||||
}
|
||||
let connected = false
|
||||
for (const net in NetworkService.networks) {
|
||||
if (NetworkService.networks[net].connected) {
|
||||
connected = true
|
||||
break
|
||||
}
|
||||
}
|
||||
return connected ? I18n.tr("quickSettings.wifi.label.wifi") : I18n.tr("quickSettings.wifi.label.disconnected")
|
||||
}
|
||||
|
||||
style: Settings.data.controlCenter.quickSettingsStyle || "modern"
|
||||
tooltipText: I18n.tr("quickSettings.wifi.tooltip.action")
|
||||
onClicked: PanelService.getPanel("wifiPanel")?.toggle(this)
|
||||
}
|
||||
@@ -69,7 +69,7 @@ Popup {
|
||||
|
||||
NIconButton {
|
||||
icon: "close"
|
||||
tooltipText: "Close"
|
||||
tooltipText: I18n.tr("tooltips.close")
|
||||
onClicked: widgetSettings.close()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,6 @@ ColumnLayout {
|
||||
var settings = Object.assign({}, widgetData || {})
|
||||
settings.onlySameOutput = valueOnlySameOutput
|
||||
settings.onlyActiveWorkspaces = valueOnlyActiveWorkspaces
|
||||
console.log(JSON.stringify(settings))
|
||||
return settings
|
||||
}
|
||||
|
||||
|
||||
+12
-9
@@ -13,6 +13,10 @@ NBox {
|
||||
property string sectionId: ""
|
||||
property var widgetModel: []
|
||||
property var availableWidgets: []
|
||||
property bool enableMoveBetweenSections: true
|
||||
|
||||
property var widgetRegistry: null
|
||||
property string settingsDialogComponent: "BarWidgetSettingsDialog.qml"
|
||||
|
||||
readonly property real miniButtonSize: Style.baseWidgetSize * 0.65
|
||||
|
||||
@@ -154,7 +158,7 @@ NBox {
|
||||
// Store the widget index for drag operations
|
||||
property int widgetIndex: index
|
||||
readonly property int buttonsWidth: Math.round(20 * scaling)
|
||||
readonly property int buttonsCount: 1 + BarWidgetRegistry.widgetHasUserSettings(modelData.id)
|
||||
readonly property int buttonsCount: 1 + (root.widgetRegistry ? root.widgetRegistry.widgetHasUserSettings(modelData.id) : 0)
|
||||
|
||||
// Visual feedback during drag
|
||||
opacity: flowDragArea.draggedIndex === index ? 0.5 : 1.0
|
||||
@@ -197,9 +201,10 @@ NBox {
|
||||
onTriggered: action => root.moveWidget(root.sectionId, index, action)
|
||||
}
|
||||
|
||||
// Update the MouseArea to use the new context menu
|
||||
// MouseArea for the context menu
|
||||
MouseArea {
|
||||
id: contextMouseArea
|
||||
enabled: enableMoveBetweenSections
|
||||
anchors.fill: parent
|
||||
acceptedButtons: Qt.RightButton
|
||||
z: -1 // Below the buttons but above background
|
||||
@@ -209,9 +214,7 @@ NBox {
|
||||
// Check if click is not on the buttons area
|
||||
const localX = mouse.x
|
||||
const buttonsStartX = parent.width - (parent.buttonsCount * parent.buttonsWidth)
|
||||
|
||||
if (localX < buttonsStartX) {
|
||||
// Use the helper function to open at mouse position
|
||||
contextMenu.openAtItem(widgetItem, mouse.x, mouse.y)
|
||||
}
|
||||
}
|
||||
@@ -236,7 +239,7 @@ NBox {
|
||||
Layout.preferredWidth: buttonsCount * buttonsWidth
|
||||
|
||||
Loader {
|
||||
active: BarWidgetRegistry.widgetHasUserSettings(modelData.id)
|
||||
active: root.widgetRegistry && root.widgetRegistry.widgetHasUserSettings(modelData.id)
|
||||
sourceComponent: NIconButton {
|
||||
icon: "settings"
|
||||
tooltipText: I18n.tr("tooltips.widget-settings")
|
||||
@@ -247,7 +250,7 @@ NBox {
|
||||
colorBgHover: Qt.alpha(Color.mOnPrimary, Style.opacityLight)
|
||||
colorFgHover: Color.mOnPrimary
|
||||
onClicked: {
|
||||
var component = Qt.createComponent(Qt.resolvedUrl("BarWidgetSettingsDialog.qml"))
|
||||
var component = Qt.createComponent(Qt.resolvedUrl(root.settingsDialogComponent))
|
||||
function instantiateAndOpen() {
|
||||
var dialog = component.createObject(root, {
|
||||
"widgetIndex": index,
|
||||
@@ -258,19 +261,19 @@ NBox {
|
||||
if (dialog) {
|
||||
dialog.open()
|
||||
} else {
|
||||
Logger.error("BarSectionEditor", "Failed to create settings dialog instance")
|
||||
Logger.error("WidgetSectionEditor", "Failed to create settings dialog instance")
|
||||
}
|
||||
}
|
||||
if (component.status === Component.Ready) {
|
||||
instantiateAndOpen()
|
||||
} else if (component.status === Component.Error) {
|
||||
Logger.error("BarSectionEditor", component.errorString())
|
||||
Logger.error("WidgetSectionEditor", component.errorString())
|
||||
} else {
|
||||
component.statusChanged.connect(function () {
|
||||
if (component.status === Component.Ready) {
|
||||
instantiateAndOpen()
|
||||
} else if (component.status === Component.Error) {
|
||||
Logger.error("BarSectionEditor", component.errorString())
|
||||
Logger.error("WidgetSectionEditor", component.errorString())
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -29,6 +29,7 @@ NPanel {
|
||||
Audio,
|
||||
Bar,
|
||||
ColorScheme,
|
||||
ControlCenter,
|
||||
OSD,
|
||||
Display,
|
||||
Dock,
|
||||
@@ -111,6 +112,10 @@ NPanel {
|
||||
id: notificationsTab
|
||||
NotificationsTab {}
|
||||
}
|
||||
Component {
|
||||
id: controlCenterTab
|
||||
ControlCenterTab {}
|
||||
}
|
||||
|
||||
// Order *DOES* matter
|
||||
function updateTabsModel() {
|
||||
@@ -124,6 +129,11 @@ NPanel {
|
||||
"label": "settings.bar.title",
|
||||
"icon": "settings-bar",
|
||||
"source": barTab
|
||||
}, {
|
||||
"id": SettingsPanel.Tab.ControlCenter,
|
||||
"label": "settings.control-center.title",
|
||||
"icon": "settings-bar",
|
||||
"source": controlCenterTab
|
||||
}, {
|
||||
"id": SettingsPanel.Tab.Dock,
|
||||
"label": "settings.dock.title",
|
||||
|
||||
@@ -5,7 +5,7 @@ import Quickshell
|
||||
import qs.Commons
|
||||
import qs.Services
|
||||
import qs.Widgets
|
||||
import qs.Modules.Settings.Bar
|
||||
import qs.Modules.Settings.Extras
|
||||
|
||||
ColumnLayout {
|
||||
id: root
|
||||
@@ -201,9 +201,11 @@ ColumnLayout {
|
||||
spacing: Style.marginM * scaling
|
||||
|
||||
// Left Section
|
||||
BarSectionEditor {
|
||||
SectionEditor {
|
||||
sectionName: "Left"
|
||||
sectionId: "left"
|
||||
settingsDialogComponent: Qt.resolvedUrl(Quickshell.shellDir + "/Modules/Settings/Bar/BarWidgetSettingsDialog.qml")
|
||||
widgetRegistry: BarWidgetRegistry
|
||||
widgetModel: Settings.data.bar.widgets.left
|
||||
availableWidgets: availableWidgets
|
||||
onAddWidget: (widgetId, section) => _addWidgetToSection(widgetId, section)
|
||||
@@ -216,9 +218,11 @@ ColumnLayout {
|
||||
}
|
||||
|
||||
// Center Section
|
||||
BarSectionEditor {
|
||||
SectionEditor {
|
||||
sectionName: "Center"
|
||||
sectionId: "center"
|
||||
settingsDialogComponent: Qt.resolvedUrl(Quickshell.shellDir + "/Modules/Settings/Bar/BarWidgetSettingsDialog.qml")
|
||||
widgetRegistry: BarWidgetRegistry
|
||||
widgetModel: Settings.data.bar.widgets.center
|
||||
availableWidgets: availableWidgets
|
||||
onAddWidget: (widgetId, section) => _addWidgetToSection(widgetId, section)
|
||||
@@ -231,9 +235,11 @@ ColumnLayout {
|
||||
}
|
||||
|
||||
// Right Section
|
||||
BarSectionEditor {
|
||||
SectionEditor {
|
||||
sectionName: "Right"
|
||||
sectionId: "right"
|
||||
settingsDialogComponent: Qt.resolvedUrl(Quickshell.shellDir + "/Modules/Settings/Bar/BarWidgetSettingsDialog.qml")
|
||||
widgetRegistry: BarWidgetRegistry
|
||||
widgetModel: Settings.data.bar.widgets.right
|
||||
availableWidgets: availableWidgets
|
||||
onAddWidget: (widgetId, section) => _addWidgetToSection(widgetId, section)
|
||||
|
||||
@@ -0,0 +1,178 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
import Quickshell
|
||||
import qs.Commons
|
||||
import qs.Services
|
||||
import qs.Widgets
|
||||
import qs.Modules.Settings.Extras
|
||||
|
||||
ColumnLayout {
|
||||
id: root
|
||||
spacing: Style.marginL * scaling
|
||||
|
||||
// Handler for drag start - disables panel background clicks
|
||||
function handleDragStart() {
|
||||
var panel = PanelService.getPanel("settingsPanel")
|
||||
if (panel && panel.disableBackgroundClick) {
|
||||
panel.disableBackgroundClick()
|
||||
}
|
||||
}
|
||||
|
||||
// Handler for drag end - re-enables panel background clicks
|
||||
function handleDragEnd() {
|
||||
var panel = PanelService.getPanel("settingsPanel")
|
||||
if (panel && panel.enableBackgroundClick) {
|
||||
panel.enableBackgroundClick()
|
||||
}
|
||||
}
|
||||
|
||||
// Quick Settings Style Section
|
||||
ColumnLayout {
|
||||
spacing: Style.marginL * scaling
|
||||
Layout.fillWidth: true
|
||||
|
||||
NHeader {
|
||||
label: I18n.tr("settings.control-center.quickSettingsStyle.section.label")
|
||||
description: I18n.tr("settings.control-center.quickSettingsStyle.section.description")
|
||||
}
|
||||
|
||||
NComboBox {
|
||||
id: quickSettingsStyle
|
||||
label: I18n.tr("settings.control-center.quickSettingsStyle.style.label")
|
||||
description: I18n.tr("settings.control-center.quickSettingsStyle.style.description")
|
||||
Layout.fillWidth: true
|
||||
model: [{
|
||||
"key": "compact",
|
||||
"name": I18n.tr("options.control-center.quickSettingsStyle.compact")
|
||||
}, {
|
||||
"key": "classic",
|
||||
"name": I18n.tr("options.control-center.quickSettingsStyle.classic")
|
||||
}, {
|
||||
"key": "modern",
|
||||
"name": I18n.tr("options.control-center.quickSettingsStyle.modern")
|
||||
}]
|
||||
currentKey: Settings.data.controlCenter.quickSettingsStyle || "compact"
|
||||
onSelected: function (key) {
|
||||
Settings.data.controlCenter.quickSettingsStyle = key
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NDivider {
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: Style.marginXL * scaling
|
||||
Layout.bottomMargin: Style.marginXL * scaling
|
||||
}
|
||||
|
||||
// Widgets Management Section
|
||||
ColumnLayout {
|
||||
spacing: Style.marginXXS * scaling
|
||||
Layout.fillWidth: true
|
||||
|
||||
NHeader {
|
||||
label: I18n.tr("settings.control-center.widgets.section.label")
|
||||
description: I18n.tr("settings.control-center.widgets.section.description")
|
||||
}
|
||||
|
||||
// Bar Sections
|
||||
ColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
Layout.topMargin: Style.marginM * scaling
|
||||
spacing: Style.marginM * scaling
|
||||
|
||||
// Quick Settings
|
||||
SectionEditor {
|
||||
sectionName: I18n.tr("settings.control-center.quickSettings.sectionName")
|
||||
sectionId: "quickSettings"
|
||||
settingsDialogComponent: ""
|
||||
widgetRegistry: ControlCenterWidgetRegistry
|
||||
widgetModel: Settings.data.controlCenter.widgets["quickSettings"]
|
||||
availableWidgets: availableWidgets
|
||||
enableMoveBetweenSections: false
|
||||
onAddWidget: (widgetId, section) => _addWidgetToSection(widgetId, section)
|
||||
onRemoveWidget: (section, index) => _removeWidgetFromSection(section, index)
|
||||
onReorderWidget: (section, fromIndex, toIndex) => _reorderWidgetInSection(section, fromIndex, toIndex)
|
||||
onUpdateWidgetSettings: (section, index, settings) => _updateWidgetSettingsInSection(section, index, settings)
|
||||
onDragPotentialStarted: root.handleDragStart()
|
||||
onDragPotentialEnded: root.handleDragEnd()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NDivider {
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: Style.marginXL * scaling
|
||||
Layout.bottomMargin: Style.marginXL * scaling
|
||||
}
|
||||
|
||||
// ---------------------------------
|
||||
// Signal functions
|
||||
// ---------------------------------
|
||||
function _addWidgetToSection(widgetId, section) {
|
||||
var newWidget = {
|
||||
"id": widgetId
|
||||
}
|
||||
if (ControlCenterWidgetRegistry.widgetHasUserSettings(widgetId)) {
|
||||
var metadata = ControlCenterWidgetRegistry.widgetMetadata[widgetId]
|
||||
if (metadata) {
|
||||
Object.keys(metadata).forEach(function (key) {
|
||||
if (key !== "allowUserSettings") {
|
||||
newWidget[key] = metadata[key]
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
Settings.data.controlCenter.widgets[section].push(newWidget)
|
||||
}
|
||||
|
||||
function _removeWidgetFromSection(section, index) {
|
||||
if (index >= 0 && index < Settings.data.controlCenter.widgets[section].length) {
|
||||
var newArray = Settings.data.controlCenter.widgets[section].slice()
|
||||
var removedWidgets = newArray.splice(index, 1)
|
||||
Settings.data.controlCenter.widgets[section] = newArray
|
||||
|
||||
// Check that we still have a control center
|
||||
if (removedWidgets[0].id === "ControlCenter" && BarService.lookupWidget("ControlCenter") === undefined) {
|
||||
ToastService.showWarning(I18n.tr("toast.missing-control-center.label"), I18n.tr("toast.missing-control-center.description"), 12000)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function _reorderWidgetInSection(section, fromIndex, toIndex) {
|
||||
if (fromIndex >= 0 && fromIndex < Settings.data.controlCenter.widgets[section].length && toIndex >= 0 && toIndex < Settings.data.controlCenter.widgets[section].length) {
|
||||
|
||||
// Create a new array to avoid modifying the original
|
||||
var newArray = Settings.data.controlCenter.widgets[section].slice()
|
||||
var item = newArray[fromIndex]
|
||||
newArray.splice(fromIndex, 1)
|
||||
newArray.splice(toIndex, 0, item)
|
||||
|
||||
Settings.data.controlCenter.widgets[section] = newArray
|
||||
//Logger.log("BarTab", "Widget reordered. New array:", JSON.stringify(newArray))
|
||||
}
|
||||
}
|
||||
|
||||
function _updateWidgetSettingsInSection(section, index, settings) {
|
||||
// Update the widget settings in the Settings data
|
||||
Settings.data.controlCenter.widgets[section][index] = settings
|
||||
//Logger.log("BarTab", `Updated widget settings for ${settings.id} in ${section} section`)
|
||||
}
|
||||
|
||||
// Base list model for all combo boxes
|
||||
ListModel {
|
||||
id: availableWidgets
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
// Fill out availableWidgets ListModel
|
||||
availableWidgets.clear()
|
||||
ControlCenterWidgetRegistry.getAvailableWidgets().forEach(entry => {
|
||||
availableWidgets.append({
|
||||
"key": entry,
|
||||
"name": entry
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user