1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2026-05-04 03:22:12 -04:00

numerous animation improvements, convert a bunch of stuff to use

Animator, etc.
This commit is contained in:
bbedward
2026-04-30 16:54:33 -04:00
committed by purian23
parent cd40f2f7ed
commit 7ccbfc6870
67 changed files with 1525 additions and 989 deletions

View File

@@ -26,9 +26,7 @@ Rectangle {
spacing: 2 spacing: 2
StyledText { StyledText {
text: keyboardHints.enterToPaste text: keyboardHints.enterToPaste ? I18n.tr("↑/↓: Navigate • Enter: Paste • Del: Delete • F10: Help", "Keyboard hints when enter-to-paste is enabled") : I18n.tr("↑/↓: Navigate • Enter/Ctrl+C: Copy • Del: Delete • F10: Help")
? I18n.tr("↑/↓: Navigate • Enter: Paste • Del: Delete • F10: Help", "Keyboard hints when enter-to-paste is enabled")
: I18n.tr("↑/↓: Navigate • Enter/Ctrl+C: Copy • Del: Delete • F10: Help")
font.pixelSize: Theme.fontSizeSmall font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceText color: Theme.surfaceText
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
@@ -43,7 +41,7 @@ Rectangle {
} }
Behavior on opacity { Behavior on opacity {
NumberAnimation { OpacityAnimator {
duration: Theme.shortDuration duration: Theme.shortDuration
easing.type: Theme.standardEasing easing.type: Theme.standardEasing
} }

View File

@@ -154,6 +154,36 @@ Item {
}); });
} }
property bool _animSyncQueued: false
function _queueAnimSync() {
if (_animSyncQueued)
return;
_animSyncQueued = true;
Qt.callLater(() => {
if (root && typeof root._flushAnimSync === "function")
root._flushAnimSync();
});
}
function _flushAnimSync() {
_animSyncQueued = false;
_syncModalAnim();
}
property bool _bodySyncQueued: false
function _queueBodySync() {
if (_bodySyncQueued)
return;
_bodySyncQueued = true;
Qt.callLater(() => {
if (root && typeof root._flushBodySync === "function")
root._flushBodySync();
});
}
function _flushBodySync() {
_bodySyncQueued = false;
_syncModalBody();
}
function _syncModalAnim() { function _syncModalAnim() {
if (!frameOwnsConnectedChrome || !_chromeClaimId) if (!frameOwnsConnectedChrome || !_chromeClaimId)
return; return;
@@ -185,10 +215,10 @@ Item {
onFrameOwnsConnectedChromeChanged: _syncModalChromeState() onFrameOwnsConnectedChromeChanged: _syncModalChromeState()
onResolvedConnectedBarSideChanged: _queueFullSync() onResolvedConnectedBarSideChanged: _queueFullSync()
onShouldBeVisibleChanged: _queueFullSync() onShouldBeVisibleChanged: _queueFullSync()
onAlignedXChanged: _syncModalBody() onAlignedXChanged: _queueBodySync()
onAlignedYChanged: _syncModalBody() onAlignedYChanged: _queueBodySync()
onAlignedWidthChanged: _syncModalBody() onAlignedWidthChanged: _queueBodySync()
onAlignedHeightChanged: _syncModalBody() onAlignedHeightChanged: _queueBodySync()
Component.onDestruction: _releaseModalChrome() Component.onDestruction: _releaseModalChrome()
@@ -456,8 +486,8 @@ Item {
readonly property real s: Math.min(1, modalContainer.scaleValue) readonly property real s: Math.min(1, modalContainer.scaleValue)
blurX: modalContainer.x + modalContainer.width * (1 - s) * 0.5 + Theme.snap(modalContainer.animX, root.dpr) blurX: modalContainer.x + modalContainer.width * (1 - s) * 0.5 + Theme.snap(modalContainer.animX, root.dpr)
blurY: modalContainer.y + modalContainer.height * (1 - s) * 0.5 + Theme.snap(modalContainer.animY, root.dpr) blurY: modalContainer.y + modalContainer.height * (1 - s) * 0.5 + Theme.snap(modalContainer.animY, root.dpr)
blurWidth: (root.shouldBeVisible && animatedContent.opacity > 0 && !root.frameOwnsConnectedChrome) ? modalContainer.width * s : 0 blurWidth: (root.shouldBeVisible && animatedContent.publishedOpacity > 0 && !root.frameOwnsConnectedChrome) ? modalContainer.width * s : 0
blurHeight: (root.shouldBeVisible && animatedContent.opacity > 0 && !root.frameOwnsConnectedChrome) ? modalContainer.height * s : 0 blurHeight: (root.shouldBeVisible && animatedContent.publishedOpacity > 0 && !root.frameOwnsConnectedChrome) ? modalContainer.height * s : 0
blurRadius: root.effectiveCornerRadius blurRadius: root.effectiveCornerRadius
} }
@@ -666,9 +696,9 @@ Item {
property real animY: root.shouldBeVisible ? 0 : root.frozenMotionOffsetY property real animY: root.shouldBeVisible ? 0 : root.frozenMotionOffsetY
onAnimXChanged: if (root.frameOwnsConnectedChrome) onAnimXChanged: if (root.frameOwnsConnectedChrome)
root._syncModalAnim() root._queueAnimSync()
onAnimYChanged: if (root.frameOwnsConnectedChrome) onAnimYChanged: if (root.frameOwnsConnectedChrome)
root._syncModalAnim() root._queueAnimSync()
readonly property real computedScaleCollapsed: root.animationScaleCollapsed readonly property real computedScaleCollapsed: root.animationScaleCollapsed
property real scaleValue: root.shouldBeVisible ? 1.0 : computedScaleCollapsed property real scaleValue: root.shouldBeVisible ? 1.0 : computedScaleCollapsed
@@ -711,11 +741,23 @@ Item {
id: animatedContent id: animatedContent
anchors.fill: parent anchors.fill: parent
clip: false clip: false
property real publishedOpacity: (Theme.isDirectionalEffect && !Theme.isConnectedEffect) ? 1 : (root.shouldBeVisible ? 1 : 0)
opacity: (Theme.isDirectionalEffect && !Theme.isConnectedEffect) ? 1 : (root.shouldBeVisible ? 1 : 0) opacity: (Theme.isDirectionalEffect && !Theme.isConnectedEffect) ? 1 : (root.shouldBeVisible ? 1 : 0)
scale: modalContainer.scaleValue scale: modalContainer.scaleValue
transformOrigin: Item.Center transformOrigin: Item.Center
Behavior on opacity { Behavior on opacity {
enabled: root.animationsEnabled && (!Theme.isDirectionalEffect || Theme.isConnectedEffect)
OpacityAnimator {
duration: Math.round(Theme.variantDuration(animationDuration, root.shouldBeVisible) * Theme.variantOpacityDurationScale)
easing.type: Easing.BezierSpline
easing.bezierCurve: root.shouldBeVisible ? root.animationEnterCurve : root.animationExitCurve
}
}
Behavior on publishedOpacity {
enabled: root.animationsEnabled && (!Theme.isDirectionalEffect || Theme.isConnectedEffect) enabled: root.animationsEnabled && (!Theme.isDirectionalEffect || Theme.isConnectedEffect)
NumberAnimation { NumberAnimation {
duration: Math.round(Theme.variantDuration(animationDuration, root.shouldBeVisible) * Theme.variantOpacityDurationScale) duration: Math.round(Theme.variantDuration(animationDuration, root.shouldBeVisible) * Theme.variantOpacityDurationScale)

View File

@@ -241,8 +241,8 @@ Item {
readonly property real s: Math.min(1, modalContainer.scaleValue) readonly property real s: Math.min(1, modalContainer.scaleValue)
blurX: modalContainer.x + modalContainer.width * (1 - s) * 0.5 + Theme.snap(modalContainer.animX, root.dpr) blurX: modalContainer.x + modalContainer.width * (1 - s) * 0.5 + Theme.snap(modalContainer.animX, root.dpr)
blurY: modalContainer.y + modalContainer.height * (1 - s) * 0.5 + Theme.snap(modalContainer.animY, root.dpr) blurY: modalContainer.y + modalContainer.height * (1 - s) * 0.5 + Theme.snap(modalContainer.animY, root.dpr)
blurWidth: (shouldBeVisible && animatedContent.opacity > 0) ? modalContainer.width * s : 0 blurWidth: (shouldBeVisible && animatedContent.publishedOpacity > 0) ? modalContainer.width * s : 0
blurHeight: (shouldBeVisible && animatedContent.opacity > 0) ? modalContainer.height * s : 0 blurHeight: (shouldBeVisible && animatedContent.publishedOpacity > 0) ? modalContainer.height * s : 0
blurRadius: root.cornerRadius blurRadius: root.cornerRadius
} }
@@ -318,7 +318,8 @@ Item {
Behavior on opacity { Behavior on opacity {
enabled: root.animationsEnabled enabled: root.animationsEnabled
DankAnim { OpacityAnimator {
easing.type: Easing.BezierSpline
duration: root.animationDuration duration: root.animationDuration
easing.bezierCurve: root.shouldBeVisible ? root.animationEnterCurve : root.animationExitCurve easing.bezierCurve: root.shouldBeVisible ? root.animationEnterCurve : root.animationExitCurve
} }
@@ -398,12 +399,24 @@ Item {
id: animatedContent id: animatedContent
anchors.fill: parent anchors.fill: parent
clip: false clip: false
property real publishedOpacity: root.shouldBeVisible ? 1 : 0
opacity: root.shouldBeVisible ? 1 : 0 opacity: root.shouldBeVisible ? 1 : 0
scale: modalContainer.scaleValue scale: modalContainer.scaleValue
x: Theme.snap(modalContainer.animX, root.dpr) + (parent.width - width) * (1 - modalContainer.scaleValue) * 0.5 x: Theme.snap(modalContainer.animX, root.dpr) + (parent.width - width) * (1 - modalContainer.scaleValue) * 0.5
y: Theme.snap(modalContainer.animY, root.dpr) + (parent.height - height) * (1 - modalContainer.scaleValue) * 0.5 y: Theme.snap(modalContainer.animY, root.dpr) + (parent.height - height) * (1 - modalContainer.scaleValue) * 0.5
Behavior on opacity { Behavior on opacity {
enabled: root.animationsEnabled
OpacityAnimator {
duration: animationDuration
easing.type: Easing.BezierSpline
easing.bezierCurve: root.shouldBeVisible ? root.animationEnterCurve : root.animationExitCurve
}
}
Behavior on publishedOpacity {
enabled: root.animationsEnabled enabled: root.animationsEnabled
NumberAnimation { NumberAnimation {
duration: animationDuration duration: animationDuration

View File

@@ -250,6 +250,36 @@ Item {
}); });
} }
property bool _animSyncQueued: false
function _queueAnimSync() {
if (_animSyncQueued)
return;
_animSyncQueued = true;
Qt.callLater(() => {
if (root && typeof root._flushAnimSync === "function")
root._flushAnimSync();
});
}
function _flushAnimSync() {
_animSyncQueued = false;
_syncModalAnim();
}
property bool _bodySyncQueued: false
function _queueBodySync() {
if (_bodySyncQueued)
return;
_bodySyncQueued = true;
Qt.callLater(() => {
if (root && typeof root._flushBodySync === "function")
root._flushBodySync();
});
}
function _flushBodySync() {
_bodySyncQueued = false;
_syncModalBody();
}
function _syncModalAnim() { function _syncModalAnim() {
if (!frameOwnsConnectedChrome || !_chromeClaimId) if (!frameOwnsConnectedChrome || !_chromeClaimId)
return; return;
@@ -281,10 +311,10 @@ Item {
onFrameOwnsConnectedChromeChanged: _syncModalChromeState() onFrameOwnsConnectedChromeChanged: _syncModalChromeState()
onResolvedConnectedBarSideChanged: _queueFullSync() onResolvedConnectedBarSideChanged: _queueFullSync()
onSpotlightOpenChanged: _queueFullSync() onSpotlightOpenChanged: _queueFullSync()
onAlignedXChanged: _syncModalBody() onAlignedXChanged: _queueBodySync()
onAlignedYChanged: _syncModalBody() onAlignedYChanged: _queueBodySync()
onAlignedWidthChanged: _syncModalBody() onAlignedWidthChanged: _queueBodySync()
onAlignedHeightChanged: _syncModalBody() onAlignedHeightChanged: _queueBodySync()
Component.onDestruction: _releaseModalChrome() Component.onDestruction: _releaseModalChrome()
@@ -571,7 +601,8 @@ Item {
Behavior on opacity { Behavior on opacity {
enabled: root.animationsEnabled && (!Theme.isDirectionalEffect || Theme.isConnectedEffect) enabled: root.animationsEnabled && (!Theme.isDirectionalEffect || Theme.isConnectedEffect)
DankAnim { NumberAnimation {
easing.type: Easing.BezierSpline
duration: Math.round(Theme.variantDuration(root.launcherAnimationDuration, launcherMotionVisible) * Theme.variantOpacityDurationScale) duration: Math.round(Theme.variantDuration(root.launcherAnimationDuration, launcherMotionVisible) * Theme.variantOpacityDurationScale)
easing.bezierCurve: launcherMotionVisible ? root.launcherEnterCurve : root.launcherExitCurve easing.bezierCurve: launcherMotionVisible ? root.launcherEnterCurve : root.launcherExitCurve
} }
@@ -597,8 +628,8 @@ Item {
readonly property real s: Math.min(1, contentContainer.scaleValue) readonly property real s: Math.min(1, contentContainer.scaleValue)
blurX: root._ccX + root.alignedWidth * (1 - s) * 0.5 + Theme.snap(contentContainer.animX, root.dpr) blurX: root._ccX + root.alignedWidth * (1 - s) * 0.5 + Theme.snap(contentContainer.animX, root.dpr)
blurY: root._ccY + root.alignedHeight * (1 - s) * 0.5 + Theme.snap(contentContainer.animY, root.dpr) blurY: root._ccY + root.alignedHeight * (1 - s) * 0.5 + Theme.snap(contentContainer.animY, root.dpr)
blurWidth: (root.spotlightOpen || root.isClosing) && contentWrapper.opacity > 0 && !root.frameOwnsConnectedChrome ? root.alignedWidth * s : 0 blurWidth: (root.spotlightOpen || root.isClosing) && contentWrapper.publishedOpacity > 0 && !root.frameOwnsConnectedChrome ? root.alignedWidth * s : 0
blurHeight: (root.spotlightOpen || root.isClosing) && contentWrapper.opacity > 0 && !root.frameOwnsConnectedChrome ? root.alignedHeight * s : 0 blurHeight: (root.spotlightOpen || root.isClosing) && contentWrapper.publishedOpacity > 0 && !root.frameOwnsConnectedChrome ? root.alignedHeight * s : 0
blurRadius: root.cornerRadius blurRadius: root.cornerRadius
} }
@@ -716,9 +747,9 @@ Item {
property real scaleValue: root._motionActive ? 1.0 : Theme.effectScaleCollapsed property real scaleValue: root._motionActive ? 1.0 : Theme.effectScaleCollapsed
onAnimXChanged: if (root.frameOwnsConnectedChrome) onAnimXChanged: if (root.frameOwnsConnectedChrome)
root._syncModalAnim() root._queueAnimSync()
onAnimYChanged: if (root.frameOwnsConnectedChrome) onAnimYChanged: if (root.frameOwnsConnectedChrome)
root._syncModalAnim() root._queueAnimSync()
Behavior on animX { Behavior on animX {
enabled: root.animationsEnabled enabled: root.animationsEnabled
@@ -769,7 +800,7 @@ Item {
id: launcherShadowLayer id: launcherShadowLayer
width: parent.width width: parent.width
height: parent.height height: parent.height
opacity: contentWrapper.opacity opacity: contentWrapper.publishedOpacity
scale: contentWrapper.scale scale: contentWrapper.scale
x: contentWrapper.x x: contentWrapper.x
y: contentWrapper.y y: contentWrapper.y
@@ -787,20 +818,44 @@ Item {
id: contentWrapper id: contentWrapper
width: parent.width width: parent.width
height: parent.height height: parent.height
property bool _renderActive: (Theme.isDirectionalEffect && !Theme.isConnectedEffect) || launcherMotionVisible
property real publishedOpacity: (Theme.isDirectionalEffect && !Theme.isConnectedEffect) ? 1 : (launcherMotionVisible ? 1 : 0)
opacity: (Theme.isDirectionalEffect && !Theme.isConnectedEffect) ? 1 : (launcherMotionVisible ? 1 : 0) opacity: (Theme.isDirectionalEffect && !Theme.isConnectedEffect) ? 1 : (launcherMotionVisible ? 1 : 0)
visible: opacity > 0 visible: _renderActive
scale: contentContainer.scaleValue scale: contentContainer.scaleValue
x: Theme.snap(contentContainer.animX + (parent.width - width) * (1 - contentContainer.scaleValue) * 0.5, root.dpr) x: Theme.snap(contentContainer.animX + (parent.width - width) * (1 - contentContainer.scaleValue) * 0.5, root.dpr)
y: Theme.snap(contentContainer.animY + (parent.height - height) * (1 - contentContainer.scaleValue) * 0.5, root.dpr) y: Theme.snap(contentContainer.animY + (parent.height - height) * (1 - contentContainer.scaleValue) * 0.5, root.dpr)
Behavior on opacity { Behavior on opacity {
enabled: root.animationsEnabled && (!Theme.isDirectionalEffect || Theme.isConnectedEffect) enabled: root.animationsEnabled && (!Theme.isDirectionalEffect || Theme.isConnectedEffect)
DankAnim { OpacityAnimator {
easing.type: Easing.BezierSpline
duration: Math.round(Theme.variantDuration(root.launcherAnimationDuration, launcherMotionVisible) * Theme.variantOpacityDurationScale) duration: Math.round(Theme.variantDuration(root.launcherAnimationDuration, launcherMotionVisible) * Theme.variantOpacityDurationScale)
easing.bezierCurve: launcherMotionVisible ? root.launcherEnterCurve : root.launcherExitCurve easing.bezierCurve: launcherMotionVisible ? root.launcherEnterCurve : root.launcherExitCurve
} }
} }
Behavior on publishedOpacity {
enabled: root.animationsEnabled && (!Theme.isDirectionalEffect || Theme.isConnectedEffect)
NumberAnimation {
easing.type: Easing.BezierSpline
duration: Math.round(Theme.variantDuration(root.launcherAnimationDuration, launcherMotionVisible) * Theme.variantOpacityDurationScale)
easing.bezierCurve: launcherMotionVisible ? root.launcherEnterCurve : root.launcherExitCurve
onRunningChanged: if (!running && contentWrapper.publishedOpacity === 0)
contentWrapper._renderActive = false
}
}
Connections {
target: root
function onLauncherMotionVisibleChanged() {
if (root.launcherMotionVisible)
contentWrapper._renderActive = true;
}
}
MouseArea { MouseArea {
anchors.fill: parent anchors.fill: parent
onPressed: mouse => mouse.accepted = true onPressed: mouse => mouse.accepted = true

View File

@@ -350,11 +350,11 @@ Item {
WindowBlur { WindowBlur {
targetWindow: launcherWindow targetWindow: launcherWindow
readonly property real s: Math.min(1, modalContainer.scale) readonly property real s: Math.min(1, modalContainer.publishedScale)
blurX: modalContainer.x + modalContainer.width * (1 - s) * 0.5 blurX: modalContainer.x + modalContainer.width * (1 - s) * 0.5
blurY: modalContainer.y + modalContainer.height * (1 - s) * 0.5 blurY: modalContainer.y + modalContainer.height * (1 - s) * 0.5
blurWidth: (contentVisible && modalContainer.opacity > 0) ? modalContainer.width * s : 0 blurWidth: (contentVisible && modalContainer.publishedOpacity > 0) ? modalContainer.width * s : 0
blurHeight: (contentVisible && modalContainer.opacity > 0) ? modalContainer.height * s : 0 blurHeight: (contentVisible && modalContainer.publishedOpacity > 0) ? modalContainer.height * s : 0
blurRadius: root.cornerRadius blurRadius: root.cornerRadius
} }
@@ -411,23 +411,55 @@ Item {
y: root.contentY y: root.contentY
width: root.alignedWidth width: root.alignedWidth
height: root.alignedHeight height: root.alignedHeight
visible: contentVisible || opacity > 0 visible: _renderActive
property bool _renderActive: contentVisible
property real publishedOpacity: contentVisible ? 1 : 0
property real publishedScale: contentVisible ? 1 : 0.96
opacity: contentVisible ? 1 : 0 opacity: contentVisible ? 1 : 0
scale: contentVisible ? 1 : 0.96 scale: contentVisible ? 1 : 0.96
transformOrigin: Item.Center transformOrigin: Item.Center
Behavior on opacity { Behavior on opacity {
DankAnim { OpacityAnimator {
easing.type: Easing.BezierSpline
duration: Theme.modalAnimationDuration duration: Theme.modalAnimationDuration
easing.bezierCurve: contentVisible ? Theme.expressiveCurves.expressiveDefaultSpatial : Theme.expressiveCurves.emphasized easing.bezierCurve: contentVisible ? Theme.expressiveCurves.expressiveDefaultSpatial : Theme.expressiveCurves.emphasized
} }
} }
Behavior on scale { Behavior on publishedOpacity {
DankAnim { NumberAnimation {
easing.type: Easing.BezierSpline
duration: Theme.modalAnimationDuration duration: Theme.modalAnimationDuration
easing.bezierCurve: contentVisible ? Theme.expressiveCurves.expressiveDefaultSpatial : Theme.expressiveCurves.emphasized easing.bezierCurve: contentVisible ? Theme.expressiveCurves.expressiveDefaultSpatial : Theme.expressiveCurves.emphasized
onRunningChanged: if (!running && modalContainer.publishedOpacity === 0)
modalContainer._renderActive = false
}
}
Behavior on scale {
ScaleAnimator {
easing.type: Easing.BezierSpline
duration: Theme.modalAnimationDuration
easing.bezierCurve: contentVisible ? Theme.expressiveCurves.expressiveDefaultSpatial : Theme.expressiveCurves.emphasized
}
}
Behavior on publishedScale {
NumberAnimation {
easing.type: Easing.BezierSpline
duration: Theme.modalAnimationDuration
easing.bezierCurve: contentVisible ? Theme.expressiveCurves.expressiveDefaultSpatial : Theme.expressiveCurves.emphasized
}
}
Connections {
target: root
function onContentVisibleChanged() {
if (root.contentVisible)
modalContainer._renderActive = true;
} }
} }

View File

@@ -1,5 +1,4 @@
import QtQuick import QtQuick
import QtCore
import Quickshell.Io import Quickshell.Io
import qs.Common import qs.Common
import qs.Widgets import qs.Widgets
@@ -22,9 +21,9 @@ Rectangle {
onShowFileInfoChanged: { onShowFileInfoChanged: {
if (showFileInfo && currentFileName && currentPath) { if (showFileInfo && currentFileName && currentPath) {
const fullPath = currentPath + "/" + currentFileName const fullPath = currentPath + "/" + currentFileName;
fileStatProcess.selectedFilePath = fullPath fileStatProcess.selectedFilePath = fullPath;
fileStatProcess.running = true fileStatProcess.running = true;
} }
} }
@@ -38,14 +37,14 @@ Rectangle {
stdout: StdioCollector { stdout: StdioCollector {
onStreamFinished: { onStreamFinished: {
if (text && text.trim()) { if (text && text.trim()) {
const parts = text.trim().split('|') const parts = text.trim().split('|');
if (parts.length >= 4) { if (parts.length >= 4) {
fileStatProcess.fileStats = { fileStatProcess.fileStats = {
"modifiedTime": parts[0], "modifiedTime": parts[0],
"permissions": parts[1], "permissions": parts[1],
"size": parseInt(parts[2]) || 0, "size": parseInt(parts[2]) || 0,
"fullPath": parts[3] "fullPath": parts[3]
} };
} }
} }
} }
@@ -60,31 +59,31 @@ Rectangle {
onCurrentFileNameChanged: { onCurrentFileNameChanged: {
if (showFileInfo && currentFileName && currentPath) { if (showFileInfo && currentFileName && currentPath) {
const fullPath = currentPath + "/" + currentFileName const fullPath = currentPath + "/" + currentFileName;
if (fullPath !== fileStatProcess.selectedFilePath) { if (fullPath !== fileStatProcess.selectedFilePath) {
fileStatProcess.selectedFilePath = fullPath fileStatProcess.selectedFilePath = fullPath;
fileStatProcess.running = true fileStatProcess.running = true;
} }
} }
} }
function updateFileInfo(filePath, fileName, isDirectory) { function updateFileInfo(filePath, fileName, isDirectory) {
if (filePath && filePath !== fileStatProcess.selectedFilePath) { if (filePath && filePath !== fileStatProcess.selectedFilePath) {
fileStatProcess.selectedFilePath = filePath fileStatProcess.selectedFilePath = filePath;
currentFileName = fileName || "" currentFileName = fileName || "";
currentFileIsDir = isDirectory || false currentFileIsDir = isDirectory || false;
let ext = "" let ext = "";
if (!isDirectory && fileName) { if (!isDirectory && fileName) {
const lastDot = fileName.lastIndexOf('.') const lastDot = fileName.lastIndexOf('.');
if (lastDot > 0) { if (lastDot > 0) {
ext = fileName.substring(lastDot + 1).toLowerCase() ext = fileName.substring(lastDot + 1).toLowerCase();
} }
} }
currentFileExtension = ext currentFileExtension = ext;
if (showFileInfo) { if (showFileInfo) {
fileStatProcess.running = true fileStatProcess.running = true;
} }
} }
} }
@@ -100,10 +99,10 @@ Rectangle {
"permissions": "", "permissions": "",
"extension": "", "extension": "",
"position": "N/A" "position": "N/A"
} };
} }
const hasValidFile = currentFileName !== "" const hasValidFile = currentFileName !== "";
return { return {
"exists": hasValidFile, "exists": hasValidFile,
"name": hasValidFile ? currentFileName : "Loading...", "name": hasValidFile ? currentFileName : "Loading...",
@@ -113,7 +112,7 @@ Rectangle {
"permissions": fileStatProcess.fileStats ? fileStatProcess.fileStats.permissions : "Loading...", "permissions": fileStatProcess.fileStats ? fileStatProcess.fileStats.permissions : "Loading...",
"extension": currentFileExtension, "extension": currentFileExtension,
"position": sourceFolderModel ? ((selectedIndex + 1) + " of " + sourceFolderModel.count) : "N/A" "position": sourceFolderModel ? ((selectedIndex + 1) + " of " + sourceFolderModel.count) : "N/A"
} };
} }
Column { Column {
@@ -209,27 +208,27 @@ Rectangle {
function formatFileSize(bytes) { function formatFileSize(bytes) {
if (bytes === 0 || !bytes) { if (bytes === 0 || !bytes) {
return "0 B" return "0 B";
} }
const k = 1024 const k = 1024;
const sizes = ['B', 'KB', 'MB', 'GB', 'TB'] const sizes = ['B', 'KB', 'MB', 'GB', 'TB'];
const i = Math.floor(Math.log(bytes) / Math.log(k)) const i = Math.floor(Math.log(bytes) / Math.log(k));
return parseFloat((bytes / Math.pow(k, i)).toFixed(1)) + ' ' + sizes[i] return parseFloat((bytes / Math.pow(k, i)).toFixed(1)) + ' ' + sizes[i];
} }
function formatDateTime(dateTimeString) { function formatDateTime(dateTimeString) {
if (!dateTimeString) { if (!dateTimeString) {
return "Unknown" return "Unknown";
} }
const parts = dateTimeString.split(' ') const parts = dateTimeString.split(' ');
if (parts.length >= 2) { if (parts.length >= 2) {
return parts[0] + " " + parts[1].split('.')[0] return parts[0] + " " + parts[1].split('.')[0];
} }
return dateTimeString return dateTimeString;
} }
Behavior on opacity { Behavior on opacity {
NumberAnimation { OpacityAnimator {
duration: Theme.shortDuration duration: Theme.shortDuration
easing.type: Theme.standardEasing easing.type: Theme.standardEasing
} }

View File

@@ -42,7 +42,7 @@ Rectangle {
} }
Behavior on opacity { Behavior on opacity {
NumberAnimation { OpacityAnimator {
duration: Theme.shortDuration duration: Theme.shortDuration
easing.type: Theme.standardEasing easing.type: Theme.standardEasing
} }

View File

@@ -180,7 +180,7 @@ Item {
opacity: (root.hasRun && !root.isRunning) ? 1 : 0 opacity: (root.hasRun && !root.isRunning) ? 1 : 0
Behavior on opacity { Behavior on opacity {
NumberAnimation { OpacityAnimator {
duration: Theme.mediumDuration duration: Theme.mediumDuration
easing.type: Theme.emphasizedEasing easing.type: Theme.emphasizedEasing
} }

View File

@@ -22,7 +22,7 @@ Rectangle {
scale: mouseArea.pressed ? 0.97 : 1 scale: mouseArea.pressed ? 0.97 : 1
Behavior on scale { Behavior on scale {
NumberAnimation { ScaleAnimator {
duration: Theme.shortDuration duration: Theme.shortDuration
easing.type: Theme.emphasizedEasing easing.type: Theme.emphasizedEasing
} }

View File

@@ -772,7 +772,7 @@ DankModal {
opacity: root.showHoldHint ? 1 : 0.5 opacity: root.showHoldHint ? 1 : 0.5
Behavior on opacity { Behavior on opacity {
NumberAnimation { OpacityAnimator {
duration: 150 duration: 150
} }
} }

View File

@@ -214,13 +214,13 @@ Item {
color: root.accentColor color: root.accentColor
Behavior on x { Behavior on x {
NumberAnimation { XAnimator {
duration: Theme.shortDuration duration: Theme.shortDuration
easing.type: Theme.standardEasing easing.type: Theme.standardEasing
} }
} }
Behavior on y { Behavior on y {
NumberAnimation { YAnimator {
duration: Theme.shortDuration duration: Theme.shortDuration
easing.type: Theme.standardEasing easing.type: Theme.standardEasing
} }
@@ -278,13 +278,13 @@ Item {
color: root.accentColor color: root.accentColor
Behavior on x { Behavior on x {
NumberAnimation { XAnimator {
duration: Theme.mediumDuration duration: Theme.mediumDuration
easing.type: Theme.emphasizedEasing easing.type: Theme.emphasizedEasing
} }
} }
Behavior on y { Behavior on y {
NumberAnimation { YAnimator {
duration: Theme.mediumDuration duration: Theme.mediumDuration
easing.type: Theme.emphasizedEasing easing.type: Theme.emphasizedEasing
} }

View File

@@ -47,7 +47,7 @@ Rectangle {
opacity: mouseArea.containsMouse ? 0.08 : 0.0 opacity: mouseArea.containsMouse ? 0.08 : 0.0
Behavior on opacity { Behavior on opacity {
NumberAnimation { OpacityAnimator {
duration: Theme.shortDuration duration: Theme.shortDuration
} }
} }

View File

@@ -23,11 +23,15 @@ Item {
signal toggleWidgetSize(int index) signal toggleWidgetSize(int index)
width: { width: {
const widgetWidth = widgetData?.width || 50 const widgetWidth = widgetData?.width || 50;
if (widgetWidth <= 25) return gridCellWidth if (widgetWidth <= 25)
else if (widgetWidth <= 50) return gridCellWidth * 2 return gridCellWidth;
else if (widgetWidth <= 75) return gridCellWidth * 3 else if (widgetWidth <= 50)
else return gridCellWidth * 4 return gridCellWidth * 2;
else if (widgetWidth <= 75)
return gridCellWidth * 3;
else
return gridCellWidth * 4;
} }
height: isSlider ? 16 : gridCellHeight height: isSlider ? 16 : gridCellHeight
@@ -42,10 +46,14 @@ Item {
z: dragArea.drag.active ? 10000 : 1 z: dragArea.drag.active ? 10000 : 1
Behavior on border.width { Behavior on border.width {
NumberAnimation { duration: 150 } NumberAnimation {
duration: 150
}
} }
Behavior on opacity { Behavior on opacity {
NumberAnimation { duration: 150 } OpacityAnimator {
duration: 150
}
} }
} }
@@ -58,14 +66,17 @@ Item {
property int globalWidgetIndex: root.widgetIndex property int globalWidgetIndex: root.widgetIndex
property int widgetWidth: root.widgetData?.width || 50 property int widgetWidth: root.widgetData?.width || 50
MouseArea { MouseArea {
id: editModeBlocker id: editModeBlocker
anchors.fill: parent anchors.fill: parent
enabled: root.editMode enabled: root.editMode
acceptedButtons: Qt.AllButtons acceptedButtons: Qt.AllButtons
onPressed: function(mouse) { mouse.accepted = true } onPressed: function (mouse) {
onWheel: function(wheel) { wheel.accepted = true } mouse.accepted = true;
}
onWheel: function (wheel) {
wheel.accepted = true;
}
z: 100 z: 100
} }
} }
@@ -79,19 +90,19 @@ Item {
drag.axis: Drag.XAndYAxis drag.axis: Drag.XAndYAxis
drag.smoothed: true drag.smoothed: true
onPressed: function(mouse) { onPressed: function (mouse) {
if (editMode) { if (editMode) {
cursorShape = Qt.ClosedHandCursor cursorShape = Qt.ClosedHandCursor;
if (root.gridLayout && root.gridLayout.moveToTop) { if (root.gridLayout && root.gridLayout.moveToTop) {
root.gridLayout.moveToTop(root) root.gridLayout.moveToTop(root);
} }
} }
} }
onReleased: function(mouse) { onReleased: function (mouse) {
if (editMode) { if (editMode) {
cursorShape = Qt.OpenHandCursor cursorShape = Qt.OpenHandCursor;
root.snapToGrid() root.snapToGrid();
} }
} }
} }
@@ -101,9 +112,11 @@ Item {
Drag.hotSpot.y: height / 2 Drag.hotSpot.y: height / 2
function swapIndices(i, j) { function swapIndices(i, j) {
if (i === j) return; if (i === j)
return;
const arr = SettingsData.controlCenterWidgets; const arr = SettingsData.controlCenterWidgets;
if (!arr || i < 0 || j < 0 || i >= arr.length || j >= arr.length) return; if (!arr || i < 0 || j < 0 || i >= arr.length || j >= arr.length)
return;
const copy = arr.slice(); const copy = arr.slice();
const tmp = copy[i]; const tmp = copy[i];
@@ -114,37 +127,41 @@ Item {
} }
function snapToGrid() { function snapToGrid() {
if (!editMode || !gridLayout) return if (!editMode || !gridLayout)
return;
const globalPos = root.mapToItem(gridLayout, 0, 0);
const cellWidth = gridLayout.width / gridColumns;
const cellHeight = gridCellHeight + Theme.spacingS;
const globalPos = root.mapToItem(gridLayout, 0, 0) const centerX = globalPos.x + (root.width / 2);
const cellWidth = gridLayout.width / gridColumns const centerY = globalPos.y + (root.height / 2);
const cellHeight = gridCellHeight + Theme.spacingS
const centerX = globalPos.x + (root.width / 2) let targetCol = Math.max(0, Math.floor(centerX / cellWidth));
const centerY = globalPos.y + (root.height / 2) let targetRow = Math.max(0, Math.floor(centerY / cellHeight));
let targetCol = Math.max(0, Math.floor(centerX / cellWidth)) targetCol = Math.min(targetCol, gridColumns - 1);
let targetRow = Math.max(0, Math.floor(centerY / cellHeight))
targetCol = Math.min(targetCol, gridColumns - 1) const newIndex = findBestInsertionIndex(targetRow, targetCol);
const newIndex = findBestInsertionIndex(targetRow, targetCol)
if (newIndex !== widgetIndex && newIndex >= 0 && newIndex < (SettingsData.controlCenterWidgets?.length || 0)) { if (newIndex !== widgetIndex && newIndex >= 0 && newIndex < (SettingsData.controlCenterWidgets?.length || 0)) {
swapIndices(widgetIndex, newIndex) swapIndices(widgetIndex, newIndex);
} }
} }
function findBestInsertionIndex(targetRow, targetCol) { function findBestInsertionIndex(targetRow, targetCol) {
const widgets = SettingsData.controlCenterWidgets || []; const widgets = SettingsData.controlCenterWidgets || [];
const n = widgets.length; const n = widgets.length;
if (!n || widgetIndex < 0 || widgetIndex >= n) return -1; if (!n || widgetIndex < 0 || widgetIndex >= n)
return -1;
function spanFor(width) { function spanFor(width) {
const w = width ?? 50; const w = width ?? 50;
if (w <= 25) return 1; if (w <= 25)
if (w <= 50) return 2; return 1;
if (w <= 75) return 3; if (w <= 50)
return 2;
if (w <= 75)
return 3;
return 4; return 4;
} }
@@ -169,7 +186,13 @@ Item {
if (i === widgetIndex) { if (i === widgetIndex) {
draggedOrigKey = centerKey; draggedOrigKey = centerKey;
} else { } else {
pos.push({ index: i, row, startCol, span, centerKey }); pos.push({
index: i,
row,
startCol,
span,
centerKey
});
} }
col += span; col += span;
@@ -179,7 +202,8 @@ Item {
} }
} }
if (pos.length === 0) return -1; if (pos.length === 0)
return -1;
const centerColCoord = targetCol + 0.5; const centerColCoord = targetCol + 0.5;
const targetKey = targetRow * cols + centerColCoord; const targetKey = targetRow * cols + centerColCoord;
@@ -192,15 +216,20 @@ Item {
} }
let lo = 0, hi = pos.length - 1; let lo = 0, hi = pos.length - 1;
if (targetKey <= pos[0].centerKey) return pos[0].index; if (targetKey <= pos[0].centerKey)
if (targetKey >= pos[hi].centerKey) return pos[hi].index; return pos[0].index;
if (targetKey >= pos[hi].centerKey)
return pos[hi].index;
while (lo <= hi) { while (lo <= hi) {
const mid = (lo + hi) >> 1; const mid = (lo + hi) >> 1;
const mk = pos[mid].centerKey; const mk = pos[mid].centerKey;
if (targetKey < mk) hi = mid - 1; if (targetKey < mk)
else if (targetKey > mk) lo = mid + 1; hi = mid - 1;
else return pos[mid].index; else if (targetKey > mk)
lo = mid + 1;
else
return pos[mid].index;
} }
const movingUp = (draggedOrigKey != null) ? (targetKey < draggedOrigKey) : false; const movingUp = (draggedOrigKey != null) ? (targetKey < draggedOrigKey) : false;
return (movingUp ? pos[lo].index : pos[hi].index); return (movingUp ? pos[lo].index : pos[hi].index);
@@ -240,11 +269,11 @@ Item {
currentSize: root.widgetData?.width || 50 currentSize: root.widgetData?.width || 50
isSlider: root.isSlider isSlider: root.isSlider
widgetIndex: root.widgetIndex widgetIndex: root.widgetIndex
onSizeChanged: (newSize) => { onSizeChanged: newSize => {
var widgets = SettingsData.controlCenterWidgets.slice() var widgets = SettingsData.controlCenterWidgets.slice();
if (widgetIndex >= 0 && widgetIndex < widgets.length) { if (widgetIndex >= 0 && widgetIndex < widgets.length) {
widgets[widgetIndex].width = newSize widgets[widgetIndex].width = newSize;
SettingsData.set("controlCenterWidgets", widgets) SettingsData.set("controlCenterWidgets", widgets);
} }
} }
} }
@@ -270,7 +299,9 @@ Item {
} }
Behavior on opacity { Behavior on opacity {
NumberAnimation { duration: 150 } OpacityAnimator {
duration: 150
}
} }
} }
@@ -283,7 +314,9 @@ Item {
z: -1 z: -1
Behavior on color { Behavior on color {
ColorAnimation { duration: Theme.shortDuration } ColorAnimation {
duration: Theme.shortDuration
}
} }
} }
} }

View File

@@ -195,7 +195,7 @@ DankPopout {
Behavior on opacity { Behavior on opacity {
enabled: !Theme.isDirectionalEffect enabled: !Theme.isDirectionalEffect
NumberAnimation { OpacityAnimator {
duration: Theme.shortDuration duration: Theme.shortDuration
easing.type: Easing.BezierSpline easing.type: Easing.BezierSpline
easing.bezierCurve: root.shouldBeVisible ? Theme.variantPopoutEnterCurve : Theme.variantPopoutExitCurve easing.bezierCurve: root.shouldBeVisible ? Theme.variantPopoutEnterCurve : Theme.variantPopoutExitCurve

View File

@@ -127,7 +127,7 @@ Item {
opacity: modalVisible ? 1 : 0 opacity: modalVisible ? 1 : 0
Behavior on opacity { Behavior on opacity {
NumberAnimation { OpacityAnimator {
duration: Theme.mediumDuration duration: Theme.mediumDuration
easing.type: Theme.emphasizedEasing easing.type: Theme.emphasizedEasing
} }
@@ -316,14 +316,14 @@ Item {
} }
Behavior on opacity { Behavior on opacity {
NumberAnimation { OpacityAnimator {
duration: Theme.mediumDuration duration: Theme.mediumDuration
easing.type: Theme.emphasizedEasing easing.type: Theme.emphasizedEasing
} }
} }
Behavior on scale { Behavior on scale {
NumberAnimation { ScaleAnimator {
duration: Theme.mediumDuration duration: Theme.mediumDuration
easing.type: Theme.emphasizedEasing easing.type: Theme.emphasizedEasing
} }

View File

@@ -64,7 +64,7 @@ Rectangle {
opacity: 0.08 opacity: 0.08
antialiasing: true antialiasing: true
Behavior on opacity { Behavior on opacity {
NumberAnimation { OpacityAnimator {
duration: Theme.shortDuration duration: Theme.shortDuration
} }
} }

View File

@@ -53,7 +53,7 @@ Rectangle {
opacity: mouseArea.containsMouse ? 0.08 : 0.0 opacity: mouseArea.containsMouse ? 0.08 : 0.0
Behavior on opacity { Behavior on opacity {
NumberAnimation { OpacityAnimator {
duration: Theme.shortDuration duration: Theme.shortDuration
} }
} }

View File

@@ -474,14 +474,14 @@ BasePill {
height: (isInOverflow && !root.overflowExpanded) ? 0 : visualHeight height: (isInOverflow && !root.overflowExpanded) ? 0 : visualHeight
Behavior on opacity { Behavior on opacity {
NumberAnimation { OpacityAnimator {
duration: Theme.shortDuration duration: Theme.shortDuration
easing.type: Easing.OutCubic easing.type: Easing.OutCubic
} }
} }
Behavior on scale { Behavior on scale {
NumberAnimation { ScaleAnimator {
duration: Theme.shortDuration duration: Theme.shortDuration
easing.type: Easing.OutCubic easing.type: Easing.OutCubic
} }
@@ -666,7 +666,7 @@ BasePill {
transformOrigin: Item.Center transformOrigin: Item.Center
scale: appItem.enlargeScale scale: appItem.enlargeScale
Behavior on scale { Behavior on scale {
NumberAnimation { ScaleAnimator {
duration: 120 duration: 120
easing.type: Easing.OutCubic easing.type: Easing.OutCubic
} }
@@ -711,7 +711,7 @@ BasePill {
transformOrigin: Item.Center transformOrigin: Item.Center
scale: appItem.enlargeScale scale: appItem.enlargeScale
Behavior on scale { Behavior on scale {
NumberAnimation { ScaleAnimator {
duration: 120 duration: 120
easing.type: Easing.OutCubic easing.type: Easing.OutCubic
} }
@@ -734,7 +734,7 @@ BasePill {
transformOrigin: Item.Center transformOrigin: Item.Center
scale: appItem.enlargeScale scale: appItem.enlargeScale
Behavior on scale { Behavior on scale {
NumberAnimation { ScaleAnimator {
duration: 120 duration: 120
easing.type: Easing.OutCubic easing.type: Easing.OutCubic
} }
@@ -758,7 +758,7 @@ BasePill {
transformOrigin: Item.Center transformOrigin: Item.Center
scale: appItem.enlargeScale scale: appItem.enlargeScale
Behavior on scale { Behavior on scale {
NumberAnimation { ScaleAnimator {
duration: 120 duration: 120
easing.type: Easing.OutCubic easing.type: Easing.OutCubic
} }

View File

@@ -36,7 +36,7 @@ Item {
rotation: isVertical ? (overflowExpanded ? 180 : 0) : (overflowExpanded ? 90 : -90) rotation: isVertical ? (overflowExpanded ? 180 : 0) : (overflowExpanded ? 90 : -90)
Behavior on rotation { Behavior on rotation {
NumberAnimation { RotationAnimator {
duration: Theme.shortDuration duration: Theme.shortDuration
easing.type: Easing.OutCubic easing.type: Easing.OutCubic
} }

View File

@@ -39,7 +39,7 @@ BasePill {
] ]
Behavior on opacity { Behavior on opacity {
NumberAnimation { OpacityAnimator {
duration: Theme.shortDuration duration: Theme.shortDuration
easing.type: Theme.standardEasing easing.type: Theme.standardEasing
} }

View File

@@ -173,7 +173,7 @@ BasePill {
opacity: root.playerAvailable ? 1 : 0 opacity: root.playerAvailable ? 1 : 0
Behavior on opacity { Behavior on opacity {
NumberAnimation { OpacityAnimator {
duration: Theme.shortDuration duration: Theme.shortDuration
easing.type: Theme.standardEasing easing.type: Theme.standardEasing
} }

View File

@@ -50,7 +50,7 @@ BasePill {
] ]
Behavior on opacity { Behavior on opacity {
NumberAnimation { OpacityAnimator {
duration: Theme.shortDuration duration: Theme.shortDuration
easing.type: Theme.standardEasing easing.type: Theme.standardEasing
} }
@@ -238,7 +238,7 @@ BasePill {
Behavior on opacity { Behavior on opacity {
enabled: hasActivePrivacy && root.visible enabled: hasActivePrivacy && root.visible
NumberAnimation { OpacityAnimator {
duration: Theme.shortDuration duration: Theme.shortDuration
easing.type: Theme.standardEasing easing.type: Theme.standardEasing
} }

View File

@@ -271,7 +271,7 @@ BasePill {
] ]
Behavior on opacity { Behavior on opacity {
NumberAnimation { OpacityAnimator {
duration: Theme.shortDuration duration: Theme.shortDuration
easing.type: Theme.standardEasing easing.type: Theme.standardEasing
} }
@@ -625,7 +625,7 @@ BasePill {
opacity: root.inlineExpanded ? 1 : 0 opacity: root.inlineExpanded ? 1 : 0
Behavior on opacity { Behavior on opacity {
NumberAnimation { OpacityAnimator {
duration: Theme.shortDuration duration: Theme.shortDuration
easing.type: Theme.standardEasing easing.type: Theme.standardEasing
} }
@@ -1214,14 +1214,14 @@ BasePill {
scale: root.menuOpen ? 1 : 0.85 scale: root.menuOpen ? 1 : 0.85
Behavior on opacity { Behavior on opacity {
NumberAnimation { OpacityAnimator {
duration: Theme.mediumDuration duration: Theme.mediumDuration
easing.type: Theme.emphasizedEasing easing.type: Theme.emphasizedEasing
} }
} }
Behavior on scale { Behavior on scale {
NumberAnimation { ScaleAnimator {
duration: Theme.mediumDuration duration: Theme.mediumDuration
easing.type: Theme.emphasizedEasing easing.type: Theme.emphasizedEasing
} }
@@ -1666,14 +1666,14 @@ BasePill {
scale: menuRoot.showMenu ? 1 : 0.85 scale: menuRoot.showMenu ? 1 : 0.85
Behavior on opacity { Behavior on opacity {
NumberAnimation { OpacityAnimator {
duration: Theme.mediumDuration duration: Theme.mediumDuration
easing.type: Theme.emphasizedEasing easing.type: Theme.emphasizedEasing
} }
} }
Behavior on scale { Behavior on scale {
NumberAnimation { ScaleAnimator {
duration: Theme.mediumDuration duration: Theme.mediumDuration
easing.type: Theme.emphasizedEasing easing.type: Theme.emphasizedEasing
} }

View File

@@ -36,7 +36,7 @@ BasePill {
} }
Behavior on opacity { Behavior on opacity {
NumberAnimation { OpacityAnimator {
duration: Theme.shortDuration duration: Theme.shortDuration
easing.type: Theme.standardEasing easing.type: Theme.standardEasing
} }

View File

@@ -47,7 +47,7 @@ BasePill {
anchors.centerIn: parent anchors.centerIn: parent
Behavior on opacity { Behavior on opacity {
NumberAnimation { OpacityAnimator {
duration: Theme.shortDuration duration: Theme.shortDuration
easing.type: Easing.InOutQuad easing.type: Easing.InOutQuad
} }

View File

@@ -1471,7 +1471,7 @@ Item {
} }
Behavior on opacity { Behavior on opacity {
NumberAnimation { OpacityAnimator {
duration: Theme.shortDuration duration: Theme.shortDuration
easing.type: Theme.emphasizedEasing easing.type: Theme.emphasizedEasing
} }

View File

@@ -97,7 +97,8 @@ Item {
Behavior on opacity { Behavior on opacity {
enabled: !Theme.isDirectionalEffect enabled: !Theme.isDirectionalEffect
DankAnim { NumberAnimation {
easing.type: Easing.BezierSpline
duration: Math.round(Theme.variantDuration(Theme.expressiveDurations.expressiveDefaultSpatial, dropdownType === 1) * Theme.variantOpacityDurationScale) duration: Math.round(Theme.variantDuration(Theme.expressiveDurations.expressiveDefaultSpatial, dropdownType === 1) * Theme.variantOpacityDurationScale)
easing.bezierCurve: dropdownType === 1 ? Theme.variantPopoutEnterCurve : Theme.variantPopoutExitCurve easing.bezierCurve: dropdownType === 1 ? Theme.variantPopoutEnterCurve : Theme.variantPopoutExitCurve
} }
@@ -238,7 +239,8 @@ Item {
Behavior on opacity { Behavior on opacity {
enabled: !Theme.isDirectionalEffect enabled: !Theme.isDirectionalEffect
DankAnim { NumberAnimation {
easing.type: Easing.BezierSpline
duration: Math.round(Theme.variantDuration(Theme.expressiveDurations.expressiveDefaultSpatial, dropdownType === 2) * Theme.variantOpacityDurationScale) duration: Math.round(Theme.variantDuration(Theme.expressiveDurations.expressiveDefaultSpatial, dropdownType === 2) * Theme.variantOpacityDurationScale)
easing.bezierCurve: dropdownType === 2 ? Theme.variantPopoutEnterCurve : Theme.variantPopoutExitCurve easing.bezierCurve: dropdownType === 2 ? Theme.variantPopoutEnterCurve : Theme.variantPopoutExitCurve
} }
@@ -393,7 +395,8 @@ Item {
Behavior on opacity { Behavior on opacity {
enabled: !Theme.isDirectionalEffect enabled: !Theme.isDirectionalEffect
DankAnim { NumberAnimation {
easing.type: Easing.BezierSpline
duration: Math.round(Theme.variantDuration(Theme.expressiveDurations.expressiveDefaultSpatial, dropdownType === 3) * Theme.variantOpacityDurationScale) duration: Math.round(Theme.variantDuration(Theme.expressiveDurations.expressiveDefaultSpatial, dropdownType === 3) * Theme.variantOpacityDurationScale)
easing.bezierCurve: dropdownType === 3 ? Theme.variantPopoutEnterCurve : Theme.variantPopoutExitCurve easing.bezierCurve: dropdownType === 3 ? Theme.variantPopoutEnterCurve : Theme.variantPopoutExitCurve
} }

View File

@@ -402,7 +402,7 @@ Rectangle {
opacity: isToday ? 0.9 : 0.7 opacity: isToday ? 0.9 : 0.7
Behavior on opacity { Behavior on opacity {
NumberAnimation { OpacityAnimator {
duration: Theme.shortDuration duration: Theme.shortDuration
easing.type: Theme.standardEasing easing.type: Theme.standardEasing
} }

View File

@@ -514,14 +514,14 @@ Item {
height: (isInOverflow && !root.overflowExpanded) ? 0 : (itemData.type === "separator" ? (root.isVertical ? 8 : root.iconSize) : (root.isVertical ? root.iconSize * 1.2 : root.iconSize)) height: (isInOverflow && !root.overflowExpanded) ? 0 : (itemData.type === "separator" ? (root.isVertical ? 8 : root.iconSize) : (root.isVertical ? root.iconSize * 1.2 : root.iconSize))
Behavior on opacity { Behavior on opacity {
NumberAnimation { OpacityAnimator {
duration: Theme.shortDuration duration: Theme.shortDuration
easing.type: Easing.OutCubic easing.type: Easing.OutCubic
} }
} }
Behavior on scale { Behavior on scale {
NumberAnimation { ScaleAnimator {
duration: Theme.shortDuration duration: Theme.shortDuration
easing.type: Easing.OutCubic easing.type: Easing.OutCubic
} }

View File

@@ -35,7 +35,7 @@ Item {
rotation: isVertical ? (overflowExpanded ? 180 : 0) : (overflowExpanded ? 90 : -90) rotation: isVertical ? (overflowExpanded ? 180 : 0) : (overflowExpanded ? 90 : -90)
Behavior on rotation { Behavior on rotation {
NumberAnimation { RotationAnimator {
duration: Theme.shortDuration duration: Theme.shortDuration
easing.type: Easing.OutCubic easing.type: Easing.OutCubic
} }

View File

@@ -1,4 +1,3 @@
import QtCore
import QtQuick import QtQuick
import QtQuick.Effects import QtQuick.Effects
import QtQuick.Layouts import QtQuick.Layouts
@@ -119,15 +118,7 @@ Item {
function greeterPamStackHasModule(moduleName) { function greeterPamStackHasModule(moduleName) {
if (pamModuleEnabled(greetdPamText, moduleName)) if (pamModuleEnabled(greetdPamText, moduleName))
return true; return true;
const includedPamStacks = [ const includedPamStacks = [["system-auth", systemAuthPamText], ["common-auth", commonAuthPamText], ["password-auth", passwordAuthPamText], ["system-login", systemLoginPamText], ["system-local-login", systemLocalLoginPamText], ["common-auth-pc", commonAuthPcPamText], ["login", loginPamText]];
["system-auth", systemAuthPamText],
["common-auth", commonAuthPamText],
["password-auth", passwordAuthPamText],
["system-login", systemLoginPamText],
["system-local-login", systemLocalLoginPamText],
["common-auth-pc", commonAuthPcPamText],
["login", loginPamText]
];
for (let i = 0; i < includedPamStacks.length; i++) { for (let i = 0; i < includedPamStacks.length; i++) {
const stack = includedPamStacks[i]; const stack = includedPamStacks[i];
if (pamTextIncludesFile(greetdPamText, stack[0]) && pamModuleEnabled(stack[1], moduleName)) if (pamTextIncludesFile(greetdPamText, stack[0]) && pamModuleEnabled(stack[1], moduleName))
@@ -609,13 +600,7 @@ Item {
running: false running: false
// sh wrapper: emits PROBE_UNAVAILABLE if gdbus is absent or fprintd unreachable, // sh wrapper: emits PROBE_UNAVAILABLE if gdbus is absent or fprintd unreachable,
// keeping the PAM-only fallback active in those cases. // keeping the PAM-only fallback active in those cases.
command: ["sh", "-c", command: ["sh", "-c", "command -v gdbus >/dev/null 2>&1 || { echo PROBE_UNAVAILABLE; exit 0; }; " + "gdbus call --system " + "--dest net.reactivated.Fprint " + "--object-path /net/reactivated/Fprint/Manager " + "--method net.reactivated.Fprint.Manager.GetDevices 2>/dev/null " + "|| echo PROBE_UNAVAILABLE"]
"command -v gdbus >/dev/null 2>&1 || { echo PROBE_UNAVAILABLE; exit 0; }; " +
"gdbus call --system " +
"--dest net.reactivated.Fprint " +
"--object-path /net/reactivated/Fprint/Manager " +
"--method net.reactivated.Fprint.Manager.GetDevices 2>/dev/null " +
"|| echo PROBE_UNAVAILABLE"]
stdout: StdioCollector { stdout: StdioCollector {
onStreamFinished: { onStreamFinished: {
if (text.includes("PROBE_UNAVAILABLE")) if (text.includes("PROBE_UNAVAILABLE"))
@@ -625,7 +610,7 @@ Item {
root.maybeAutoStartExternalAuth(); root.maybeAutoStartExternalAuth();
} }
} }
onExited: function(exitCode, exitStatus) { onExited: function (exitCode, exitStatus) {
if (!root.fprintdProbeComplete) if (!root.fprintdProbeComplete)
root.maybeAutoStartExternalAuth(); // PAM-only fallback stays active root.maybeAutoStartExternalAuth(); // PAM-only fallback stays active
} }
@@ -729,7 +714,7 @@ Item {
} }
Behavior on opacity { Behavior on opacity {
NumberAnimation { OpacityAnimator {
duration: Theme.mediumDuration duration: Theme.mediumDuration
easing.type: Theme.standardEasing easing.type: Theme.standardEasing
} }
@@ -1027,7 +1012,7 @@ Item {
opacity: (GreeterState.showPasswordInput ? GreeterState.passwordBuffer.length === 0 : GreeterState.usernameInput.length === 0) ? 1 : 0 opacity: (GreeterState.showPasswordInput ? GreeterState.passwordBuffer.length === 0 : GreeterState.usernameInput.length === 0) ? 1 : 0
Behavior on opacity { Behavior on opacity {
NumberAnimation { OpacityAnimator {
duration: Theme.mediumDuration duration: Theme.mediumDuration
easing.type: Theme.standardEasing easing.type: Theme.standardEasing
} }
@@ -1064,7 +1049,7 @@ Item {
horizontalAlignment: implicitWidth > width ? Text.AlignRight : Text.AlignLeft horizontalAlignment: implicitWidth > width ? Text.AlignRight : Text.AlignLeft
Behavior on opacity { Behavior on opacity {
NumberAnimation { OpacityAnimator {
duration: Theme.mediumDuration duration: Theme.mediumDuration
easing.type: Theme.standardEasing easing.type: Theme.standardEasing
} }
@@ -1136,7 +1121,7 @@ Item {
} }
Behavior on opacity { Behavior on opacity {
NumberAnimation { OpacityAnimator {
duration: Theme.shortDuration duration: Theme.shortDuration
easing.type: Theme.standardEasing easing.type: Theme.standardEasing
} }
@@ -1166,7 +1151,7 @@ Item {
opacity: root.authFeedbackMessage !== "" ? 1 : 0 opacity: root.authFeedbackMessage !== "" ? 1 : 0
Behavior on opacity { Behavior on opacity {
NumberAnimation { OpacityAnimator {
duration: Theme.shortDuration duration: Theme.shortDuration
easing.type: Theme.standardEasing easing.type: Theme.standardEasing
} }
@@ -1184,7 +1169,7 @@ Item {
enabled: GreeterState.showPasswordInput enabled: GreeterState.showPasswordInput
Behavior on opacity { Behavior on opacity {
NumberAnimation { OpacityAnimator {
duration: Theme.mediumDuration duration: Theme.mediumDuration
easing.type: Theme.standardEasing easing.type: Theme.standardEasing
} }
@@ -1754,7 +1739,7 @@ Item {
authTimeout.interval = defaultAuthTimeoutMs; authTimeout.interval = defaultAuthTimeoutMs;
authTimeout.stop(); authTimeout.stop();
if (resumePasswordSubmit) { if (resumePasswordSubmit) {
Qt.callLater(function() { Qt.callLater(function () {
root.startAuthSession(true); root.startAuthSession(true);
}); });
return; return;

View File

@@ -779,7 +779,7 @@ Rectangle {
opacity: root.showHoldHint ? 1 : 0.5 opacity: root.showHoldHint ? 1 : 0.5
Behavior on opacity { Behavior on opacity {
NumberAnimation { OpacityAnimator {
duration: 150 duration: 150
} }
} }

View File

@@ -214,7 +214,7 @@ Item {
} }
Behavior on opacity { Behavior on opacity {
NumberAnimation { OpacityAnimator {
duration: Theme.mediumDuration duration: Theme.mediumDuration
easing.type: Theme.standardEasing easing.type: Theme.standardEasing
} }
@@ -740,7 +740,7 @@ Item {
opacity: pam.passwd.active ? 0 : 1 opacity: pam.passwd.active ? 0 : 1
Behavior on opacity { Behavior on opacity {
NumberAnimation { OpacityAnimator {
duration: Theme.mediumDuration duration: Theme.mediumDuration
easing.type: Theme.standardEasing easing.type: Theme.standardEasing
} }
@@ -879,7 +879,7 @@ Item {
opacity: (demoMode || root.passwordBuffer.length === 0) ? 1 : 0 opacity: (demoMode || root.passwordBuffer.length === 0) ? 1 : 0
Behavior on opacity { Behavior on opacity {
NumberAnimation { OpacityAnimator {
duration: Theme.mediumDuration duration: Theme.mediumDuration
easing.type: Theme.standardEasing easing.type: Theme.standardEasing
} }
@@ -916,7 +916,7 @@ Item {
horizontalAlignment: implicitWidth > width ? Text.AlignRight : Text.AlignLeft horizontalAlignment: implicitWidth > width ? Text.AlignRight : Text.AlignLeft
Behavior on opacity { Behavior on opacity {
NumberAnimation { OpacityAnimator {
duration: Theme.mediumDuration duration: Theme.mediumDuration
easing.type: Theme.standardEasing easing.type: Theme.standardEasing
} }
@@ -1053,7 +1053,7 @@ Item {
} }
Behavior on opacity { Behavior on opacity {
NumberAnimation { OpacityAnimator {
duration: Theme.shortDuration duration: Theme.shortDuration
easing.type: Theme.standardEasing easing.type: Theme.standardEasing
} }
@@ -1084,7 +1084,7 @@ Item {
opacity: text.length > 0 ? 1 : 0 opacity: text.length > 0 ? 1 : 0
Behavior on opacity { Behavior on opacity {
NumberAnimation { OpacityAnimator {
duration: Theme.shortDuration duration: Theme.shortDuration
easing.type: Theme.standardEasing easing.type: Theme.standardEasing
} }
@@ -1114,7 +1114,7 @@ Item {
} }
Behavior on opacity { Behavior on opacity {
NumberAnimation { OpacityAnimator {
duration: Theme.shortDuration duration: Theme.shortDuration
easing.type: Theme.standardEasing easing.type: Theme.standardEasing
} }

View File

@@ -47,7 +47,7 @@ FocusScope {
} }
Behavior on opacity { Behavior on opacity {
NumberAnimation { OpacityAnimator {
duration: 200 duration: 200
} }
} }

View File

@@ -1,19 +1,18 @@
pragma ComponentBehavior: Bound
import QtQuick import QtQuick
import QtQuick.Controls import QtQuick.Controls
import QtQuick.Layouts import QtQuick.Layouts
import Quickshell.Io
import qs.Common import qs.Common
import qs.Services import qs.Services
import qs.Widgets import qs.Widgets
pragma ComponentBehavior: Bound
Column { Column {
id: root id: root
Component.onCompleted: { Component.onCompleted: {
if (PluginService.isPluginLoaded("dankNotepadModule")) { if (PluginService.isPluginLoaded("dankNotepadModule")) {
pluginHighlightedHtml = SettingsData.getBuiltInPluginSetting("dankNotepadModule", "highlightedHtml", "") pluginHighlightedHtml = SettingsData.getBuiltInPluginSetting("dankNotepadModule", "highlightedHtml", "");
} }
} }
@@ -33,65 +32,57 @@ Column {
property string lastPluginContent: "" property string lastPluginContent: ""
property int loadRequestId: 0 property int loadRequestId: 0
signal saveRequested() signal saveRequested
signal openRequested() signal openRequested
signal newRequested() signal newRequested
signal previewRequested() signal previewRequested
signal escapePressed() signal escapePressed
signal contentChanged() signal contentChanged
signal settingsRequested() signal settingsRequested
function hasUnsavedChanges() { function hasUnsavedChanges() {
if (!currentTab || !contentLoaded) { if (!currentTab || !contentLoaded) {
return false return false;
} }
if (currentTab.isTemporary) { if (currentTab.isTemporary) {
return textArea.text.length > 0 return textArea.text.length > 0;
} }
return textArea.text !== lastSavedContent return textArea.text !== lastSavedContent;
} }
function loadCurrentTabContent() { function loadCurrentTabContent() {
if (!currentTab) return if (!currentTab)
return;
const requestedTabId = currentTab.id const requestedTabId = currentTab.id;
const requestId = ++loadRequestId const requestId = ++loadRequestId;
contentLoaded = false contentLoaded = false;
NotepadStorageService.loadTabContent( NotepadStorageService.loadTabContent(NotepadStorageService.currentTabIndex, content => {
NotepadStorageService.currentTabIndex, const activeTab = NotepadStorageService.tabs.length > NotepadStorageService.currentTabIndex ? NotepadStorageService.tabs[NotepadStorageService.currentTabIndex] : null;
(content) => { if (requestId !== loadRequestId || !activeTab || activeTab.id !== requestedTabId)
const activeTab = NotepadStorageService.tabs.length > NotepadStorageService.currentTabIndex return;
? NotepadStorageService.tabs[NotepadStorageService.currentTabIndex] lastSavedContent = content;
: null textArea.text = content;
if (requestId !== loadRequestId || !activeTab || activeTab.id !== requestedTabId) contentLoaded = true;
return syncContentToPlugin();
});
lastSavedContent = content
textArea.text = content
contentLoaded = true
syncContentToPlugin()
}
)
} }
function saveCurrentTabContent() { function saveCurrentTabContent() {
if (!currentTab || !contentLoaded) return if (!currentTab || !contentLoaded)
return;
NotepadStorageService.saveTabContent( NotepadStorageService.saveTabContent(NotepadStorageService.currentTabIndex, textArea.text);
NotepadStorageService.currentTabIndex, lastSavedContent = textArea.text;
textArea.text
)
lastSavedContent = textArea.text
} }
function autoSaveToSession() { function autoSaveToSession() {
if (!currentTab || !contentLoaded) return if (!currentTab || !contentLoaded)
saveCurrentTabContent() return;
saveCurrentTabContent();
} }
function setTextDocumentLineHeight() { function setTextDocumentLineHeight() {
return return;
} }
property string lastTextForLineModel: "" property string lastTextForLineModel: ""
@@ -99,147 +90,146 @@ Column {
function updateLineModel() { function updateLineModel() {
if (!SettingsData.notepadShowLineNumbers) { if (!SettingsData.notepadShowLineNumbers) {
lineModel = [] lineModel = [];
lastTextForLineModel = "" lastTextForLineModel = "";
return return;
} }
if (textArea.text !== lastTextForLineModel || lineModel.length === 0) { if (textArea.text !== lastTextForLineModel || lineModel.length === 0) {
lastTextForLineModel = textArea.text lastTextForLineModel = textArea.text;
lineModel = textArea.text.split('\n') lineModel = textArea.text.split('\n');
} }
} }
function performSearch() { function performSearch() {
let matches = [] let matches = [];
currentMatchIndex = -1 currentMatchIndex = -1;
if (!searchQuery || searchQuery.length === 0) { if (!searchQuery || searchQuery.length === 0) {
searchMatches = [] searchMatches = [];
matchCount = 0 matchCount = 0;
textArea.select(0, 0) textArea.select(0, 0);
return return;
} }
const text = textArea.text const text = textArea.text;
const query = searchQuery.toLowerCase() const query = searchQuery.toLowerCase();
let index = 0 let index = 0;
while (index < text.length) { while (index < text.length) {
const foundIndex = text.toLowerCase().indexOf(query, index) const foundIndex = text.toLowerCase().indexOf(query, index);
if (foundIndex === -1) break if (foundIndex === -1)
break;
matches.push({ matches.push({
start: foundIndex, start: foundIndex,
end: foundIndex + searchQuery.length end: foundIndex + searchQuery.length
}) });
index = foundIndex + 1 index = foundIndex + 1;
} }
searchMatches = matches searchMatches = matches;
matchCount = matches.length matchCount = matches.length;
if (matchCount > 0) { if (matchCount > 0) {
currentMatchIndex = 0 currentMatchIndex = 0;
highlightCurrentMatch() highlightCurrentMatch();
} else { } else {
textArea.select(0, 0) textArea.select(0, 0);
} }
} }
function highlightCurrentMatch() { function highlightCurrentMatch() {
if (currentMatchIndex >= 0 && currentMatchIndex < searchMatches.length) { if (currentMatchIndex >= 0 && currentMatchIndex < searchMatches.length) {
const match = searchMatches[currentMatchIndex] const match = searchMatches[currentMatchIndex];
textArea.cursorPosition = match.start textArea.cursorPosition = match.start;
textArea.moveCursorSelection(match.end, TextEdit.SelectCharacters) textArea.moveCursorSelection(match.end, TextEdit.SelectCharacters);
const flickable = textArea.parent const flickable = textArea.parent;
if (flickable && flickable.contentY !== undefined) { if (flickable && flickable.contentY !== undefined) {
const lineHeight = textArea.font.pixelSize * 1.5 const lineHeight = textArea.font.pixelSize * 1.5;
const approxLine = textArea.text.substring(0, match.start).split('\n').length const approxLine = textArea.text.substring(0, match.start).split('\n').length;
const targetY = approxLine * lineHeight - flickable.height / 2 const targetY = approxLine * lineHeight - flickable.height / 2;
flickable.contentY = Math.max(0, Math.min(targetY, flickable.contentHeight - flickable.height)) flickable.contentY = Math.max(0, Math.min(targetY, flickable.contentHeight - flickable.height));
} }
} }
} }
function findNext() { function findNext() {
if (matchCount === 0 || searchMatches.length === 0) return if (matchCount === 0 || searchMatches.length === 0)
return;
currentMatchIndex = (currentMatchIndex + 1) % matchCount currentMatchIndex = (currentMatchIndex + 1) % matchCount;
highlightCurrentMatch() highlightCurrentMatch();
} }
function findPrevious() { function findPrevious() {
if (matchCount === 0 || searchMatches.length === 0) return if (matchCount === 0 || searchMatches.length === 0)
return;
currentMatchIndex = currentMatchIndex <= 0 ? matchCount - 1 : currentMatchIndex - 1 currentMatchIndex = currentMatchIndex <= 0 ? matchCount - 1 : currentMatchIndex - 1;
highlightCurrentMatch() highlightCurrentMatch();
} }
function showSearch() { function showSearch() {
searchVisible = true searchVisible = true;
Qt.callLater(() => { Qt.callLater(() => {
searchField.forceActiveFocus() searchField.forceActiveFocus();
}) });
} }
function togglePreview() { function togglePreview() {
if (!inlinePreviewVisible) { if (!inlinePreviewVisible) {
inlinePreviewVisible = true inlinePreviewVisible = true;
previewMode = "split" previewMode = "split";
} else if (previewMode === "split") { } else if (previewMode === "split") {
previewMode = "full" previewMode = "full";
} else { } else {
inlinePreviewVisible = false inlinePreviewVisible = false;
previewMode = "split" previewMode = "split";
} }
syncContentToPlugin() syncContentToPlugin();
} }
function renderPreviewHtml() { function renderPreviewHtml() {
if (!inlinePreviewVisible) return "" if (!inlinePreviewVisible)
return pluginHighlightedHtml.length > 0 ? pluginHighlightedHtml : "<p><i>Rendering preview…</i></p>" return "";
return pluginHighlightedHtml.length > 0 ? pluginHighlightedHtml : "<p><i>Rendering preview…</i></p>";
} }
function syncContentToPlugin() { function syncContentToPlugin() {
if (!PluginService.isPluginLoaded("dankNotepadModule")) if (!PluginService.isPluginLoaded("dankNotepadModule"))
return return;
if (!currentTab) if (!currentTab)
return return;
const filePath = currentTab?.filePath || "";
const filePath = currentTab?.filePath || "" const ext = filePath.split('.').pop().toLowerCase();
const ext = filePath.split('.').pop().toLowerCase() const content = textArea.text;
const content = textArea.text
if (content === lastPluginContent && SettingsData.getBuiltInPluginSetting("dankNotepadModule", "previewActive", false) === inlinePreviewVisible) { if (content === lastPluginContent && SettingsData.getBuiltInPluginSetting("dankNotepadModule", "previewActive", false) === inlinePreviewVisible) {
return return;
} }
lastPluginContent = content lastPluginContent = content;
SettingsData.setBuiltInPluginSetting("dankNotepadModule", "previewActive", inlinePreviewVisible) SettingsData.setBuiltInPluginSetting("dankNotepadModule", "previewActive", inlinePreviewVisible);
SettingsData.setBuiltInPluginSetting("dankNotepadModule", "currentFilePath", filePath) SettingsData.setBuiltInPluginSetting("dankNotepadModule", "currentFilePath", filePath);
SettingsData.setBuiltInPluginSetting("dankNotepadModule", "currentFileExtension", ext) SettingsData.setBuiltInPluginSetting("dankNotepadModule", "currentFileExtension", ext);
SettingsData.setBuiltInPluginSetting("dankNotepadModule", "sourceContent", content) SettingsData.setBuiltInPluginSetting("dankNotepadModule", "sourceContent", content);
SettingsData.setBuiltInPluginSetting("dankNotepadModule", "updatedAt", Date.now()) SettingsData.setBuiltInPluginSetting("dankNotepadModule", "updatedAt", Date.now());
} }
function hideSearch() { function hideSearch() {
searchVisible = false searchVisible = false;
searchQuery = "" searchQuery = "";
searchMatches = [] searchMatches = [];
matchCount = 0 matchCount = 0;
currentMatchIndex = -1 currentMatchIndex = -1;
textArea.select(0, 0) textArea.select(0, 0);
textArea.forceActiveFocus() textArea.forceActiveFocus();
} }
function copyPlainTextToClipboard() { function copyPlainTextToClipboard() {
if (!inlinePreviewVisible || !textArea.text) return if (!inlinePreviewVisible || !textArea.text)
return;
const content = textArea.text const content = textArea.text;
if (content.length > 0) { if (content.length > 0) {
const proc = Qt.createQmlObject(` const proc = Qt.createQmlObject(`
import QtQuick import QtQuick
@@ -249,22 +239,19 @@ Column {
command: ["sh", "-c", "printf '%s' \\"$CONTENT\\" | dms clipboard copy"] command: ["sh", "-c", "printf '%s' \\"$CONTENT\\" | dms clipboard copy"]
environment: { "CONTENT": content } environment: { "CONTENT": content }
running: false running: false
}`, }`, root, "copyProc");
root, proc.content = content;
"copyProc" proc.running = true;
)
proc.content = content
proc.running = true
proc.exited.connect(() => { proc.exited.connect(() => {
ToastService.showInfo(I18n.tr("Copied to clipboard")) ToastService.showInfo(I18n.tr("Copied to clipboard"));
proc.destroy() proc.destroy();
}) });
} }
} }
function copyHtmlToClipboard() { function copyHtmlToClipboard() {
if (!inlinePreviewVisible || !pluginHighlightedHtml) return if (!inlinePreviewVisible || !pluginHighlightedHtml)
return;
if (pluginHighlightedHtml.length > 0) { if (pluginHighlightedHtml.length > 0) {
const proc = Qt.createQmlObject(` const proc = Qt.createQmlObject(`
import QtQuick import QtQuick
@@ -274,16 +261,13 @@ Column {
command: ["sh", "-c", "printf '%s' \\"$CONTENT\\" | dms clipboard copy"] command: ["sh", "-c", "printf '%s' \\"$CONTENT\\" | dms clipboard copy"]
environment: { "CONTENT": content } environment: { "CONTENT": content }
running: false running: false
}`, }`, root, "copyProcHtml");
root, proc.content = pluginHighlightedHtml;
"copyProcHtml" proc.running = true;
)
proc.content = pluginHighlightedHtml
proc.running = true
proc.exited.connect(() => { proc.exited.connect(() => {
ToastService.showInfo(I18n.tr("HTML copied to clipboard")) ToastService.showInfo(I18n.tr("HTML copied to clipboard"));
proc.destroy() proc.destroy();
}) });
} }
} }
@@ -301,7 +285,7 @@ Column {
radius: Theme.cornerRadius radius: Theme.cornerRadius
Behavior on opacity { Behavior on opacity {
NumberAnimation { OpacityAnimator {
duration: Theme.shortDuration duration: Theme.shortDuration
easing.type: Theme.standardEasing easing.type: Theme.standardEasing
} }
@@ -334,43 +318,43 @@ Column {
clip: true clip: true
Component.onCompleted: { Component.onCompleted: {
text = root.searchQuery text = root.searchQuery;
} }
Connections { Connections {
target: root target: root
function onSearchQueryChanged() { function onSearchQueryChanged() {
if (searchField.text !== root.searchQuery) { if (searchField.text !== root.searchQuery) {
searchField.text = root.searchQuery searchField.text = root.searchQuery;
} }
} }
} }
onTextChanged: { onTextChanged: {
if (root.searchQuery !== text) { if (root.searchQuery !== text) {
root.searchQuery = text root.searchQuery = text;
root.performSearch() root.performSearch();
} }
} }
Keys.onEscapePressed: event => { Keys.onEscapePressed: event => {
root.hideSearch() root.hideSearch();
event.accepted = true event.accepted = true;
} }
Keys.onReturnPressed: event => { Keys.onReturnPressed: event => {
if (event.modifiers & Qt.ShiftModifier) { if (event.modifiers & Qt.ShiftModifier) {
root.findPrevious() root.findPrevious();
} else { } else {
root.findNext() root.findNext();
} }
event.accepted = true event.accepted = true;
} }
Keys.onEnterPressed: event => { Keys.onEnterPressed: event => {
if (event.modifiers & Qt.ShiftModifier) { if (event.modifiers & Qt.ShiftModifier) {
root.findPrevious() root.findPrevious();
} else { } else {
root.findNext() root.findNext();
} }
event.accepted = true event.accepted = true;
} }
} }
@@ -541,31 +525,41 @@ Column {
SequentialAnimation on opacity { SequentialAnimation on opacity {
running: textArea.activeFocus running: textArea.activeFocus
loops: Animation.Infinite loops: Animation.Infinite
PropertyAnimation { from: 1.0; to: 0.0; duration: 650; easing.type: Easing.InOutQuad } PropertyAnimation {
PropertyAnimation { from: 0.0; to: 1.0; duration: 650; easing.type: Easing.InOutQuad } from: 1.0
to: 0.0
duration: 650
easing.type: Easing.InOutQuad
}
PropertyAnimation {
from: 0.0
to: 1.0
duration: 650
easing.type: Easing.InOutQuad
}
} }
} }
Component.onCompleted: { Component.onCompleted: {
loadCurrentTabContent() loadCurrentTabContent();
setTextDocumentLineHeight() setTextDocumentLineHeight();
root.updateLineModel() root.updateLineModel();
Qt.callLater(() => { Qt.callLater(() => {
textArea.forceActiveFocus() textArea.forceActiveFocus();
}) });
} }
Connections { Connections {
target: NotepadStorageService target: NotepadStorageService
function onCurrentTabIndexChanged() { function onCurrentTabIndexChanged() {
loadCurrentTabContent() loadCurrentTabContent();
Qt.callLater(() => { Qt.callLater(() => {
textArea.forceActiveFocus() textArea.forceActiveFocus();
}) });
} }
function onTabsChanged() { function onTabsChanged() {
if (NotepadStorageService.tabs.length > 0 && !contentLoaded) { if (NotepadStorageService.tabs.length > 0 && !contentLoaded) {
loadCurrentTabContent() loadCurrentTabContent();
} }
} }
} }
@@ -573,53 +567,53 @@ Column {
Connections { Connections {
target: SettingsData target: SettingsData
function onNotepadShowLineNumbersChanged() { function onNotepadShowLineNumbersChanged() {
root.updateLineModel() root.updateLineModel();
} }
} }
onTextChanged: { onTextChanged: {
if (contentLoaded && text !== lastSavedContent) { if (contentLoaded && text !== lastSavedContent) {
autoSaveTimer.restart() autoSaveTimer.restart();
} }
root.contentChanged() root.contentChanged();
root.updateLineModel() root.updateLineModel();
pluginSyncTimer.restart() pluginSyncTimer.restart();
} }
Keys.onEscapePressed: (event) => { Keys.onEscapePressed: event => {
root.escapePressed() root.escapePressed();
event.accepted = true event.accepted = true;
} }
Keys.onPressed: (event) => { Keys.onPressed: event => {
if (event.modifiers & Qt.ControlModifier) { if (event.modifiers & Qt.ControlModifier) {
switch (event.key) { switch (event.key) {
case Qt.Key_S: case Qt.Key_S:
event.accepted = true event.accepted = true;
root.saveRequested() root.saveRequested();
break break;
case Qt.Key_O: case Qt.Key_O:
event.accepted = true event.accepted = true;
root.openRequested() root.openRequested();
break break;
case Qt.Key_N: case Qt.Key_N:
event.accepted = true event.accepted = true;
root.newRequested() root.newRequested();
break break;
case Qt.Key_A: case Qt.Key_A:
event.accepted = true event.accepted = true;
textArea.selectAll() textArea.selectAll();
break break;
case Qt.Key_F: case Qt.Key_F:
event.accepted = true event.accepted = true;
root.showSearch() root.showSearch();
break break;
case Qt.Key_P: case Qt.Key_P:
if (PluginService.isPluginLoaded("dankNotepadModule")) { if (PluginService.isPluginLoaded("dankNotepadModule")) {
event.accepted = true event.accepted = true;
root.previewRequested() root.previewRequested();
} }
break break;
} }
} }
} }
@@ -845,19 +839,16 @@ Column {
StyledText { StyledText {
text: { text: {
const len = textArea.text.length; const len = textArea.text.length;
if (len === 0) return I18n.tr("Empty"); if (len === 0)
return len === 1 return I18n.tr("Empty");
? I18n.tr("%1 character").arg(len) return len === 1 ? I18n.tr("%1 character").arg(len) : I18n.tr("%1 characters").arg(len);
: I18n.tr("%1 characters").arg(len);
} }
font.pixelSize: Theme.fontSizeSmall font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceTextMedium color: Theme.surfaceTextMedium
} }
StyledText { StyledText {
text: textArea.lineCount === 1 text: textArea.lineCount === 1 ? I18n.tr("Line: %1").arg(textArea.lineCount) : I18n.tr("Lines: %1").arg(textArea.lineCount)
? I18n.tr("Line: %1").arg(textArea.lineCount)
: I18n.tr("Lines: %1").arg(textArea.lineCount)
font.pixelSize: Theme.fontSizeSmall font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceTextMedium color: Theme.surfaceTextMedium
visible: textArea.text.length > 0 visible: textArea.text.length > 0
@@ -867,29 +858,29 @@ Column {
StyledText { StyledText {
text: { text: {
if (autoSaveTimer.running) { if (autoSaveTimer.running) {
return I18n.tr("Auto-saving...") return I18n.tr("Auto-saving...");
} }
if (hasUnsavedChanges()) { if (hasUnsavedChanges()) {
if (currentTab && currentTab.isTemporary) { if (currentTab && currentTab.isTemporary) {
return I18n.tr("Unsaved note...") return I18n.tr("Unsaved note...");
} else { } else {
return I18n.tr("Unsaved changes") return I18n.tr("Unsaved changes");
} }
} else { } else {
return I18n.tr("Saved") return I18n.tr("Saved");
} }
} }
font.pixelSize: Theme.fontSizeSmall font.pixelSize: Theme.fontSizeSmall
color: { color: {
if (autoSaveTimer.running) { if (autoSaveTimer.running) {
return Theme.primary return Theme.primary;
} }
if (hasUnsavedChanges()) { if (hasUnsavedChanges()) {
return Theme.warning return Theme.warning;
} else { } else {
return Theme.success return Theme.success;
} }
} }
opacity: textArea.text.length > 0 ? 1.0 : 0.0 opacity: textArea.text.length > 0 ? 1.0 : 0.0
@@ -902,7 +893,7 @@ Column {
interval: 2000 interval: 2000
repeat: false repeat: false
onTriggered: { onTriggered: {
autoSaveToSession() autoSaveToSession();
} }
} }
@@ -917,7 +908,7 @@ Column {
target: SettingsData target: SettingsData
function onBuiltInPluginSettingsChanged() { function onBuiltInPluginSettingsChanged() {
if (PluginService.isPluginLoaded("dankNotepadModule")) { if (PluginService.isPluginLoaded("dankNotepadModule")) {
pluginHighlightedHtml = SettingsData.getBuiltInPluginSetting("dankNotepadModule", "highlightedHtml", "") pluginHighlightedHtml = SettingsData.getBuiltInPluginSetting("dankNotepadModule", "highlightedHtml", "");
} }
} }
} }

View File

@@ -283,7 +283,7 @@ Item {
Behavior on x { Behavior on x {
enabled: !swipeDragHandler.active && delegateRoot.__delegateInitialized enabled: !swipeDragHandler.active && delegateRoot.__delegateInitialized
NumberAnimation { XAnimator {
duration: Theme.notificationExitDuration duration: Theme.notificationExitDuration
easing.type: Theme.standardEasing easing.type: Theme.standardEasing
} }
@@ -291,7 +291,7 @@ Item {
Behavior on opacity { Behavior on opacity {
enabled: delegateRoot.__delegateInitialized enabled: delegateRoot.__delegateInitialized
NumberAnimation { OpacityAnimator {
duration: delegateRoot.__delegateInitialized ? Theme.notificationExitDuration : 0 duration: delegateRoot.__delegateInitialized ? Theme.notificationExitDuration : 0
} }
} }

View File

@@ -226,7 +226,7 @@ DankListView {
Behavior on x { Behavior on x {
enabled: !swipeDragHandler.active && !delegateRoot.isDismissing && (listView.swipingCardIndex === -1 || !delegateRoot.isAdjacentToSwipe) && listView.listInitialized enabled: !swipeDragHandler.active && !delegateRoot.isDismissing && (listView.swipingCardIndex === -1 || !delegateRoot.isAdjacentToSwipe) && listView.listInitialized
NumberAnimation { XAnimator {
duration: Theme.shortDuration duration: Theme.shortDuration
easing.type: Theme.standardEasing easing.type: Theme.standardEasing
} }
@@ -234,7 +234,7 @@ DankListView {
Behavior on opacity { Behavior on opacity {
enabled: listView.listInitialized enabled: listView.listInitialized
NumberAnimation { OpacityAnimator {
duration: listView.listInitialized ? Theme.shortDuration : 0 duration: listView.listInitialized ? Theme.shortDuration : 0
} }
} }

View File

@@ -75,7 +75,7 @@ Rectangle {
Behavior on scale { Behavior on scale {
enabled: listLevelScaleAnimationsEnabled enabled: listLevelScaleAnimationsEnabled
NumberAnimation { ScaleAnimator {
duration: Theme.shortDuration duration: Theme.shortDuration
easing.type: Theme.standardEasing easing.type: Theme.standardEasing
} }
@@ -545,7 +545,7 @@ Rectangle {
Behavior on x { Behavior on x {
enabled: !expandedSwipeHandler.active && !expandedDelegateWrapper.isDismissing enabled: !expandedSwipeHandler.active && !expandedDelegateWrapper.isDismissing
NumberAnimation { XAnimator {
duration: Theme.shortDuration duration: Theme.shortDuration
easing.type: Theme.standardEasing easing.type: Theme.standardEasing
} }
@@ -553,7 +553,7 @@ Rectangle {
Behavior on scale { Behavior on scale {
enabled: !expandedSwipeHandler.active enabled: !expandedSwipeHandler.active
NumberAnimation { ScaleAnimator {
duration: Theme.shortDuration duration: Theme.shortDuration
easing.type: Theme.standardEasing easing.type: Theme.standardEasing
} }
@@ -762,7 +762,7 @@ Rectangle {
spacing: contentSpacing spacing: contentSpacing
Behavior on opacity { Behavior on opacity {
NumberAnimation { OpacityAnimator {
duration: Theme.shortDuration duration: Theme.shortDuration
easing.type: Theme.standardEasing easing.type: Theme.standardEasing
} }
@@ -822,7 +822,7 @@ Rectangle {
color: isHovered ? Theme.withAlpha(Theme.primary, Theme.stateLayerHover) : "transparent" color: isHovered ? Theme.withAlpha(Theme.primary, Theme.stateLayerHover) : "transparent"
Behavior on opacity { Behavior on opacity {
NumberAnimation { OpacityAnimator {
duration: Theme.shortDuration duration: Theme.shortDuration
easing.type: Theme.standardEasing easing.type: Theme.standardEasing
} }

View File

@@ -42,7 +42,7 @@ Rectangle {
} }
Behavior on opacity { Behavior on opacity {
NumberAnimation { OpacityAnimator {
duration: Theme.shortDuration duration: Theme.shortDuration
easing.type: Theme.standardEasing easing.type: Theme.standardEasing
} }

View File

@@ -27,7 +27,7 @@ Rectangle {
opacity: expanded ? 1 : 0 opacity: expanded ? 1 : 0
Behavior on opacity { Behavior on opacity {
NumberAnimation { OpacityAnimator {
duration: Theme.shortDuration duration: Theme.shortDuration
easing.type: Theme.emphasizedEasing easing.type: Theme.emphasizedEasing
} }
@@ -123,327 +123,327 @@ Rectangle {
anchors.margins: Theme.spacingL anchors.margins: Theme.spacingL
spacing: Theme.spacingM spacing: Theme.spacingM
StyledText { StyledText {
text: I18n.tr("Notification Settings") text: I18n.tr("Notification Settings")
font.pixelSize: Theme.fontSizeMedium font.pixelSize: Theme.fontSizeMedium
font.weight: Font.Bold font.weight: Font.Bold
color: Theme.surfaceText color: Theme.surfaceText
}
Item {
width: parent.width
height: Math.max(dndRow.implicitHeight, dndToggle.implicitHeight) + Theme.spacingS
Row {
id: dndRow
anchors.left: parent.left
anchors.verticalCenter: parent.verticalCenter
spacing: Theme.spacingM
DankIcon {
name: SessionData.doNotDisturb ? "notifications_off" : "notifications"
size: Theme.iconSizeSmall
color: SessionData.doNotDisturb ? Theme.error : Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
StyledText {
text: I18n.tr("Do Not Disturb")
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
} }
DankToggle { Item {
id: dndToggle width: parent.width
anchors.right: parent.right height: Math.max(dndRow.implicitHeight, dndToggle.implicitHeight) + Theme.spacingS
anchors.verticalCenter: parent.verticalCenter
checked: SessionData.doNotDisturb
onToggled: SessionData.setDoNotDisturb(!SessionData.doNotDisturb)
}
}
Rectangle { Row {
width: parent.width id: dndRow
height: 1 anchors.left: parent.left
color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.1) anchors.verticalCenter: parent.verticalCenter
} spacing: Theme.spacingM
StyledText { DankIcon {
text: I18n.tr("Notification Timeouts") name: SessionData.doNotDisturb ? "notifications_off" : "notifications"
font.pixelSize: Theme.fontSizeSmall size: Theme.iconSizeSmall
font.weight: Font.Medium color: SessionData.doNotDisturb ? Theme.error : Theme.surfaceText
color: Theme.surfaceVariantText anchors.verticalCenter: parent.verticalCenter
}
DankDropdown {
text: I18n.tr("Low Priority")
description: I18n.tr("Timeout for low priority notifications")
currentValue: getTimeoutText(SettingsData.notificationTimeoutLow)
options: timeoutOptions.map(opt => opt.text)
onValueChanged: value => {
for (let i = 0; i < timeoutOptions.length; i++) {
if (timeoutOptions[i].text === value) {
SettingsData.set("notificationTimeoutLow", timeoutOptions[i].value);
break;
} }
}
}
}
DankDropdown {
text: I18n.tr("Normal Priority")
description: I18n.tr("Timeout for normal priority notifications")
currentValue: getTimeoutText(SettingsData.notificationTimeoutNormal)
options: timeoutOptions.map(opt => opt.text)
onValueChanged: value => {
for (let i = 0; i < timeoutOptions.length; i++) {
if (timeoutOptions[i].text === value) {
SettingsData.set("notificationTimeoutNormal", timeoutOptions[i].value);
break;
}
}
}
}
DankDropdown {
text: I18n.tr("Critical Priority")
description: I18n.tr("Timeout for critical priority notifications")
currentValue: getTimeoutText(SettingsData.notificationTimeoutCritical)
options: timeoutOptions.map(opt => opt.text)
onValueChanged: value => {
for (let i = 0; i < timeoutOptions.length; i++) {
if (timeoutOptions[i].text === value) {
SettingsData.set("notificationTimeoutCritical", timeoutOptions[i].value);
break;
}
}
}
}
Rectangle {
width: parent.width
height: 1
color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.1)
}
Item {
width: parent.width
height: Math.max(overlayRow.implicitHeight, overlayToggle.implicitHeight) + Theme.spacingS
Row {
id: overlayRow
anchors.left: parent.left
anchors.right: overlayToggle.left
anchors.rightMargin: Theme.spacingM
anchors.verticalCenter: parent.verticalCenter
spacing: Theme.spacingM
DankIcon {
name: "notifications_active"
size: Theme.iconSizeSmall
color: SettingsData.notificationOverlayEnabled ? Theme.primary : Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
Column {
spacing: 2
anchors.verticalCenter: parent.verticalCenter
width: overlayRow.width - Theme.iconSizeSmall - Theme.spacingM
StyledText { StyledText {
width: parent.width text: I18n.tr("Do Not Disturb")
text: I18n.tr("Notification Overlay")
font.pixelSize: Theme.fontSizeSmall font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceText color: Theme.surfaceText
wrapMode: Text.Wrap anchors.verticalCenter: parent.verticalCenter
} }
}
StyledText { DankToggle {
width: parent.width id: dndToggle
text: I18n.tr("Display all priorities over fullscreen apps") anchors.right: parent.right
font.pixelSize: Theme.fontSizeSmall - 1 anchors.verticalCenter: parent.verticalCenter
color: Theme.surfaceVariantText checked: SessionData.doNotDisturb
wrapMode: Text.Wrap onToggled: SessionData.setDoNotDisturb(!SessionData.doNotDisturb)
}
}
Rectangle {
width: parent.width
height: 1
color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.1)
}
StyledText {
text: I18n.tr("Notification Timeouts")
font.pixelSize: Theme.fontSizeSmall
font.weight: Font.Medium
color: Theme.surfaceVariantText
}
DankDropdown {
text: I18n.tr("Low Priority")
description: I18n.tr("Timeout for low priority notifications")
currentValue: getTimeoutText(SettingsData.notificationTimeoutLow)
options: timeoutOptions.map(opt => opt.text)
onValueChanged: value => {
for (let i = 0; i < timeoutOptions.length; i++) {
if (timeoutOptions[i].text === value) {
SettingsData.set("notificationTimeoutLow", timeoutOptions[i].value);
break;
}
} }
} }
} }
DankToggle { DankDropdown {
id: overlayToggle text: I18n.tr("Normal Priority")
anchors.right: parent.right description: I18n.tr("Timeout for normal priority notifications")
anchors.verticalCenter: parent.verticalCenter currentValue: getTimeoutText(SettingsData.notificationTimeoutNormal)
checked: SettingsData.notificationOverlayEnabled options: timeoutOptions.map(opt => opt.text)
onToggled: toggled => SettingsData.set("notificationOverlayEnabled", toggled) onValueChanged: value => {
for (let i = 0; i < timeoutOptions.length; i++) {
if (timeoutOptions[i].text === value) {
SettingsData.set("notificationTimeoutNormal", timeoutOptions[i].value);
break;
}
}
}
} }
}
Item { DankDropdown {
width: parent.width text: I18n.tr("Critical Priority")
height: Math.max(privacyRow.implicitHeight, privacyToggle.implicitHeight) + Theme.spacingS description: I18n.tr("Timeout for critical priority notifications")
currentValue: getTimeoutText(SettingsData.notificationTimeoutCritical)
options: timeoutOptions.map(opt => opt.text)
onValueChanged: value => {
for (let i = 0; i < timeoutOptions.length; i++) {
if (timeoutOptions[i].text === value) {
SettingsData.set("notificationTimeoutCritical", timeoutOptions[i].value);
break;
}
}
}
}
Row { Rectangle {
id: privacyRow width: parent.width
anchors.left: parent.left height: 1
anchors.right: privacyToggle.left color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.1)
anchors.rightMargin: Theme.spacingM }
anchors.verticalCenter: parent.verticalCenter
spacing: Theme.spacingM
DankIcon { Item {
name: "privacy_tip" width: parent.width
size: Theme.iconSizeSmall height: Math.max(overlayRow.implicitHeight, overlayToggle.implicitHeight) + Theme.spacingS
color: SettingsData.notificationPopupPrivacyMode ? Theme.primary : Theme.surfaceText
Row {
id: overlayRow
anchors.left: parent.left
anchors.right: overlayToggle.left
anchors.rightMargin: Theme.spacingM
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
spacing: Theme.spacingM
DankIcon {
name: "notifications_active"
size: Theme.iconSizeSmall
color: SettingsData.notificationOverlayEnabled ? Theme.primary : Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
Column {
spacing: 2
anchors.verticalCenter: parent.verticalCenter
width: overlayRow.width - Theme.iconSizeSmall - Theme.spacingM
StyledText {
width: parent.width
text: I18n.tr("Notification Overlay")
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceText
wrapMode: Text.Wrap
}
StyledText {
width: parent.width
text: I18n.tr("Display all priorities over fullscreen apps")
font.pixelSize: Theme.fontSizeSmall - 1
color: Theme.surfaceVariantText
wrapMode: Text.Wrap
}
}
} }
Column { DankToggle {
spacing: 2 id: overlayToggle
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
width: privacyRow.width - Theme.iconSizeSmall - Theme.spacingM checked: SettingsData.notificationOverlayEnabled
onToggled: toggled => SettingsData.set("notificationOverlayEnabled", toggled)
}
}
Item {
width: parent.width
height: Math.max(privacyRow.implicitHeight, privacyToggle.implicitHeight) + Theme.spacingS
Row {
id: privacyRow
anchors.left: parent.left
anchors.right: privacyToggle.left
anchors.rightMargin: Theme.spacingM
anchors.verticalCenter: parent.verticalCenter
spacing: Theme.spacingM
DankIcon {
name: "privacy_tip"
size: Theme.iconSizeSmall
color: SettingsData.notificationPopupPrivacyMode ? Theme.primary : Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
Column {
spacing: 2
anchors.verticalCenter: parent.verticalCenter
width: privacyRow.width - Theme.iconSizeSmall - Theme.spacingM
StyledText {
width: parent.width
text: I18n.tr("Privacy Mode")
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceText
wrapMode: Text.Wrap
}
StyledText {
width: parent.width
text: I18n.tr("Hide notification content until expanded")
font.pixelSize: Theme.fontSizeSmall - 1
color: Theme.surfaceVariantText
wrapMode: Text.Wrap
}
}
}
DankToggle {
id: privacyToggle
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
checked: SettingsData.notificationPopupPrivacyMode
onToggled: toggled => SettingsData.set("notificationPopupPrivacyMode", toggled)
}
}
Rectangle {
width: parent.width
height: 1
color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.1)
}
StyledText {
text: I18n.tr("History Settings")
font.pixelSize: Theme.fontSizeSmall
font.weight: Font.Medium
color: Theme.surfaceVariantText
}
Item {
width: parent.width
height: Math.max(lowRow.implicitHeight, lowToggle.implicitHeight) + Theme.spacingS
Row {
id: lowRow
anchors.left: parent.left
anchors.verticalCenter: parent.verticalCenter
spacing: Theme.spacingM
DankIcon {
name: "low_priority"
size: Theme.iconSizeSmall
color: SettingsData.notificationHistorySaveLow ? Theme.primary : Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
StyledText { StyledText {
width: parent.width text: I18n.tr("Low Priority")
text: I18n.tr("Privacy Mode")
font.pixelSize: Theme.fontSizeSmall font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceText color: Theme.surfaceText
wrapMode: Text.Wrap anchors.verticalCenter: parent.verticalCenter
}
}
DankToggle {
id: lowToggle
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
checked: SettingsData.notificationHistorySaveLow
onToggled: toggled => SettingsData.set("notificationHistorySaveLow", toggled)
}
}
Item {
width: parent.width
height: Math.max(normalRow.implicitHeight, normalToggle.implicitHeight) + Theme.spacingS
Row {
id: normalRow
anchors.left: parent.left
anchors.verticalCenter: parent.verticalCenter
spacing: Theme.spacingM
DankIcon {
name: "notifications"
size: Theme.iconSizeSmall
color: SettingsData.notificationHistorySaveNormal ? Theme.primary : Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
} }
StyledText { StyledText {
width: parent.width text: I18n.tr("Normal Priority")
text: I18n.tr("Hide notification content until expanded") font.pixelSize: Theme.fontSizeSmall
font.pixelSize: Theme.fontSizeSmall - 1 color: Theme.surfaceText
color: Theme.surfaceVariantText anchors.verticalCenter: parent.verticalCenter
wrapMode: Text.Wrap
} }
} }
}
DankToggle { DankToggle {
id: privacyToggle id: normalToggle
anchors.right: parent.right anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
checked: SettingsData.notificationPopupPrivacyMode
onToggled: toggled => SettingsData.set("notificationPopupPrivacyMode", toggled)
}
}
Rectangle {
width: parent.width
height: 1
color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.1)
}
StyledText {
text: I18n.tr("History Settings")
font.pixelSize: Theme.fontSizeSmall
font.weight: Font.Medium
color: Theme.surfaceVariantText
}
Item {
width: parent.width
height: Math.max(lowRow.implicitHeight, lowToggle.implicitHeight) + Theme.spacingS
Row {
id: lowRow
anchors.left: parent.left
anchors.verticalCenter: parent.verticalCenter
spacing: Theme.spacingM
DankIcon {
name: "low_priority"
size: Theme.iconSizeSmall
color: SettingsData.notificationHistorySaveLow ? Theme.primary : Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
StyledText {
text: I18n.tr("Low Priority")
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
checked: SettingsData.notificationHistorySaveNormal
onToggled: toggled => SettingsData.set("notificationHistorySaveNormal", toggled)
} }
} }
DankToggle { Item {
id: lowToggle width: parent.width
anchors.right: parent.right height: Math.max(criticalRow.implicitHeight, criticalToggle.implicitHeight) + Theme.spacingS
anchors.verticalCenter: parent.verticalCenter
checked: SettingsData.notificationHistorySaveLow Row {
onToggled: toggled => SettingsData.set("notificationHistorySaveLow", toggled) id: criticalRow
anchors.left: parent.left
anchors.verticalCenter: parent.verticalCenter
spacing: Theme.spacingM
DankIcon {
name: "priority_high"
size: Theme.iconSizeSmall
color: SettingsData.notificationHistorySaveCritical ? Theme.primary : Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
StyledText {
text: I18n.tr("Critical Priority")
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
}
DankToggle {
id: criticalToggle
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
checked: SettingsData.notificationHistorySaveCritical
onToggled: toggled => SettingsData.set("notificationHistorySaveCritical", toggled)
}
} }
} }
Item {
width: parent.width
height: Math.max(normalRow.implicitHeight, normalToggle.implicitHeight) + Theme.spacingS
Row {
id: normalRow
anchors.left: parent.left
anchors.verticalCenter: parent.verticalCenter
spacing: Theme.spacingM
DankIcon {
name: "notifications"
size: Theme.iconSizeSmall
color: SettingsData.notificationHistorySaveNormal ? Theme.primary : Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
StyledText {
text: I18n.tr("Normal Priority")
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
}
DankToggle {
id: normalToggle
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
checked: SettingsData.notificationHistorySaveNormal
onToggled: toggled => SettingsData.set("notificationHistorySaveNormal", toggled)
}
}
Item {
width: parent.width
height: Math.max(criticalRow.implicitHeight, criticalToggle.implicitHeight) + Theme.spacingS
Row {
id: criticalRow
anchors.left: parent.left
anchors.verticalCenter: parent.verticalCenter
spacing: Theme.spacingM
DankIcon {
name: "priority_high"
size: Theme.iconSizeSmall
color: SettingsData.notificationHistorySaveCritical ? Theme.primary : Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
StyledText {
text: I18n.tr("Critical Priority")
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
}
DankToggle {
id: criticalToggle
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
checked: SettingsData.notificationHistorySaveCritical
onToggled: toggled => SettingsData.set("notificationHistorySaveCritical", toggled)
}
}
}
} }
} }

View File

@@ -36,10 +36,13 @@ PanelWindow {
WindowBlur { WindowBlur {
targetWindow: win targetWindow: win
blurX: content.x + content.cardInset + swipeTx.x + tx.x readonly property real s: Math.min(1, content.scale) * Math.max(0, content.opacity)
blurY: content.y + content.cardInset + swipeTx.y + tx.y readonly property real innerW: Math.max(0, content.width - content.cardInset * 2)
blurWidth: !win._finalized && !win.connectedFrameMode ? Math.max(0, content.width - content.cardInset * 2) : 0 readonly property real innerH: Math.max(0, content.height - content.cardInset * 2)
blurHeight: !win._finalized && !win.connectedFrameMode ? Math.max(0, content.height - content.cardInset * 2) : 0 blurX: content.x + content.cardInset + swipeTx.x + tx.x + innerW * (1 - s) * 0.5
blurY: content.y + content.cardInset + swipeTx.y + tx.y + innerH * (1 - s) * 0.5
blurWidth: !win._finalized && !win.connectedFrameMode ? innerW * s : 0
blurHeight: !win._finalized && !win.connectedFrameMode ? innerH * s : 0
blurRadius: win.connectedFrameMode ? Theme.connectedSurfaceRadius : Theme.cornerRadius blurRadius: win.connectedFrameMode ? Theme.connectedSurfaceRadius : Theme.cornerRadius
} }
@@ -993,7 +996,7 @@ PanelWindow {
z: 20 z: 20
Behavior on opacity { Behavior on opacity {
NumberAnimation { OpacityAnimator {
duration: Theme.shortDuration duration: Theme.shortDuration
easing.type: Theme.standardEasing easing.type: Theme.standardEasing
} }
@@ -1048,7 +1051,7 @@ PanelWindow {
visible: actionCount < 3 && cardHoverHandler.hovered visible: actionCount < 3 && cardHoverHandler.hovered
opacity: visible ? 1 : 0 opacity: visible ? 1 : 0
Behavior on opacity { Behavior on opacity {
NumberAnimation { OpacityAnimator {
duration: Theme.shortDuration duration: Theme.shortDuration
easing.type: Theme.standardEasing easing.type: Theme.standardEasing
} }
@@ -1136,7 +1139,7 @@ PanelWindow {
} }
onTranslationChanged: { onTranslationChanged: {
if (win.exiting) if (win.exiting || content.swipeDismissing)
return; return;
content.swipeOffset = translation.x; content.swipeOffset = translation.x;
@@ -1152,7 +1155,7 @@ PanelWindow {
} }
Behavior on opacity { Behavior on opacity {
enabled: !content.swipeActive enabled: !content.swipeActive && !content.swipeDismissing
NumberAnimation { NumberAnimation {
duration: Theme.shortDuration duration: Theme.shortDuration
} }
@@ -1269,7 +1272,6 @@ PanelWindow {
NumberAnimation { NumberAnimation {
target: content target: content
property: "opacity" property: "opacity"
from: 1
to: Theme.isDirectionalEffect ? 1 : 0 to: Theme.isDirectionalEffect ? 1 : 0
duration: Theme.notificationExitDuration duration: Theme.notificationExitDuration
easing.type: Easing.BezierSpline easing.type: Easing.BezierSpline
@@ -1279,7 +1281,6 @@ PanelWindow {
NumberAnimation { NumberAnimation {
target: content target: content
property: "scale" property: "scale"
from: 1
to: Theme.isDirectionalEffect ? 1 : Theme.effectScaleCollapsed to: Theme.isDirectionalEffect ? 1 : Theme.effectScaleCollapsed
duration: Theme.notificationExitDuration duration: Theme.notificationExitDuration
easing.type: Easing.BezierSpline easing.type: Easing.BezierSpline

View File

@@ -519,7 +519,7 @@ Item {
} }
Behavior on opacity { Behavior on opacity {
NumberAnimation { OpacityAnimator {
duration: Theme.shortDuration duration: Theme.shortDuration
easing.type: Theme.standardEasing easing.type: Theme.standardEasing
} }

View File

@@ -182,7 +182,7 @@ SettingsCard {
opacity: visible ? 1 : 0 opacity: visible ? 1 : 0
Behavior on opacity { Behavior on opacity {
NumberAnimation { OpacityAnimator {
duration: Theme.mediumDuration duration: Theme.mediumDuration
easing.type: Theme.emphasizedEasing easing.type: Theme.emphasizedEasing
} }

View File

@@ -107,7 +107,7 @@ Item {
} }
Behavior on opacity { Behavior on opacity {
NumberAnimation { OpacityAnimator {
duration: Theme.mediumDuration duration: Theme.mediumDuration
easing.type: Theme.emphasizedEasing easing.type: Theme.emphasizedEasing
} }

View File

@@ -587,7 +587,7 @@ FloatingWindow {
border.color: buttonState === "incompatible" ? Theme.warning : Theme.outline border.color: buttonState === "incompatible" ? Theme.warning : Theme.outline
Behavior on opacity { Behavior on opacity {
NumberAnimation { OpacityAnimator {
duration: Theme.shortDuration duration: Theme.shortDuration
easing.type: Theme.standardEasing easing.type: Theme.standardEasing
} }

View File

@@ -619,7 +619,7 @@ FloatingWindow {
border.color: isInstalled ? (uninstallMouseArea.containsMouse ? Theme.error : Theme.outline) : "transparent" border.color: isInstalled ? (uninstallMouseArea.containsMouse ? Theme.error : Theme.outline) : "transparent"
Behavior on opacity { Behavior on opacity {
NumberAnimation { OpacityAnimator {
duration: Theme.shortDuration duration: Theme.shortDuration
easing.type: Theme.standardEasing easing.type: Theme.standardEasing
} }

View File

@@ -380,7 +380,7 @@ Item {
} }
Behavior on scale { Behavior on scale {
NumberAnimation { ScaleAnimator {
duration: Theme.shortDuration duration: Theme.shortDuration
easing.type: Theme.emphasizedEasing easing.type: Theme.emphasizedEasing
} }
@@ -633,7 +633,7 @@ Item {
scale: isActive ? 1.03 : 1 scale: isActive ? 1.03 : 1
Behavior on scale { Behavior on scale {
NumberAnimation { ScaleAnimator {
duration: Theme.shortDuration duration: Theme.shortDuration
easing.type: Theme.emphasizedEasing easing.type: Theme.emphasizedEasing
} }
@@ -989,7 +989,7 @@ Item {
} }
Behavior on scale { Behavior on scale {
NumberAnimation { ScaleAnimator {
duration: Theme.shortDuration duration: Theme.shortDuration
easing.type: Theme.emphasizedEasing easing.type: Theme.emphasizedEasing
} }

View File

@@ -308,7 +308,7 @@ Column {
} }
Behavior on opacity { Behavior on opacity {
NumberAnimation { OpacityAnimator {
duration: Theme.shortDuration duration: Theme.shortDuration
easing.type: Theme.standardEasing easing.type: Theme.standardEasing
} }
@@ -620,7 +620,7 @@ Column {
} }
Behavior on opacity { Behavior on opacity {
NumberAnimation { OpacityAnimator {
duration: Theme.shortDuration duration: Theme.shortDuration
easing.type: Theme.standardEasing easing.type: Theme.standardEasing
} }

View File

@@ -97,7 +97,7 @@ Item {
} }
Behavior on opacity { Behavior on opacity {
NumberAnimation { OpacityAnimator {
duration: Theme.mediumDuration duration: Theme.mediumDuration
easing.type: Theme.emphasizedEasing easing.type: Theme.emphasizedEasing
} }

View File

@@ -416,7 +416,7 @@ PanelWindow {
} }
Behavior on opacity { Behavior on opacity {
NumberAnimation { OpacityAnimator {
duration: Theme.mediumDuration duration: Theme.mediumDuration
easing.type: Theme.emphasizedEasing easing.type: Theme.emphasizedEasing
} }

View File

@@ -48,268 +48,271 @@ Scope {
bottom: true bottom: true
} }
HyprlandFocusGrab { HyprlandFocusGrab {
id: grab id: grab
windows: [root] windows: [root]
active: false active: false
property bool hasBeenActivated: false property bool hasBeenActivated: false
onActiveChanged: { onActiveChanged: {
if (active) { if (active) {
hasBeenActivated = true hasBeenActivated = true;
}
}
onCleared: () => {
if (hasBeenActivated && overviewScope.overviewOpen) {
overviewScope.overviewOpen = false
}
}
}
Connections {
target: overviewScope
function onOverviewOpenChanged() {
if (overviewScope.overviewOpen) {
grab.hasBeenActivated = false
if (CompositorService.useHyprlandFocusGrab)
delayedGrabTimer.start()
} else {
delayedGrabTimer.stop()
grab.active = false
grab.hasBeenActivated = false
}
}
}
Connections {
target: root
function onMonitorIsFocusedChanged() {
if (!CompositorService.useHyprlandFocusGrab)
return;
if (overviewScope.overviewOpen && root.monitorIsFocused && !grab.active) {
grab.hasBeenActivated = false
grab.active = true
} else if (overviewScope.overviewOpen && !root.monitorIsFocused && grab.active) {
grab.active = false
}
}
}
Timer {
id: delayedGrabTimer
interval: 150
repeat: false
onTriggered: {
if (CompositorService.useHyprlandFocusGrab && overviewScope.overviewOpen && root.monitorIsFocused) {
grab.active = true
}
}
}
Timer {
id: closeTimer
interval: Theme.expressiveDurations.expressiveDefaultSpatial + 120
onTriggered: {
root.visible = false
}
}
Rectangle {
id: background
anchors.fill: parent
color: "black"
opacity: overviewScope.overviewOpen ? 0.5 : 0
Behavior on opacity {
NumberAnimation {
duration: Theme.variantDuration(Theme.expressiveDurations.expressiveDefaultSpatial, overviewScope.overviewOpen)
easing.type: Easing.BezierSpline
easing.bezierCurve: overviewScope.overviewOpen ? Theme.variantModalEnterCurve : Theme.variantModalExitCurve
}
}
MouseArea {
anchors.fill: parent
onClicked: mouse => {
const localPos = mapToItem(contentContainer, mouse.x, mouse.y)
if (localPos.x < 0 || localPos.x > contentContainer.width || localPos.y < 0 || localPos.y > contentContainer.height) {
overviewScope.overviewOpen = false
closeTimer.restart()
} }
} }
} onCleared: () => {
} if (hasBeenActivated && overviewScope.overviewOpen) {
overviewScope.overviewOpen = false;
Item {
id: contentContainer
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: parent.top
anchors.topMargin: 100
width: childrenRect.width
height: childrenRect.height
opacity: overviewScope.overviewOpen ? 1 : 0
transform: [scaleTransform, motionTransform]
Scale {
id: scaleTransform
origin.x: contentContainer.width / 2
origin.y: contentContainer.height / 2
xScale: overviewScope.overviewOpen ? 1 : Theme.effectScaleCollapsed
yScale: overviewScope.overviewOpen ? 1 : Theme.effectScaleCollapsed
Behavior on xScale {
NumberAnimation {
duration: Theme.variantDuration(Theme.expressiveDurations.expressiveDefaultSpatial, overviewScope.overviewOpen)
easing.type: Easing.BezierSpline
easing.bezierCurve: overviewScope.overviewOpen ? Theme.variantModalEnterCurve : Theme.variantModalExitCurve
}
}
Behavior on yScale {
NumberAnimation {
duration: Theme.variantDuration(Theme.expressiveDurations.expressiveDefaultSpatial, overviewScope.overviewOpen)
easing.type: Easing.BezierSpline
easing.bezierCurve: overviewScope.overviewOpen ? Theme.variantModalEnterCurve : Theme.variantModalExitCurve
} }
} }
} }
Translate { Connections {
id: motionTransform target: overviewScope
x: { function onOverviewOpenChanged() {
if (overviewScope.overviewOpen) if (overviewScope.overviewOpen) {
return 0; grab.hasBeenActivated = false;
if (Theme.isDirectionalEffect) if (CompositorService.useHyprlandFocusGrab)
return 0; delayedGrabTimer.start();
if (Theme.isDepthEffect)
return Theme.effectAnimOffset * 0.25;
return 0;
}
y: {
if (overviewScope.overviewOpen)
return 0;
if (Theme.isDirectionalEffect)
return -Math.max(contentContainer.height * 0.8, Theme.effectAnimOffset * 1.1);
if (Theme.isDepthEffect)
return Math.max(Theme.effectAnimOffset * 0.85, 28);
return Theme.effectAnimOffset;
}
Behavior on x {
NumberAnimation {
duration: Theme.variantDuration(Theme.expressiveDurations.expressiveDefaultSpatial, overviewScope.overviewOpen)
easing.type: Easing.BezierSpline
easing.bezierCurve: overviewScope.overviewOpen ? Theme.variantModalEnterCurve : Theme.variantModalExitCurve
}
}
Behavior on y {
NumberAnimation {
duration: Theme.variantDuration(Theme.expressiveDurations.expressiveDefaultSpatial, overviewScope.overviewOpen)
easing.type: Easing.BezierSpline
easing.bezierCurve: overviewScope.overviewOpen ? Theme.variantModalEnterCurve : Theme.variantModalExitCurve
}
}
}
Behavior on opacity {
NumberAnimation {
duration: Theme.variantDuration(Theme.expressiveDurations.expressiveDefaultSpatial, overviewScope.overviewOpen)
easing.type: Easing.BezierSpline
easing.bezierCurve: overviewScope.overviewOpen ? Theme.variantModalEnterCurve : Theme.variantModalExitCurve
}
}
Loader {
id: overviewLoader
active: overviewScope.overviewOpen
asynchronous: false
sourceComponent: OverviewWidget {
panelWindow: root
overviewOpen: overviewScope.overviewOpen
}
}
}
FocusScope {
id: focusScope
anchors.fill: parent
visible: overviewScope.overviewOpen
focus: overviewScope.overviewOpen && root.monitorIsFocused
Keys.onEscapePressed: event => {
if (!root.monitorIsFocused) return
overviewScope.overviewOpen = false
closeTimer.restart()
event.accepted = true
}
Keys.onPressed: event => {
if (!root.monitorIsFocused) return
if (event.key === Qt.Key_Left || event.key === Qt.Key_Right) {
if (!overviewLoader.item) return
const thisMonitorWorkspaceIds = overviewLoader.item.thisMonitorWorkspaceIds
if (thisMonitorWorkspaceIds.length === 0) return
const currentId = root.monitor.activeWorkspace?.id ?? thisMonitorWorkspaceIds[0]
const currentIndex = thisMonitorWorkspaceIds.indexOf(currentId)
let targetIndex
if (event.key === Qt.Key_Left) {
targetIndex = currentIndex - 1
if (targetIndex < 0) targetIndex = thisMonitorWorkspaceIds.length - 1
} else { } else {
targetIndex = currentIndex + 1 delayedGrabTimer.stop();
if (targetIndex >= thisMonitorWorkspaceIds.length) targetIndex = 0 grab.active = false;
grab.hasBeenActivated = false;
} }
const targetId = thisMonitorWorkspaceIds[targetIndex]
Hyprland.dispatch("workspace " + targetId)
event.accepted = true
}
}
onVisibleChanged: {
if (visible && overviewScope.overviewOpen && root.monitorIsFocused) {
Qt.callLater(() => focusScope.forceActiveFocus())
} }
} }
Connections { Connections {
target: root target: root
function onMonitorIsFocusedChanged() { function onMonitorIsFocusedChanged() {
if (root.monitorIsFocused && overviewScope.overviewOpen) { if (!CompositorService.useHyprlandFocusGrab)
Qt.callLater(() => focusScope.forceActiveFocus()) return;
if (overviewScope.overviewOpen && root.monitorIsFocused && !grab.active) {
grab.hasBeenActivated = false;
grab.active = true;
} else if (overviewScope.overviewOpen && !root.monitorIsFocused && grab.active) {
grab.active = false;
}
}
}
Timer {
id: delayedGrabTimer
interval: 150
repeat: false
onTriggered: {
if (CompositorService.useHyprlandFocusGrab && overviewScope.overviewOpen && root.monitorIsFocused) {
grab.active = true;
}
}
}
Timer {
id: closeTimer
interval: Theme.expressiveDurations.expressiveDefaultSpatial + 120
onTriggered: {
root.visible = false;
}
}
Rectangle {
id: background
anchors.fill: parent
color: "black"
opacity: overviewScope.overviewOpen ? 0.5 : 0
Behavior on opacity {
OpacityAnimator {
duration: Theme.variantDuration(Theme.expressiveDurations.expressiveDefaultSpatial, overviewScope.overviewOpen)
easing.type: Easing.BezierSpline
easing.bezierCurve: overviewScope.overviewOpen ? Theme.variantModalEnterCurve : Theme.variantModalExitCurve
}
}
MouseArea {
anchors.fill: parent
onClicked: mouse => {
const localPos = mapToItem(contentContainer, mouse.x, mouse.y);
if (localPos.x < 0 || localPos.x > contentContainer.width || localPos.y < 0 || localPos.y > contentContainer.height) {
overviewScope.overviewOpen = false;
closeTimer.restart();
}
}
}
}
Item {
id: contentContainer
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: parent.top
anchors.topMargin: 100
width: childrenRect.width
height: childrenRect.height
opacity: overviewScope.overviewOpen ? 1 : 0
transform: [scaleTransform, motionTransform]
Scale {
id: scaleTransform
origin.x: contentContainer.width / 2
origin.y: contentContainer.height / 2
xScale: overviewScope.overviewOpen ? 1 : Theme.effectScaleCollapsed
yScale: overviewScope.overviewOpen ? 1 : Theme.effectScaleCollapsed
Behavior on xScale {
NumberAnimation {
duration: Theme.variantDuration(Theme.expressiveDurations.expressiveDefaultSpatial, overviewScope.overviewOpen)
easing.type: Easing.BezierSpline
easing.bezierCurve: overviewScope.overviewOpen ? Theme.variantModalEnterCurve : Theme.variantModalExitCurve
}
}
Behavior on yScale {
NumberAnimation {
duration: Theme.variantDuration(Theme.expressiveDurations.expressiveDefaultSpatial, overviewScope.overviewOpen)
easing.type: Easing.BezierSpline
easing.bezierCurve: overviewScope.overviewOpen ? Theme.variantModalEnterCurve : Theme.variantModalExitCurve
}
}
}
Translate {
id: motionTransform
x: {
if (overviewScope.overviewOpen)
return 0;
if (Theme.isDirectionalEffect)
return 0;
if (Theme.isDepthEffect)
return Theme.effectAnimOffset * 0.25;
return 0;
}
y: {
if (overviewScope.overviewOpen)
return 0;
if (Theme.isDirectionalEffect)
return -Math.max(contentContainer.height * 0.8, Theme.effectAnimOffset * 1.1);
if (Theme.isDepthEffect)
return Math.max(Theme.effectAnimOffset * 0.85, 28);
return Theme.effectAnimOffset;
}
Behavior on x {
NumberAnimation {
duration: Theme.variantDuration(Theme.expressiveDurations.expressiveDefaultSpatial, overviewScope.overviewOpen)
easing.type: Easing.BezierSpline
easing.bezierCurve: overviewScope.overviewOpen ? Theme.variantModalEnterCurve : Theme.variantModalExitCurve
}
}
Behavior on y {
NumberAnimation {
duration: Theme.variantDuration(Theme.expressiveDurations.expressiveDefaultSpatial, overviewScope.overviewOpen)
easing.type: Easing.BezierSpline
easing.bezierCurve: overviewScope.overviewOpen ? Theme.variantModalEnterCurve : Theme.variantModalExitCurve
}
}
}
Behavior on opacity {
OpacityAnimator {
duration: Theme.variantDuration(Theme.expressiveDurations.expressiveDefaultSpatial, overviewScope.overviewOpen)
easing.type: Easing.BezierSpline
easing.bezierCurve: overviewScope.overviewOpen ? Theme.variantModalEnterCurve : Theme.variantModalExitCurve
}
}
Loader {
id: overviewLoader
active: overviewScope.overviewOpen
asynchronous: false
sourceComponent: OverviewWidget {
panelWindow: root
overviewOpen: overviewScope.overviewOpen
}
}
}
FocusScope {
id: focusScope
anchors.fill: parent
visible: overviewScope.overviewOpen
focus: overviewScope.overviewOpen && root.monitorIsFocused
Keys.onEscapePressed: event => {
if (!root.monitorIsFocused)
return;
overviewScope.overviewOpen = false;
closeTimer.restart();
event.accepted = true;
}
Keys.onPressed: event => {
if (!root.monitorIsFocused)
return;
if (event.key === Qt.Key_Left || event.key === Qt.Key_Right) {
if (!overviewLoader.item)
return;
const thisMonitorWorkspaceIds = overviewLoader.item.thisMonitorWorkspaceIds;
if (thisMonitorWorkspaceIds.length === 0)
return;
const currentId = root.monitor.activeWorkspace?.id ?? thisMonitorWorkspaceIds[0];
const currentIndex = thisMonitorWorkspaceIds.indexOf(currentId);
let targetIndex;
if (event.key === Qt.Key_Left) {
targetIndex = currentIndex - 1;
if (targetIndex < 0)
targetIndex = thisMonitorWorkspaceIds.length - 1;
} else {
targetIndex = currentIndex + 1;
if (targetIndex >= thisMonitorWorkspaceIds.length)
targetIndex = 0;
}
const targetId = thisMonitorWorkspaceIds[targetIndex];
Hyprland.dispatch("workspace " + targetId);
event.accepted = true;
}
}
onVisibleChanged: {
if (visible && overviewScope.overviewOpen && root.monitorIsFocused) {
Qt.callLater(() => focusScope.forceActiveFocus());
}
}
Connections {
target: root
function onMonitorIsFocusedChanged() {
if (root.monitorIsFocused && overviewScope.overviewOpen) {
Qt.callLater(() => focusScope.forceActiveFocus());
}
}
}
}
onVisibleChanged: {
if (visible && overviewScope.overviewOpen) {
Qt.callLater(() => focusScope.forceActiveFocus());
} else if (!visible) {
grab.active = false;
}
}
Connections {
target: overviewScope
function onOverviewOpenChanged() {
if (overviewScope.overviewOpen) {
closeTimer.stop();
root.visible = true;
Qt.callLater(() => focusScope.forceActiveFocus());
} else {
closeTimer.restart();
grab.active = false;
} }
} }
} }
} }
onVisibleChanged: {
if (visible && overviewScope.overviewOpen) {
Qt.callLater(() => focusScope.forceActiveFocus())
} else if (!visible) {
grab.active = false
}
}
Connections {
target: overviewScope
function onOverviewOpenChanged() {
if (overviewScope.overviewOpen) {
closeTimer.stop()
root.visible = true
Qt.callLater(() => focusScope.forceActiveFocus())
} else {
closeTimer.restart()
grab.active = false
}
}
}
}
} }
} }
} }

View File

@@ -28,7 +28,8 @@ Rectangle {
Behavior on scale { Behavior on scale {
enabled: enableScaleAnimation && Theme.currentAnimationSpeed !== SettingsData.AnimationSpeed.None enabled: enableScaleAnimation && Theme.currentAnimationSpeed !== SettingsData.AnimationSpeed.None
DankAnim { ScaleAnimator {
easing.type: Easing.BezierSpline
duration: 100 duration: 100
easing.bezierCurve: Theme.expressiveCurves.standard easing.bezierCurve: Theme.expressiveCurves.standard
} }

View File

@@ -197,7 +197,7 @@ Row {
Behavior on opacity { Behavior on opacity {
enabled: root.userInteracted enabled: root.userInteracted
NumberAnimation { OpacityAnimator {
duration: Theme.shortDuration duration: Theme.shortDuration
easing.type: Theme.standardEasing easing.type: Theme.standardEasing
} }
@@ -205,7 +205,7 @@ Row {
Behavior on scale { Behavior on scale {
enabled: root.userInteracted enabled: root.userInteracted
NumberAnimation { ScaleAnimator {
duration: Theme.shortDuration duration: Theme.shortDuration
easing.type: Theme.emphasizedEasing easing.type: Theme.emphasizedEasing
} }

View File

@@ -45,7 +45,8 @@ ColumnLayout {
Behavior on rotation { Behavior on rotation {
enabled: Theme.currentAnimationSpeed !== SettingsData.AnimationSpeed.None enabled: Theme.currentAnimationSpeed !== SettingsData.AnimationSpeed.None
DankAnim { RotationAnimator {
easing.type: Easing.BezierSpline
duration: Theme.shortDuration duration: Theme.shortDuration
easing.bezierCurve: Theme.expressiveCurves.standard easing.bezierCurve: Theme.expressiveCurves.standard
} }
@@ -88,7 +89,8 @@ ColumnLayout {
Behavior on opacity { Behavior on opacity {
enabled: Theme.currentAnimationSpeed !== SettingsData.AnimationSpeed.None enabled: Theme.currentAnimationSpeed !== SettingsData.AnimationSpeed.None
DankAnim { OpacityAnimator {
easing.type: Easing.BezierSpline
duration: Theme.shortDuration duration: Theme.shortDuration
easing.bezierCurve: Theme.expressiveCurves.standard easing.bezierCurve: Theme.expressiveCurves.standard
} }
@@ -108,7 +110,8 @@ ColumnLayout {
Behavior on opacity { Behavior on opacity {
enabled: Theme.currentAnimationSpeed !== SettingsData.AnimationSpeed.None enabled: Theme.currentAnimationSpeed !== SettingsData.AnimationSpeed.None
DankAnim { OpacityAnimator {
easing.type: Easing.BezierSpline
duration: Theme.shortDuration duration: Theme.shortDuration
easing.bezierCurve: Theme.expressiveCurves.standard easing.bezierCurve: Theme.expressiveCurves.standard
} }

View File

@@ -187,7 +187,7 @@ Item {
anchors.rightMargin: Theme.spacingS anchors.rightMargin: Theme.spacingS
Behavior on rotation { Behavior on rotation {
NumberAnimation { RotationAnimator {
duration: Theme.shortDuration duration: Theme.shortDuration
easing.type: Theme.standardEasing easing.type: Theme.standardEasing
} }

View File

@@ -157,7 +157,7 @@ Item {
opacity: (locationInput.getActiveFocus() && locationInput.text.length > 2) ? 1 : 0 opacity: (locationInput.getActiveFocus() && locationInput.text.length > 2) ? 1 : 0
Behavior on opacity { Behavior on opacity {
NumberAnimation { OpacityAnimator {
duration: Theme.shortDuration duration: Theme.shortDuration
easing.type: Theme.standardEasing easing.type: Theme.standardEasing
} }

View File

@@ -315,14 +315,14 @@ PanelWindow {
} }
Behavior on opacity { Behavior on opacity {
NumberAnimation { OpacityAnimator {
duration: animationDuration duration: animationDuration
easing.type: animationEasing easing.type: animationEasing
} }
} }
Behavior on scale { Behavior on scale {
NumberAnimation { ScaleAnimator {
duration: animationDuration duration: animationDuration
easing.type: animationEasing easing.type: animationEasing
} }

View File

@@ -273,13 +273,44 @@ Item {
}); });
} }
property bool _animSyncQueued: false
function _queueAnimSync() {
if (_animSyncQueued)
return;
_animSyncQueued = true;
Qt.callLater(() => {
if (root && typeof root._flushAnimSync === "function")
root._flushAnimSync();
});
}
function _flushAnimSync() {
_animSyncQueued = false;
_syncPopoutAnim("x");
_syncPopoutAnim("y");
}
property bool _bodySyncQueued: false
function _queueBodySync() {
if (_bodySyncQueued)
return;
_bodySyncQueued = true;
Qt.callLater(() => {
if (root && typeof root._flushBodySync === "function")
root._flushBodySync();
});
}
function _flushBodySync() {
_bodySyncQueued = false;
_syncPopoutBody();
}
onAlignedXChanged: _queueFullSync() onAlignedXChanged: _queueFullSync()
onAlignedYChanged: _queueFullSync() onAlignedYChanged: _queueFullSync()
onAlignedWidthChanged: _queueFullSync() onAlignedWidthChanged: _queueFullSync()
onContentAnimXChanged: _syncPopoutAnim("x") onContentAnimXChanged: _queueAnimSync()
onContentAnimYChanged: _syncPopoutAnim("y") onContentAnimYChanged: _queueAnimSync()
onRenderedAlignedYChanged: _syncPopoutBody() onRenderedAlignedYChanged: _queueBodySync()
onRenderedAlignedHeightChanged: _syncPopoutBody() onRenderedAlignedHeightChanged: _queueBodySync()
onScreenChanged: _queueFullSync() onScreenChanged: _queueFullSync()
onEffectiveBarPositionChanged: _queueFullSync() onEffectiveBarPositionChanged: _queueFullSync()
@@ -676,8 +707,8 @@ Item {
blurX: trackBlurFromBarEdge ? contentContainer.x + (contentContainer.barRight ? _dxClamp : 0) : contentContainer.x + contentContainer.width * (1 - s) * 0.5 + Theme.snap(contentContainer.animX, root.dpr) - contentContainer.horizontalConnectorExtent * s blurX: trackBlurFromBarEdge ? contentContainer.x + (contentContainer.barRight ? _dxClamp : 0) : contentContainer.x + contentContainer.width * (1 - s) * 0.5 + Theme.snap(contentContainer.animX, root.dpr) - contentContainer.horizontalConnectorExtent * s
blurY: trackBlurFromBarEdge ? contentContainer.y + (contentContainer.barBottom ? _dyClamp : 0) : contentContainer.y + contentContainer.height * (1 - s) * 0.5 + Theme.snap(contentContainer.animY, root.dpr) - contentContainer.verticalConnectorExtent * s blurY: trackBlurFromBarEdge ? contentContainer.y + (contentContainer.barBottom ? _dyClamp : 0) : contentContainer.y + contentContainer.height * (1 - s) * 0.5 + Theme.snap(contentContainer.animY, root.dpr) - contentContainer.verticalConnectorExtent * s
blurWidth: (shouldBeVisible && contentWrapper.opacity > 0) ? (trackBlurFromBarEdge ? Math.max(0, contentContainer.width - Math.abs(_dxClamp)) : (contentContainer.width + contentContainer.horizontalConnectorExtent * 2) * s) : 0 blurWidth: (shouldBeVisible && contentWrapper.publishedOpacity > 0) ? (trackBlurFromBarEdge ? Math.max(0, contentContainer.width - Math.abs(_dxClamp)) : (contentContainer.width + contentContainer.horizontalConnectorExtent * 2) * s) : 0
blurHeight: (shouldBeVisible && contentWrapper.opacity > 0) ? (trackBlurFromBarEdge ? Math.max(0, contentContainer.height - Math.abs(_dyClamp)) : (contentContainer.height + contentContainer.verticalConnectorExtent * 2) * s) : 0 blurHeight: (shouldBeVisible && contentWrapper.publishedOpacity > 0) ? (trackBlurFromBarEdge ? Math.max(0, contentContainer.height - Math.abs(_dyClamp)) : (contentContainer.height + contentContainer.verticalConnectorExtent * 2) * s) : 0
blurRadius: Theme.isConnectedEffect ? Theme.connectedCornerRadius : Theme.connectedSurfaceRadius blurRadius: Theme.isConnectedEffect ? Theme.connectedCornerRadius : Theme.connectedSurfaceRadius
} }
@@ -959,7 +990,7 @@ Item {
width: rollOutAdjuster.baseWidth + extraLeft + extraRight width: rollOutAdjuster.baseWidth + extraLeft + extraRight
height: rollOutAdjuster.baseHeight + extraTop + extraBottom height: rollOutAdjuster.baseHeight + extraTop + extraBottom
opacity: contentWrapper.opacity opacity: contentWrapper.publishedOpacity
scale: contentWrapper.scale scale: contentWrapper.scale
x: contentWrapper.x - extraLeft x: contentWrapper.x - extraLeft
y: contentWrapper.y - extraTop y: contentWrapper.y - extraTop
@@ -1024,23 +1055,48 @@ Item {
id: contentWrapper id: contentWrapper
width: rollOutAdjuster.baseWidth width: rollOutAdjuster.baseWidth
height: rollOutAdjuster.baseHeight height: rollOutAdjuster.baseHeight
property bool _renderActive: Theme.isDirectionalEffect || shouldBeVisible
property bool _animating: false
property real publishedOpacity: Theme.isDirectionalEffect ? 1 : (shouldBeVisible ? 1 : 0)
opacity: Theme.isDirectionalEffect ? 1 : (shouldBeVisible ? 1 : 0) opacity: Theme.isDirectionalEffect ? 1 : (shouldBeVisible ? 1 : 0)
visible: opacity > 0 visible: _renderActive
scale: contentContainer.scaleValue scale: contentContainer.scaleValue
x: Theme.snap(contentContainer.animX + (rollOutAdjuster.baseWidth - width) * (1 - scale) * 0.5, root.dpr) x: Theme.snap(contentContainer.animX + (rollOutAdjuster.baseWidth - width) * (1 - scale) * 0.5, root.dpr)
y: Theme.snap(contentContainer.animY + (rollOutAdjuster.baseHeight - height) * (1 - scale) * 0.5, root.dpr) y: Theme.snap(contentContainer.animY + (rollOutAdjuster.baseHeight - height) * (1 - scale) * 0.5, root.dpr)
layer.enabled: contentWrapper.opacity < 1 layer.enabled: _animating || (!Theme.isDirectionalEffect && publishedOpacity < 1)
layer.smooth: false layer.smooth: false
layer.textureSize: root.dpr > 1 ? Qt.size(Math.ceil(width * root.dpr), Math.ceil(height * root.dpr)) : Qt.size(0, 0) layer.textureSize: root.dpr > 1 ? Qt.size(Math.ceil(width * root.dpr), Math.ceil(height * root.dpr)) : Qt.size(0, 0)
Behavior on opacity { Behavior on opacity {
enabled: !Theme.isDirectionalEffect
OpacityAnimator {
duration: Math.round(Theme.variantDuration(animationDuration, shouldBeVisible) * Theme.variantOpacityDurationScale)
easing.type: Easing.BezierSpline
easing.bezierCurve: root.shouldBeVisible ? root.animationEnterCurve : root.animationExitCurve
onRunningChanged: contentWrapper._animating = running
}
}
Behavior on publishedOpacity {
enabled: !Theme.isDirectionalEffect enabled: !Theme.isDirectionalEffect
NumberAnimation { NumberAnimation {
duration: Math.round(Theme.variantDuration(animationDuration, shouldBeVisible) * Theme.variantOpacityDurationScale) duration: Math.round(Theme.variantDuration(animationDuration, shouldBeVisible) * Theme.variantOpacityDurationScale)
easing.type: Easing.BezierSpline easing.type: Easing.BezierSpline
easing.bezierCurve: root.shouldBeVisible ? root.animationEnterCurve : root.animationExitCurve easing.bezierCurve: root.shouldBeVisible ? root.animationEnterCurve : root.animationExitCurve
onRunningChanged: if (!running && contentWrapper.publishedOpacity === 0)
contentWrapper._renderActive = false
}
}
Connections {
target: root
function onShouldBeVisibleChanged() {
if (root.shouldBeVisible)
contentWrapper._renderActive = true;
} }
} }

View File

@@ -527,7 +527,7 @@ Item {
targetWindow: contentWindow targetWindow: contentWindow
readonly property real s: Math.min(1, contentContainer.scaleValue) readonly property real s: Math.min(1, contentContainer.scaleValue)
readonly property bool trackBlurFromBarEdge: root.fluidStandaloneActive readonly property bool trackBlurFromBarEdge: root.fluidStandaloneActive
readonly property bool blurAlive: trackBlurFromBarEdge ? (contentContainer.revealWidth > 0 && contentContainer.revealHeight > 0) : (root.shouldBeVisible && contentWrapper.opacity > 0) readonly property bool blurAlive: trackBlurFromBarEdge ? (contentContainer.revealWidth > 0 && contentContainer.revealHeight > 0) : (root.shouldBeVisible && contentWrapper.publishedOpacity > 0)
blurX: trackBlurFromBarEdge ? contentContainer.x + contentContainer.revealX : contentContainer.x + contentContainer.width * (1 - s) * 0.5 + Theme.snap(contentContainer.animX, root.dpr) blurX: trackBlurFromBarEdge ? contentContainer.x + contentContainer.revealX : contentContainer.x + contentContainer.width * (1 - s) * 0.5 + Theme.snap(contentContainer.animX, root.dpr)
blurY: trackBlurFromBarEdge ? contentContainer.y + contentContainer.revealY : contentContainer.y + contentContainer.height * (1 - s) * 0.5 + Theme.snap(contentContainer.animY, root.dpr) blurY: trackBlurFromBarEdge ? contentContainer.y + contentContainer.revealY : contentContainer.y + contentContainer.height * (1 - s) * 0.5 + Theme.snap(contentContainer.animY, root.dpr)
@@ -595,9 +595,7 @@ Item {
Item { Item {
id: contentContainer id: contentContainer
x: shadowBuffer + root.alignedX - root._surfaceBodyX x: shadowBuffer + root.alignedX - root._surfaceBodyX
y: root._fullHeight y: root._fullHeight ? (root.fluidStandaloneActive ? root.renderedAlignedY : root.alignedY) : shadowBuffer + (root.fluidStandaloneActive ? root.renderedAlignedY : root.alignedY) - root._surfaceBodyY
? (root.fluidStandaloneActive ? root.renderedAlignedY : root.alignedY)
: shadowBuffer + (root.fluidStandaloneActive ? root.renderedAlignedY : root.alignedY) - root._surfaceBodyY
width: root.alignedWidth width: root.alignedWidth
height: root.fluidStandaloneActive ? root.renderedAlignedHeight : root.alignedHeight height: root.fluidStandaloneActive ? root.renderedAlignedHeight : root.alignedHeight
@@ -759,7 +757,7 @@ Item {
id: shadowSource id: shadowSource
width: rollOutAdjuster.baseWidth width: rollOutAdjuster.baseWidth
height: rollOutAdjuster.baseHeight height: rollOutAdjuster.baseHeight
opacity: contentWrapper.opacity opacity: contentWrapper.publishedOpacity
scale: root.fluidStandaloneActive ? 1 : contentWrapper.scale scale: root.fluidStandaloneActive ? 1 : contentWrapper.scale
x: root.fluidStandaloneActive ? 0 : contentWrapper.x x: root.fluidStandaloneActive ? 0 : contentWrapper.x
y: root.fluidStandaloneActive ? 0 : contentWrapper.y y: root.fluidStandaloneActive ? 0 : contentWrapper.y
@@ -775,23 +773,52 @@ Item {
id: contentWrapper id: contentWrapper
width: rollOutAdjuster.baseWidth width: rollOutAdjuster.baseWidth
height: rollOutAdjuster.baseHeight height: rollOutAdjuster.baseHeight
// _renderActive pins visibility/layer for the full transition; flipped true on shouldBeVisible rising,
// false only after the close animation completes. publishedOpacity tracks Item.opacity but on the GUI
// thread so consumers (WindowBlur, ElevationShadow, sibling rect) see interpolated values while the
// visual runs on the render thread via OpacityAnimator.
property bool _renderActive: Theme.isDirectionalEffect || shouldBeVisible
property bool _animating: false
property real publishedOpacity: Theme.isDirectionalEffect ? 1 : (shouldBeVisible ? 1 : 0)
opacity: Theme.isDirectionalEffect ? 1 : (shouldBeVisible ? 1 : 0) opacity: Theme.isDirectionalEffect ? 1 : (shouldBeVisible ? 1 : 0)
visible: opacity > 0 visible: _renderActive
scale: contentContainer.scaleValue scale: contentContainer.scaleValue
transformOrigin: Item.Center transformOrigin: Item.Center
x: Theme.snap(contentContainer.animX + (rollOutAdjuster.baseWidth - width) * (1 - contentContainer.scaleValue) * 0.5, root.dpr) x: Theme.snap(contentContainer.animX + (rollOutAdjuster.baseWidth - width) * (1 - contentContainer.scaleValue) * 0.5, root.dpr)
y: Theme.snap(contentContainer.animY + (rollOutAdjuster.baseHeight - height) * (1 - contentContainer.scaleValue) * 0.5, root.dpr) y: Theme.snap(contentContainer.animY + (rollOutAdjuster.baseHeight - height) * (1 - contentContainer.scaleValue) * 0.5, root.dpr)
layer.enabled: contentWrapper.opacity < 1 layer.enabled: _animating || (!Theme.isDirectionalEffect && publishedOpacity < 1)
layer.smooth: false layer.smooth: false
layer.textureSize: root.dpr > 1 ? Qt.size(Math.ceil(width * root.dpr), Math.ceil(height * root.dpr)) : Qt.size(0, 0) layer.textureSize: root.dpr > 1 ? Qt.size(Math.ceil(width * root.dpr), Math.ceil(height * root.dpr)) : Qt.size(0, 0)
Behavior on opacity { Behavior on opacity {
enabled: !Theme.isDirectionalEffect
OpacityAnimator {
duration: Math.round(Theme.variantDuration(root.animationDuration, root.shouldBeVisible) * Theme.variantOpacityDurationScale)
easing.type: Easing.BezierSpline
easing.bezierCurve: root.shouldBeVisible ? root.animationEnterCurve : root.animationExitCurve
onRunningChanged: contentWrapper._animating = running
}
}
Behavior on publishedOpacity {
enabled: !Theme.isDirectionalEffect enabled: !Theme.isDirectionalEffect
NumberAnimation { NumberAnimation {
duration: Math.round(Theme.variantDuration(root.animationDuration, root.shouldBeVisible) * Theme.variantOpacityDurationScale) duration: Math.round(Theme.variantDuration(root.animationDuration, root.shouldBeVisible) * Theme.variantOpacityDurationScale)
easing.type: Easing.BezierSpline easing.type: Easing.BezierSpline
easing.bezierCurve: root.shouldBeVisible ? root.animationEnterCurve : root.animationExitCurve easing.bezierCurve: root.shouldBeVisible ? root.animationEnterCurve : root.animationExitCurve
onRunningChanged: if (!running && contentWrapper.publishedOpacity === 0)
contentWrapper._renderActive = false
}
}
Connections {
target: root
function onShouldBeVisibleChanged() {
if (root.shouldBeVisible)
contentWrapper._renderActive = true;
} }
} }
@@ -808,7 +835,7 @@ Item {
height: rollOutAdjuster.baseHeight height: rollOutAdjuster.baseHeight
x: root.fluidStandaloneActive ? 0 : contentWrapper.x x: root.fluidStandaloneActive ? 0 : contentWrapper.x
y: root.fluidStandaloneActive ? 0 : contentWrapper.y y: root.fluidStandaloneActive ? 0 : contentWrapper.y
opacity: contentWrapper.opacity opacity: contentWrapper.publishedOpacity
scale: root.fluidStandaloneActive ? 1 : contentWrapper.scale scale: root.fluidStandaloneActive ? 1 : contentWrapper.scale
visible: contentWrapper.visible visible: contentWrapper.visible
radius: Theme.cornerRadius radius: Theme.cornerRadius

View File

@@ -23,7 +23,7 @@ ScrollBar {
visible: policy !== ScrollBar.AlwaysOff visible: policy !== ScrollBar.AlwaysOff
Behavior on opacity { Behavior on opacity {
NumberAnimation { OpacityAnimator {
duration: 160 duration: 160
easing.type: Easing.OutQuad easing.type: Easing.OutQuad
} }

View File

@@ -225,7 +225,7 @@ Item {
y: parent.midY - height / 2 y: parent.midY - height / 2
z: 3 z: 3
Behavior on x { Behavior on x {
NumberAnimation { XAnimator {
duration: 80 duration: 80
} }
} }

View File

@@ -171,7 +171,7 @@ Item {
scale: active ? 1.05 : 1.0 scale: active ? 1.05 : 1.0
Behavior on scale { Behavior on scale {
NumberAnimation { ScaleAnimator {
duration: Theme.shortDuration duration: Theme.shortDuration
easing.type: Theme.standardEasing easing.type: Theme.standardEasing
} }
@@ -278,7 +278,7 @@ Item {
} }
Behavior on opacity { Behavior on opacity {
NumberAnimation { OpacityAnimator {
duration: Theme.shortDuration duration: Theme.shortDuration
easing.type: Theme.standardEasing easing.type: Theme.standardEasing
} }

View File

@@ -201,7 +201,7 @@ FocusScope {
Behavior on x { Behavior on x {
enabled: indicator.animationEnabled enabled: indicator.animationEnabled
NumberAnimation { XAnimator {
duration: Theme.mediumDuration duration: Theme.mediumDuration
easing.type: Theme.standardEasing easing.type: Theme.standardEasing
} }

View File

@@ -168,14 +168,14 @@ Item {
scale: (toggle.checked && toggle.enabled) ? 1 : 0.6 scale: (toggle.checked && toggle.enabled) ? 1 : 0.6
Behavior on opacity { Behavior on opacity {
NumberAnimation { OpacityAnimator {
duration: Anims.durShort duration: Anims.durShort
easing.type: Easing.BezierSpline easing.type: Easing.BezierSpline
easing.bezierCurve: Anims.emphasized easing.bezierCurve: Anims.emphasized
} }
} }
Behavior on scale { Behavior on scale {
NumberAnimation { ScaleAnimator {
duration: Anims.durShort duration: Anims.durShort
easing.type: Easing.BezierSpline easing.type: Easing.BezierSpline
easing.bezierCurve: Anims.emphasized easing.bezierCurve: Anims.emphasized

View File

@@ -20,7 +20,7 @@ Rectangle {
} }
Behavior on opacity { Behavior on opacity {
NumberAnimation { OpacityAnimator {
duration: standardAnimation.duration duration: standardAnimation.duration
easing.type: standardAnimation["easing.type"] easing.type: standardAnimation["easing.type"]
easing.bezierCurve: standardAnimation["easing.bezierCurve"] easing.bezierCurve: standardAnimation["easing.bezierCurve"]

View File

@@ -40,7 +40,7 @@ Text {
//renderType: Text.NativeRendering //renderType: Text.NativeRendering
Behavior on opacity { Behavior on opacity {
NumberAnimation { OpacityAnimator {
duration: standardAnimation.duration duration: standardAnimation.duration
easing.type: standardAnimation["easing.type"] easing.type: standardAnimation["easing.type"]
easing.bezierCurve: standardAnimation["easing.bezierCurve"] easing.bezierCurve: standardAnimation["easing.bezierCurve"]

294
scripts/format-staged.py Executable file
View File

@@ -0,0 +1,294 @@
#!/usr/bin/env python3
"""Format staged .qml files using qmlls (the Qt QML language server).
Per file:
1. Speak LSP over stdio to qmlls: initialize -> didOpen -> formatting,
apply returned edits, save, `git add`.
2. Run qmllint on the formatted file and warn about unused imports
(informational only — never modifies files).
Refuses to run if any staged file also has unstaged changes, since `git add`
would silently absorb those into the commit.
"""
import json
import os
import shutil
import subprocess
import sys
from pathlib import Path
TAB_SIZE = 4
QMLLS_CANDIDATES = ["qmlls6", "qmlls"]
QMLLINT_CANDIDATES = ["/usr/lib/qt6/bin/qmllint", "qmllint6", "qmllint"]
def git(*args, cwd=None):
return subprocess.run(
["git", *args],
cwd=cwd,
capture_output=True,
text=True,
check=True,
).stdout
def repo_root():
return Path(git("rev-parse", "--show-toplevel").strip())
def staged_qml_files(root):
out = git("diff", "--cached", "--name-only", "--diff-filter=ACMR", cwd=root)
return [root / line for line in out.splitlines() if line.endswith(".qml")]
def has_unstaged_changes(root, file):
rel = str(file.relative_to(root))
return git("diff", "--name-only", "--", rel, cwd=root).strip() != ""
def find_qmlls():
for name in QMLLS_CANDIDATES:
path = shutil.which(name)
if path:
return path
return None
def find_qmllint():
for candidate in QMLLINT_CANDIDATES:
path = candidate if "/" in candidate and Path(candidate).is_file() else shutil.which(candidate)
if not path:
continue
try:
result = subprocess.run([path, "--help"], capture_output=True, text=True, timeout=5)
except (subprocess.TimeoutExpired, OSError):
continue
if "--json" in result.stdout:
return path
return None
def lint_unused_imports(qmllint, file):
"""Return a list of (line, message, suspect) for unused-import warnings.
`suspect` is True when the same line also has an import-resolution failure,
which often means the warning is a false positive (qmllint couldn't find
the module, so its 'unused' verdict is unreliable).
"""
result = subprocess.run(
[qmllint, "--unused-imports", "warning", "--json", "-", str(file)],
capture_output=True, text=True,
)
try:
data = json.loads(result.stdout)
except json.JSONDecodeError:
return []
files = data.get("files", [])
if not files:
return []
warnings = files[0].get("warnings", [])
failed_lines = {w["line"] for w in warnings if w.get("id") == "import" and "line" in w}
findings = []
for w in warnings:
if w.get("id") != "unused-imports" or "line" not in w:
continue
line = w["line"]
findings.append((line, w.get("message", "Unused import"), line in failed_lines))
findings.sort(key=lambda x: x[0])
return findings
class LspClient:
def __init__(self, command):
self.proc = subprocess.Popen(
command,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.DEVNULL,
)
self._next_id = 1
def _send(self, msg):
body = json.dumps(msg).encode("utf-8")
header = f"Content-Length: {len(body)}\r\n\r\n".encode("ascii")
self.proc.stdin.write(header + body)
self.proc.stdin.flush()
def _read(self):
headers = {}
while True:
line = self.proc.stdout.readline()
if not line:
raise RuntimeError("qmlls closed unexpectedly")
line = line.decode("ascii").rstrip("\r\n")
if line == "":
break
key, _, value = line.partition(":")
headers[key.strip().lower()] = value.strip()
length = int(headers["content-length"])
body = b""
while len(body) < length:
chunk = self.proc.stdout.read(length - len(body))
if not chunk:
raise RuntimeError("qmlls closed mid-message")
body += chunk
return json.loads(body)
def request(self, method, params):
req_id = self._next_id
self._next_id += 1
self._send({"jsonrpc": "2.0", "id": req_id, "method": method, "params": params})
while True:
msg = self._read()
if msg.get("id") == req_id and ("result" in msg or "error" in msg):
if "error" in msg:
raise RuntimeError(f"LSP {method} error: {msg['error']}")
return msg.get("result")
if "id" in msg and "method" in msg:
# Server-to-client request — reply with null so it doesn't stall.
self._send({"jsonrpc": "2.0", "id": msg["id"], "result": None})
def notify(self, method, params):
self._send({"jsonrpc": "2.0", "method": method, "params": params})
def shutdown(self):
try:
self.request("shutdown", None)
self.notify("exit", None)
except Exception:
pass
try:
self.proc.wait(timeout=2)
except subprocess.TimeoutExpired:
self.proc.kill()
def apply_edits(text, edits):
"""Apply LSP TextEdits (non-overlapping) to text, end-first."""
if not edits:
return text
lines = text.splitlines(keepends=True)
line_starts = [0]
for line in lines:
line_starts.append(line_starts[-1] + len(line))
def offset(pos):
line = pos["line"]
if line >= len(line_starts):
return len(text)
return min(line_starts[line] + pos["character"], len(text))
sorted_edits = sorted(
edits,
key=lambda e: (e["range"]["start"]["line"], e["range"]["start"]["character"]),
reverse=True,
)
for edit in sorted_edits:
start = offset(edit["range"]["start"])
end = offset(edit["range"]["end"])
text = text[:start] + edit["newText"] + text[end:]
return text
def main():
root = repo_root()
files = staged_qml_files(root)
if not files:
print("No staged .qml files.")
return 0
dirty = [f for f in files if has_unstaged_changes(root, f)]
if dirty:
print("Refusing to format: staged files have unstaged changes:", file=sys.stderr)
for f in dirty:
print(f" {f.relative_to(root)}", file=sys.stderr)
print("\nStash or stage those changes first.", file=sys.stderr)
return 1
qmlls = find_qmlls()
if not qmlls:
print(f"qmlls not found (tried: {', '.join(QMLLS_CANDIDATES)})", file=sys.stderr)
return 1
qmllint = find_qmllint()
if not qmllint:
print("warning: qmllint with --json not found; skipping unused-import checks", file=sys.stderr)
client = LspClient([qmlls])
changed = 0
unused_by_file = {}
try:
client.request("initialize", {
"processId": os.getpid(),
"rootUri": root.as_uri(),
"workspaceFolders": [{"uri": root.as_uri(), "name": root.name}],
"capabilities": {
"textDocument": {
"formatting": {"dynamicRegistration": False},
"synchronization": {"dynamicRegistration": False},
},
},
})
client.notify("initialized", {})
for file in files:
rel = file.relative_to(root)
print(f" {rel} ... ", end="", flush=True)
original = file.read_text()
uri = file.as_uri()
client.notify("textDocument/didOpen", {
"textDocument": {
"uri": uri,
"languageId": "qml",
"version": 1,
"text": original,
},
})
edits = client.request("textDocument/formatting", {
"textDocument": {"uri": uri},
"options": {"tabSize": TAB_SIZE, "insertSpaces": True},
})
client.notify("textDocument/didClose", {"textDocument": {"uri": uri}})
new_text = apply_edits(original, edits or [])
if new_text == original:
print("unchanged")
continue
file.write_text(new_text)
git("add", "--", str(rel), cwd=root)
changed += 1
print("formatted & staged")
if qmllint:
for file in files:
findings = lint_unused_imports(qmllint, file)
if findings:
unused_by_file[file] = findings
print(f"\n{changed} of {len(files)} file(s) changed.")
if unused_by_file:
print("\nUnused import warnings (informational, not auto-removed):")
for file, findings in unused_by_file.items():
rel = file.relative_to(root)
for line, message, suspect in findings:
suffix = " [suspect: import didn't resolve]" if suspect else ""
print(f" {rel}:{line} {message}{suffix}")
return 0
finally:
client.shutdown()
if __name__ == "__main__":
sys.exit(main())