Merge branch 'noctalia-dev:main' into powermenu-ipc
This commit is contained in:
commit
5cee4c234a
45 changed files with 815 additions and 260 deletions
|
|
@ -144,6 +144,7 @@ Loader {
|
|||
maskEnabled: true
|
||||
maskSource: maskTexture
|
||||
maskInverted: false
|
||||
maskSpreadAtMax: 0.75
|
||||
}
|
||||
|
||||
mask: Region {}
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ Variants {
|
|||
layer.enabled: true
|
||||
}
|
||||
|
||||
// Left
|
||||
// Left Section - Dynamic Widgets
|
||||
Row {
|
||||
id: leftSection
|
||||
|
||||
|
|
@ -57,14 +57,25 @@ Variants {
|
|||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: Style.marginS * scaling
|
||||
|
||||
SystemMonitor {}
|
||||
|
||||
ActiveWindow {}
|
||||
|
||||
MediaMini {}
|
||||
Repeater {
|
||||
model: Settings.data.bar.widgets.left
|
||||
delegate: Loader {
|
||||
id: leftWidgetLoader
|
||||
sourceComponent: widgetLoader.getWidgetComponent(modelData)
|
||||
active: true
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
onStatusChanged: {
|
||||
if (status === Loader.Error) {
|
||||
widgetLoader.onWidgetFailed(modelData, "Loader error")
|
||||
} else if (status === Loader.Ready) {
|
||||
widgetLoader.onWidgetLoaded(modelData)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Center
|
||||
// Center Section - Dynamic Widgets
|
||||
Row {
|
||||
id: centerSection
|
||||
|
||||
|
|
@ -73,10 +84,25 @@ Variants {
|
|||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: Style.marginS * scaling
|
||||
|
||||
Workspace {}
|
||||
Repeater {
|
||||
model: Settings.data.bar.widgets.center
|
||||
delegate: Loader {
|
||||
id: centerWidgetLoader
|
||||
sourceComponent: widgetLoader.getWidgetComponent(modelData)
|
||||
active: true
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
onStatusChanged: {
|
||||
if (status === Loader.Error) {
|
||||
widgetLoader.onWidgetFailed(modelData, "Loader error")
|
||||
} else if (status === Loader.Ready) {
|
||||
widgetLoader.onWidgetLoaded(modelData)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Right
|
||||
// Right Section - Dynamic Widgets
|
||||
Row {
|
||||
id: rightSection
|
||||
|
||||
|
|
@ -86,44 +112,38 @@ Variants {
|
|||
anchors.verticalCenter: bar.verticalCenter
|
||||
spacing: Style.marginS * scaling
|
||||
|
||||
ScreenRecorderIndicator {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
Repeater {
|
||||
model: Settings.data.bar.widgets.right
|
||||
delegate: Loader {
|
||||
id: rightWidgetLoader
|
||||
sourceComponent: widgetLoader.getWidgetComponent(modelData)
|
||||
active: true
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
onStatusChanged: {
|
||||
if (status === Loader.Error) {
|
||||
widgetLoader.onWidgetFailed(modelData, "Loader error")
|
||||
} else if (status === Loader.Ready) {
|
||||
widgetLoader.onWidgetLoaded(modelData)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Tray {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
NotificationHistory {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
WiFi {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
Bluetooth {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
Battery {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
Volume {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
Brightness {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
Clock {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
SidePanelToggle {}
|
||||
}
|
||||
}
|
||||
|
||||
// Widget loader instance
|
||||
WidgetLoader {
|
||||
id: widgetLoader
|
||||
|
||||
onWidgetFailed: function (widgetName, error) {
|
||||
Logger.error("Bar", `Widget failed: ${widgetName} - ${error}`)
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize widget loading tracking
|
||||
Component.onCompleted: {
|
||||
const allWidgets = [...Settings.data.bar.widgets.left, ...Settings.data.bar.widgets.center, ...Settings.data.bar.widgets.right]
|
||||
widgetLoader.initializeLoading(allWidgets)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,43 +0,0 @@
|
|||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import QtQuick.Controls
|
||||
import Quickshell
|
||||
import Quickshell.Wayland
|
||||
import qs.Commons
|
||||
import qs.Services
|
||||
import qs.Widgets
|
||||
|
||||
NIconButton {
|
||||
id: root
|
||||
|
||||
readonly property bool wifiEnabled: Settings.data.network.wifiEnabled
|
||||
|
||||
sizeMultiplier: 0.8
|
||||
visible: wifiEnabled
|
||||
|
||||
colorBg: Color.mSurfaceVariant
|
||||
colorFg: Color.mOnSurface
|
||||
colorBorder: Color.transparent
|
||||
colorBorderHover: Color.transparent
|
||||
|
||||
icon: {
|
||||
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"
|
||||
}
|
||||
tooltipText: "WiFi Networks"
|
||||
onClicked: {
|
||||
wifiPanel.toggle(screen)
|
||||
}
|
||||
|
||||
WiFiPanel {
|
||||
id: wifiPanel
|
||||
}
|
||||
}
|
||||
|
|
@ -11,7 +11,7 @@ Row {
|
|||
id: root
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: Style.marginS * scaling
|
||||
visible: (Settings.data.bar.showActiveWindow && getTitle() !== "")
|
||||
visible: getTitle() !== ""
|
||||
|
||||
property bool showingFullTitle: false
|
||||
property int lastWindowIndex: -1
|
||||
|
|
@ -22,8 +22,6 @@ NPill {
|
|||
|
||||
// Choose icon based on charge and charging state
|
||||
function batteryIcon() {
|
||||
if (!show)
|
||||
return ""
|
||||
|
||||
if (charging)
|
||||
return "battery_android_bolt"
|
||||
|
|
@ -10,9 +10,7 @@ import qs.Widgets
|
|||
NIconButton {
|
||||
id: root
|
||||
|
||||
readonly property bool bluetoothEnabled: Settings.data.network.bluetoothEnabled
|
||||
sizeMultiplier: 0.8
|
||||
visible: bluetoothEnabled
|
||||
|
||||
colorBg: Color.mSurfaceVariant
|
||||
colorFg: Color.mOnSurface
|
||||
|
|
@ -33,8 +31,4 @@ NIconButton {
|
|||
onClicked: {
|
||||
bluetoothPanel.toggle(screen)
|
||||
}
|
||||
|
||||
BluetoothPanel {
|
||||
id: bluetoothPanel
|
||||
}
|
||||
}
|
||||
|
|
@ -10,7 +10,7 @@ Item {
|
|||
|
||||
width: pill.width
|
||||
height: pill.height
|
||||
visible: Settings.data.bar.showBrightness && firstBrightnessReceived && getMonitor() !== null
|
||||
visible: getMonitor() !== null
|
||||
|
||||
// Used to avoid opening the pill on Quickshell startup
|
||||
property bool firstBrightnessReceived: false
|
||||
|
|
@ -11,7 +11,8 @@ Row {
|
|||
id: root
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: Style.marginS * scaling
|
||||
visible: Settings.data.bar.showMedia && (MediaService.canPlay || MediaService.canPause)
|
||||
visible: MediaService.currentPlayer !== null
|
||||
width: MediaService.currentPlayer !== null ? implicitWidth : 0
|
||||
|
||||
function getTitle() {
|
||||
return MediaService.trackTitle + (MediaService.trackArtist !== "" ? ` - ${MediaService.trackArtist}` : "")
|
||||
|
|
@ -109,14 +110,14 @@ Row {
|
|||
visible: Settings.data.audio.showMiniplayerAlbumArt
|
||||
|
||||
Rectangle {
|
||||
width: 16 * scaling
|
||||
height: 16 * scaling
|
||||
width: 18 * scaling
|
||||
height: 18 * scaling
|
||||
radius: width * 0.5
|
||||
color: Color.transparent
|
||||
antialiasing: true
|
||||
clip: true
|
||||
|
||||
NImageRounded {
|
||||
NImageCircled {
|
||||
id: trackArt
|
||||
visible: MediaService.trackArtUrl.toString() !== ""
|
||||
anchors.fill: parent
|
||||
|
|
@ -126,8 +127,6 @@ Row {
|
|||
fallbackIcon: MediaService.isPlaying ? "pause" : "play_arrow"
|
||||
borderWidth: 0
|
||||
border.color: Color.transparent
|
||||
imageRadius: width
|
||||
antialiasing: true
|
||||
}
|
||||
|
||||
// Fallback icon when no album art available
|
||||
|
|
@ -10,7 +10,6 @@ import qs.Widgets
|
|||
NIconButton {
|
||||
id: root
|
||||
|
||||
visible: Settings.data.bar.showNotificationsHistory
|
||||
sizeMultiplier: 0.8
|
||||
icon: "notifications"
|
||||
tooltipText: "Notification History"
|
||||
|
|
@ -8,7 +8,6 @@ Row {
|
|||
id: root
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: Style.marginS * scaling
|
||||
visible: (Settings.data.bar.showSystemInfo)
|
||||
|
||||
Rectangle {
|
||||
// Let the Rectangle size itself based on its content (the Row)
|
||||
|
|
@ -12,9 +12,8 @@ import qs.Widgets
|
|||
Rectangle {
|
||||
readonly property real itemSize: 24 * scaling
|
||||
|
||||
visible: Settings.data.bar.showTray && (SystemTray.items.values.length > 0)
|
||||
visible: SystemTray.items.values.length > 0
|
||||
width: tray.width + Style.marginM * scaling * 2
|
||||
|
||||
height: Math.round(Style.capsuleHeight * scaling)
|
||||
radius: Math.round(Style.radiusM * scaling)
|
||||
color: Color.mSurfaceVariant
|
||||
|
|
@ -95,14 +94,14 @@ Rectangle {
|
|||
return
|
||||
}
|
||||
|
||||
if (modelData.hasMenu && modelData.menu && trayMenu) {
|
||||
if (modelData.hasMenu && modelData.menu && trayMenu.item) {
|
||||
trayPanel.open()
|
||||
|
||||
// Anchor the menu to the tray icon item (parent) and position it below the icon
|
||||
const menuX = (width / 2) - (trayMenu.width / 2)
|
||||
const menuX = (width / 2) - (trayMenu.item.width / 2)
|
||||
const menuY = (Style.barHeight * scaling)
|
||||
trayMenu.menu = modelData.menu
|
||||
trayMenu.showAt(parent, menuX, menuY)
|
||||
trayMenu.item.menu = modelData.menu
|
||||
trayMenu.item.showAt(parent, menuX, menuY)
|
||||
} else {
|
||||
Logger.log("Tray", "No menu available for", modelData.id, "or trayMenu not set")
|
||||
}
|
||||
|
|
@ -142,7 +141,7 @@ Rectangle {
|
|||
|
||||
function close() {
|
||||
visible = false
|
||||
trayMenu.hideMenu()
|
||||
trayMenu.item.hideMenu()
|
||||
}
|
||||
|
||||
// Clicking outside of the rectangle to close
|
||||
|
|
@ -151,8 +150,9 @@ Rectangle {
|
|||
onClicked: trayPanel.close()
|
||||
}
|
||||
|
||||
TrayMenu {
|
||||
Loader {
|
||||
id: trayMenu
|
||||
source: "TrayMenu.qml"
|
||||
}
|
||||
}
|
||||
}
|
||||
54
Modules/Bar/Widgets/WiFi.qml
Normal file
54
Modules/Bar/Widgets/WiFi.qml
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import QtQuick.Controls
|
||||
import Quickshell
|
||||
import Quickshell.Wayland
|
||||
import qs.Commons
|
||||
import qs.Services
|
||||
import qs.Widgets
|
||||
|
||||
NIconButton {
|
||||
id: root
|
||||
|
||||
sizeMultiplier: 0.8
|
||||
|
||||
Component.onCompleted: {
|
||||
Logger.log("WiFi", "Widget component completed")
|
||||
Logger.log("WiFi", "NetworkService available:", !!NetworkService)
|
||||
if (NetworkService) {
|
||||
Logger.log("WiFi", "NetworkService.networks available:", !!NetworkService.networks)
|
||||
}
|
||||
}
|
||||
|
||||
colorBg: Color.mSurfaceVariant
|
||||
colorFg: Color.mOnSurface
|
||||
colorBorder: Color.transparent
|
||||
colorBorderHover: Color.transparent
|
||||
|
||||
icon: {
|
||||
try {
|
||||
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"
|
||||
} catch (error) {
|
||||
Logger.error("WiFi", "Error getting icon:", error)
|
||||
return "wifi"
|
||||
}
|
||||
}
|
||||
tooltipText: "WiFi Networks"
|
||||
onClicked: {
|
||||
try {
|
||||
Logger.log("WiFi", "Button clicked, toggling panel")
|
||||
wifiPanel.toggle(screen)
|
||||
} catch (error) {
|
||||
Logger.error("WiFi", "Error toggling panel:", error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -225,7 +225,7 @@ NPanel {
|
|||
Layout.bottomMargin: Style.marginM * scaling
|
||||
radius: Style.radiusM * scaling
|
||||
color: Color.mSurface
|
||||
border.color: searchInput.activeFocus ? Color.mTertiary : Color.mOutline
|
||||
border.color: searchInput.activeFocus ? Color.mSecondary : Color.mOutline
|
||||
border.width: Math.max(1, searchInput.activeFocus ? Style.borderM * scaling : Style.borderS * scaling)
|
||||
|
||||
Item {
|
||||
|
|
@ -355,7 +355,7 @@ NPanel {
|
|||
height: 65 * scaling
|
||||
radius: Style.radiusM * scaling
|
||||
property bool isSelected: index === selectedIndex
|
||||
color: (appCardArea.containsMouse || isSelected) ? Color.mTertiary : Color.mSurface
|
||||
color: (appCardArea.containsMouse || isSelected) ? Color.mSecondary : Color.mSurface
|
||||
|
||||
Behavior on color {
|
||||
ColorAnimation {
|
||||
|
|
|
|||
|
|
@ -294,13 +294,14 @@ Loader {
|
|||
|
||||
// Animated avatar with glow effect or audio visualizer
|
||||
Rectangle {
|
||||
width: 120 * scaling
|
||||
height: 120 * scaling
|
||||
width: 108 * scaling
|
||||
height: 108 * scaling
|
||||
radius: width * 0.5
|
||||
color: Color.transparent
|
||||
border.color: Color.mPrimary
|
||||
border.width: Math.max(1, Style.borderL * scaling)
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
z: 10
|
||||
|
||||
// Circular audio visualizer when music is playing
|
||||
Loader {
|
||||
|
|
@ -464,13 +465,12 @@ Loader {
|
|||
}
|
||||
}
|
||||
|
||||
NImageRounded {
|
||||
NImageCircled {
|
||||
anchors.centerIn: parent
|
||||
width: 100 * scaling
|
||||
height: 100 * scaling
|
||||
imagePath: Settings.data.general.avatarImage
|
||||
fallbackIcon: "person"
|
||||
imageRadius: width * 0.5
|
||||
}
|
||||
|
||||
// Hover animation
|
||||
|
|
|
|||
|
|
@ -111,7 +111,7 @@ NPanel {
|
|||
width: notificationList ? notificationList.width : 380 * scaling
|
||||
height: Math.max(80, notificationContent.height + 30)
|
||||
radius: Style.radiusM * scaling
|
||||
color: notificationMouseArea.containsMouse ? Color.mTertiary : Color.mSurfaceVariant
|
||||
color: notificationMouseArea.containsMouse ? Color.mSecondary : Color.mSurfaceVariant
|
||||
|
||||
RowLayout {
|
||||
anchors {
|
||||
|
|
|
|||
|
|
@ -215,7 +215,7 @@ NPanel {
|
|||
if (pending)
|
||||
return Color.applyOpacity(Color.mPrimary, "20")
|
||||
if (mouseArea.containsMouse)
|
||||
return Color.mTertiary
|
||||
return Color.mSecondary
|
||||
return Color.transparent
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@ NPanel {
|
|||
id: barTab
|
||||
Tabs.BarTab {}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: audioTab
|
||||
Tabs.AudioTab {}
|
||||
|
|
|
|||
|
|
@ -199,7 +199,7 @@ ColumnLayout {
|
|||
width: contributorsGrid.cellWidth - Style.marginL * scaling
|
||||
height: contributorsGrid.cellHeight - Style.marginXS * scaling
|
||||
radius: Style.radiusL * scaling
|
||||
color: contributorArea.containsMouse ? Color.mTertiary : Color.transparent
|
||||
color: contributorArea.containsMouse ? Color.mSecondary : Color.transparent
|
||||
|
||||
RowLayout {
|
||||
anchors.fill: parent
|
||||
|
|
@ -211,14 +211,13 @@ ColumnLayout {
|
|||
Layout.preferredWidth: Style.baseWidgetSize * 2 * scaling
|
||||
Layout.preferredHeight: Style.baseWidgetSize * 2 * scaling
|
||||
|
||||
NImageRounded {
|
||||
NImageCircled {
|
||||
imagePath: modelData.avatar_url || ""
|
||||
anchors.fill: parent
|
||||
anchors.margins: Style.marginXS * scaling
|
||||
fallbackIcon: "person"
|
||||
borderColor: Color.mPrimary
|
||||
borderWidth: Math.max(1, Style.borderM * scaling)
|
||||
imageRadius: width * 0.5
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -33,12 +33,6 @@ ColumnLayout {
|
|||
spacing: Style.marginL * scaling
|
||||
Layout.fillWidth: true
|
||||
|
||||
NText {
|
||||
text: "Bar Components"
|
||||
font.pointSize: Style.fontSizeXXL * scaling
|
||||
font.weight: Style.fontWeightBold
|
||||
color: Color.mOnSurface
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
spacing: Style.marginXXS * scaling
|
||||
|
|
@ -78,70 +72,7 @@ ColumnLayout {
|
|||
}
|
||||
}
|
||||
|
||||
NToggle {
|
||||
label: "Show Active Window"
|
||||
description: "Display the title of the currently focused window."
|
||||
checked: Settings.data.bar.showActiveWindow
|
||||
onToggled: checked => {
|
||||
Settings.data.bar.showActiveWindow = checked
|
||||
}
|
||||
}
|
||||
|
||||
NToggle {
|
||||
label: "Show Active Window's Icon"
|
||||
description: "Display the app icon next to the title of the currently focused window."
|
||||
checked: Settings.data.bar.showActiveWindowIcon
|
||||
onToggled: checked => {
|
||||
Settings.data.bar.showActiveWindowIcon = checked
|
||||
}
|
||||
}
|
||||
|
||||
NToggle {
|
||||
label: "Show System Info"
|
||||
description: "Display system statistics (CPU, RAM, Temperature)."
|
||||
checked: Settings.data.bar.showSystemInfo
|
||||
onToggled: checked => {
|
||||
Settings.data.bar.showSystemInfo = checked
|
||||
}
|
||||
}
|
||||
|
||||
NToggle {
|
||||
label: "Show Media"
|
||||
description: "Display media controls and information."
|
||||
checked: Settings.data.bar.showMedia
|
||||
onToggled: checked => {
|
||||
Settings.data.bar.showMedia = checked
|
||||
}
|
||||
}
|
||||
|
||||
NToggle {
|
||||
label: "Show Notifications History"
|
||||
description: "Display a shortcut to the notifications history."
|
||||
checked: Settings.data.bar.showNotificationsHistory
|
||||
onToggled: checked => {
|
||||
Settings.data.bar.showNotificationsHistory = checked
|
||||
}
|
||||
}
|
||||
|
||||
NToggle {
|
||||
label: "Show Applications Tray"
|
||||
description: "Display the applications tray."
|
||||
checked: Settings.data.bar.showTray
|
||||
onToggled: checked => {
|
||||
Settings.data.bar.showTray = checked
|
||||
}
|
||||
}
|
||||
|
||||
NToggle {
|
||||
label: "Show Battery Percentage"
|
||||
description: "Show battery percentage at all times."
|
||||
checked: Settings.data.bar.alwaysShowBatteryPercentage
|
||||
onToggled: checked => {
|
||||
Settings.data.bar.alwaysShowBatteryPercentage = checked
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
ColumnLayout {
|
||||
spacing: Style.marginXXS * scaling
|
||||
Layout.fillWidth: true
|
||||
|
||||
|
|
@ -179,7 +110,168 @@ ColumnLayout {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
NToggle {
|
||||
label: "Show Active Window's Icon"
|
||||
description: "Display the app icon next to the title of the currently focused window."
|
||||
checked: Settings.data.bar.showActiveWindowIcon
|
||||
onToggled: checked => {
|
||||
Settings.data.bar.showActiveWindowIcon = checked
|
||||
}
|
||||
}
|
||||
|
||||
NToggle {
|
||||
label: "Show Battery Percentage"
|
||||
description: "Show battery percentage at all times."
|
||||
checked: Settings.data.bar.alwaysShowBatteryPercentage
|
||||
onToggled: checked => {
|
||||
Settings.data.bar.alwaysShowBatteryPercentage = checked
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
NDivider {
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: Style.marginL * scaling
|
||||
Layout.bottomMargin: Style.marginL * scaling
|
||||
}
|
||||
|
||||
// Widgets Management Section
|
||||
ColumnLayout {
|
||||
spacing: Style.marginXXS * scaling
|
||||
Layout.fillWidth: true
|
||||
|
||||
NText {
|
||||
text: "Widgets Positioning"
|
||||
font.pointSize: Style.fontSizeL * scaling
|
||||
font.weight: Style.fontWeightBold
|
||||
color: Color.mOnSurface
|
||||
}
|
||||
|
||||
NText {
|
||||
text: "Add, remove, or reorder widgets in each section of the bar using the control buttons."
|
||||
font.pointSize: Style.fontSizeXS * scaling
|
||||
color: Color.mOnSurfaceVariant
|
||||
wrapMode: Text.WordWrap
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
// Bar Sections
|
||||
ColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
Layout.topMargin: Style.marginM * scaling
|
||||
spacing: Style.marginM * scaling
|
||||
|
||||
// Left Section
|
||||
NWidgetCard {
|
||||
sectionName: "Left"
|
||||
widgetModel: Settings.data.bar.widgets.left
|
||||
availableWidgets: availableWidgets
|
||||
scrollView: scrollView
|
||||
onAddWidget: (widgetName, section) => addWidgetToSection(widgetName, section)
|
||||
onRemoveWidget: (section, index) => removeWidgetFromSection(section, index)
|
||||
onReorderWidget: (section, fromIndex, toIndex) => reorderWidgetInSection(section, fromIndex, toIndex)
|
||||
}
|
||||
|
||||
// Center Section
|
||||
NWidgetCard {
|
||||
sectionName: "Center"
|
||||
widgetModel: Settings.data.bar.widgets.center
|
||||
availableWidgets: availableWidgets
|
||||
scrollView: scrollView
|
||||
onAddWidget: (widgetName, section) => addWidgetToSection(widgetName, section)
|
||||
onRemoveWidget: (section, index) => removeWidgetFromSection(section, index)
|
||||
onReorderWidget: (section, fromIndex, toIndex) => reorderWidgetInSection(section, fromIndex, toIndex)
|
||||
}
|
||||
|
||||
// Right Section
|
||||
NWidgetCard {
|
||||
sectionName: "Right"
|
||||
widgetModel: Settings.data.bar.widgets.right
|
||||
availableWidgets: availableWidgets
|
||||
scrollView: scrollView
|
||||
onAddWidget: (widgetName, section) => addWidgetToSection(widgetName, section)
|
||||
onRemoveWidget: (section, index) => removeWidgetFromSection(section, index)
|
||||
onReorderWidget: (section, fromIndex, toIndex) => reorderWidgetInSection(section, fromIndex, toIndex)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Helper functions
|
||||
function addWidgetToSection(widgetName, section) {
|
||||
console.log("Adding widget", widgetName, "to section", section)
|
||||
var sectionArray = Settings.data.bar.widgets[section]
|
||||
if (sectionArray) {
|
||||
// Create a new array to avoid modifying the original
|
||||
var newArray = sectionArray.slice()
|
||||
newArray.push(widgetName)
|
||||
console.log("Widget added. New array:", JSON.stringify(newArray))
|
||||
|
||||
// Assign the new array
|
||||
Settings.data.bar.widgets[section] = newArray
|
||||
}
|
||||
}
|
||||
|
||||
function removeWidgetFromSection(section, index) {
|
||||
console.log("Removing widget from section", section, "at index", index)
|
||||
var sectionArray = Settings.data.bar.widgets[section]
|
||||
if (sectionArray && index >= 0 && index < sectionArray.length) {
|
||||
// Create a new array to avoid modifying the original
|
||||
var newArray = sectionArray.slice()
|
||||
newArray.splice(index, 1)
|
||||
console.log("Widget removed. New array:", JSON.stringify(newArray))
|
||||
|
||||
// Assign the new array
|
||||
Settings.data.bar.widgets[section] = newArray
|
||||
}
|
||||
}
|
||||
|
||||
function reorderWidgetInSection(section, fromIndex, toIndex) {
|
||||
console.log("Reordering widget in section", section, "from", fromIndex, "to", toIndex)
|
||||
var sectionArray = Settings.data.bar.widgets[section]
|
||||
if (sectionArray && fromIndex >= 0 && fromIndex < sectionArray.length && toIndex >= 0
|
||||
&& toIndex < sectionArray.length) {
|
||||
|
||||
// Create a new array to avoid modifying the original
|
||||
var newArray = sectionArray.slice()
|
||||
var item = newArray[fromIndex]
|
||||
newArray.splice(fromIndex, 1)
|
||||
newArray.splice(toIndex, 0, item)
|
||||
console.log("Widget reordered. New array:", JSON.stringify(newArray))
|
||||
|
||||
// Assign the new array
|
||||
Settings.data.bar.widgets[section] = newArray
|
||||
}
|
||||
}
|
||||
|
||||
// Widget loader for discovering available widgets
|
||||
WidgetLoader {
|
||||
id: widgetLoader
|
||||
}
|
||||
|
||||
ListModel {
|
||||
id: availableWidgets
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
discoverWidgets()
|
||||
}
|
||||
|
||||
// Automatically discover available widgets using WidgetLoader
|
||||
function discoverWidgets() {
|
||||
availableWidgets.clear()
|
||||
|
||||
// Use WidgetLoader to discover available widgets
|
||||
const discoveredWidgets = widgetLoader.discoverAvailableWidgets()
|
||||
|
||||
// Add discovered widgets to the ListModel
|
||||
discoveredWidgets.forEach(widget => {
|
||||
availableWidgets.append(widget)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -51,13 +51,13 @@ ColumnLayout {
|
|||
spacing: Style.marginL * scaling
|
||||
|
||||
// Avatar preview
|
||||
NImageRounded {
|
||||
NImageCircled {
|
||||
width: 64 * scaling
|
||||
height: 64 * scaling
|
||||
imagePath: Settings.data.general.avatarImage
|
||||
fallbackIcon: "person"
|
||||
borderColor: Color.mPrimary
|
||||
borderWidth: Math.max(1, Style.borderM)
|
||||
borderWidth: Math.max(1, Style.borderM * scaling)
|
||||
}
|
||||
|
||||
NTextInput {
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@ NBox {
|
|||
// implicitWidth: 120 * scaling
|
||||
// implicitHeight: 30 * scaling
|
||||
color: Color.transparent
|
||||
border.color: playerSelector.activeFocus ? Color.mTertiary : Color.mOutline
|
||||
border.color: playerSelector.activeFocus ? Color.mSecondary : Color.mOutline
|
||||
border.width: Math.max(1, Style.borderS * scaling)
|
||||
radius: Style.radiusM * scaling
|
||||
}
|
||||
|
|
@ -138,7 +138,7 @@ NBox {
|
|||
|
||||
background: Rectangle {
|
||||
width: popup.width - Style.marginS * scaling * 2
|
||||
color: highlighted ? Color.mTertiary : Color.transparent
|
||||
color: highlighted ? Color.mSecondary : Color.transparent
|
||||
radius: Style.radiusXS * scaling
|
||||
}
|
||||
}
|
||||
|
|
@ -164,7 +164,7 @@ NBox {
|
|||
border.width: Math.max(1, Style.borderS * scaling)
|
||||
clip: true
|
||||
|
||||
NImageRounded {
|
||||
NImageCircled {
|
||||
id: trackArt
|
||||
visible: MediaService.trackArtUrl.toString() !== ""
|
||||
|
||||
|
|
@ -174,7 +174,6 @@ NBox {
|
|||
fallbackIcon: "music_note"
|
||||
borderColor: Color.mOutline
|
||||
borderWidth: Math.max(1, Style.borderS * scaling)
|
||||
imageRadius: width * 0.5
|
||||
}
|
||||
|
||||
// Fallback icon when no album art available
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ NBox {
|
|||
anchors.margins: Style.marginM * scaling
|
||||
spacing: Style.marginM * scaling
|
||||
|
||||
NImageRounded {
|
||||
NImageCircled {
|
||||
width: Style.baseWidgetSize * 1.25 * scaling
|
||||
height: Style.baseWidgetSize * 1.25 * scaling
|
||||
imagePath: Settings.data.general.avatarImage
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue