Merge branch 'main' into patch-3

This commit is contained in:
notiant
2025-11-26 18:55:49 +01:00
committed by GitHub
48 changed files with 670 additions and 769 deletions
+10 -2
View File
@@ -23,6 +23,8 @@ Item {
property color customBackgroundColor: Color.transparent
property color customTextIconColor: Color.transparent
readonly property bool collapseToIcon: forceClose && !forceOpen
// Effective shown state (true if hovered/animated open or forced)
readonly property bool revealed: !forceClose && (forceOpen || showPill)
@@ -66,7 +68,7 @@ Item {
}
}
width: pillHeight + Math.max(0, pill.width - pillOverlap)
width: collapseToIcon ? pillHeight : pillHeight + Math.max(0, pill.width - pillOverlap)
height: pillHeight
Connections {
@@ -81,7 +83,7 @@ Item {
// Unified background for the entire pill area to avoid overlapping opacity
Rectangle {
id: pillBackground
width: root.width
width: collapseToIcon ? pillHeight : root.width
height: pillHeight
radius: halfPillHeight
color: root.bgColor
@@ -290,6 +292,8 @@ Item {
}
function show() {
if (collapseToIcon)
return;
if (!showPill) {
shouldAnimateHide = autoHide;
showAnim.start();
@@ -300,6 +304,8 @@ Item {
}
function hide() {
if (collapseToIcon)
return;
if (forceOpen) {
return;
}
@@ -310,6 +316,8 @@ Item {
}
function showDelayed() {
if (collapseToIcon)
return;
if (!showPill) {
shouldAnimateHide = autoHide;
showTimer.start();
+10 -2
View File
@@ -24,6 +24,8 @@ Item {
property color customBackgroundColor: Color.transparent
property color customTextIconColor: Color.transparent
readonly property bool collapseToIcon: forceClose && !forceOpen
signal shown
signal hidden
signal entered
@@ -76,7 +78,7 @@ Item {
// For vertical bars: width is just icon size, height includes pill space
width: buttonSize
height: revealed ? (buttonSize + maxPillHeight - pillOverlap) : buttonSize
height: collapseToIcon ? buttonSize : (revealed ? (buttonSize + maxPillHeight - pillOverlap) : buttonSize)
Connections {
target: root
@@ -91,7 +93,7 @@ Item {
Rectangle {
id: pillBackground
width: buttonSize
height: revealed ? (buttonSize + maxPillHeight - pillOverlap) : buttonSize
height: collapseToIcon ? buttonSize : (revealed ? (buttonSize + maxPillHeight - pillOverlap) : buttonSize)
radius: halfButtonSize
color: root.bgColor
@@ -321,6 +323,8 @@ Item {
}
function show() {
if (collapseToIcon)
return;
if (!showPill) {
shouldAnimateHide = autoHide;
showAnim.start();
@@ -331,6 +335,8 @@ Item {
}
function hide() {
if (collapseToIcon)
return;
if (forceOpen) {
return;
}
@@ -341,6 +347,8 @@ Item {
}
function showDelayed() {
if (collapseToIcon)
return;
if (!showPill) {
shouldAnimateHide = autoHide;
showTimer.start();
+1 -1
View File
@@ -87,7 +87,7 @@ Item {
}
autoHide: false
forceOpen: !isBarVertical && root.displayMode === "alwaysShow"
forceClose: isBarVertical || root.displayMode === "alwaysHide" || BluetoothService.connectedDevices.length === 0
forceClose: isBarVertical || root.displayMode === "alwaysHide"
onClicked: PanelService.getPanel("bluetoothPanel", screen)?.toggle(this)
onRightClicked: {
var popupMenuWindow = PanelService.getPopupMenuWindow(screen);
+2
View File
@@ -47,6 +47,8 @@ Item {
function getIcon() {
var monitor = getMonitor();
var brightness = monitor ? monitor.brightness : 0;
if (brightness <= 0.001)
return "sun-off";
return brightness <= 0.5 ? "brightness-low" : "brightness-high";
}
+5 -3
View File
@@ -409,16 +409,17 @@ Item {
anchors.fill: parent
anchors.margins: showProgressRing ? (3 * scaling) : 0.5 // Adjusted to align with progress circle better
NImageCircled {
NImageRounded {
id: trackArt
anchors.fill: parent
anchors.margins: showProgressRing ? 0 : -1 * scaling // Add negative margin to make album art larger when no progress ring
radius: width * 0.5
visible: showAlbumArt && hasActivePlayer
imagePath: MediaService.trackArtUrl
fallbackIcon: MediaService.isPlaying ? "media-pause" : "media-play"
fallbackIconSize: showProgressRing ? 10 : 12 // Larger fallback icon when no progress ring
borderWidth: 0
border.color: Color.transparent
borderColor: Color.transparent
z: 1 // In front of the progress circle
}
@@ -649,9 +650,10 @@ Item {
z: 1 // Above the visualizer and progress ring
// Album Art
NImageCircled {
NImageRounded {
anchors.fill: parent
visible: showAlbumArt && hasActivePlayer
radius: width * 0.5
imagePath: MediaService.trackArtUrl
fallbackIcon: MediaService.isPlaying ? "media-pause" : "media-play"
fallbackIconSize: 12
+8 -4
View File
@@ -161,10 +161,14 @@ Rectangle {
}
//Logger.d("Tray", "wildCardMatch - Input str:", str, "rule:", rule)
// Escape all special regex characters in the rule
let escapedRule = rule.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
// Convert '*' to '.*' for wildcard matching
let pattern = escapedRule.replace(/\\\*/g, '.*');
// First, convert '*' to a placeholder to preserve it, then escape other special regex characters
// Use a unique placeholder that won't appear in normal strings
const placeholder = '\uE000'; // Private use character
let processedRule = rule.replace(/\*/g, placeholder);
// Escape all special regex characters (but placeholder won't match this)
let escapedRule = processedRule.replace(/[.+?^${}()|[\]\\]/g, '\\$&');
// Convert placeholder back to '.*' for wildcard matching
let pattern = escapedRule.replace(new RegExp(placeholder, 'g'), '.*');
// Add ^ and $ to match the entire string
pattern = '^' + pattern + '$';
+1 -1
View File
@@ -109,7 +109,7 @@ Item {
}
autoHide: false
forceOpen: !isBarVertical && root.displayMode === "alwaysShow"
forceClose: isBarVertical || root.displayMode === "alwaysHide" || !pill.text
forceClose: isBarVertical || root.displayMode === "alwaysHide"
onClicked: PanelService.getPanel("wifiPanel", screen)?.toggle(this)
onRightClicked: {
var popupMenuWindow = PanelService.getPopupMenuWindow(screen);
+4 -2
View File
@@ -301,10 +301,11 @@ Loader {
}
}
NImageCircled {
NImageRounded {
anchors.centerIn: parent
width: 66
height: 66
radius: width * 0.5
imagePath: Settings.preprocessPath(Settings.data.general.avatarImage)
fallbackIcon: "person"
@@ -631,9 +632,10 @@ Loader {
color: Color.transparent
clip: true
NImageCircled {
NImageRounded {
anchors.fill: parent
anchors.margins: 2
radius: width * 0.5
imagePath: MediaService.trackArtUrl
fallbackIcon: "disc"
fallbackIconSize: Style.fontSizeM
+10 -11
View File
@@ -398,17 +398,16 @@ Variants {
Layout.topMargin: Style.marginM
Layout.bottomMargin: Style.marginM
ColumnLayout {
NImageCircled {
Layout.preferredWidth: Math.round(40 * Style.uiScaleRatio)
Layout.preferredHeight: Math.round(40 * Style.uiScaleRatio)
Layout.alignment: Qt.AlignVCenter
imagePath: model.originalImage || ""
borderColor: Color.transparent
borderWidth: 0
fallbackIcon: "bell"
fallbackIconSize: 24
}
NImageRounded {
Layout.preferredWidth: Math.round(40 * Style.uiScaleRatio)
Layout.preferredHeight: Math.round(40 * Style.uiScaleRatio)
Layout.alignment: Qt.AlignVCenter
radius: width * 0.5
imagePath: model.originalImage || ""
borderColor: Color.transparent
borderWidth: 0
fallbackIcon: "bell"
fallbackIconSize: 24
}
ColumnLayout {
+7 -3
View File
@@ -49,12 +49,16 @@ Variants {
case OSD.Type.Volume:
if (isMuted)
return "volume-mute";
if (currentVolume <= Number.EPSILON)
return "volume-zero";
// Show volume-x icon when volume is effectively 0% (within rounding threshold)
if (currentVolume < 0.005)
return "volume-x";
return currentVolume <= 0.5 ? "volume-low" : "volume-high";
case OSD.Type.InputVolume:
return isInputMuted ? "microphone-off" : "microphone";
case OSD.Type.Brightness:
// Show sun-off icon when brightness is effectively 0% (within rounding threshold)
if (currentBrightness < 0.005)
return "sun-off";
return currentBrightness <= 0.5 ? "brightness-low" : "brightness-high";
case OSD.Type.LockKey:
return "keyboard";
@@ -488,7 +492,7 @@ Variants {
color: root.currentOSDType === OSD.Type.LockKey ? root.getProgressColor() : Color.mOnSurface
pointSize: root.currentOSDType === OSD.Type.LockKey ? Style.fontSizeM : Style.fontSizeS
family: Settings.data.ui.fontFixed
font.weight: root.currentOSDType === OSD.Type.LockKey ? Style.fontWeightMedium : Style.fontWeightNormal
font.weight: root.currentOSDType === OSD.Type.LockKey ? Style.fontWeightMedium : Style.fontWeightRegular
Layout.fillWidth: true
Layout.alignment: Qt.AlignHCenter
horizontalAlignment: Text.AlignHCenter
+2 -3
View File
@@ -19,8 +19,7 @@ SmartPanel {
readonly property bool isReady: battery && battery.ready && battery.isLaptopBattery && battery.isPresent
readonly property int percent: isReady ? Math.round(battery.percentage * 100) : -1
readonly property bool charging: isReady ? battery.state === UPowerDeviceState.Charging : false
readonly property bool healthSupported: isReady && battery.healthSupported
readonly property bool healthAvailable: healthSupported
readonly property bool healthAvailable: isReady && battery.healthSupported
readonly property int healthPercent: healthAvailable ? Math.round(battery.healthPercentage) : -1
readonly property bool powerProfileAvailable: PowerProfileService.available
readonly property var powerProfiles: [PowerProfile.PowerSaver, PowerProfile.Balanced, PowerProfile.Performance]
@@ -117,7 +116,7 @@ SmartPanel {
ColumnLayout {
NText {
text: I18n.tr("battery.charge-level")
text: I18n.tr("battery.battery-level")
color: Color.mOnSurface
pointSize: Style.fontSizeS
}
@@ -25,9 +25,10 @@ NBox {
anchors.margins: Style.marginM
spacing: Style.marginM
NImageCircled {
NImageRounded {
Layout.preferredWidth: Math.round(Style.baseWidgetSize * 1.25 * Style.uiScaleRatio)
Layout.preferredHeight: Math.round(Style.baseWidgetSize * 1.25 * Style.uiScaleRatio)
radius: width * 0.5
imagePath: Settings.preprocessPath(Settings.data.general.avatarImage)
fallbackIcon: "person"
borderColor: Color.mPrimary
+2 -2
View File
@@ -689,7 +689,7 @@ SmartPanel {
id: imagePreview
anchors.fill: parent
visible: modelData.isImage && !modelData.emojiChar
imageRadius: Style.radiusM
radius: Style.radiusM
// This property creates a dependency on the service's revision counter
readonly property int _rev: ClipboardService.revision
@@ -934,7 +934,7 @@ SmartPanel {
id: gridImagePreview
anchors.fill: parent
visible: modelData.isImage && !modelData.emojiChar
imageRadius: Style.radiusM
radius: Style.radiusM
readonly property int _rev: ClipboardService.revision
@@ -197,10 +197,11 @@ SmartPanel {
spacing: Style.marginM
// Icon
NImageCircled {
NImageRounded {
anchors.verticalCenter: parent.verticalCenter
width: Math.round(40 * Style.uiScaleRatio)
height: Math.round(40 * Style.uiScaleRatio)
anchors.verticalCenter: parent.verticalCenter
radius: width * 0.5
imagePath: model.cachedImage || model.originalImage || ""
borderColor: Color.transparent
borderWidth: 0
@@ -59,10 +59,11 @@ ColumnLayout {
description: I18n.tr("bar.widget-settings.control-center.icon.description")
}
NImageCircled {
NImageRounded {
Layout.preferredWidth: Style.fontSizeXL * 2
Layout.preferredHeight: Style.fontSizeXL * 2
Layout.alignment: Qt.AlignVCenter
radius: width * 0.5
imagePath: valueCustomIconPath
visible: valueCustomIconPath !== ""
}
+3 -2
View File
@@ -189,10 +189,11 @@ ColumnLayout {
Layout.preferredWidth: Style.baseWidgetSize * 2 * Style.uiScaleRatio
Layout.preferredHeight: Style.baseWidgetSize * 2 * Style.uiScaleRatio
NImageCircled {
imagePath: modelData.avatar_url || ""
NImageRounded {
anchors.fill: parent
anchors.margins: Style.marginXS
radius: width * 0.5
imagePath: modelData.avatar_url || ""
fallbackIcon: "person"
borderColor: contributorArea.containsMouse ? Color.mOnHover : Color.mPrimary
borderWidth: Style.borderM
+2 -1
View File
@@ -21,9 +21,10 @@ ColumnLayout {
spacing: Style.marginL
// Avatar preview
NImageCircled {
NImageRounded {
Layout.preferredWidth: 88 * Style.uiScaleRatio
Layout.preferredHeight: width
radius: width * 0.5
imagePath: Settings.preprocessPath(Settings.data.general.avatarImage)
fallbackIcon: "person"
borderColor: Color.mPrimary
@@ -401,7 +401,6 @@ SmartPanel {
Settings.data.general.scaleRatio = selectedScaleRatio;
Settings.data.bar.position = selectedBarPosition;
Settings.data.setupCompleted = true;
// Save settings immediately and wait for settingsSaved signal before closing
Settings.saveImmediate();
+8 -2
View File
@@ -43,8 +43,14 @@ SmartPanel {
function wildCardMatch(str, rule) {
if (!str || !rule)
return false;
let escaped = rule.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
let pattern = '^' + escaped.replace(/\\\*/g, '.*') + '$';
// First, convert '*' to a placeholder to preserve it, then escape other special regex characters
// Use a unique placeholder that won't appear in normal strings
const placeholder = '\uE000'; // Private use character
let processedRule = rule.replace(/\*/g, placeholder);
// Escape all special regex characters (but placeholder won't match this)
let escaped = processedRule.replace(/[.+?^${}()|[\]\\]/g, '\\$&');
// Convert placeholder back to '.*' for wildcard matching
let pattern = '^' + escaped.replace(new RegExp(placeholder, 'g'), '.*') + '$';
try {
return new RegExp(pattern, 'i').test(str);
} catch (e) {