mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-05-02 02:22:06 -04:00
numerous animation improvements, convert a bunch of stuff to use
Animator, etc.
This commit is contained in:
@@ -26,9 +26,7 @@ Rectangle {
|
||||
spacing: 2
|
||||
|
||||
StyledText {
|
||||
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")
|
||||
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")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceText
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
@@ -43,7 +41,7 @@ Rectangle {
|
||||
}
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
OpacityAnimator {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.standardEasing
|
||||
}
|
||||
|
||||
@@ -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() {
|
||||
if (!frameOwnsConnectedChrome || !_chromeClaimId)
|
||||
return;
|
||||
@@ -185,10 +215,10 @@ Item {
|
||||
onFrameOwnsConnectedChromeChanged: _syncModalChromeState()
|
||||
onResolvedConnectedBarSideChanged: _queueFullSync()
|
||||
onShouldBeVisibleChanged: _queueFullSync()
|
||||
onAlignedXChanged: _syncModalBody()
|
||||
onAlignedYChanged: _syncModalBody()
|
||||
onAlignedWidthChanged: _syncModalBody()
|
||||
onAlignedHeightChanged: _syncModalBody()
|
||||
onAlignedXChanged: _queueBodySync()
|
||||
onAlignedYChanged: _queueBodySync()
|
||||
onAlignedWidthChanged: _queueBodySync()
|
||||
onAlignedHeightChanged: _queueBodySync()
|
||||
|
||||
Component.onDestruction: _releaseModalChrome()
|
||||
|
||||
@@ -456,8 +486,8 @@ Item {
|
||||
readonly property real s: Math.min(1, modalContainer.scaleValue)
|
||||
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)
|
||||
blurWidth: (root.shouldBeVisible && animatedContent.opacity > 0 && !root.frameOwnsConnectedChrome) ? modalContainer.width * s : 0
|
||||
blurHeight: (root.shouldBeVisible && animatedContent.opacity > 0 && !root.frameOwnsConnectedChrome) ? modalContainer.height * s : 0
|
||||
blurWidth: (root.shouldBeVisible && animatedContent.publishedOpacity > 0 && !root.frameOwnsConnectedChrome) ? modalContainer.width * s : 0
|
||||
blurHeight: (root.shouldBeVisible && animatedContent.publishedOpacity > 0 && !root.frameOwnsConnectedChrome) ? modalContainer.height * s : 0
|
||||
blurRadius: root.effectiveCornerRadius
|
||||
}
|
||||
|
||||
@@ -666,9 +696,9 @@ Item {
|
||||
property real animY: root.shouldBeVisible ? 0 : root.frozenMotionOffsetY
|
||||
|
||||
onAnimXChanged: if (root.frameOwnsConnectedChrome)
|
||||
root._syncModalAnim()
|
||||
root._queueAnimSync()
|
||||
onAnimYChanged: if (root.frameOwnsConnectedChrome)
|
||||
root._syncModalAnim()
|
||||
root._queueAnimSync()
|
||||
|
||||
readonly property real computedScaleCollapsed: root.animationScaleCollapsed
|
||||
property real scaleValue: root.shouldBeVisible ? 1.0 : computedScaleCollapsed
|
||||
@@ -711,11 +741,23 @@ Item {
|
||||
id: animatedContent
|
||||
anchors.fill: parent
|
||||
clip: false
|
||||
|
||||
property real publishedOpacity: (Theme.isDirectionalEffect && !Theme.isConnectedEffect) ? 1 : (root.shouldBeVisible ? 1 : 0)
|
||||
|
||||
opacity: (Theme.isDirectionalEffect && !Theme.isConnectedEffect) ? 1 : (root.shouldBeVisible ? 1 : 0)
|
||||
scale: modalContainer.scaleValue
|
||||
transformOrigin: Item.Center
|
||||
|
||||
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)
|
||||
NumberAnimation {
|
||||
duration: Math.round(Theme.variantDuration(animationDuration, root.shouldBeVisible) * Theme.variantOpacityDurationScale)
|
||||
|
||||
@@ -241,8 +241,8 @@ Item {
|
||||
readonly property real s: Math.min(1, modalContainer.scaleValue)
|
||||
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)
|
||||
blurWidth: (shouldBeVisible && animatedContent.opacity > 0) ? modalContainer.width * s : 0
|
||||
blurHeight: (shouldBeVisible && animatedContent.opacity > 0) ? modalContainer.height * s : 0
|
||||
blurWidth: (shouldBeVisible && animatedContent.publishedOpacity > 0) ? modalContainer.width * s : 0
|
||||
blurHeight: (shouldBeVisible && animatedContent.publishedOpacity > 0) ? modalContainer.height * s : 0
|
||||
blurRadius: root.cornerRadius
|
||||
}
|
||||
|
||||
@@ -318,7 +318,8 @@ Item {
|
||||
|
||||
Behavior on opacity {
|
||||
enabled: root.animationsEnabled
|
||||
DankAnim {
|
||||
OpacityAnimator {
|
||||
easing.type: Easing.BezierSpline
|
||||
duration: root.animationDuration
|
||||
easing.bezierCurve: root.shouldBeVisible ? root.animationEnterCurve : root.animationExitCurve
|
||||
}
|
||||
@@ -398,12 +399,24 @@ Item {
|
||||
id: animatedContent
|
||||
anchors.fill: parent
|
||||
clip: false
|
||||
|
||||
property real publishedOpacity: root.shouldBeVisible ? 1 : 0
|
||||
|
||||
opacity: root.shouldBeVisible ? 1 : 0
|
||||
scale: modalContainer.scaleValue
|
||||
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
|
||||
|
||||
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
|
||||
NumberAnimation {
|
||||
duration: animationDuration
|
||||
|
||||
@@ -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() {
|
||||
if (!frameOwnsConnectedChrome || !_chromeClaimId)
|
||||
return;
|
||||
@@ -281,10 +311,10 @@ Item {
|
||||
onFrameOwnsConnectedChromeChanged: _syncModalChromeState()
|
||||
onResolvedConnectedBarSideChanged: _queueFullSync()
|
||||
onSpotlightOpenChanged: _queueFullSync()
|
||||
onAlignedXChanged: _syncModalBody()
|
||||
onAlignedYChanged: _syncModalBody()
|
||||
onAlignedWidthChanged: _syncModalBody()
|
||||
onAlignedHeightChanged: _syncModalBody()
|
||||
onAlignedXChanged: _queueBodySync()
|
||||
onAlignedYChanged: _queueBodySync()
|
||||
onAlignedWidthChanged: _queueBodySync()
|
||||
onAlignedHeightChanged: _queueBodySync()
|
||||
|
||||
Component.onDestruction: _releaseModalChrome()
|
||||
|
||||
@@ -571,7 +601,8 @@ Item {
|
||||
|
||||
Behavior on opacity {
|
||||
enabled: root.animationsEnabled && (!Theme.isDirectionalEffect || Theme.isConnectedEffect)
|
||||
DankAnim {
|
||||
NumberAnimation {
|
||||
easing.type: Easing.BezierSpline
|
||||
duration: Math.round(Theme.variantDuration(root.launcherAnimationDuration, launcherMotionVisible) * Theme.variantOpacityDurationScale)
|
||||
easing.bezierCurve: launcherMotionVisible ? root.launcherEnterCurve : root.launcherExitCurve
|
||||
}
|
||||
@@ -597,8 +628,8 @@ Item {
|
||||
readonly property real s: Math.min(1, contentContainer.scaleValue)
|
||||
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)
|
||||
blurWidth: (root.spotlightOpen || root.isClosing) && contentWrapper.opacity > 0 && !root.frameOwnsConnectedChrome ? root.alignedWidth * s : 0
|
||||
blurHeight: (root.spotlightOpen || root.isClosing) && contentWrapper.opacity > 0 && !root.frameOwnsConnectedChrome ? root.alignedHeight * s : 0
|
||||
blurWidth: (root.spotlightOpen || root.isClosing) && contentWrapper.publishedOpacity > 0 && !root.frameOwnsConnectedChrome ? root.alignedWidth * s : 0
|
||||
blurHeight: (root.spotlightOpen || root.isClosing) && contentWrapper.publishedOpacity > 0 && !root.frameOwnsConnectedChrome ? root.alignedHeight * s : 0
|
||||
blurRadius: root.cornerRadius
|
||||
}
|
||||
|
||||
@@ -716,9 +747,9 @@ Item {
|
||||
property real scaleValue: root._motionActive ? 1.0 : Theme.effectScaleCollapsed
|
||||
|
||||
onAnimXChanged: if (root.frameOwnsConnectedChrome)
|
||||
root._syncModalAnim()
|
||||
root._queueAnimSync()
|
||||
onAnimYChanged: if (root.frameOwnsConnectedChrome)
|
||||
root._syncModalAnim()
|
||||
root._queueAnimSync()
|
||||
|
||||
Behavior on animX {
|
||||
enabled: root.animationsEnabled
|
||||
@@ -769,7 +800,7 @@ Item {
|
||||
id: launcherShadowLayer
|
||||
width: parent.width
|
||||
height: parent.height
|
||||
opacity: contentWrapper.opacity
|
||||
opacity: contentWrapper.publishedOpacity
|
||||
scale: contentWrapper.scale
|
||||
x: contentWrapper.x
|
||||
y: contentWrapper.y
|
||||
@@ -787,20 +818,44 @@ Item {
|
||||
id: contentWrapper
|
||||
width: parent.width
|
||||
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)
|
||||
visible: opacity > 0
|
||||
visible: _renderActive
|
||||
scale: contentContainer.scaleValue
|
||||
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)
|
||||
|
||||
Behavior on opacity {
|
||||
enabled: root.animationsEnabled && (!Theme.isDirectionalEffect || Theme.isConnectedEffect)
|
||||
DankAnim {
|
||||
OpacityAnimator {
|
||||
easing.type: Easing.BezierSpline
|
||||
duration: Math.round(Theme.variantDuration(root.launcherAnimationDuration, launcherMotionVisible) * Theme.variantOpacityDurationScale)
|
||||
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 {
|
||||
anchors.fill: parent
|
||||
onPressed: mouse => mouse.accepted = true
|
||||
|
||||
@@ -350,11 +350,11 @@ Item {
|
||||
|
||||
WindowBlur {
|
||||
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
|
||||
blurY: modalContainer.y + modalContainer.height * (1 - s) * 0.5
|
||||
blurWidth: (contentVisible && modalContainer.opacity > 0) ? modalContainer.width * s : 0
|
||||
blurHeight: (contentVisible && modalContainer.opacity > 0) ? modalContainer.height * s : 0
|
||||
blurWidth: (contentVisible && modalContainer.publishedOpacity > 0) ? modalContainer.width * s : 0
|
||||
blurHeight: (contentVisible && modalContainer.publishedOpacity > 0) ? modalContainer.height * s : 0
|
||||
blurRadius: root.cornerRadius
|
||||
}
|
||||
|
||||
@@ -411,23 +411,55 @@ Item {
|
||||
y: root.contentY
|
||||
width: root.alignedWidth
|
||||
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
|
||||
scale: contentVisible ? 1 : 0.96
|
||||
transformOrigin: Item.Center
|
||||
|
||||
Behavior on opacity {
|
||||
DankAnim {
|
||||
OpacityAnimator {
|
||||
easing.type: Easing.BezierSpline
|
||||
duration: Theme.modalAnimationDuration
|
||||
easing.bezierCurve: contentVisible ? Theme.expressiveCurves.expressiveDefaultSpatial : Theme.expressiveCurves.emphasized
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on scale {
|
||||
DankAnim {
|
||||
Behavior on publishedOpacity {
|
||||
NumberAnimation {
|
||||
easing.type: Easing.BezierSpline
|
||||
duration: Theme.modalAnimationDuration
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import QtQuick
|
||||
import QtCore
|
||||
import Quickshell.Io
|
||||
import qs.Common
|
||||
import qs.Widgets
|
||||
@@ -22,9 +21,9 @@ Rectangle {
|
||||
|
||||
onShowFileInfoChanged: {
|
||||
if (showFileInfo && currentFileName && currentPath) {
|
||||
const fullPath = currentPath + "/" + currentFileName
|
||||
fileStatProcess.selectedFilePath = fullPath
|
||||
fileStatProcess.running = true
|
||||
const fullPath = currentPath + "/" + currentFileName;
|
||||
fileStatProcess.selectedFilePath = fullPath;
|
||||
fileStatProcess.running = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,14 +37,14 @@ Rectangle {
|
||||
stdout: StdioCollector {
|
||||
onStreamFinished: {
|
||||
if (text && text.trim()) {
|
||||
const parts = text.trim().split('|')
|
||||
const parts = text.trim().split('|');
|
||||
if (parts.length >= 4) {
|
||||
fileStatProcess.fileStats = {
|
||||
"modifiedTime": parts[0],
|
||||
"permissions": parts[1],
|
||||
"size": parseInt(parts[2]) || 0,
|
||||
"fullPath": parts[3]
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -60,31 +59,31 @@ Rectangle {
|
||||
|
||||
onCurrentFileNameChanged: {
|
||||
if (showFileInfo && currentFileName && currentPath) {
|
||||
const fullPath = currentPath + "/" + currentFileName
|
||||
const fullPath = currentPath + "/" + currentFileName;
|
||||
if (fullPath !== fileStatProcess.selectedFilePath) {
|
||||
fileStatProcess.selectedFilePath = fullPath
|
||||
fileStatProcess.running = true
|
||||
fileStatProcess.selectedFilePath = fullPath;
|
||||
fileStatProcess.running = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function updateFileInfo(filePath, fileName, isDirectory) {
|
||||
if (filePath && filePath !== fileStatProcess.selectedFilePath) {
|
||||
fileStatProcess.selectedFilePath = filePath
|
||||
currentFileName = fileName || ""
|
||||
currentFileIsDir = isDirectory || false
|
||||
fileStatProcess.selectedFilePath = filePath;
|
||||
currentFileName = fileName || "";
|
||||
currentFileIsDir = isDirectory || false;
|
||||
|
||||
let ext = ""
|
||||
let ext = "";
|
||||
if (!isDirectory && fileName) {
|
||||
const lastDot = fileName.lastIndexOf('.')
|
||||
const lastDot = fileName.lastIndexOf('.');
|
||||
if (lastDot > 0) {
|
||||
ext = fileName.substring(lastDot + 1).toLowerCase()
|
||||
ext = fileName.substring(lastDot + 1).toLowerCase();
|
||||
}
|
||||
}
|
||||
currentFileExtension = ext
|
||||
currentFileExtension = ext;
|
||||
|
||||
if (showFileInfo) {
|
||||
fileStatProcess.running = true
|
||||
fileStatProcess.running = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -100,10 +99,10 @@ Rectangle {
|
||||
"permissions": "",
|
||||
"extension": "",
|
||||
"position": "N/A"
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
const hasValidFile = currentFileName !== ""
|
||||
const hasValidFile = currentFileName !== "";
|
||||
return {
|
||||
"exists": hasValidFile,
|
||||
"name": hasValidFile ? currentFileName : "Loading...",
|
||||
@@ -113,7 +112,7 @@ Rectangle {
|
||||
"permissions": fileStatProcess.fileStats ? fileStatProcess.fileStats.permissions : "Loading...",
|
||||
"extension": currentFileExtension,
|
||||
"position": sourceFolderModel ? ((selectedIndex + 1) + " of " + sourceFolderModel.count) : "N/A"
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
Column {
|
||||
@@ -209,27 +208,27 @@ Rectangle {
|
||||
|
||||
function formatFileSize(bytes) {
|
||||
if (bytes === 0 || !bytes) {
|
||||
return "0 B"
|
||||
return "0 B";
|
||||
}
|
||||
const k = 1024
|
||||
const sizes = ['B', 'KB', 'MB', 'GB', 'TB']
|
||||
const i = Math.floor(Math.log(bytes) / Math.log(k))
|
||||
return parseFloat((bytes / Math.pow(k, i)).toFixed(1)) + ' ' + sizes[i]
|
||||
const k = 1024;
|
||||
const sizes = ['B', 'KB', 'MB', 'GB', 'TB'];
|
||||
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
||||
return parseFloat((bytes / Math.pow(k, i)).toFixed(1)) + ' ' + sizes[i];
|
||||
}
|
||||
|
||||
function formatDateTime(dateTimeString) {
|
||||
if (!dateTimeString) {
|
||||
return "Unknown"
|
||||
return "Unknown";
|
||||
}
|
||||
const parts = dateTimeString.split(' ')
|
||||
const parts = dateTimeString.split(' ');
|
||||
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 {
|
||||
NumberAnimation {
|
||||
OpacityAnimator {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.standardEasing
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ Rectangle {
|
||||
}
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
OpacityAnimator {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.standardEasing
|
||||
}
|
||||
|
||||
@@ -180,7 +180,7 @@ Item {
|
||||
opacity: (root.hasRun && !root.isRunning) ? 1 : 0
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
OpacityAnimator {
|
||||
duration: Theme.mediumDuration
|
||||
easing.type: Theme.emphasizedEasing
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ Rectangle {
|
||||
scale: mouseArea.pressed ? 0.97 : 1
|
||||
|
||||
Behavior on scale {
|
||||
NumberAnimation {
|
||||
ScaleAnimator {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.emphasizedEasing
|
||||
}
|
||||
|
||||
@@ -772,7 +772,7 @@ DankModal {
|
||||
opacity: root.showHoldHint ? 1 : 0.5
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
OpacityAnimator {
|
||||
duration: 150
|
||||
}
|
||||
}
|
||||
|
||||
@@ -214,13 +214,13 @@ Item {
|
||||
color: root.accentColor
|
||||
|
||||
Behavior on x {
|
||||
NumberAnimation {
|
||||
XAnimator {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.standardEasing
|
||||
}
|
||||
}
|
||||
Behavior on y {
|
||||
NumberAnimation {
|
||||
YAnimator {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.standardEasing
|
||||
}
|
||||
@@ -278,13 +278,13 @@ Item {
|
||||
color: root.accentColor
|
||||
|
||||
Behavior on x {
|
||||
NumberAnimation {
|
||||
XAnimator {
|
||||
duration: Theme.mediumDuration
|
||||
easing.type: Theme.emphasizedEasing
|
||||
}
|
||||
}
|
||||
Behavior on y {
|
||||
NumberAnimation {
|
||||
YAnimator {
|
||||
duration: Theme.mediumDuration
|
||||
easing.type: Theme.emphasizedEasing
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ Rectangle {
|
||||
opacity: mouseArea.containsMouse ? 0.08 : 0.0
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
OpacityAnimator {
|
||||
duration: Theme.shortDuration
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,11 +23,15 @@ Item {
|
||||
signal toggleWidgetSize(int index)
|
||||
|
||||
width: {
|
||||
const widgetWidth = widgetData?.width || 50
|
||||
if (widgetWidth <= 25) return gridCellWidth
|
||||
else if (widgetWidth <= 50) return gridCellWidth * 2
|
||||
else if (widgetWidth <= 75) return gridCellWidth * 3
|
||||
else return gridCellWidth * 4
|
||||
const widgetWidth = widgetData?.width || 50;
|
||||
if (widgetWidth <= 25)
|
||||
return gridCellWidth;
|
||||
else if (widgetWidth <= 50)
|
||||
return gridCellWidth * 2;
|
||||
else if (widgetWidth <= 75)
|
||||
return gridCellWidth * 3;
|
||||
else
|
||||
return gridCellWidth * 4;
|
||||
}
|
||||
height: isSlider ? 16 : gridCellHeight
|
||||
|
||||
@@ -42,10 +46,14 @@ Item {
|
||||
z: dragArea.drag.active ? 10000 : 1
|
||||
|
||||
Behavior on border.width {
|
||||
NumberAnimation { duration: 150 }
|
||||
NumberAnimation {
|
||||
duration: 150
|
||||
}
|
||||
}
|
||||
Behavior on opacity {
|
||||
NumberAnimation { duration: 150 }
|
||||
OpacityAnimator {
|
||||
duration: 150
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,14 +66,17 @@ Item {
|
||||
property int globalWidgetIndex: root.widgetIndex
|
||||
property int widgetWidth: root.widgetData?.width || 50
|
||||
|
||||
|
||||
MouseArea {
|
||||
id: editModeBlocker
|
||||
anchors.fill: parent
|
||||
enabled: root.editMode
|
||||
acceptedButtons: Qt.AllButtons
|
||||
onPressed: function(mouse) { mouse.accepted = true }
|
||||
onWheel: function(wheel) { wheel.accepted = true }
|
||||
onPressed: function (mouse) {
|
||||
mouse.accepted = true;
|
||||
}
|
||||
onWheel: function (wheel) {
|
||||
wheel.accepted = true;
|
||||
}
|
||||
z: 100
|
||||
}
|
||||
}
|
||||
@@ -79,19 +90,19 @@ Item {
|
||||
drag.axis: Drag.XAndYAxis
|
||||
drag.smoothed: true
|
||||
|
||||
onPressed: function(mouse) {
|
||||
onPressed: function (mouse) {
|
||||
if (editMode) {
|
||||
cursorShape = Qt.ClosedHandCursor
|
||||
cursorShape = Qt.ClosedHandCursor;
|
||||
if (root.gridLayout && root.gridLayout.moveToTop) {
|
||||
root.gridLayout.moveToTop(root)
|
||||
root.gridLayout.moveToTop(root);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onReleased: function(mouse) {
|
||||
onReleased: function (mouse) {
|
||||
if (editMode) {
|
||||
cursorShape = Qt.OpenHandCursor
|
||||
root.snapToGrid()
|
||||
cursorShape = Qt.OpenHandCursor;
|
||||
root.snapToGrid();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -101,9 +112,11 @@ Item {
|
||||
Drag.hotSpot.y: height / 2
|
||||
|
||||
function swapIndices(i, j) {
|
||||
if (i === j) return;
|
||||
if (i === j)
|
||||
return;
|
||||
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 tmp = copy[i];
|
||||
@@ -114,37 +127,41 @@ Item {
|
||||
}
|
||||
|
||||
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 cellWidth = gridLayout.width / gridColumns
|
||||
const cellHeight = gridCellHeight + Theme.spacingS
|
||||
const centerX = globalPos.x + (root.width / 2);
|
||||
const centerY = globalPos.y + (root.height / 2);
|
||||
|
||||
const centerX = globalPos.x + (root.width / 2)
|
||||
const centerY = globalPos.y + (root.height / 2)
|
||||
let targetCol = Math.max(0, Math.floor(centerX / cellWidth));
|
||||
let targetRow = Math.max(0, Math.floor(centerY / cellHeight));
|
||||
|
||||
let targetCol = Math.max(0, Math.floor(centerX / cellWidth))
|
||||
let targetRow = Math.max(0, Math.floor(centerY / cellHeight))
|
||||
targetCol = Math.min(targetCol, gridColumns - 1);
|
||||
|
||||
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)) {
|
||||
swapIndices(widgetIndex, newIndex)
|
||||
swapIndices(widgetIndex, newIndex);
|
||||
}
|
||||
}
|
||||
|
||||
function findBestInsertionIndex(targetRow, targetCol) {
|
||||
const widgets = SettingsData.controlCenterWidgets || [];
|
||||
const n = widgets.length;
|
||||
if (!n || widgetIndex < 0 || widgetIndex >= n) return -1;
|
||||
if (!n || widgetIndex < 0 || widgetIndex >= n)
|
||||
return -1;
|
||||
|
||||
function spanFor(width) {
|
||||
const w = width ?? 50;
|
||||
if (w <= 25) return 1;
|
||||
if (w <= 50) return 2;
|
||||
if (w <= 75) return 3;
|
||||
if (w <= 25)
|
||||
return 1;
|
||||
if (w <= 50)
|
||||
return 2;
|
||||
if (w <= 75)
|
||||
return 3;
|
||||
return 4;
|
||||
}
|
||||
|
||||
@@ -169,7 +186,13 @@ Item {
|
||||
if (i === widgetIndex) {
|
||||
draggedOrigKey = centerKey;
|
||||
} else {
|
||||
pos.push({ index: i, row, startCol, span, centerKey });
|
||||
pos.push({
|
||||
index: i,
|
||||
row,
|
||||
startCol,
|
||||
span,
|
||||
centerKey
|
||||
});
|
||||
}
|
||||
|
||||
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 targetKey = targetRow * cols + centerColCoord;
|
||||
@@ -192,15 +216,20 @@ Item {
|
||||
}
|
||||
|
||||
let lo = 0, hi = pos.length - 1;
|
||||
if (targetKey <= pos[0].centerKey) return pos[0].index;
|
||||
if (targetKey >= pos[hi].centerKey) return pos[hi].index;
|
||||
if (targetKey <= pos[0].centerKey)
|
||||
return pos[0].index;
|
||||
if (targetKey >= pos[hi].centerKey)
|
||||
return pos[hi].index;
|
||||
|
||||
while (lo <= hi) {
|
||||
const mid = (lo + hi) >> 1;
|
||||
const mk = pos[mid].centerKey;
|
||||
if (targetKey < mk) hi = mid - 1;
|
||||
else if (targetKey > mk) lo = mid + 1;
|
||||
else return pos[mid].index;
|
||||
if (targetKey < mk)
|
||||
hi = mid - 1;
|
||||
else if (targetKey > mk)
|
||||
lo = mid + 1;
|
||||
else
|
||||
return pos[mid].index;
|
||||
}
|
||||
const movingUp = (draggedOrigKey != null) ? (targetKey < draggedOrigKey) : false;
|
||||
return (movingUp ? pos[lo].index : pos[hi].index);
|
||||
@@ -240,11 +269,11 @@ Item {
|
||||
currentSize: root.widgetData?.width || 50
|
||||
isSlider: root.isSlider
|
||||
widgetIndex: root.widgetIndex
|
||||
onSizeChanged: (newSize) => {
|
||||
var widgets = SettingsData.controlCenterWidgets.slice()
|
||||
onSizeChanged: newSize => {
|
||||
var widgets = SettingsData.controlCenterWidgets.slice();
|
||||
if (widgetIndex >= 0 && widgetIndex < widgets.length) {
|
||||
widgets[widgetIndex].width = newSize
|
||||
SettingsData.set("controlCenterWidgets", widgets)
|
||||
widgets[widgetIndex].width = newSize;
|
||||
SettingsData.set("controlCenterWidgets", widgets);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -270,7 +299,9 @@ Item {
|
||||
}
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation { duration: 150 }
|
||||
OpacityAnimator {
|
||||
duration: 150
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -283,7 +314,9 @@ Item {
|
||||
z: -1
|
||||
|
||||
Behavior on color {
|
||||
ColorAnimation { duration: Theme.shortDuration }
|
||||
ColorAnimation {
|
||||
duration: Theme.shortDuration
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -195,7 +195,7 @@ DankPopout {
|
||||
|
||||
Behavior on opacity {
|
||||
enabled: !Theme.isDirectionalEffect
|
||||
NumberAnimation {
|
||||
OpacityAnimator {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Easing.BezierSpline
|
||||
easing.bezierCurve: root.shouldBeVisible ? Theme.variantPopoutEnterCurve : Theme.variantPopoutExitCurve
|
||||
|
||||
@@ -127,7 +127,7 @@ Item {
|
||||
opacity: modalVisible ? 1 : 0
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
OpacityAnimator {
|
||||
duration: Theme.mediumDuration
|
||||
easing.type: Theme.emphasizedEasing
|
||||
}
|
||||
@@ -316,14 +316,14 @@ Item {
|
||||
}
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
OpacityAnimator {
|
||||
duration: Theme.mediumDuration
|
||||
easing.type: Theme.emphasizedEasing
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on scale {
|
||||
NumberAnimation {
|
||||
ScaleAnimator {
|
||||
duration: Theme.mediumDuration
|
||||
easing.type: Theme.emphasizedEasing
|
||||
}
|
||||
|
||||
@@ -64,7 +64,7 @@ Rectangle {
|
||||
opacity: 0.08
|
||||
antialiasing: true
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
OpacityAnimator {
|
||||
duration: Theme.shortDuration
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@ Rectangle {
|
||||
opacity: mouseArea.containsMouse ? 0.08 : 0.0
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
OpacityAnimator {
|
||||
duration: Theme.shortDuration
|
||||
}
|
||||
}
|
||||
|
||||
@@ -474,14 +474,14 @@ BasePill {
|
||||
height: (isInOverflow && !root.overflowExpanded) ? 0 : visualHeight
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
OpacityAnimator {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Easing.OutCubic
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on scale {
|
||||
NumberAnimation {
|
||||
ScaleAnimator {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Easing.OutCubic
|
||||
}
|
||||
@@ -666,7 +666,7 @@ BasePill {
|
||||
transformOrigin: Item.Center
|
||||
scale: appItem.enlargeScale
|
||||
Behavior on scale {
|
||||
NumberAnimation {
|
||||
ScaleAnimator {
|
||||
duration: 120
|
||||
easing.type: Easing.OutCubic
|
||||
}
|
||||
@@ -711,7 +711,7 @@ BasePill {
|
||||
transformOrigin: Item.Center
|
||||
scale: appItem.enlargeScale
|
||||
Behavior on scale {
|
||||
NumberAnimation {
|
||||
ScaleAnimator {
|
||||
duration: 120
|
||||
easing.type: Easing.OutCubic
|
||||
}
|
||||
@@ -734,7 +734,7 @@ BasePill {
|
||||
transformOrigin: Item.Center
|
||||
scale: appItem.enlargeScale
|
||||
Behavior on scale {
|
||||
NumberAnimation {
|
||||
ScaleAnimator {
|
||||
duration: 120
|
||||
easing.type: Easing.OutCubic
|
||||
}
|
||||
@@ -758,7 +758,7 @@ BasePill {
|
||||
transformOrigin: Item.Center
|
||||
scale: appItem.enlargeScale
|
||||
Behavior on scale {
|
||||
NumberAnimation {
|
||||
ScaleAnimator {
|
||||
duration: 120
|
||||
easing.type: Easing.OutCubic
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ Item {
|
||||
rotation: isVertical ? (overflowExpanded ? 180 : 0) : (overflowExpanded ? 90 : -90)
|
||||
|
||||
Behavior on rotation {
|
||||
NumberAnimation {
|
||||
RotationAnimator {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Easing.OutCubic
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ BasePill {
|
||||
]
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
OpacityAnimator {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.standardEasing
|
||||
}
|
||||
|
||||
@@ -173,7 +173,7 @@ BasePill {
|
||||
opacity: root.playerAvailable ? 1 : 0
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
OpacityAnimator {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.standardEasing
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@ BasePill {
|
||||
]
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
OpacityAnimator {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.standardEasing
|
||||
}
|
||||
@@ -238,7 +238,7 @@ BasePill {
|
||||
Behavior on opacity {
|
||||
enabled: hasActivePrivacy && root.visible
|
||||
|
||||
NumberAnimation {
|
||||
OpacityAnimator {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.standardEasing
|
||||
}
|
||||
|
||||
@@ -271,7 +271,7 @@ BasePill {
|
||||
]
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
OpacityAnimator {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.standardEasing
|
||||
}
|
||||
@@ -625,7 +625,7 @@ BasePill {
|
||||
opacity: root.inlineExpanded ? 1 : 0
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
OpacityAnimator {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.standardEasing
|
||||
}
|
||||
@@ -1214,14 +1214,14 @@ BasePill {
|
||||
scale: root.menuOpen ? 1 : 0.85
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
OpacityAnimator {
|
||||
duration: Theme.mediumDuration
|
||||
easing.type: Theme.emphasizedEasing
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on scale {
|
||||
NumberAnimation {
|
||||
ScaleAnimator {
|
||||
duration: Theme.mediumDuration
|
||||
easing.type: Theme.emphasizedEasing
|
||||
}
|
||||
@@ -1666,14 +1666,14 @@ BasePill {
|
||||
scale: menuRoot.showMenu ? 1 : 0.85
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
OpacityAnimator {
|
||||
duration: Theme.mediumDuration
|
||||
easing.type: Theme.emphasizedEasing
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on scale {
|
||||
NumberAnimation {
|
||||
ScaleAnimator {
|
||||
duration: Theme.mediumDuration
|
||||
easing.type: Theme.emphasizedEasing
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ BasePill {
|
||||
}
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
OpacityAnimator {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.standardEasing
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ BasePill {
|
||||
anchors.centerIn: parent
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
OpacityAnimator {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Easing.InOutQuad
|
||||
}
|
||||
|
||||
@@ -1471,7 +1471,7 @@ Item {
|
||||
}
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
OpacityAnimator {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.emphasizedEasing
|
||||
}
|
||||
|
||||
@@ -97,7 +97,8 @@ Item {
|
||||
|
||||
Behavior on opacity {
|
||||
enabled: !Theme.isDirectionalEffect
|
||||
DankAnim {
|
||||
NumberAnimation {
|
||||
easing.type: Easing.BezierSpline
|
||||
duration: Math.round(Theme.variantDuration(Theme.expressiveDurations.expressiveDefaultSpatial, dropdownType === 1) * Theme.variantOpacityDurationScale)
|
||||
easing.bezierCurve: dropdownType === 1 ? Theme.variantPopoutEnterCurve : Theme.variantPopoutExitCurve
|
||||
}
|
||||
@@ -238,7 +239,8 @@ Item {
|
||||
|
||||
Behavior on opacity {
|
||||
enabled: !Theme.isDirectionalEffect
|
||||
DankAnim {
|
||||
NumberAnimation {
|
||||
easing.type: Easing.BezierSpline
|
||||
duration: Math.round(Theme.variantDuration(Theme.expressiveDurations.expressiveDefaultSpatial, dropdownType === 2) * Theme.variantOpacityDurationScale)
|
||||
easing.bezierCurve: dropdownType === 2 ? Theme.variantPopoutEnterCurve : Theme.variantPopoutExitCurve
|
||||
}
|
||||
@@ -393,7 +395,8 @@ Item {
|
||||
|
||||
Behavior on opacity {
|
||||
enabled: !Theme.isDirectionalEffect
|
||||
DankAnim {
|
||||
NumberAnimation {
|
||||
easing.type: Easing.BezierSpline
|
||||
duration: Math.round(Theme.variantDuration(Theme.expressiveDurations.expressiveDefaultSpatial, dropdownType === 3) * Theme.variantOpacityDurationScale)
|
||||
easing.bezierCurve: dropdownType === 3 ? Theme.variantPopoutEnterCurve : Theme.variantPopoutExitCurve
|
||||
}
|
||||
|
||||
@@ -402,7 +402,7 @@ Rectangle {
|
||||
opacity: isToday ? 0.9 : 0.7
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
OpacityAnimator {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.standardEasing
|
||||
}
|
||||
|
||||
@@ -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))
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
OpacityAnimator {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Easing.OutCubic
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on scale {
|
||||
NumberAnimation {
|
||||
ScaleAnimator {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Easing.OutCubic
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ Item {
|
||||
rotation: isVertical ? (overflowExpanded ? 180 : 0) : (overflowExpanded ? 90 : -90)
|
||||
|
||||
Behavior on rotation {
|
||||
NumberAnimation {
|
||||
RotationAnimator {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Easing.OutCubic
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import QtCore
|
||||
import QtQuick
|
||||
import QtQuick.Effects
|
||||
import QtQuick.Layouts
|
||||
@@ -119,15 +118,7 @@ Item {
|
||||
function greeterPamStackHasModule(moduleName) {
|
||||
if (pamModuleEnabled(greetdPamText, moduleName))
|
||||
return true;
|
||||
const includedPamStacks = [
|
||||
["system-auth", systemAuthPamText],
|
||||
["common-auth", commonAuthPamText],
|
||||
["password-auth", passwordAuthPamText],
|
||||
["system-login", systemLoginPamText],
|
||||
["system-local-login", systemLocalLoginPamText],
|
||||
["common-auth-pc", commonAuthPcPamText],
|
||||
["login", loginPamText]
|
||||
];
|
||||
const includedPamStacks = [["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++) {
|
||||
const stack = includedPamStacks[i];
|
||||
if (pamTextIncludesFile(greetdPamText, stack[0]) && pamModuleEnabled(stack[1], moduleName))
|
||||
@@ -609,13 +600,7 @@ Item {
|
||||
running: false
|
||||
// sh wrapper: emits PROBE_UNAVAILABLE if gdbus is absent or fprintd unreachable,
|
||||
// keeping the PAM-only fallback active in those cases.
|
||||
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: ["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"]
|
||||
stdout: StdioCollector {
|
||||
onStreamFinished: {
|
||||
if (text.includes("PROBE_UNAVAILABLE"))
|
||||
@@ -625,7 +610,7 @@ Item {
|
||||
root.maybeAutoStartExternalAuth();
|
||||
}
|
||||
}
|
||||
onExited: function(exitCode, exitStatus) {
|
||||
onExited: function (exitCode, exitStatus) {
|
||||
if (!root.fprintdProbeComplete)
|
||||
root.maybeAutoStartExternalAuth(); // PAM-only fallback stays active
|
||||
}
|
||||
@@ -729,7 +714,7 @@ Item {
|
||||
}
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
OpacityAnimator {
|
||||
duration: Theme.mediumDuration
|
||||
easing.type: Theme.standardEasing
|
||||
}
|
||||
@@ -1027,7 +1012,7 @@ Item {
|
||||
opacity: (GreeterState.showPasswordInput ? GreeterState.passwordBuffer.length === 0 : GreeterState.usernameInput.length === 0) ? 1 : 0
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
OpacityAnimator {
|
||||
duration: Theme.mediumDuration
|
||||
easing.type: Theme.standardEasing
|
||||
}
|
||||
@@ -1064,7 +1049,7 @@ Item {
|
||||
horizontalAlignment: implicitWidth > width ? Text.AlignRight : Text.AlignLeft
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
OpacityAnimator {
|
||||
duration: Theme.mediumDuration
|
||||
easing.type: Theme.standardEasing
|
||||
}
|
||||
@@ -1136,7 +1121,7 @@ Item {
|
||||
}
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
OpacityAnimator {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.standardEasing
|
||||
}
|
||||
@@ -1166,7 +1151,7 @@ Item {
|
||||
opacity: root.authFeedbackMessage !== "" ? 1 : 0
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
OpacityAnimator {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.standardEasing
|
||||
}
|
||||
@@ -1184,7 +1169,7 @@ Item {
|
||||
enabled: GreeterState.showPasswordInput
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
OpacityAnimator {
|
||||
duration: Theme.mediumDuration
|
||||
easing.type: Theme.standardEasing
|
||||
}
|
||||
@@ -1754,7 +1739,7 @@ Item {
|
||||
authTimeout.interval = defaultAuthTimeoutMs;
|
||||
authTimeout.stop();
|
||||
if (resumePasswordSubmit) {
|
||||
Qt.callLater(function() {
|
||||
Qt.callLater(function () {
|
||||
root.startAuthSession(true);
|
||||
});
|
||||
return;
|
||||
|
||||
@@ -779,7 +779,7 @@ Rectangle {
|
||||
opacity: root.showHoldHint ? 1 : 0.5
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
OpacityAnimator {
|
||||
duration: 150
|
||||
}
|
||||
}
|
||||
|
||||
@@ -214,7 +214,7 @@ Item {
|
||||
}
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
OpacityAnimator {
|
||||
duration: Theme.mediumDuration
|
||||
easing.type: Theme.standardEasing
|
||||
}
|
||||
@@ -740,7 +740,7 @@ Item {
|
||||
opacity: pam.passwd.active ? 0 : 1
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
OpacityAnimator {
|
||||
duration: Theme.mediumDuration
|
||||
easing.type: Theme.standardEasing
|
||||
}
|
||||
@@ -879,7 +879,7 @@ Item {
|
||||
opacity: (demoMode || root.passwordBuffer.length === 0) ? 1 : 0
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
OpacityAnimator {
|
||||
duration: Theme.mediumDuration
|
||||
easing.type: Theme.standardEasing
|
||||
}
|
||||
@@ -916,7 +916,7 @@ Item {
|
||||
horizontalAlignment: implicitWidth > width ? Text.AlignRight : Text.AlignLeft
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
OpacityAnimator {
|
||||
duration: Theme.mediumDuration
|
||||
easing.type: Theme.standardEasing
|
||||
}
|
||||
@@ -1053,7 +1053,7 @@ Item {
|
||||
}
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
OpacityAnimator {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.standardEasing
|
||||
}
|
||||
@@ -1084,7 +1084,7 @@ Item {
|
||||
opacity: text.length > 0 ? 1 : 0
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
OpacityAnimator {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.standardEasing
|
||||
}
|
||||
@@ -1114,7 +1114,7 @@ Item {
|
||||
}
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
OpacityAnimator {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.standardEasing
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ FocusScope {
|
||||
}
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
OpacityAnimator {
|
||||
duration: 200
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,19 +1,18 @@
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
import Quickshell.Io
|
||||
import qs.Common
|
||||
import qs.Services
|
||||
import qs.Widgets
|
||||
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
Column {
|
||||
id: root
|
||||
|
||||
Component.onCompleted: {
|
||||
if (PluginService.isPluginLoaded("dankNotepadModule")) {
|
||||
pluginHighlightedHtml = SettingsData.getBuiltInPluginSetting("dankNotepadModule", "highlightedHtml", "")
|
||||
pluginHighlightedHtml = SettingsData.getBuiltInPluginSetting("dankNotepadModule", "highlightedHtml", "");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,65 +32,57 @@ Column {
|
||||
property string lastPluginContent: ""
|
||||
property int loadRequestId: 0
|
||||
|
||||
signal saveRequested()
|
||||
signal openRequested()
|
||||
signal newRequested()
|
||||
signal previewRequested()
|
||||
signal escapePressed()
|
||||
signal contentChanged()
|
||||
signal settingsRequested()
|
||||
signal saveRequested
|
||||
signal openRequested
|
||||
signal newRequested
|
||||
signal previewRequested
|
||||
signal escapePressed
|
||||
signal contentChanged
|
||||
signal settingsRequested
|
||||
|
||||
function hasUnsavedChanges() {
|
||||
if (!currentTab || !contentLoaded) {
|
||||
return false
|
||||
return false;
|
||||
}
|
||||
|
||||
if (currentTab.isTemporary) {
|
||||
return textArea.text.length > 0
|
||||
return textArea.text.length > 0;
|
||||
}
|
||||
return textArea.text !== lastSavedContent
|
||||
return textArea.text !== lastSavedContent;
|
||||
}
|
||||
|
||||
function loadCurrentTabContent() {
|
||||
if (!currentTab) return
|
||||
|
||||
const requestedTabId = currentTab.id
|
||||
const requestId = ++loadRequestId
|
||||
contentLoaded = false
|
||||
NotepadStorageService.loadTabContent(
|
||||
NotepadStorageService.currentTabIndex,
|
||||
(content) => {
|
||||
const activeTab = NotepadStorageService.tabs.length > NotepadStorageService.currentTabIndex
|
||||
? NotepadStorageService.tabs[NotepadStorageService.currentTabIndex]
|
||||
: null
|
||||
if (requestId !== loadRequestId || !activeTab || activeTab.id !== requestedTabId)
|
||||
return
|
||||
|
||||
lastSavedContent = content
|
||||
textArea.text = content
|
||||
contentLoaded = true
|
||||
syncContentToPlugin()
|
||||
}
|
||||
)
|
||||
if (!currentTab)
|
||||
return;
|
||||
const requestedTabId = currentTab.id;
|
||||
const requestId = ++loadRequestId;
|
||||
contentLoaded = false;
|
||||
NotepadStorageService.loadTabContent(NotepadStorageService.currentTabIndex, content => {
|
||||
const activeTab = NotepadStorageService.tabs.length > NotepadStorageService.currentTabIndex ? NotepadStorageService.tabs[NotepadStorageService.currentTabIndex] : null;
|
||||
if (requestId !== loadRequestId || !activeTab || activeTab.id !== requestedTabId)
|
||||
return;
|
||||
lastSavedContent = content;
|
||||
textArea.text = content;
|
||||
contentLoaded = true;
|
||||
syncContentToPlugin();
|
||||
});
|
||||
}
|
||||
|
||||
function saveCurrentTabContent() {
|
||||
if (!currentTab || !contentLoaded) return
|
||||
|
||||
NotepadStorageService.saveTabContent(
|
||||
NotepadStorageService.currentTabIndex,
|
||||
textArea.text
|
||||
)
|
||||
lastSavedContent = textArea.text
|
||||
if (!currentTab || !contentLoaded)
|
||||
return;
|
||||
NotepadStorageService.saveTabContent(NotepadStorageService.currentTabIndex, textArea.text);
|
||||
lastSavedContent = textArea.text;
|
||||
}
|
||||
|
||||
function autoSaveToSession() {
|
||||
if (!currentTab || !contentLoaded) return
|
||||
saveCurrentTabContent()
|
||||
if (!currentTab || !contentLoaded)
|
||||
return;
|
||||
saveCurrentTabContent();
|
||||
}
|
||||
|
||||
function setTextDocumentLineHeight() {
|
||||
return
|
||||
return;
|
||||
}
|
||||
|
||||
property string lastTextForLineModel: ""
|
||||
@@ -99,147 +90,146 @@ Column {
|
||||
|
||||
function updateLineModel() {
|
||||
if (!SettingsData.notepadShowLineNumbers) {
|
||||
lineModel = []
|
||||
lastTextForLineModel = ""
|
||||
return
|
||||
lineModel = [];
|
||||
lastTextForLineModel = "";
|
||||
return;
|
||||
}
|
||||
|
||||
if (textArea.text !== lastTextForLineModel || lineModel.length === 0) {
|
||||
lastTextForLineModel = textArea.text
|
||||
lineModel = textArea.text.split('\n')
|
||||
lastTextForLineModel = textArea.text;
|
||||
lineModel = textArea.text.split('\n');
|
||||
}
|
||||
}
|
||||
|
||||
function performSearch() {
|
||||
let matches = []
|
||||
currentMatchIndex = -1
|
||||
let matches = [];
|
||||
currentMatchIndex = -1;
|
||||
|
||||
if (!searchQuery || searchQuery.length === 0) {
|
||||
searchMatches = []
|
||||
matchCount = 0
|
||||
textArea.select(0, 0)
|
||||
return
|
||||
searchMatches = [];
|
||||
matchCount = 0;
|
||||
textArea.select(0, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
const text = textArea.text
|
||||
const query = searchQuery.toLowerCase()
|
||||
let index = 0
|
||||
const text = textArea.text;
|
||||
const query = searchQuery.toLowerCase();
|
||||
let index = 0;
|
||||
|
||||
while (index < text.length) {
|
||||
const foundIndex = text.toLowerCase().indexOf(query, index)
|
||||
if (foundIndex === -1) break
|
||||
|
||||
const foundIndex = text.toLowerCase().indexOf(query, index);
|
||||
if (foundIndex === -1)
|
||||
break;
|
||||
matches.push({
|
||||
start: foundIndex,
|
||||
end: foundIndex + searchQuery.length
|
||||
})
|
||||
index = foundIndex + 1
|
||||
});
|
||||
index = foundIndex + 1;
|
||||
}
|
||||
|
||||
searchMatches = matches
|
||||
matchCount = matches.length
|
||||
searchMatches = matches;
|
||||
matchCount = matches.length;
|
||||
|
||||
if (matchCount > 0) {
|
||||
currentMatchIndex = 0
|
||||
highlightCurrentMatch()
|
||||
currentMatchIndex = 0;
|
||||
highlightCurrentMatch();
|
||||
} else {
|
||||
textArea.select(0, 0)
|
||||
textArea.select(0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
function highlightCurrentMatch() {
|
||||
if (currentMatchIndex >= 0 && currentMatchIndex < searchMatches.length) {
|
||||
const match = searchMatches[currentMatchIndex]
|
||||
const match = searchMatches[currentMatchIndex];
|
||||
|
||||
textArea.cursorPosition = match.start
|
||||
textArea.moveCursorSelection(match.end, TextEdit.SelectCharacters)
|
||||
textArea.cursorPosition = match.start;
|
||||
textArea.moveCursorSelection(match.end, TextEdit.SelectCharacters);
|
||||
|
||||
const flickable = textArea.parent
|
||||
const flickable = textArea.parent;
|
||||
if (flickable && flickable.contentY !== undefined) {
|
||||
const lineHeight = textArea.font.pixelSize * 1.5
|
||||
const approxLine = textArea.text.substring(0, match.start).split('\n').length
|
||||
const targetY = approxLine * lineHeight - flickable.height / 2
|
||||
flickable.contentY = Math.max(0, Math.min(targetY, flickable.contentHeight - flickable.height))
|
||||
const lineHeight = textArea.font.pixelSize * 1.5;
|
||||
const approxLine = textArea.text.substring(0, match.start).split('\n').length;
|
||||
const targetY = approxLine * lineHeight - flickable.height / 2;
|
||||
flickable.contentY = Math.max(0, Math.min(targetY, flickable.contentHeight - flickable.height));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function findNext() {
|
||||
if (matchCount === 0 || searchMatches.length === 0) return
|
||||
|
||||
currentMatchIndex = (currentMatchIndex + 1) % matchCount
|
||||
highlightCurrentMatch()
|
||||
if (matchCount === 0 || searchMatches.length === 0)
|
||||
return;
|
||||
currentMatchIndex = (currentMatchIndex + 1) % matchCount;
|
||||
highlightCurrentMatch();
|
||||
}
|
||||
|
||||
function findPrevious() {
|
||||
if (matchCount === 0 || searchMatches.length === 0) return
|
||||
|
||||
currentMatchIndex = currentMatchIndex <= 0 ? matchCount - 1 : currentMatchIndex - 1
|
||||
highlightCurrentMatch()
|
||||
if (matchCount === 0 || searchMatches.length === 0)
|
||||
return;
|
||||
currentMatchIndex = currentMatchIndex <= 0 ? matchCount - 1 : currentMatchIndex - 1;
|
||||
highlightCurrentMatch();
|
||||
}
|
||||
|
||||
function showSearch() {
|
||||
searchVisible = true
|
||||
searchVisible = true;
|
||||
Qt.callLater(() => {
|
||||
searchField.forceActiveFocus()
|
||||
})
|
||||
searchField.forceActiveFocus();
|
||||
});
|
||||
}
|
||||
|
||||
function togglePreview() {
|
||||
if (!inlinePreviewVisible) {
|
||||
inlinePreviewVisible = true
|
||||
previewMode = "split"
|
||||
inlinePreviewVisible = true;
|
||||
previewMode = "split";
|
||||
} else if (previewMode === "split") {
|
||||
previewMode = "full"
|
||||
previewMode = "full";
|
||||
} else {
|
||||
inlinePreviewVisible = false
|
||||
previewMode = "split"
|
||||
inlinePreviewVisible = false;
|
||||
previewMode = "split";
|
||||
}
|
||||
syncContentToPlugin()
|
||||
syncContentToPlugin();
|
||||
}
|
||||
|
||||
function renderPreviewHtml() {
|
||||
if (!inlinePreviewVisible) return ""
|
||||
return pluginHighlightedHtml.length > 0 ? pluginHighlightedHtml : "<p><i>Rendering preview…</i></p>"
|
||||
if (!inlinePreviewVisible)
|
||||
return "";
|
||||
return pluginHighlightedHtml.length > 0 ? pluginHighlightedHtml : "<p><i>Rendering preview…</i></p>";
|
||||
}
|
||||
|
||||
function syncContentToPlugin() {
|
||||
if (!PluginService.isPluginLoaded("dankNotepadModule"))
|
||||
return
|
||||
|
||||
return;
|
||||
if (!currentTab)
|
||||
return
|
||||
|
||||
const filePath = currentTab?.filePath || ""
|
||||
const ext = filePath.split('.').pop().toLowerCase()
|
||||
const content = textArea.text
|
||||
return;
|
||||
const filePath = currentTab?.filePath || "";
|
||||
const ext = filePath.split('.').pop().toLowerCase();
|
||||
const content = textArea.text;
|
||||
|
||||
if (content === lastPluginContent && SettingsData.getBuiltInPluginSetting("dankNotepadModule", "previewActive", false) === inlinePreviewVisible) {
|
||||
return
|
||||
return;
|
||||
}
|
||||
|
||||
lastPluginContent = content
|
||||
SettingsData.setBuiltInPluginSetting("dankNotepadModule", "previewActive", inlinePreviewVisible)
|
||||
SettingsData.setBuiltInPluginSetting("dankNotepadModule", "currentFilePath", filePath)
|
||||
SettingsData.setBuiltInPluginSetting("dankNotepadModule", "currentFileExtension", ext)
|
||||
SettingsData.setBuiltInPluginSetting("dankNotepadModule", "sourceContent", content)
|
||||
SettingsData.setBuiltInPluginSetting("dankNotepadModule", "updatedAt", Date.now())
|
||||
lastPluginContent = content;
|
||||
SettingsData.setBuiltInPluginSetting("dankNotepadModule", "previewActive", inlinePreviewVisible);
|
||||
SettingsData.setBuiltInPluginSetting("dankNotepadModule", "currentFilePath", filePath);
|
||||
SettingsData.setBuiltInPluginSetting("dankNotepadModule", "currentFileExtension", ext);
|
||||
SettingsData.setBuiltInPluginSetting("dankNotepadModule", "sourceContent", content);
|
||||
SettingsData.setBuiltInPluginSetting("dankNotepadModule", "updatedAt", Date.now());
|
||||
}
|
||||
|
||||
function hideSearch() {
|
||||
searchVisible = false
|
||||
searchQuery = ""
|
||||
searchMatches = []
|
||||
matchCount = 0
|
||||
currentMatchIndex = -1
|
||||
textArea.select(0, 0)
|
||||
textArea.forceActiveFocus()
|
||||
searchVisible = false;
|
||||
searchQuery = "";
|
||||
searchMatches = [];
|
||||
matchCount = 0;
|
||||
currentMatchIndex = -1;
|
||||
textArea.select(0, 0);
|
||||
textArea.forceActiveFocus();
|
||||
}
|
||||
|
||||
function copyPlainTextToClipboard() {
|
||||
if (!inlinePreviewVisible || !textArea.text) return
|
||||
|
||||
const content = textArea.text
|
||||
if (!inlinePreviewVisible || !textArea.text)
|
||||
return;
|
||||
const content = textArea.text;
|
||||
if (content.length > 0) {
|
||||
const proc = Qt.createQmlObject(`
|
||||
import QtQuick
|
||||
@@ -249,22 +239,19 @@ Column {
|
||||
command: ["sh", "-c", "printf '%s' \\"$CONTENT\\" | dms clipboard copy"]
|
||||
environment: { "CONTENT": content }
|
||||
running: false
|
||||
}`,
|
||||
root,
|
||||
"copyProc"
|
||||
)
|
||||
proc.content = content
|
||||
proc.running = true
|
||||
}`, root, "copyProc");
|
||||
proc.content = content;
|
||||
proc.running = true;
|
||||
proc.exited.connect(() => {
|
||||
ToastService.showInfo(I18n.tr("Copied to clipboard"))
|
||||
proc.destroy()
|
||||
})
|
||||
ToastService.showInfo(I18n.tr("Copied to clipboard"));
|
||||
proc.destroy();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function copyHtmlToClipboard() {
|
||||
if (!inlinePreviewVisible || !pluginHighlightedHtml) return
|
||||
|
||||
if (!inlinePreviewVisible || !pluginHighlightedHtml)
|
||||
return;
|
||||
if (pluginHighlightedHtml.length > 0) {
|
||||
const proc = Qt.createQmlObject(`
|
||||
import QtQuick
|
||||
@@ -274,16 +261,13 @@ Column {
|
||||
command: ["sh", "-c", "printf '%s' \\"$CONTENT\\" | dms clipboard copy"]
|
||||
environment: { "CONTENT": content }
|
||||
running: false
|
||||
}`,
|
||||
root,
|
||||
"copyProcHtml"
|
||||
)
|
||||
proc.content = pluginHighlightedHtml
|
||||
proc.running = true
|
||||
}`, root, "copyProcHtml");
|
||||
proc.content = pluginHighlightedHtml;
|
||||
proc.running = true;
|
||||
proc.exited.connect(() => {
|
||||
ToastService.showInfo(I18n.tr("HTML copied to clipboard"))
|
||||
proc.destroy()
|
||||
})
|
||||
ToastService.showInfo(I18n.tr("HTML copied to clipboard"));
|
||||
proc.destroy();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -301,7 +285,7 @@ Column {
|
||||
radius: Theme.cornerRadius
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
OpacityAnimator {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.standardEasing
|
||||
}
|
||||
@@ -334,43 +318,43 @@ Column {
|
||||
clip: true
|
||||
|
||||
Component.onCompleted: {
|
||||
text = root.searchQuery
|
||||
text = root.searchQuery;
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: root
|
||||
function onSearchQueryChanged() {
|
||||
if (searchField.text !== root.searchQuery) {
|
||||
searchField.text = root.searchQuery
|
||||
searchField.text = root.searchQuery;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onTextChanged: {
|
||||
if (root.searchQuery !== text) {
|
||||
root.searchQuery = text
|
||||
root.performSearch()
|
||||
root.searchQuery = text;
|
||||
root.performSearch();
|
||||
}
|
||||
}
|
||||
Keys.onEscapePressed: event => {
|
||||
root.hideSearch()
|
||||
event.accepted = true
|
||||
root.hideSearch();
|
||||
event.accepted = true;
|
||||
}
|
||||
Keys.onReturnPressed: event => {
|
||||
if (event.modifiers & Qt.ShiftModifier) {
|
||||
root.findPrevious()
|
||||
root.findPrevious();
|
||||
} else {
|
||||
root.findNext()
|
||||
root.findNext();
|
||||
}
|
||||
event.accepted = true
|
||||
event.accepted = true;
|
||||
}
|
||||
Keys.onEnterPressed: event => {
|
||||
if (event.modifiers & Qt.ShiftModifier) {
|
||||
root.findPrevious()
|
||||
root.findPrevious();
|
||||
} else {
|
||||
root.findNext()
|
||||
root.findNext();
|
||||
}
|
||||
event.accepted = true
|
||||
event.accepted = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -541,31 +525,41 @@ Column {
|
||||
SequentialAnimation on opacity {
|
||||
running: textArea.activeFocus
|
||||
loops: Animation.Infinite
|
||||
PropertyAnimation { 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 }
|
||||
PropertyAnimation {
|
||||
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: {
|
||||
loadCurrentTabContent()
|
||||
setTextDocumentLineHeight()
|
||||
root.updateLineModel()
|
||||
loadCurrentTabContent();
|
||||
setTextDocumentLineHeight();
|
||||
root.updateLineModel();
|
||||
Qt.callLater(() => {
|
||||
textArea.forceActiveFocus()
|
||||
})
|
||||
textArea.forceActiveFocus();
|
||||
});
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: NotepadStorageService
|
||||
function onCurrentTabIndexChanged() {
|
||||
loadCurrentTabContent()
|
||||
loadCurrentTabContent();
|
||||
Qt.callLater(() => {
|
||||
textArea.forceActiveFocus()
|
||||
})
|
||||
textArea.forceActiveFocus();
|
||||
});
|
||||
}
|
||||
function onTabsChanged() {
|
||||
if (NotepadStorageService.tabs.length > 0 && !contentLoaded) {
|
||||
loadCurrentTabContent()
|
||||
loadCurrentTabContent();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -573,53 +567,53 @@ Column {
|
||||
Connections {
|
||||
target: SettingsData
|
||||
function onNotepadShowLineNumbersChanged() {
|
||||
root.updateLineModel()
|
||||
root.updateLineModel();
|
||||
}
|
||||
}
|
||||
|
||||
onTextChanged: {
|
||||
if (contentLoaded && text !== lastSavedContent) {
|
||||
autoSaveTimer.restart()
|
||||
autoSaveTimer.restart();
|
||||
}
|
||||
root.contentChanged()
|
||||
root.updateLineModel()
|
||||
pluginSyncTimer.restart()
|
||||
root.contentChanged();
|
||||
root.updateLineModel();
|
||||
pluginSyncTimer.restart();
|
||||
}
|
||||
|
||||
Keys.onEscapePressed: (event) => {
|
||||
root.escapePressed()
|
||||
event.accepted = true
|
||||
Keys.onEscapePressed: event => {
|
||||
root.escapePressed();
|
||||
event.accepted = true;
|
||||
}
|
||||
|
||||
Keys.onPressed: (event) => {
|
||||
Keys.onPressed: event => {
|
||||
if (event.modifiers & Qt.ControlModifier) {
|
||||
switch (event.key) {
|
||||
case Qt.Key_S:
|
||||
event.accepted = true
|
||||
root.saveRequested()
|
||||
break
|
||||
event.accepted = true;
|
||||
root.saveRequested();
|
||||
break;
|
||||
case Qt.Key_O:
|
||||
event.accepted = true
|
||||
root.openRequested()
|
||||
break
|
||||
event.accepted = true;
|
||||
root.openRequested();
|
||||
break;
|
||||
case Qt.Key_N:
|
||||
event.accepted = true
|
||||
root.newRequested()
|
||||
break
|
||||
event.accepted = true;
|
||||
root.newRequested();
|
||||
break;
|
||||
case Qt.Key_A:
|
||||
event.accepted = true
|
||||
textArea.selectAll()
|
||||
break
|
||||
event.accepted = true;
|
||||
textArea.selectAll();
|
||||
break;
|
||||
case Qt.Key_F:
|
||||
event.accepted = true
|
||||
root.showSearch()
|
||||
break
|
||||
event.accepted = true;
|
||||
root.showSearch();
|
||||
break;
|
||||
case Qt.Key_P:
|
||||
if (PluginService.isPluginLoaded("dankNotepadModule")) {
|
||||
event.accepted = true
|
||||
root.previewRequested()
|
||||
event.accepted = true;
|
||||
root.previewRequested();
|
||||
}
|
||||
break
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -845,19 +839,16 @@ Column {
|
||||
StyledText {
|
||||
text: {
|
||||
const len = textArea.text.length;
|
||||
if (len === 0) return I18n.tr("Empty");
|
||||
return len === 1
|
||||
? I18n.tr("%1 character").arg(len)
|
||||
: I18n.tr("%1 characters").arg(len);
|
||||
if (len === 0)
|
||||
return I18n.tr("Empty");
|
||||
return len === 1 ? I18n.tr("%1 character").arg(len) : I18n.tr("%1 characters").arg(len);
|
||||
}
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceTextMedium
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: textArea.lineCount === 1
|
||||
? I18n.tr("Line: %1").arg(textArea.lineCount)
|
||||
: I18n.tr("Lines: %1").arg(textArea.lineCount)
|
||||
text: textArea.lineCount === 1 ? I18n.tr("Line: %1").arg(textArea.lineCount) : I18n.tr("Lines: %1").arg(textArea.lineCount)
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceTextMedium
|
||||
visible: textArea.text.length > 0
|
||||
@@ -867,29 +858,29 @@ Column {
|
||||
StyledText {
|
||||
text: {
|
||||
if (autoSaveTimer.running) {
|
||||
return I18n.tr("Auto-saving...")
|
||||
return I18n.tr("Auto-saving...");
|
||||
}
|
||||
|
||||
if (hasUnsavedChanges()) {
|
||||
if (currentTab && currentTab.isTemporary) {
|
||||
return I18n.tr("Unsaved note...")
|
||||
return I18n.tr("Unsaved note...");
|
||||
} else {
|
||||
return I18n.tr("Unsaved changes")
|
||||
return I18n.tr("Unsaved changes");
|
||||
}
|
||||
} else {
|
||||
return I18n.tr("Saved")
|
||||
return I18n.tr("Saved");
|
||||
}
|
||||
}
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: {
|
||||
if (autoSaveTimer.running) {
|
||||
return Theme.primary
|
||||
return Theme.primary;
|
||||
}
|
||||
|
||||
if (hasUnsavedChanges()) {
|
||||
return Theme.warning
|
||||
return Theme.warning;
|
||||
} else {
|
||||
return Theme.success
|
||||
return Theme.success;
|
||||
}
|
||||
}
|
||||
opacity: textArea.text.length > 0 ? 1.0 : 0.0
|
||||
@@ -902,7 +893,7 @@ Column {
|
||||
interval: 2000
|
||||
repeat: false
|
||||
onTriggered: {
|
||||
autoSaveToSession()
|
||||
autoSaveToSession();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -917,7 +908,7 @@ Column {
|
||||
target: SettingsData
|
||||
function onBuiltInPluginSettingsChanged() {
|
||||
if (PluginService.isPluginLoaded("dankNotepadModule")) {
|
||||
pluginHighlightedHtml = SettingsData.getBuiltInPluginSetting("dankNotepadModule", "highlightedHtml", "")
|
||||
pluginHighlightedHtml = SettingsData.getBuiltInPluginSetting("dankNotepadModule", "highlightedHtml", "");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -283,7 +283,7 @@ Item {
|
||||
|
||||
Behavior on x {
|
||||
enabled: !swipeDragHandler.active && delegateRoot.__delegateInitialized
|
||||
NumberAnimation {
|
||||
XAnimator {
|
||||
duration: Theme.notificationExitDuration
|
||||
easing.type: Theme.standardEasing
|
||||
}
|
||||
@@ -291,7 +291,7 @@ Item {
|
||||
|
||||
Behavior on opacity {
|
||||
enabled: delegateRoot.__delegateInitialized
|
||||
NumberAnimation {
|
||||
OpacityAnimator {
|
||||
duration: delegateRoot.__delegateInitialized ? Theme.notificationExitDuration : 0
|
||||
}
|
||||
}
|
||||
|
||||
@@ -226,7 +226,7 @@ DankListView {
|
||||
|
||||
Behavior on x {
|
||||
enabled: !swipeDragHandler.active && !delegateRoot.isDismissing && (listView.swipingCardIndex === -1 || !delegateRoot.isAdjacentToSwipe) && listView.listInitialized
|
||||
NumberAnimation {
|
||||
XAnimator {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.standardEasing
|
||||
}
|
||||
@@ -234,7 +234,7 @@ DankListView {
|
||||
|
||||
Behavior on opacity {
|
||||
enabled: listView.listInitialized
|
||||
NumberAnimation {
|
||||
OpacityAnimator {
|
||||
duration: listView.listInitialized ? Theme.shortDuration : 0
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,7 +75,7 @@ Rectangle {
|
||||
|
||||
Behavior on scale {
|
||||
enabled: listLevelScaleAnimationsEnabled
|
||||
NumberAnimation {
|
||||
ScaleAnimator {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.standardEasing
|
||||
}
|
||||
@@ -545,7 +545,7 @@ Rectangle {
|
||||
|
||||
Behavior on x {
|
||||
enabled: !expandedSwipeHandler.active && !expandedDelegateWrapper.isDismissing
|
||||
NumberAnimation {
|
||||
XAnimator {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.standardEasing
|
||||
}
|
||||
@@ -553,7 +553,7 @@ Rectangle {
|
||||
|
||||
Behavior on scale {
|
||||
enabled: !expandedSwipeHandler.active
|
||||
NumberAnimation {
|
||||
ScaleAnimator {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.standardEasing
|
||||
}
|
||||
@@ -762,7 +762,7 @@ Rectangle {
|
||||
spacing: contentSpacing
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
OpacityAnimator {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.standardEasing
|
||||
}
|
||||
@@ -822,7 +822,7 @@ Rectangle {
|
||||
color: isHovered ? Theme.withAlpha(Theme.primary, Theme.stateLayerHover) : "transparent"
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
OpacityAnimator {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.standardEasing
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ Rectangle {
|
||||
}
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
OpacityAnimator {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.standardEasing
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ Rectangle {
|
||||
|
||||
opacity: expanded ? 1 : 0
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
OpacityAnimator {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.emphasizedEasing
|
||||
}
|
||||
@@ -123,327 +123,327 @@ Rectangle {
|
||||
anchors.margins: Theme.spacingL
|
||||
spacing: Theme.spacingM
|
||||
|
||||
StyledText {
|
||||
text: I18n.tr("Notification Settings")
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
font.weight: Font.Bold
|
||||
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
|
||||
}
|
||||
StyledText {
|
||||
text: I18n.tr("Notification Settings")
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
font.weight: Font.Bold
|
||||
color: Theme.surfaceText
|
||||
}
|
||||
|
||||
DankToggle {
|
||||
id: dndToggle
|
||||
anchors.right: parent.right
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
checked: SessionData.doNotDisturb
|
||||
onToggled: SessionData.setDoNotDisturb(!SessionData.doNotDisturb)
|
||||
}
|
||||
}
|
||||
Item {
|
||||
width: parent.width
|
||||
height: Math.max(dndRow.implicitHeight, dndToggle.implicitHeight) + Theme.spacingS
|
||||
|
||||
Rectangle {
|
||||
width: parent.width
|
||||
height: 1
|
||||
color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.1)
|
||||
}
|
||||
Row {
|
||||
id: dndRow
|
||||
anchors.left: parent.left
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: Theme.spacingM
|
||||
|
||||
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;
|
||||
DankIcon {
|
||||
name: SessionData.doNotDisturb ? "notifications_off" : "notifications"
|
||||
size: Theme.iconSizeSmall
|
||||
color: SessionData.doNotDisturb ? Theme.error : Theme.surfaceText
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
width: parent.width
|
||||
text: I18n.tr("Notification Overlay")
|
||||
text: I18n.tr("Do Not Disturb")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceText
|
||||
wrapMode: Text.Wrap
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
}
|
||||
|
||||
StyledText {
|
||||
width: parent.width
|
||||
text: I18n.tr("Display all priorities over fullscreen apps")
|
||||
font.pixelSize: Theme.fontSizeSmall - 1
|
||||
color: Theme.surfaceVariantText
|
||||
wrapMode: Text.Wrap
|
||||
DankToggle {
|
||||
id: dndToggle
|
||||
anchors.right: parent.right
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
checked: SessionData.doNotDisturb
|
||||
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 {
|
||||
id: overlayToggle
|
||||
anchors.right: parent.right
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
checked: SettingsData.notificationOverlayEnabled
|
||||
onToggled: toggled => SettingsData.set("notificationOverlayEnabled", toggled)
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
width: parent.width
|
||||
height: Math.max(privacyRow.implicitHeight, privacyToggle.implicitHeight) + Theme.spacingS
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Row {
|
||||
id: privacyRow
|
||||
anchors.left: parent.left
|
||||
anchors.right: privacyToggle.left
|
||||
anchors.rightMargin: Theme.spacingM
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: Theme.spacingM
|
||||
Rectangle {
|
||||
width: parent.width
|
||||
height: 1
|
||||
color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.1)
|
||||
}
|
||||
|
||||
DankIcon {
|
||||
name: "privacy_tip"
|
||||
size: Theme.iconSizeSmall
|
||||
color: SettingsData.notificationPopupPrivacyMode ? Theme.primary : Theme.surfaceText
|
||||
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 {
|
||||
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 {
|
||||
spacing: 2
|
||||
DankToggle {
|
||||
id: overlayToggle
|
||||
anchors.right: parent.right
|
||||
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 {
|
||||
width: parent.width
|
||||
text: I18n.tr("Privacy Mode")
|
||||
text: I18n.tr("Low Priority")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
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 {
|
||||
width: parent.width
|
||||
text: I18n.tr("Hide notification content until expanded")
|
||||
font.pixelSize: Theme.fontSizeSmall - 1
|
||||
color: Theme.surfaceVariantText
|
||||
wrapMode: Text.Wrap
|
||||
text: I18n.tr("Normal Priority")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceText
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
text: I18n.tr("Low Priority")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceText
|
||||
DankToggle {
|
||||
id: normalToggle
|
||||
anchors.right: parent.right
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
checked: SettingsData.notificationHistorySaveNormal
|
||||
onToggled: toggled => SettingsData.set("notificationHistorySaveNormal", toggled)
|
||||
}
|
||||
}
|
||||
|
||||
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(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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,10 +36,13 @@ PanelWindow {
|
||||
|
||||
WindowBlur {
|
||||
targetWindow: win
|
||||
blurX: content.x + content.cardInset + swipeTx.x + tx.x
|
||||
blurY: content.y + content.cardInset + swipeTx.y + tx.y
|
||||
blurWidth: !win._finalized && !win.connectedFrameMode ? Math.max(0, content.width - content.cardInset * 2) : 0
|
||||
blurHeight: !win._finalized && !win.connectedFrameMode ? Math.max(0, content.height - content.cardInset * 2) : 0
|
||||
readonly property real s: Math.min(1, content.scale) * Math.max(0, content.opacity)
|
||||
readonly property real innerW: Math.max(0, content.width - content.cardInset * 2)
|
||||
readonly property real innerH: Math.max(0, content.height - content.cardInset * 2)
|
||||
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
|
||||
}
|
||||
|
||||
@@ -993,7 +996,7 @@ PanelWindow {
|
||||
z: 20
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
OpacityAnimator {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.standardEasing
|
||||
}
|
||||
@@ -1048,7 +1051,7 @@ PanelWindow {
|
||||
visible: actionCount < 3 && cardHoverHandler.hovered
|
||||
opacity: visible ? 1 : 0
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
OpacityAnimator {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.standardEasing
|
||||
}
|
||||
@@ -1136,7 +1139,7 @@ PanelWindow {
|
||||
}
|
||||
|
||||
onTranslationChanged: {
|
||||
if (win.exiting)
|
||||
if (win.exiting || content.swipeDismissing)
|
||||
return;
|
||||
|
||||
content.swipeOffset = translation.x;
|
||||
@@ -1152,7 +1155,7 @@ PanelWindow {
|
||||
}
|
||||
|
||||
Behavior on opacity {
|
||||
enabled: !content.swipeActive
|
||||
enabled: !content.swipeActive && !content.swipeDismissing
|
||||
NumberAnimation {
|
||||
duration: Theme.shortDuration
|
||||
}
|
||||
@@ -1269,7 +1272,6 @@ PanelWindow {
|
||||
NumberAnimation {
|
||||
target: content
|
||||
property: "opacity"
|
||||
from: 1
|
||||
to: Theme.isDirectionalEffect ? 1 : 0
|
||||
duration: Theme.notificationExitDuration
|
||||
easing.type: Easing.BezierSpline
|
||||
@@ -1279,7 +1281,6 @@ PanelWindow {
|
||||
NumberAnimation {
|
||||
target: content
|
||||
property: "scale"
|
||||
from: 1
|
||||
to: Theme.isDirectionalEffect ? 1 : Theme.effectScaleCollapsed
|
||||
duration: Theme.notificationExitDuration
|
||||
easing.type: Easing.BezierSpline
|
||||
|
||||
@@ -519,7 +519,7 @@ Item {
|
||||
}
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
OpacityAnimator {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.standardEasing
|
||||
}
|
||||
|
||||
@@ -182,7 +182,7 @@ SettingsCard {
|
||||
opacity: visible ? 1 : 0
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
OpacityAnimator {
|
||||
duration: Theme.mediumDuration
|
||||
easing.type: Theme.emphasizedEasing
|
||||
}
|
||||
|
||||
@@ -107,7 +107,7 @@ Item {
|
||||
}
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
OpacityAnimator {
|
||||
duration: Theme.mediumDuration
|
||||
easing.type: Theme.emphasizedEasing
|
||||
}
|
||||
|
||||
@@ -587,7 +587,7 @@ FloatingWindow {
|
||||
border.color: buttonState === "incompatible" ? Theme.warning : Theme.outline
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
OpacityAnimator {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.standardEasing
|
||||
}
|
||||
|
||||
@@ -619,7 +619,7 @@ FloatingWindow {
|
||||
border.color: isInstalled ? (uninstallMouseArea.containsMouse ? Theme.error : Theme.outline) : "transparent"
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
OpacityAnimator {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.standardEasing
|
||||
}
|
||||
|
||||
@@ -380,7 +380,7 @@ Item {
|
||||
}
|
||||
|
||||
Behavior on scale {
|
||||
NumberAnimation {
|
||||
ScaleAnimator {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.emphasizedEasing
|
||||
}
|
||||
@@ -633,7 +633,7 @@ Item {
|
||||
scale: isActive ? 1.03 : 1
|
||||
|
||||
Behavior on scale {
|
||||
NumberAnimation {
|
||||
ScaleAnimator {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.emphasizedEasing
|
||||
}
|
||||
@@ -989,7 +989,7 @@ Item {
|
||||
}
|
||||
|
||||
Behavior on scale {
|
||||
NumberAnimation {
|
||||
ScaleAnimator {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.emphasizedEasing
|
||||
}
|
||||
|
||||
@@ -308,7 +308,7 @@ Column {
|
||||
}
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
OpacityAnimator {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.standardEasing
|
||||
}
|
||||
@@ -620,7 +620,7 @@ Column {
|
||||
}
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
OpacityAnimator {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.standardEasing
|
||||
}
|
||||
|
||||
@@ -97,7 +97,7 @@ Item {
|
||||
}
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
OpacityAnimator {
|
||||
duration: Theme.mediumDuration
|
||||
easing.type: Theme.emphasizedEasing
|
||||
}
|
||||
|
||||
@@ -416,7 +416,7 @@ PanelWindow {
|
||||
}
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
OpacityAnimator {
|
||||
duration: Theme.mediumDuration
|
||||
easing.type: Theme.emphasizedEasing
|
||||
}
|
||||
|
||||
@@ -48,268 +48,271 @@ Scope {
|
||||
bottom: true
|
||||
}
|
||||
|
||||
HyprlandFocusGrab {
|
||||
id: grab
|
||||
windows: [root]
|
||||
active: false
|
||||
property bool hasBeenActivated: false
|
||||
onActiveChanged: {
|
||||
if (active) {
|
||||
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()
|
||||
HyprlandFocusGrab {
|
||||
id: grab
|
||||
windows: [root]
|
||||
active: false
|
||||
property bool hasBeenActivated: false
|
||||
onActiveChanged: {
|
||||
if (active) {
|
||||
hasBeenActivated = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
onCleared: () => {
|
||||
if (hasBeenActivated && overviewScope.overviewOpen) {
|
||||
overviewScope.overviewOpen = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
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
|
||||
Connections {
|
||||
target: overviewScope
|
||||
function onOverviewOpenChanged() {
|
||||
if (overviewScope.overviewOpen) {
|
||||
grab.hasBeenActivated = false;
|
||||
if (CompositorService.useHyprlandFocusGrab)
|
||||
delayedGrabTimer.start();
|
||||
} else {
|
||||
targetIndex = currentIndex + 1
|
||||
if (targetIndex >= thisMonitorWorkspaceIds.length) targetIndex = 0
|
||||
delayedGrabTimer.stop();
|
||||
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 {
|
||||
target: root
|
||||
function onMonitorIsFocusedChanged() {
|
||||
if (root.monitorIsFocused && overviewScope.overviewOpen) {
|
||||
Qt.callLater(() => focusScope.forceActiveFocus())
|
||||
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 {
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,7 +28,8 @@ Rectangle {
|
||||
|
||||
Behavior on scale {
|
||||
enabled: enableScaleAnimation && Theme.currentAnimationSpeed !== SettingsData.AnimationSpeed.None
|
||||
DankAnim {
|
||||
ScaleAnimator {
|
||||
easing.type: Easing.BezierSpline
|
||||
duration: 100
|
||||
easing.bezierCurve: Theme.expressiveCurves.standard
|
||||
}
|
||||
|
||||
@@ -197,7 +197,7 @@ Row {
|
||||
|
||||
Behavior on opacity {
|
||||
enabled: root.userInteracted
|
||||
NumberAnimation {
|
||||
OpacityAnimator {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.standardEasing
|
||||
}
|
||||
@@ -205,7 +205,7 @@ Row {
|
||||
|
||||
Behavior on scale {
|
||||
enabled: root.userInteracted
|
||||
NumberAnimation {
|
||||
ScaleAnimator {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.emphasizedEasing
|
||||
}
|
||||
|
||||
@@ -45,7 +45,8 @@ ColumnLayout {
|
||||
|
||||
Behavior on rotation {
|
||||
enabled: Theme.currentAnimationSpeed !== SettingsData.AnimationSpeed.None
|
||||
DankAnim {
|
||||
RotationAnimator {
|
||||
easing.type: Easing.BezierSpline
|
||||
duration: Theme.shortDuration
|
||||
easing.bezierCurve: Theme.expressiveCurves.standard
|
||||
}
|
||||
@@ -88,7 +89,8 @@ ColumnLayout {
|
||||
|
||||
Behavior on opacity {
|
||||
enabled: Theme.currentAnimationSpeed !== SettingsData.AnimationSpeed.None
|
||||
DankAnim {
|
||||
OpacityAnimator {
|
||||
easing.type: Easing.BezierSpline
|
||||
duration: Theme.shortDuration
|
||||
easing.bezierCurve: Theme.expressiveCurves.standard
|
||||
}
|
||||
@@ -108,7 +110,8 @@ ColumnLayout {
|
||||
|
||||
Behavior on opacity {
|
||||
enabled: Theme.currentAnimationSpeed !== SettingsData.AnimationSpeed.None
|
||||
DankAnim {
|
||||
OpacityAnimator {
|
||||
easing.type: Easing.BezierSpline
|
||||
duration: Theme.shortDuration
|
||||
easing.bezierCurve: Theme.expressiveCurves.standard
|
||||
}
|
||||
|
||||
@@ -187,7 +187,7 @@ Item {
|
||||
anchors.rightMargin: Theme.spacingS
|
||||
|
||||
Behavior on rotation {
|
||||
NumberAnimation {
|
||||
RotationAnimator {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.standardEasing
|
||||
}
|
||||
|
||||
@@ -157,7 +157,7 @@ Item {
|
||||
opacity: (locationInput.getActiveFocus() && locationInput.text.length > 2) ? 1 : 0
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
OpacityAnimator {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.standardEasing
|
||||
}
|
||||
|
||||
@@ -315,14 +315,14 @@ PanelWindow {
|
||||
}
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
OpacityAnimator {
|
||||
duration: animationDuration
|
||||
easing.type: animationEasing
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on scale {
|
||||
NumberAnimation {
|
||||
ScaleAnimator {
|
||||
duration: animationDuration
|
||||
easing.type: animationEasing
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
onAlignedYChanged: _queueFullSync()
|
||||
onAlignedWidthChanged: _queueFullSync()
|
||||
onContentAnimXChanged: _syncPopoutAnim("x")
|
||||
onContentAnimYChanged: _syncPopoutAnim("y")
|
||||
onRenderedAlignedYChanged: _syncPopoutBody()
|
||||
onRenderedAlignedHeightChanged: _syncPopoutBody()
|
||||
onContentAnimXChanged: _queueAnimSync()
|
||||
onContentAnimYChanged: _queueAnimSync()
|
||||
onRenderedAlignedYChanged: _queueBodySync()
|
||||
onRenderedAlignedHeightChanged: _queueBodySync()
|
||||
onScreenChanged: _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
|
||||
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
|
||||
blurHeight: (shouldBeVisible && contentWrapper.opacity > 0) ? (trackBlurFromBarEdge ? Math.max(0, contentContainer.height - Math.abs(_dyClamp)) : (contentContainer.height + contentContainer.verticalConnectorExtent * 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.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
|
||||
}
|
||||
|
||||
@@ -959,7 +990,7 @@ Item {
|
||||
|
||||
width: rollOutAdjuster.baseWidth + extraLeft + extraRight
|
||||
height: rollOutAdjuster.baseHeight + extraTop + extraBottom
|
||||
opacity: contentWrapper.opacity
|
||||
opacity: contentWrapper.publishedOpacity
|
||||
scale: contentWrapper.scale
|
||||
x: contentWrapper.x - extraLeft
|
||||
y: contentWrapper.y - extraTop
|
||||
@@ -1024,23 +1055,48 @@ Item {
|
||||
id: contentWrapper
|
||||
width: rollOutAdjuster.baseWidth
|
||||
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)
|
||||
visible: opacity > 0
|
||||
visible: _renderActive
|
||||
|
||||
scale: contentContainer.scaleValue
|
||||
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)
|
||||
|
||||
layer.enabled: contentWrapper.opacity < 1
|
||||
layer.enabled: _animating || (!Theme.isDirectionalEffect && publishedOpacity < 1)
|
||||
layer.smooth: false
|
||||
layer.textureSize: root.dpr > 1 ? Qt.size(Math.ceil(width * root.dpr), Math.ceil(height * root.dpr)) : Qt.size(0, 0)
|
||||
|
||||
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
|
||||
NumberAnimation {
|
||||
duration: Math.round(Theme.variantDuration(animationDuration, shouldBeVisible) * Theme.variantOpacityDurationScale)
|
||||
easing.type: Easing.BezierSpline
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -527,7 +527,7 @@ Item {
|
||||
targetWindow: contentWindow
|
||||
readonly property real s: Math.min(1, contentContainer.scaleValue)
|
||||
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)
|
||||
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 {
|
||||
id: contentContainer
|
||||
x: shadowBuffer + root.alignedX - root._surfaceBodyX
|
||||
y: root._fullHeight
|
||||
? (root.fluidStandaloneActive ? root.renderedAlignedY : root.alignedY)
|
||||
: shadowBuffer + (root.fluidStandaloneActive ? root.renderedAlignedY : root.alignedY) - root._surfaceBodyY
|
||||
y: root._fullHeight ? (root.fluidStandaloneActive ? root.renderedAlignedY : root.alignedY) : shadowBuffer + (root.fluidStandaloneActive ? root.renderedAlignedY : root.alignedY) - root._surfaceBodyY
|
||||
width: root.alignedWidth
|
||||
height: root.fluidStandaloneActive ? root.renderedAlignedHeight : root.alignedHeight
|
||||
|
||||
@@ -759,7 +757,7 @@ Item {
|
||||
id: shadowSource
|
||||
width: rollOutAdjuster.baseWidth
|
||||
height: rollOutAdjuster.baseHeight
|
||||
opacity: contentWrapper.opacity
|
||||
opacity: contentWrapper.publishedOpacity
|
||||
scale: root.fluidStandaloneActive ? 1 : contentWrapper.scale
|
||||
x: root.fluidStandaloneActive ? 0 : contentWrapper.x
|
||||
y: root.fluidStandaloneActive ? 0 : contentWrapper.y
|
||||
@@ -775,23 +773,52 @@ Item {
|
||||
id: contentWrapper
|
||||
width: rollOutAdjuster.baseWidth
|
||||
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)
|
||||
visible: opacity > 0
|
||||
visible: _renderActive
|
||||
scale: contentContainer.scaleValue
|
||||
transformOrigin: Item.Center
|
||||
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)
|
||||
|
||||
layer.enabled: contentWrapper.opacity < 1
|
||||
layer.enabled: _animating || (!Theme.isDirectionalEffect && publishedOpacity < 1)
|
||||
layer.smooth: false
|
||||
layer.textureSize: root.dpr > 1 ? Qt.size(Math.ceil(width * root.dpr), Math.ceil(height * root.dpr)) : Qt.size(0, 0)
|
||||
|
||||
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
|
||||
NumberAnimation {
|
||||
duration: Math.round(Theme.variantDuration(root.animationDuration, root.shouldBeVisible) * Theme.variantOpacityDurationScale)
|
||||
easing.type: Easing.BezierSpline
|
||||
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
|
||||
x: root.fluidStandaloneActive ? 0 : contentWrapper.x
|
||||
y: root.fluidStandaloneActive ? 0 : contentWrapper.y
|
||||
opacity: contentWrapper.opacity
|
||||
opacity: contentWrapper.publishedOpacity
|
||||
scale: root.fluidStandaloneActive ? 1 : contentWrapper.scale
|
||||
visible: contentWrapper.visible
|
||||
radius: Theme.cornerRadius
|
||||
|
||||
@@ -23,7 +23,7 @@ ScrollBar {
|
||||
visible: policy !== ScrollBar.AlwaysOff
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
OpacityAnimator {
|
||||
duration: 160
|
||||
easing.type: Easing.OutQuad
|
||||
}
|
||||
|
||||
@@ -225,7 +225,7 @@ Item {
|
||||
y: parent.midY - height / 2
|
||||
z: 3
|
||||
Behavior on x {
|
||||
NumberAnimation {
|
||||
XAnimator {
|
||||
duration: 80
|
||||
}
|
||||
}
|
||||
|
||||
@@ -171,7 +171,7 @@ Item {
|
||||
scale: active ? 1.05 : 1.0
|
||||
|
||||
Behavior on scale {
|
||||
NumberAnimation {
|
||||
ScaleAnimator {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.standardEasing
|
||||
}
|
||||
@@ -278,7 +278,7 @@ Item {
|
||||
}
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
OpacityAnimator {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.standardEasing
|
||||
}
|
||||
|
||||
@@ -201,7 +201,7 @@ FocusScope {
|
||||
|
||||
Behavior on x {
|
||||
enabled: indicator.animationEnabled
|
||||
NumberAnimation {
|
||||
XAnimator {
|
||||
duration: Theme.mediumDuration
|
||||
easing.type: Theme.standardEasing
|
||||
}
|
||||
|
||||
@@ -168,14 +168,14 @@ Item {
|
||||
scale: (toggle.checked && toggle.enabled) ? 1 : 0.6
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
OpacityAnimator {
|
||||
duration: Anims.durShort
|
||||
easing.type: Easing.BezierSpline
|
||||
easing.bezierCurve: Anims.emphasized
|
||||
}
|
||||
}
|
||||
Behavior on scale {
|
||||
NumberAnimation {
|
||||
ScaleAnimator {
|
||||
duration: Anims.durShort
|
||||
easing.type: Easing.BezierSpline
|
||||
easing.bezierCurve: Anims.emphasized
|
||||
|
||||
@@ -20,7 +20,7 @@ Rectangle {
|
||||
}
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
OpacityAnimator {
|
||||
duration: standardAnimation.duration
|
||||
easing.type: standardAnimation["easing.type"]
|
||||
easing.bezierCurve: standardAnimation["easing.bezierCurve"]
|
||||
|
||||
@@ -40,7 +40,7 @@ Text {
|
||||
//renderType: Text.NativeRendering
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
OpacityAnimator {
|
||||
duration: standardAnimation.duration
|
||||
easing.type: standardAnimation["easing.type"]
|
||||
easing.bezierCurve: standardAnimation["easing.bezierCurve"]
|
||||
|
||||
294
scripts/format-staged.py
Executable file
294
scripts/format-staged.py
Executable 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())
|
||||
Reference in New Issue
Block a user