mirror of
https://github.com/zoriya/noctalia-shell.git
synced 2026-06-05 19:45:51 +00:00
Merge branch 'main' into patch-3
This commit is contained in:
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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";
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 + '$';
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 !== ""
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user