1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2026-01-24 21:42:51 -05:00

qmlfmt with 4 space

This commit is contained in:
bbedward
2025-08-20 00:05:14 -04:00
parent 6e0977c719
commit b688bbfe83
154 changed files with 28809 additions and 27639 deletions

View File

@@ -21,123 +21,124 @@ DankModal {
property Component clipboardContent
function updateFilteredModel() {
filteredClipboardModel.clear();
filteredClipboardModel.clear()
for (var i = 0; i < clipboardModel.count; i++) {
const entry = clipboardModel.get(i).entry;
const entry = clipboardModel.get(i).entry
if (searchText.trim().length === 0) {
filteredClipboardModel.append({
"entry": entry
});
"entry": entry
})
} else {
const content = getEntryPreview(entry).toLowerCase();
const content = getEntryPreview(entry).toLowerCase()
if (content.includes(searchText.toLowerCase()))
filteredClipboardModel.append({
"entry": entry
});
"entry": entry
})
}
}
clipboardHistoryModal.totalCount = filteredClipboardModel.count;
clipboardHistoryModal.totalCount = filteredClipboardModel.count
// Clamp selectedIndex to valid range
if (filteredClipboardModel.count === 0) {
keyboardNavigationActive = false;
selectedIndex = 0;
keyboardNavigationActive = false
selectedIndex = 0
} else if (selectedIndex >= filteredClipboardModel.count) {
selectedIndex = filteredClipboardModel.count - 1;
selectedIndex = filteredClipboardModel.count - 1
}
}
function toggle() {
if (shouldBeVisible)
hide();
hide()
else
show();
show()
}
function show() {
open();
clipboardHistoryModal.searchText = "";
initializeThumbnailSystem();
refreshClipboard();
keyboardController.reset();
Qt.callLater(function() {
open()
clipboardHistoryModal.searchText = ""
initializeThumbnailSystem()
refreshClipboard()
keyboardController.reset()
Qt.callLater(function () {
if (contentLoader.item && contentLoader.item.searchField) {
contentLoader.item.searchField.text = "";
contentLoader.item.searchField.forceActiveFocus();
contentLoader.item.searchField.text = ""
contentLoader.item.searchField.forceActiveFocus()
}
});
})
}
function hide() {
close();
clipboardHistoryModal.searchText = "";
updateFilteredModel();
keyboardController.reset();
cleanupTempFiles();
close()
clipboardHistoryModal.searchText = ""
updateFilteredModel()
keyboardController.reset()
cleanupTempFiles()
}
function initializeThumbnailSystem() {
}
function initializeThumbnailSystem() {}
function cleanupTempFiles() {
Quickshell.execDetached(["sh", "-c", "rm -f /tmp/clipboard_*.png"]);
Quickshell.execDetached(["sh", "-c", "rm -f /tmp/clipboard_*.png"])
}
function generateThumbnails() {
}
function generateThumbnails() {}
function refreshClipboard() {
clipboardProcess.running = true;
clipboardProcess.running = true
}
function copyEntry(entry) {
const entryId = entry.split('\t')[0];
Quickshell.execDetached(["sh", "-c", `cliphist decode ${entryId} | wl-copy`]);
ToastService.showInfo("Copied to clipboard");
hide();
const entryId = entry.split('\t')[0]
Quickshell.execDetached(
["sh", "-c", `cliphist decode ${entryId} | wl-copy`])
ToastService.showInfo("Copied to clipboard")
hide()
}
function deleteEntry(entry) {
deleteProcess.deletedEntry = entry;
deleteProcess.deletedEntry = entry
deleteProcess.command = ["sh", "-c", `echo '${entry.replace(
/'/g, "'\\''")}' | cliphist delete`];
deleteProcess.running = true;
/'/g, "'\\''")}' | cliphist delete`]
deleteProcess.running = true
}
function clearAll() {
clearProcess.running = true;
clearProcess.running = true
}
function getEntryPreview(entry) {
let content = entry.replace(/^\s*\d+\s+/, "");
if (content.includes("image/") || content.includes("binary data") || /\.(png|jpg|jpeg|gif|bmp|webp)/i.test(content)) {
const dimensionMatch = content.match(/(\d+)x(\d+)/);
let content = entry.replace(/^\s*\d+\s+/, "")
if (content.includes("image/") || content.includes("binary data")
|| /\.(png|jpg|jpeg|gif|bmp|webp)/i.test(content)) {
const dimensionMatch = content.match(/(\d+)x(\d+)/)
if (dimensionMatch)
return `Image ${dimensionMatch[1]}×${dimensionMatch[2]}`;
return `Image ${dimensionMatch[1]}×${dimensionMatch[2]}`
const typeMatch = content.match(/\b(png|jpg|jpeg|gif|bmp|webp)\b/i);
const typeMatch = content.match(/\b(png|jpg|jpeg|gif|bmp|webp)\b/i)
if (typeMatch)
return `Image (${typeMatch[1].toUpperCase()})`;
return `Image (${typeMatch[1].toUpperCase()})`
return "Image";
return "Image"
}
if (content.length > 100)
return content.substring(0, 100) + "...";
return content.substring(0, 100) + "..."
return content;
return content
}
function getEntryType(entry) {
if (entry.includes("image/") || entry.includes("binary data") || /\.(png|jpg|jpeg|gif|bmp|webp)/i.test(entry) || /\b(png|jpg|jpeg|gif|bmp|webp)\b/i.test(entry))
return "image";
if (entry.includes("image/") || entry.includes("binary data")
|| /\.(png|jpg|jpeg|gif|bmp|webp)/i.test(entry)
|| /\b(png|jpg|jpeg|gif|bmp|webp)\b/i.test(entry))
return "image"
if (entry.length > 200)
return "long_text";
return "long_text"
return "text";
return "text"
}
visible: false
@@ -149,10 +150,10 @@ DankModal {
borderWidth: 1
enableShadow: true
onBackgroundClicked: {
hide();
hide()
}
modalFocusScope.Keys.onPressed: function(event) {
keyboardController.handleKey(event);
modalFocusScope.Keys.onPressed: function (event) {
keyboardController.handleKey(event)
}
content: clipboardContent
@@ -160,107 +161,116 @@ DankModal {
id: keyboardController
function reset() {
selectedIndex = 0;
keyboardNavigationActive = false;
showKeyboardHints = false;
selectedIndex = 0
keyboardNavigationActive = false
showKeyboardHints = false
if (typeof clipboardListView !== 'undefined' && clipboardListView)
clipboardListView.keyboardActive = false;
clipboardListView.keyboardActive = false
}
function selectNext() {
if (filteredClipboardModel.count === 0)
return ;
return
keyboardNavigationActive = true;
selectedIndex = Math.min(selectedIndex + 1, filteredClipboardModel.count - 1);
keyboardNavigationActive = true
selectedIndex = Math.min(selectedIndex + 1,
filteredClipboardModel.count - 1)
}
function selectPrevious() {
if (filteredClipboardModel.count === 0)
return ;
return
keyboardNavigationActive = true;
selectedIndex = Math.max(selectedIndex - 1, 0);
keyboardNavigationActive = true
selectedIndex = Math.max(selectedIndex - 1, 0)
}
function copySelected() {
if (filteredClipboardModel.count === 0 || selectedIndex < 0 || selectedIndex >= filteredClipboardModel.count)
return ;
if (filteredClipboardModel.count === 0 || selectedIndex < 0
|| selectedIndex >= filteredClipboardModel.count)
return
var selectedEntry = filteredClipboardModel.get(selectedIndex).entry;
copyEntry(selectedEntry);
var selectedEntry = filteredClipboardModel.get(selectedIndex).entry
copyEntry(selectedEntry)
}
function deleteSelected() {
if (filteredClipboardModel.count === 0 || selectedIndex < 0 || selectedIndex >= filteredClipboardModel.count)
return ;
if (filteredClipboardModel.count === 0 || selectedIndex < 0
|| selectedIndex >= filteredClipboardModel.count)
return
var selectedEntry = filteredClipboardModel.get(selectedIndex).entry;
deleteEntry(selectedEntry);
var selectedEntry = filteredClipboardModel.get(selectedIndex).entry
deleteEntry(selectedEntry)
}
function handleKey(event) {
if (event.key === Qt.Key_Escape) {
if (keyboardNavigationActive) {
keyboardNavigationActive = false;
if (typeof clipboardListView !== 'undefined' && clipboardListView)
clipboardListView.keyboardActive = false;
keyboardNavigationActive = false
if (typeof clipboardListView !== 'undefined'
&& clipboardListView)
clipboardListView.keyboardActive = false
event.accepted = true;
event.accepted = true
} else {
hide();
event.accepted = true;
hide()
event.accepted = true
}
} else if (event.key === Qt.Key_Down) {
if (!keyboardNavigationActive) {
keyboardNavigationActive = true;
selectedIndex = 0;
if (typeof clipboardListView !== 'undefined' && clipboardListView)
clipboardListView.keyboardActive = true;
keyboardNavigationActive = true
selectedIndex = 0
if (typeof clipboardListView !== 'undefined'
&& clipboardListView)
clipboardListView.keyboardActive = true
event.accepted = true;
event.accepted = true
} else {
selectNext();
event.accepted = true;
selectNext()
event.accepted = true
}
} else if (event.key === Qt.Key_Up) {
if (!keyboardNavigationActive) {
keyboardNavigationActive = true;
selectedIndex = 0;
if (typeof clipboardListView !== 'undefined' && clipboardListView)
clipboardListView.keyboardActive = true;
keyboardNavigationActive = true
selectedIndex = 0
if (typeof clipboardListView !== 'undefined'
&& clipboardListView)
clipboardListView.keyboardActive = true
event.accepted = true;
event.accepted = true
} else if (selectedIndex === 0) {
keyboardNavigationActive = false;
if (typeof clipboardListView !== 'undefined' && clipboardListView)
clipboardListView.keyboardActive = false;
keyboardNavigationActive = false
if (typeof clipboardListView !== 'undefined'
&& clipboardListView)
clipboardListView.keyboardActive = false
event.accepted = true;
event.accepted = true
} else {
selectPrevious();
event.accepted = true;
selectPrevious()
event.accepted = true
}
} else if (event.key === Qt.Key_Delete && (event.modifiers & Qt.ShiftModifier)) {
clearAll();
hide();
event.accepted = true;
} else if (event.key === Qt.Key_Delete
&& (event.modifiers & Qt.ShiftModifier)) {
clearAll()
hide()
event.accepted = true
} else if (keyboardNavigationActive) {
if ((event.key === Qt.Key_C && (event.modifiers & Qt.ControlModifier)) || event.key === Qt.Key_Return || event.key === Qt.Key_Enter) {
copySelected();
event.accepted = true;
if ((event.key === Qt.Key_C
&& (event.modifiers & Qt.ControlModifier))
|| event.key === Qt.Key_Return
|| event.key === Qt.Key_Enter) {
copySelected()
event.accepted = true
} else if (event.key === Qt.Key_Delete) {
deleteSelected();
event.accepted = true;
deleteSelected()
event.accepted = true
}
}
if (event.key === Qt.Key_F10) {
showKeyboardHints = !showKeyboardHints;
event.accepted = true;
showKeyboardHints = !showKeyboardHints
event.accepted = true
}
}
}
DankModal {
@@ -269,8 +279,8 @@ DankModal {
visible: showClearConfirmation
width: 350
height: 150
onBackgroundClicked: {
showClearConfirmation = false;
onBackgroundClicked: {
showClearConfirmation = false
}
content: Component {
@@ -326,7 +336,6 @@ DankModal {
cursorShape: Qt.PointingHandCursor
onClicked: showClearConfirmation = false
}
}
Rectangle {
@@ -350,22 +359,16 @@ DankModal {
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
clearAll();
showClearConfirmation = false;
hide();
clearAll()
showClearConfirmation = false
hide()
}
}
}
}
}
}
}
}
ListModel {
@@ -384,19 +387,17 @@ DankModal {
stdout: StdioCollector {
onStreamFinished: {
clipboardModel.clear();
const lines = text.trim().split('\n');
clipboardModel.clear()
const lines = text.trim().split('\n')
for (const line of lines) {
if (line.trim().length > 0)
clipboardModel.append({
"entry": line
});
"entry": line
})
}
updateFilteredModel();
updateFilteredModel()
}
}
}
Process {
@@ -405,33 +406,35 @@ DankModal {
property string deletedEntry: ""
running: false
onExited: (exitCode) => {
if (exitCode === 0) {
// Just remove the item from models instead of re-fetching everything
for (var i = 0; i < clipboardModel.count; i++) {
if (clipboardModel.get(i).entry === deleteProcess.deletedEntry) {
clipboardModel.remove(i);
break;
}
}
for (var j = 0; j < filteredClipboardModel.count; j++) {
if (filteredClipboardModel.get(j).entry === deleteProcess.deletedEntry) {
filteredClipboardModel.remove(j);
break;
}
}
clipboardHistoryModal.totalCount = filteredClipboardModel.count;
// Clamp selectedIndex to valid range
if (filteredClipboardModel.count === 0) {
keyboardNavigationActive = false;
selectedIndex = 0;
} else if (selectedIndex >= filteredClipboardModel.count) {
selectedIndex = filteredClipboardModel.count - 1;
}
} else {
console.warn("Failed to delete clipboard entry");
}
}
onExited: exitCode => {
if (exitCode === 0) {
// Just remove the item from models instead of re-fetching everything
for (var i = 0; i < clipboardModel.count; i++) {
if (clipboardModel.get(
i).entry === deleteProcess.deletedEntry) {
clipboardModel.remove(i)
break
}
}
for (var j = 0; j < filteredClipboardModel.count; j++) {
if (filteredClipboardModel.get(
j).entry === deleteProcess.deletedEntry) {
filteredClipboardModel.remove(j)
break
}
}
clipboardHistoryModal.totalCount = filteredClipboardModel.count
// Clamp selectedIndex to valid range
if (filteredClipboardModel.count === 0) {
keyboardNavigationActive = false
selectedIndex = 0
} else if (selectedIndex >= filteredClipboardModel.count) {
selectedIndex = filteredClipboardModel.count - 1
}
} else {
console.warn("Failed to delete clipboard entry")
}
}
}
Process {
@@ -439,30 +442,31 @@ DankModal {
command: ["cliphist", "wipe"]
running: false
onExited: (exitCode) => {
if (exitCode === 0) {
clipboardModel.clear();
filteredClipboardModel.clear();
totalCount = 0;
} else {
}
}
onExited: exitCode => {
if (exitCode === 0) {
clipboardModel.clear()
filteredClipboardModel.clear()
totalCount = 0
} else {
}
}
}
IpcHandler {
function open() {
clipboardHistoryModal.show();
return "CLIPBOARD_OPEN_SUCCESS";
clipboardHistoryModal.show()
return "CLIPBOARD_OPEN_SUCCESS"
}
function close() {
hide();
return "CLIPBOARD_CLOSE_SUCCESS";
hide()
return "CLIPBOARD_CLOSE_SUCCESS"
}
function toggle() {
clipboardHistoryModal.toggle();
return "CLIPBOARD_TOGGLE_SUCCESS";
clipboardHistoryModal.toggle()
return "CLIPBOARD_TOGGLE_SUCCESS"
}
target: "clipboard"
@@ -472,7 +476,7 @@ DankModal {
Item {
id: clipboardContent
property alias searchField: searchField
anchors.fill: parent
Column {
@@ -504,7 +508,6 @@ DankModal {
font.weight: Font.Medium
anchors.verticalCenter: parent.verticalCenter
}
}
Row {
@@ -518,7 +521,7 @@ DankModal {
iconColor: showKeyboardHints ? Theme.primary : Theme.surfaceText
hoverColor: Theme.primaryHover
onClicked: {
showKeyboardHints = !showKeyboardHints;
showKeyboardHints = !showKeyboardHints
}
}
@@ -528,7 +531,7 @@ DankModal {
iconColor: Theme.error
hoverColor: Theme.errorHover
onClicked: {
showClearConfirmation = true;
showClearConfirmation = true
}
}
@@ -539,9 +542,7 @@ DankModal {
hoverColor: Theme.errorHover
onClicked: hide()
}
}
}
DankTextField {
@@ -555,25 +556,25 @@ DankModal {
ignoreLeftRightKeys: true
keyForwardTargets: [modalFocusScope]
onTextChanged: {
clipboardHistoryModal.searchText = text;
updateFilteredModel();
clipboardHistoryModal.searchText = text
updateFilteredModel()
}
Keys.onEscapePressed: function(event) {
hide();
event.accepted = true;
Keys.onEscapePressed: function (event) {
hide()
event.accepted = true
}
Component.onCompleted: {
Qt.callLater(function() {
forceActiveFocus();
});
Qt.callLater(function () {
forceActiveFocus()
})
}
Connections {
target: clipboardHistoryModal
function onOpened() {
Qt.callLater(function() {
searchField.forceActiveFocus();
});
Qt.callLater(function () {
searchField.forceActiveFocus()
})
}
}
}
@@ -592,15 +593,15 @@ DankModal {
function ensureVisible(index) {
if (index < 0 || index >= count)
return ;
return
var itemHeight = 72 + spacing;
var itemY = index * itemHeight;
var itemBottom = itemY + itemHeight;
var itemHeight = 72 + spacing
var itemY = index * itemHeight
var itemBottom = itemY + itemHeight
if (itemY < contentY)
contentY = itemY;
contentY = itemY
else if (itemBottom > contentY + height)
contentY = itemBottom - height;
contentY = itemBottom - height
}
anchors.fill: parent
@@ -618,8 +619,7 @@ DankModal {
flickableDirection: Flickable.VerticalFlick
onCurrentIndexChanged: {
if (keyboardNavigationActive && currentIndex >= 0)
ensureVisible(currentIndex);
ensureVisible(currentIndex)
}
StyledText {
@@ -640,7 +640,8 @@ DankModal {
delegate: Rectangle {
property string entryType: getEntryType(model.entry)
property string entryPreview: getEntryPreview(model.entry)
property string entryPreview: getEntryPreview(
model.entry)
property int entryIndex: index + 1
property string entryData: model.entry
property alias thumbnailImageSource: thumbnailImageSource
@@ -649,18 +650,25 @@ DankModal {
height: 72
radius: Theme.cornerRadius
color: {
if (keyboardNavigationActive && index === selectedIndex)
return Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.2);
if (keyboardNavigationActive
&& index === selectedIndex)
return Qt.rgba(Theme.surfaceVariant.r,
Theme.surfaceVariant.g,
Theme.surfaceVariant.b, 0.2)
return mouseArea.containsMouse ? Theme.primaryHover : Theme.primaryBackground;
return mouseArea.containsMouse ? Theme.primaryHover : Theme.primaryBackground
}
border.color: {
if (keyboardNavigationActive && index === selectedIndex)
return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.5);
if (keyboardNavigationActive
&& index === selectedIndex)
return Qt.rgba(Theme.primary.r,
Theme.primary.g,
Theme.primary.b, 0.5)
return Theme.outlineStrong;
return Theme.outlineStrong
}
border.width: keyboardNavigationActive && index === selectedIndex ? 1.5 : 1
border.width: keyboardNavigationActive
&& index === selectedIndex ? 1.5 : 1
Row {
anchors.fill: parent
@@ -682,7 +690,6 @@ DankModal {
font.weight: Font.Bold
color: Theme.primary
}
}
Row {
@@ -698,10 +705,12 @@ DankModal {
CachingImage {
id: thumbnailImageSource
property string entryId: model.entry.split('\t')[0]
property string entryId: model.entry.split(
'\t')[0]
anchors.fill: parent
source: entryType === "image" && imageLoader.imageData ? `data:image/png;base64,${imageLoader.imageData}` : ""
source: entryType === "image"
&& imageLoader.imageData ? `data:image/png;base64,${imageLoader.imageData}` : ""
fillMode: Image.PreserveAspectCrop
smooth: true
cache: true
@@ -718,12 +727,10 @@ DankModal {
stdout: StdioCollector {
onStreamFinished: {
imageLoader.imageData = text.trim();
imageLoader.imageData = text.trim()
}
}
}
}
MultiEffect {
@@ -732,7 +739,8 @@ DankModal {
source: thumbnailImageSource
maskEnabled: true
maskSource: clipboardCircularMask
visible: entryType === "image" && thumbnailImageSource.status === Image.Ready
visible: entryType === "image"
&& thumbnailImageSource.status === Image.Ready
maskThresholdMin: 0.5
maskSpreadAtMin: 1
}
@@ -752,25 +760,25 @@ DankModal {
color: "black"
antialiasing: true
}
}
DankIcon {
visible: !(entryType === "image" && thumbnailImageSource.status === Image.Ready)
visible: !(entryType === "image"
&& thumbnailImageSource.status
=== Image.Ready)
name: {
if (entryType === "image")
return "image";
return "image"
if (entryType === "long_text")
return "subject";
return "subject"
return "content_copy";
return "content_copy"
}
size: Theme.iconSize
color: Theme.primary
anchors.centerIn: parent
}
}
Column {
@@ -782,11 +790,11 @@ DankModal {
text: {
switch (entryType) {
case "image":
return "Image • " + entryPreview;
return "Image • " + entryPreview
case "long_text":
return "Long Text";
return "Long Text"
default:
return "Text";
return "Text"
}
}
font.pixelSize: Theme.fontSizeSmall
@@ -807,11 +815,8 @@ DankModal {
maximumLineCount: entryType === "long_text" ? 3 : 1
elide: Text.ElideRight
}
}
}
}
DankActionButton {
@@ -823,7 +828,7 @@ DankModal {
iconColor: Theme.error
hoverColor: Theme.errorHover
onClicked: {
deleteEntry(model.entry);
deleteEntry(model.entry)
}
}
@@ -836,11 +841,8 @@ DankModal {
cursorShape: Qt.PointingHandCursor
onClicked: copyEntry(model.entry)
}
}
}
}
Item {
@@ -852,11 +854,8 @@ DankModal {
duration: Theme.shortDuration
easing.type: Theme.standardEasing
}
}
}
}
Rectangle {
@@ -866,7 +865,9 @@ DankModal {
anchors.margins: Theme.spacingL
height: 80
radius: Theme.cornerRadius
color: Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, 0.95)
color: Qt.rgba(Theme.surfaceContainer.r,
Theme.surfaceContainer.g,
Theme.surfaceContainer.b, 0.95)
border.color: Theme.primary
border.width: 2
opacity: showKeyboardHints ? 1 : 0
@@ -889,7 +890,6 @@ DankModal {
color: Theme.surfaceText
anchors.horizontalCenter: parent.horizontalCenter
}
}
Behavior on opacity {
@@ -897,13 +897,8 @@ DankModal {
duration: Theme.shortDuration
easing.type: Theme.standardEasing
}
}
}
}
}
}

View File

@@ -34,10 +34,10 @@ PanelWindow {
property bool allowFocusOverride: false
property bool allowStacking: false
signal opened()
signal dialogClosed()
signal backgroundClicked()
signal opened
signal dialogClosed
signal backgroundClicked
Connections {
target: ModalManager
function onCloseAllModalsExcept(excludedModal) {
@@ -49,25 +49,24 @@ PanelWindow {
function open() {
ModalManager.openModal(root)
closeTimer.stop();
shouldBeVisible = true;
visible = true;
focusScope.forceActiveFocus();
closeTimer.stop()
shouldBeVisible = true
visible = true
focusScope.forceActiveFocus()
}
function close() {
shouldBeVisible = false;
closeTimer.restart();
shouldBeVisible = false
closeTimer.restart()
}
function toggle() {
if (shouldBeVisible)
close();
close()
else
open();
open()
}
visible: shouldBeVisible
color: "transparent"
WlrLayershell.layer: WlrLayershell.Overlay
@@ -75,13 +74,13 @@ PanelWindow {
WlrLayershell.keyboardFocus: shouldHaveFocus ? WlrKeyboardFocus.Exclusive : WlrKeyboardFocus.None
onVisibleChanged: {
if (root.visible) {
opened();
opened()
} else {
if (Qt.inputMethod) {
Qt.inputMethod.hide();
Qt.inputMethod.reset();
Qt.inputMethod.hide()
Qt.inputMethod.reset()
}
dialogClosed();
dialogClosed()
}
}
@@ -90,12 +89,10 @@ PanelWindow {
interval: animationDuration + 50
onTriggered: {
visible = false;
visible = false
}
}
anchors {
top: true
left: true
@@ -114,12 +111,15 @@ PanelWindow {
MouseArea {
anchors.fill: parent
enabled: root.closeOnBackgroundClick
onClicked: (mouse) => {
var localPos = mapToItem(contentContainer, mouse.x, mouse.y);
if (localPos.x < 0 || localPos.x > contentContainer.width || localPos.y < 0 || localPos.y > contentContainer.height)
root.backgroundClicked();
}
onClicked: mouse => {
var localPos = mapToItem(contentContainer,
mouse.x, mouse.y)
if (localPos.x < 0
|| localPos.x > contentContainer.width
|| localPos.y < 0
|| localPos.y > contentContainer.height)
root.backgroundClicked()
}
}
Behavior on opacity {
@@ -127,9 +127,7 @@ PanelWindow {
duration: root.animationDuration
easing.type: root.animationEasing
}
}
}
Rectangle {
@@ -140,17 +138,18 @@ PanelWindow {
anchors.centerIn: positioning === "center" ? parent : undefined
x: {
if (positioning === "top-right")
return Math.max(Theme.spacingL, root.screenWidth - width - Theme.spacingL);
return Math.max(Theme.spacingL,
root.screenWidth - width - Theme.spacingL)
else if (positioning === "custom")
return root.customPosition.x;
return 0; // Will be overridden by anchors.centerIn when positioning === "center"
return root.customPosition.x
return 0 // Will be overridden by anchors.centerIn when positioning === "center"
}
y: {
if (positioning === "top-right")
return Theme.barHeight + Theme.spacingXS;
return Theme.barHeight + Theme.spacingXS
else if (positioning === "custom")
return root.customPosition.y;
return 0; // Will be overridden by anchors.centerIn when positioning === "center"
return root.customPosition.y
return 0 // Will be overridden by anchors.centerIn when positioning === "center"
}
color: root.backgroundColor
radius: root.cornerRadius
@@ -160,9 +159,9 @@ PanelWindow {
opacity: root.shouldBeVisible ? 1 : 0
scale: {
if (root.animationType === "scale")
return root.shouldBeVisible ? 1 : 0.9;
return root.shouldBeVisible ? 1 : 0.9
return 1;
return 1
}
transform: root.animationType === "slide" ? slideTransform : null
@@ -186,7 +185,6 @@ PanelWindow {
duration: root.animationDuration
easing.type: root.animationEasing
}
}
Behavior on scale {
@@ -196,7 +194,6 @@ PanelWindow {
duration: root.animationDuration
easing.type: root.animationEasing
}
}
layer.effect: MultiEffect {
@@ -207,7 +204,6 @@ PanelWindow {
shadowColor: Theme.shadowStrong
shadowOpacity: 0.3
}
}
FocusScope {
@@ -217,31 +213,35 @@ PanelWindow {
anchors.fill: parent
visible: root.visible // Only active when the modal is visible
focus: root.visible
Keys.onEscapePressed: (event) => {
console.log("DankModal escape pressed - shouldHaveFocus:", shouldHaveFocus, "closeOnEscapeKey:", root.closeOnEscapeKey, "objectName:", root.objectName || "unnamed");
if (root.closeOnEscapeKey && shouldHaveFocus) {
console.log("DankModal handling escape");
root.close();
event.accepted = true;
}
}
Keys.onEscapePressed: event => {
console.log(
"DankModal escape pressed - shouldHaveFocus:",
shouldHaveFocus, "closeOnEscapeKey:",
root.closeOnEscapeKey, "objectName:",
root.objectName || "unnamed")
if (root.closeOnEscapeKey
&& shouldHaveFocus) {
console.log("DankModal handling escape")
root.close()
event.accepted = true
}
}
onVisibleChanged: {
if (visible && shouldHaveFocus)
Qt.callLater(function() {
focusScope.forceActiveFocus();
});
Qt.callLater(function () {
focusScope.forceActiveFocus()
})
}
Connections {
target: root
function onShouldHaveFocusChanged() {
if (shouldHaveFocus && visible) {
Qt.callLater(function() {
focusScope.forceActiveFocus();
});
Qt.callLater(function () {
focusScope.forceActiveFocus()
})
}
}
}
}
}

View File

@@ -9,290 +9,291 @@ import qs.Common
import qs.Widgets
DankModal {
id: fileBrowserModal
objectName: "fileBrowserModal"
allowStacking: true
id: fileBrowserModal
objectName: "fileBrowserModal"
allowStacking: true
signal fileSelected(string path)
signal fileSelected(string path)
property string homeDir: StandardPaths.writableLocation(
StandardPaths.HomeLocation)
property string currentPath: ""
property var fileExtensions: ["*.*"]
property string browserTitle: "Select File"
property string browserIcon: "folder_open"
property string browserType: "generic" // "wallpaper" or "profile" for last path memory
property string homeDir: StandardPaths.writableLocation(
StandardPaths.HomeLocation)
property string currentPath: ""
property var fileExtensions: ["*.*"]
property string browserTitle: "Select File"
property string browserIcon: "folder_open"
property string browserType: "generic" // "wallpaper" or "profile" for last path memory
FolderListModel {
id: folderModel
showDirsFirst: true
showDotAndDotDot: false
showHidden: false
nameFilters: fileExtensions
showFiles: true
showDirs: true
folder: currentPath ? "file://" + currentPath : "file://" + homeDir
}
function isImageFile(fileName) {
if (!fileName)
return false
var ext = fileName.toLowerCase().split('.').pop()
return ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp', 'svg'].includes(ext)
}
function getLastPath() {
var lastPath = ""
if (browserType === "wallpaper") {
lastPath = SessionData.wallpaperLastPath
} else if (browserType === "profile") {
lastPath = SessionData.profileLastPath
FolderListModel {
id: folderModel
showDirsFirst: true
showDotAndDotDot: false
showHidden: false
nameFilters: fileExtensions
showFiles: true
showDirs: true
folder: currentPath ? "file://" + currentPath : "file://" + homeDir
}
if (lastPath && lastPath !== "") {
return lastPath
}
return homeDir
}
function saveLastPath(path) {
if (browserType === "wallpaper") {
SessionData.setWallpaperLastPath(path)
} else if (browserType === "profile") {
SessionData.setProfileLastPath(path)
}
}
Component.onCompleted: {
currentPath = getLastPath()
}
width: 800
height: 600
enableShadow: true
visible: false
onBackgroundClicked: close()
onVisibleChanged: {
if (visible) {
var startPath = getLastPath()
currentPath = startPath
}
}
onCurrentPathChanged: {
}
function navigateUp() {
var path = currentPath
if (path === homeDir) {
return
function isImageFile(fileName) {
if (!fileName)
return false
var ext = fileName.toLowerCase().split('.').pop()
return ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp', 'svg'].includes(ext)
}
var lastSlash = path.lastIndexOf('/')
if (lastSlash > 0) {
var newPath = path.substring(0, lastSlash)
if (newPath.length < homeDir.length) {
currentPath = homeDir
saveLastPath(homeDir)
} else {
currentPath = newPath
saveLastPath(newPath)
}
}
}
function navigateTo(path) {
currentPath = path
saveLastPath(path) // Save the path when navigating
}
content: Component {
Column {
anchors.fill: parent
anchors.margins: Theme.spacingM
spacing: Theme.spacingS
Item {
width: parent.width
height: 40
Row {
spacing: Theme.spacingM
anchors.verticalCenter: parent.verticalCenter
DankIcon {
name: browserIcon
size: Theme.iconSizeLarge
color: Theme.primary
anchors.verticalCenter: parent.verticalCenter
}
StyledText {
text: browserTitle
font.pixelSize: Theme.fontSizeXLarge
color: Theme.surfaceText
font.weight: Font.Medium
anchors.verticalCenter: parent.verticalCenter
}
function getLastPath() {
var lastPath = ""
if (browserType === "wallpaper") {
lastPath = SessionData.wallpaperLastPath
} else if (browserType === "profile") {
lastPath = SessionData.profileLastPath
}
DankActionButton {
circular: false
iconName: "close"
iconSize: Theme.iconSize - 4
iconColor: Theme.surfaceText
hoverColor: Theme.errorHover
onClicked: fileBrowserModal.close()
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
if (lastPath && lastPath !== "") {
return lastPath
}
}
return homeDir
}
Row {
width: parent.width
spacing: Theme.spacingS
function saveLastPath(path) {
if (browserType === "wallpaper") {
SessionData.setWallpaperLastPath(path)
} else if (browserType === "profile") {
SessionData.setProfileLastPath(path)
}
}
StyledRect {
width: 32
height: 32
radius: Theme.cornerRadius
color: mouseArea.containsMouse
&& currentPath !== homeDir ? Theme.surfaceVariant : "transparent"
opacity: currentPath !== homeDir ? 1.0 : 0.0
Component.onCompleted: {
currentPath = getLastPath()
}
DankIcon {
anchors.centerIn: parent
name: "arrow_back"
size: Theme.iconSizeSmall
color: Theme.surfaceText
}
width: 800
height: 600
enableShadow: true
visible: false
MouseArea {
id: mouseArea
onBackgroundClicked: close()
onVisibleChanged: {
if (visible) {
var startPath = getLastPath()
currentPath = startPath
}
}
onCurrentPathChanged: {
}
function navigateUp() {
var path = currentPath
if (path === homeDir) {
return
}
var lastSlash = path.lastIndexOf('/')
if (lastSlash > 0) {
var newPath = path.substring(0, lastSlash)
if (newPath.length < homeDir.length) {
currentPath = homeDir
saveLastPath(homeDir)
} else {
currentPath = newPath
saveLastPath(newPath)
}
}
}
function navigateTo(path) {
currentPath = path
saveLastPath(path) // Save the path when navigating
}
content: Component {
Column {
anchors.fill: parent
hoverEnabled: currentPath !== homeDir
cursorShape: currentPath !== homeDir ? Qt.PointingHandCursor : Qt.ArrowCursor
enabled: currentPath !== homeDir
onClicked: navigateUp()
}
}
StyledText {
text: fileBrowserModal.currentPath.replace("file://", "")
font.pixelSize: Theme.fontSizeMedium
color: Theme.surfaceText
font.weight: Font.Medium
width: parent.width - 40 - Theme.spacingS
elide: Text.ElideMiddle
anchors.verticalCenter: parent.verticalCenter
maximumLineCount: 1
wrapMode: Text.NoWrap
}
}
DankGridView {
id: fileGrid
width: parent.width
height: parent.height - 80
clip: true
cellWidth: 150
cellHeight: 130
cacheBuffer: 260
model: folderModel
ScrollBar.vertical: ScrollBar {
policy: ScrollBar.AsNeeded
}
ScrollBar.horizontal: ScrollBar {
policy: ScrollBar.AlwaysOff
}
delegate: StyledRect {
id: delegateRoot
required property bool fileIsDir
required property string filePath
required property string fileName
required property url fileURL
width: 140
height: 120
radius: Theme.cornerRadius
color: mouseArea.containsMouse ? Theme.surfaceVariant : "transparent"
border.color: Theme.outline
border.width: mouseArea.containsMouse ? 1 : 0
Column {
anchors.centerIn: parent
spacing: Theme.spacingXS
anchors.margins: Theme.spacingM
spacing: Theme.spacingS
Item {
width: 80
height: 60
anchors.horizontalCenter: parent.horizontalCenter
width: parent.width
height: 40
CachingImage {
anchors.fill: parent
imagePath: !delegateRoot.fileIsDir ? delegateRoot.filePath : ""
fillMode: Image.PreserveAspectCrop
visible: !delegateRoot.fileIsDir && isImageFile(
delegateRoot.fileName)
maxCacheSize: 80
}
Row {
spacing: Theme.spacingM
anchors.verticalCenter: parent.verticalCenter
DankIcon {
anchors.centerIn: parent
name: "description"
size: Theme.iconSizeLarge
color: Theme.primary
visible: !delegateRoot.fileIsDir && !isImageFile(
delegateRoot.fileName)
}
DankIcon {
name: browserIcon
size: Theme.iconSizeLarge
color: Theme.primary
anchors.verticalCenter: parent.verticalCenter
}
DankIcon {
anchors.centerIn: parent
name: "folder"
size: Theme.iconSizeLarge
color: Theme.primary
visible: delegateRoot.fileIsDir
}
StyledText {
text: browserTitle
font.pixelSize: Theme.fontSizeXLarge
color: Theme.surfaceText
font.weight: Font.Medium
anchors.verticalCenter: parent.verticalCenter
}
}
DankActionButton {
circular: false
iconName: "close"
iconSize: Theme.iconSize - 4
iconColor: Theme.surfaceText
hoverColor: Theme.errorHover
onClicked: fileBrowserModal.close()
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
}
}
StyledText {
text: delegateRoot.fileName || ""
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceText
width: 120
elide: Text.ElideMiddle
horizontalAlignment: Text.AlignHCenter
anchors.horizontalCenter: parent.horizontalCenter
maximumLineCount: 2
wrapMode: Text.WordWrap
}
}
Row {
width: parent.width
spacing: Theme.spacingS
MouseArea {
id: mouseArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
StyledRect {
width: 32
height: 32
radius: Theme.cornerRadius
color: mouseArea.containsMouse
&& currentPath !== homeDir ? Theme.surfaceVariant : "transparent"
opacity: currentPath !== homeDir ? 1.0 : 0.0
onClicked: {
if (delegateRoot.fileIsDir) {
navigateTo(delegateRoot.filePath)
} else {
fileSelected(delegateRoot.filePath)
}
DankIcon {
anchors.centerIn: parent
name: "arrow_back"
size: Theme.iconSizeSmall
color: Theme.surfaceText
}
MouseArea {
id: mouseArea
anchors.fill: parent
hoverEnabled: currentPath !== homeDir
cursorShape: currentPath
!== homeDir ? Qt.PointingHandCursor : Qt.ArrowCursor
enabled: currentPath !== homeDir
onClicked: navigateUp()
}
}
StyledText {
text: fileBrowserModal.currentPath.replace("file://", "")
font.pixelSize: Theme.fontSizeMedium
color: Theme.surfaceText
font.weight: Font.Medium
width: parent.width - 40 - Theme.spacingS
elide: Text.ElideMiddle
anchors.verticalCenter: parent.verticalCenter
maximumLineCount: 1
wrapMode: Text.NoWrap
}
}
DankGridView {
id: fileGrid
width: parent.width
height: parent.height - 80
clip: true
cellWidth: 150
cellHeight: 130
cacheBuffer: 260
model: folderModel
ScrollBar.vertical: ScrollBar {
policy: ScrollBar.AsNeeded
}
ScrollBar.horizontal: ScrollBar {
policy: ScrollBar.AlwaysOff
}
delegate: StyledRect {
id: delegateRoot
required property bool fileIsDir
required property string filePath
required property string fileName
required property url fileURL
width: 140
height: 120
radius: Theme.cornerRadius
color: mouseArea.containsMouse ? Theme.surfaceVariant : "transparent"
border.color: Theme.outline
border.width: mouseArea.containsMouse ? 1 : 0
Column {
anchors.centerIn: parent
spacing: Theme.spacingXS
Item {
width: 80
height: 60
anchors.horizontalCenter: parent.horizontalCenter
CachingImage {
anchors.fill: parent
imagePath: !delegateRoot.fileIsDir ? delegateRoot.filePath : ""
fillMode: Image.PreserveAspectCrop
visible: !delegateRoot.fileIsDir && isImageFile(
delegateRoot.fileName)
maxCacheSize: 80
}
DankIcon {
anchors.centerIn: parent
name: "description"
size: Theme.iconSizeLarge
color: Theme.primary
visible: !delegateRoot.fileIsDir
&& !isImageFile(delegateRoot.fileName)
}
DankIcon {
anchors.centerIn: parent
name: "folder"
size: Theme.iconSizeLarge
color: Theme.primary
visible: delegateRoot.fileIsDir
}
}
StyledText {
text: delegateRoot.fileName || ""
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceText
width: 120
elide: Text.ElideMiddle
horizontalAlignment: Text.AlignHCenter
anchors.horizontalCenter: parent.horizontalCenter
maximumLineCount: 2
wrapMode: Text.WordWrap
}
}
MouseArea {
id: mouseArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
if (delegateRoot.fileIsDir) {
navigateTo(delegateRoot.filePath)
} else {
fileSelected(delegateRoot.filePath)
}
}
}
}
}
}
}
}
}
}
}

View File

@@ -8,195 +8,202 @@ import qs.Services
import qs.Widgets
DankModal {
id: root
id: root
property bool networkInfoModalVisible: false
property string networkSSID: ""
property var networkData: null
property string networkDetails: ""
property bool networkInfoModalVisible: false
property string networkSSID: ""
property var networkData: null
property string networkDetails: ""
function showNetworkInfo(ssid, data) {
networkSSID = ssid
networkData = data
networkInfoModalVisible = true
open()
NetworkService.fetchNetworkInfo(ssid)
}
function hideDialog() {
networkInfoModalVisible = false
close()
networkSSID = ""
networkData = null
networkDetails = ""
}
visible: networkInfoModalVisible
width: 600
height: 500
enableShadow: true
onBackgroundClicked: {
hideDialog()
}
onVisibleChanged: {
if (!visible) {
networkSSID = ""
networkData = null
networkDetails = ""
function showNetworkInfo(ssid, data) {
networkSSID = ssid
networkData = data
networkInfoModalVisible = true
open()
NetworkService.fetchNetworkInfo(ssid)
}
}
content: Component {
Item {
anchors.fill: parent
function hideDialog() {
networkInfoModalVisible = false
close()
networkSSID = ""
networkData = null
networkDetails = ""
}
Column {
anchors.fill: parent
anchors.margins: Theme.spacingL
spacing: Theme.spacingL
Row {
width: parent.width
Column {
width: parent.width - 40
spacing: Theme.spacingXS
StyledText {
text: "Network Information"
font.pixelSize: Theme.fontSizeLarge
color: Theme.surfaceText
font.weight: Font.Medium
}
StyledText {
text: "Details for \"" + networkSSID + "\""
font.pixelSize: Theme.fontSizeMedium
color: Theme.surfaceTextMedium
width: parent.width
elide: Text.ElideRight
}
}
DankActionButton {
iconName: "close"
iconSize: Theme.iconSize - 4
iconColor: Theme.surfaceText
hoverColor: Theme.errorHover
onClicked: {
root.hideDialog()
}
}
}
Flickable {
width: parent.width
height: parent.height - 140
clip: true
contentWidth: width
contentHeight: detailsRect.height
// Qt 6.9+ scrolling: flickDeceleration/maximumFlickVelocity only affect touch now
interactive: true
flickDeceleration: 1500
maximumFlickVelocity: 2000
boundsBehavior: Flickable.DragAndOvershootBounds
boundsMovement: Flickable.FollowBoundsBehavior
pressDelay: 0
flickableDirection: Flickable.VerticalFlick
// Custom wheel handler for Qt 6.9+ responsive mouse wheel scrolling
WheelHandler {
acceptedDevices: PointerDevice.Mouse | PointerDevice.TouchPad
onWheel: event => {
let delta = event.pixelDelta.y
!== 0 ? event.pixelDelta.y * 1.8 : event.angleDelta.y / 120 * 60
let newY = parent.contentY - delta
newY = Math.max(0, Math.min(
parent.contentHeight - parent.height,
newY))
parent.contentY = newY
event.accepted = true
}
}
Rectangle {
id: detailsRect
width: parent.width
height: Math.max(parent.parent.height,
detailsText.contentHeight + Theme.spacingM * 2)
radius: Theme.cornerRadius
color: Theme.surfaceHover
border.color: Theme.outlineStrong
border.width: 1
StyledText {
id: detailsText
anchors.fill: parent
anchors.margins: Theme.spacingM
text: NetworkService.networkInfoDetails.replace(/\\n/g, '\n')
|| "No information available"
font.pixelSize: Theme.fontSizeMedium
color: Theme.surfaceText
wrapMode: Text.WordWrap
lineHeight: 1.5
}
}
ScrollBar.vertical: ScrollBar {
policy: ScrollBar.AsNeeded
}
ScrollBar.horizontal: ScrollBar {
policy: ScrollBar.AlwaysOff
}
visible: networkInfoModalVisible
width: 600
height: 500
enableShadow: true
onBackgroundClicked: {
hideDialog()
}
onVisibleChanged: {
if (!visible) {
networkSSID = ""
networkData = null
networkDetails = ""
}
}
content: Component {
Item {
width: parent.width
height: 40
anchors.fill: parent
Rectangle {
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
width: Math.max(70, closeText.contentWidth + Theme.spacingM * 2)
height: 36
radius: Theme.cornerRadius
color: closeArea.containsMouse ? Qt.darker(Theme.primary,
1.1) : Theme.primary
Column {
anchors.fill: parent
anchors.margins: Theme.spacingL
spacing: Theme.spacingL
StyledText {
id: closeText
Row {
width: parent.width
anchors.centerIn: parent
text: "Close"
font.pixelSize: Theme.fontSizeMedium
color: Theme.background
font.weight: Font.Medium
Column {
width: parent.width - 40
spacing: Theme.spacingXS
StyledText {
text: "Network Information"
font.pixelSize: Theme.fontSizeLarge
color: Theme.surfaceText
font.weight: Font.Medium
}
StyledText {
text: "Details for \"" + networkSSID + "\""
font.pixelSize: Theme.fontSizeMedium
color: Theme.surfaceTextMedium
width: parent.width
elide: Text.ElideRight
}
}
DankActionButton {
iconName: "close"
iconSize: Theme.iconSize - 4
iconColor: Theme.surfaceText
hoverColor: Theme.errorHover
onClicked: {
root.hideDialog()
}
}
}
Flickable {
width: parent.width
height: parent.height - 140
clip: true
contentWidth: width
contentHeight: detailsRect.height
// Qt 6.9+ scrolling: flickDeceleration/maximumFlickVelocity only affect touch now
interactive: true
flickDeceleration: 1500
maximumFlickVelocity: 2000
boundsBehavior: Flickable.DragAndOvershootBounds
boundsMovement: Flickable.FollowBoundsBehavior
pressDelay: 0
flickableDirection: Flickable.VerticalFlick
// Custom wheel handler for Qt 6.9+ responsive mouse wheel scrolling
WheelHandler {
acceptedDevices: PointerDevice.Mouse | PointerDevice.TouchPad
onWheel: event => {
let delta = event.pixelDelta.y
!== 0 ? event.pixelDelta.y
* 1.8 : event.angleDelta.y / 120 * 60
let newY = parent.contentY - delta
newY = Math.max(
0, Math.min(
parent.contentHeight - parent.height,
newY))
parent.contentY = newY
event.accepted = true
}
}
Rectangle {
id: detailsRect
width: parent.width
height: Math.max(
parent.parent.height,
detailsText.contentHeight + Theme.spacingM * 2)
radius: Theme.cornerRadius
color: Theme.surfaceHover
border.color: Theme.outlineStrong
border.width: 1
StyledText {
id: detailsText
anchors.fill: parent
anchors.margins: Theme.spacingM
text: NetworkService.networkInfoDetails.replace(
/\\n/g,
'\n') || "No information available"
font.pixelSize: Theme.fontSizeMedium
color: Theme.surfaceText
wrapMode: Text.WordWrap
lineHeight: 1.5
}
}
ScrollBar.vertical: ScrollBar {
policy: ScrollBar.AsNeeded
}
ScrollBar.horizontal: ScrollBar {
policy: ScrollBar.AlwaysOff
}
}
Item {
width: parent.width
height: 40
Rectangle {
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
width: Math.max(
70,
closeText.contentWidth + Theme.spacingM * 2)
height: 36
radius: Theme.cornerRadius
color: closeArea.containsMouse ? Qt.darker(
Theme.primary,
1.1) : Theme.primary
StyledText {
id: closeText
anchors.centerIn: parent
text: "Close"
font.pixelSize: Theme.fontSizeMedium
color: Theme.background
font.weight: Font.Medium
}
MouseArea {
id: closeArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
root.hideDialog()
}
}
Behavior on color {
ColorAnimation {
duration: Theme.shortDuration
easing.type: Theme.standardEasing
}
}
}
}
}
MouseArea {
id: closeArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
root.hideDialog()
}
}
Behavior on color {
ColorAnimation {
duration: Theme.shortDuration
easing.type: Theme.standardEasing
}
}
}
}
}
}
}
}

View File

@@ -11,7 +11,7 @@ import qs.Widgets
DankModal {
id: notificationModal
width: 500
height: 700
visible: false
@@ -20,28 +20,28 @@ DankModal {
notificationModalOpen = false
modalKeyboardController.reset()
}
modalFocusScope.Keys.onPressed: function(event) {
modalFocusScope.Keys.onPressed: function (event) {
modalKeyboardController.handleKey(event)
}
NotificationKeyboardController {
id: modalKeyboardController
listView: null
isOpen: notificationModal.notificationModalOpen
onClose: function() { notificationModal.hide() }
onClose: function () {
notificationModal.hide()
}
}
property bool notificationModalOpen: false
property var notificationListRef: null
function show() {
notificationModalOpen = true
open()
modalKeyboardController.reset()
if (modalKeyboardController && notificationListRef) {
modalKeyboardController.listView = notificationListRef
modalKeyboardController.rebuildFlatNavigation()
@@ -61,7 +61,6 @@ DankModal {
show()
}
IpcHandler {
function open() {
notificationModal.show()
@@ -96,7 +95,7 @@ DankModal {
id: notificationHeader
keyboardController: modalKeyboardController
}
NotificationSettings {
id: notificationSettings
expanded: notificationHeader.showSettings
@@ -104,11 +103,11 @@ DankModal {
KeyboardNavigatedNotificationList {
id: notificationList
width: parent.width
height: parent.height - y
keyboardController: modalKeyboardController
Component.onCompleted: {
notificationModal.notificationListRef = notificationList
if (modalKeyboardController) {
@@ -117,7 +116,6 @@ DankModal {
}
}
}
}
NotificationKeyboardHints {
@@ -128,9 +126,8 @@ DankModal {
anchors.margins: Theme.spacingL
showHints: modalKeyboardController.showKeyboardHints
}
}
}
content: notificationContent
}
}

View File

@@ -7,159 +7,160 @@ import qs.Services
import qs.Widgets
DankModal {
id: root
id: root
property string powerConfirmAction: ""
property string powerConfirmTitle: ""
property string powerConfirmMessage: ""
property string powerConfirmAction: ""
property string powerConfirmTitle: ""
property string powerConfirmMessage: ""
function show(action, title, message) {
powerConfirmAction = action
powerConfirmTitle = title
powerConfirmMessage = message
open()
}
function executePowerAction(action) {
switch (action) {
case "logout":
NiriService.quit()
break
case "suspend":
Quickshell.execDetached(["systemctl", "suspend"])
break
case "reboot":
Quickshell.execDetached(["systemctl", "reboot"])
break
case "poweroff":
Quickshell.execDetached(["systemctl", "poweroff"])
break
function show(action, title, message) {
powerConfirmAction = action
powerConfirmTitle = title
powerConfirmMessage = message
open()
}
}
shouldBeVisible: false
width: 350
height: 160
enableShadow: false
onBackgroundClicked: {
close()
}
content: Component {
Item {
anchors.fill: parent
Column {
anchors.centerIn: parent
width: parent.width - Theme.spacingM * 2
spacing: Theme.spacingM
StyledText {
text: powerConfirmTitle
font.pixelSize: Theme.fontSizeLarge
color: {
switch (powerConfirmAction) {
case "poweroff":
return Theme.error
case "reboot":
return Theme.warning
default:
return Theme.surfaceText
}
}
font.weight: Font.Medium
width: parent.width
horizontalAlignment: Text.AlignHCenter
function executePowerAction(action) {
switch (action) {
case "logout":
NiriService.quit()
break
case "suspend":
Quickshell.execDetached(["systemctl", "suspend"])
break
case "reboot":
Quickshell.execDetached(["systemctl", "reboot"])
break
case "poweroff":
Quickshell.execDetached(["systemctl", "poweroff"])
break
}
}
StyledText {
text: powerConfirmMessage
font.pixelSize: Theme.fontSizeMedium
color: Theme.surfaceText
width: parent.width
horizontalAlignment: Text.AlignHCenter
wrapMode: Text.WordWrap
}
shouldBeVisible: false
width: 350
height: 160
enableShadow: false
onBackgroundClicked: {
close()
}
content: Component {
Item {
height: Theme.spacingS
anchors.fill: parent
Column {
anchors.centerIn: parent
width: parent.width - Theme.spacingM * 2
spacing: Theme.spacingM
StyledText {
text: powerConfirmTitle
font.pixelSize: Theme.fontSizeLarge
color: {
switch (powerConfirmAction) {
case "poweroff":
return Theme.error
case "reboot":
return Theme.warning
default:
return Theme.surfaceText
}
}
font.weight: Font.Medium
width: parent.width
horizontalAlignment: Text.AlignHCenter
}
StyledText {
text: powerConfirmMessage
font.pixelSize: Theme.fontSizeMedium
color: Theme.surfaceText
width: parent.width
horizontalAlignment: Text.AlignHCenter
wrapMode: Text.WordWrap
}
Item {
height: Theme.spacingS
}
Row {
anchors.horizontalCenter: parent.horizontalCenter
spacing: Theme.spacingM
Rectangle {
width: 120
height: 40
radius: Theme.cornerRadius
color: cancelButton.containsMouse ? Theme.surfaceTextPressed : Theme.surfaceVariantAlpha
StyledText {
text: "Cancel"
font.pixelSize: Theme.fontSizeMedium
color: Theme.surfaceText
font.weight: Font.Medium
anchors.centerIn: parent
}
MouseArea {
id: cancelButton
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
close()
}
}
}
Rectangle {
width: 120
height: 40
radius: Theme.cornerRadius
color: {
let baseColor
switch (powerConfirmAction) {
case "poweroff":
baseColor = Theme.error
break
case "reboot":
baseColor = Theme.warning
break
default:
baseColor = Theme.primary
break
}
return confirmButton.containsMouse ? Qt.rgba(
baseColor.r,
baseColor.g,
baseColor.b,
0.9) : baseColor
}
StyledText {
text: "Confirm"
font.pixelSize: Theme.fontSizeMedium
color: Theme.primaryText
font.weight: Font.Medium
anchors.centerIn: parent
}
MouseArea {
id: confirmButton
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
close()
executePowerAction(powerConfirmAction)
}
}
}
}
}
}
Row {
anchors.horizontalCenter: parent.horizontalCenter
spacing: Theme.spacingM
Rectangle {
width: 120
height: 40
radius: Theme.cornerRadius
color: cancelButton.containsMouse ? Theme.surfaceTextPressed : Theme.surfaceVariantAlpha
StyledText {
text: "Cancel"
font.pixelSize: Theme.fontSizeMedium
color: Theme.surfaceText
font.weight: Font.Medium
anchors.centerIn: parent
}
MouseArea {
id: cancelButton
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
close()
}
}
}
Rectangle {
width: 120
height: 40
radius: Theme.cornerRadius
color: {
let baseColor
switch (powerConfirmAction) {
case "poweroff":
baseColor = Theme.error
break
case "reboot":
baseColor = Theme.warning
break
default:
baseColor = Theme.primary
break
}
return confirmButton.containsMouse ? Qt.rgba(baseColor.r,
baseColor.g,
baseColor.b,
0.9) : baseColor
}
StyledText {
text: "Confirm"
font.pixelSize: Theme.fontSizeMedium
color: Theme.primaryText
font.weight: Font.Medium
anchors.centerIn: parent
}
MouseArea {
id: confirmButton
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
close()
executePowerAction(powerConfirmAction)
}
}
}
}
}
}
}
}

View File

@@ -19,29 +19,28 @@ DankModal {
function show() {
if (!DgopService.dgopAvailable) {
console.warn("ProcessListModal: dgop is not available");
return ;
console.warn("ProcessListModal: dgop is not available")
return
}
open();
UserInfoService.getUptime();
open()
UserInfoService.getUptime()
}
function hide() {
close();
close()
if (processContextMenu.visible)
processContextMenu.close();
processContextMenu.close()
}
function toggle() {
if (!DgopService.dgopAvailable) {
console.warn("ProcessListModal: dgop is not available");
return ;
console.warn("ProcessListModal: dgop is not available")
return
}
if (shouldBeVisible)
hide();
hide()
else
show();
show()
}
width: 900
@@ -58,23 +57,18 @@ DankModal {
ProcessesTab {
contextMenu: processContextMenu
}
}
Component {
id: performanceTabComponent
PerformanceTab {
}
PerformanceTab {}
}
Component {
id: systemTabComponent
SystemTab {
}
SystemTab {}
}
ProcessContextMenu {
@@ -85,19 +79,19 @@ DankModal {
Item {
anchors.fill: parent
focus: true
Keys.onPressed: function(event) {
Keys.onPressed: function (event) {
if (event.key === Qt.Key_Escape) {
processListModal.hide();
event.accepted = true;
processListModal.hide()
event.accepted = true
} else if (event.key === Qt.Key_1) {
currentTab = 0;
event.accepted = true;
currentTab = 0
event.accepted = true
} else if (event.key === Qt.Key_2) {
currentTab = 1;
event.accepted = true;
currentTab = 1
event.accepted = true
} else if (event.key === Qt.Key_3) {
currentTab = 2;
event.accepted = true;
currentTab = 2
event.accepted = true
}
}
@@ -139,9 +133,7 @@ DankModal {
horizontalAlignment: Text.AlignHCenter
wrapMode: Text.WordWrap
}
}
}
ColumnLayout {
@@ -175,7 +167,6 @@ DankModal {
onClicked: processListModal.hide()
Layout.alignment: Qt.AlignVCenter
}
}
Rectangle {
@@ -210,17 +201,18 @@ DankModal {
name: {
switch (index) {
case 0:
return "list_alt";
return "list_alt"
case 1:
return "analytics";
return "analytics"
case 2:
return "settings";
return "settings"
default:
return "tab";
return "tab"
}
}
size: Theme.iconSize - 2
color: currentTab === index ? Theme.primary : Theme.surfaceText
color: currentTab
=== index ? Theme.primary : Theme.surfaceText
opacity: currentTab === index ? 1 : 0.7
anchors.verticalCenter: parent.verticalCenter
@@ -228,16 +220,15 @@ DankModal {
ColorAnimation {
duration: Theme.shortDuration
}
}
}
StyledText {
text: modelData
font.pixelSize: Theme.fontSizeLarge
font.weight: Font.Medium
color: currentTab === index ? Theme.primary : Theme.surfaceText
color: currentTab
=== index ? Theme.primary : Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
anchors.verticalCenterOffset: -1
@@ -245,11 +236,8 @@ DankModal {
ColorAnimation {
duration: Theme.shortDuration
}
}
}
}
MouseArea {
@@ -259,7 +247,7 @@ DankModal {
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
currentTab = index;
currentTab = index
}
}
@@ -267,22 +255,16 @@ DankModal {
ColorAnimation {
duration: Theme.shortDuration
}
}
Behavior on border.color {
ColorAnimation {
duration: Theme.shortDuration
}
}
}
}
}
}
Rectangle {
@@ -308,9 +290,7 @@ DankModal {
duration: Theme.mediumDuration
easing.type: Theme.emphasizedEasing
}
}
}
Loader {
@@ -328,9 +308,7 @@ DankModal {
duration: Theme.mediumDuration
easing.type: Theme.emphasizedEasing
}
}
}
Loader {
@@ -348,17 +326,10 @@ DankModal {
duration: Theme.mediumDuration
easing.type: Theme.emphasizedEasing
}
}
}
}
}
}
}
}

View File

@@ -14,21 +14,21 @@ DankModal {
property Component settingsContent
signal closingModal()
signal closingModal
function show() {
open();
open()
}
function hide() {
close();
close()
}
function toggle() {
if (shouldBeVisible)
hide();
hide()
else
show();
show()
}
objectName: "settingsModal"
@@ -40,18 +40,18 @@ DankModal {
IpcHandler {
function open() {
settingsModal.show();
return "SETTINGS_OPEN_SUCCESS";
settingsModal.show()
return "SETTINGS_OPEN_SUCCESS"
}
function close() {
settingsModal.hide();
return "SETTINGS_CLOSE_SUCCESS";
settingsModal.hide()
return "SETTINGS_CLOSE_SUCCESS"
}
function toggle() {
settingsModal.toggle();
return "SETTINGS_TOGGLE_SUCCESS";
settingsModal.toggle()
return "SETTINGS_TOGGLE_SUCCESS"
}
target: "settings"
@@ -103,7 +103,6 @@ DankModal {
hoverColor: Theme.errorHover
onClicked: settingsModal.hide()
}
}
// Main content with side navigation
@@ -153,7 +152,8 @@ DankModal {
height: 80
anchors.verticalCenter: parent.verticalCenter
property bool hasImage: profileImageSource.status === Image.Ready
property bool hasImage: profileImageSource.status
=== Image.Ready
Rectangle {
anchors.fill: parent
@@ -168,10 +168,11 @@ DankModal {
id: profileImageSource
source: {
if (PortalService.profileImage === "")
return "";
if (PortalService.profileImage.startsWith("/"))
return "file://" + PortalService.profileImage;
return PortalService.profileImage;
return ""
if (PortalService.profileImage.startsWith(
"/"))
return "file://" + PortalService.profileImage
return PortalService.profileImage
}
smooth: true
asynchronous: true
@@ -226,7 +227,8 @@ DankModal {
name: "warning"
size: Theme.iconSizeLarge
color: Theme.error
visible: PortalService.profileImage !== "" && profileImageSource.status === Image.Error
visible: PortalService.profileImage !== ""
&& profileImageSource.status === Image.Error
}
// Hover overlay with edit and clear buttons
@@ -235,54 +237,58 @@ DankModal {
radius: width / 2
color: Qt.rgba(0, 0, 0, 0.7)
visible: profileMouseArea.containsMouse
Row {
anchors.centerIn: parent
spacing: 4
Rectangle {
width: 28
height: 28
radius: 14
color: Qt.rgba(255, 255, 255, 0.9)
color: Qt.rgba(255, 255,
255, 0.9)
DankIcon {
anchors.centerIn: parent
name: "edit"
size: 16
color: "black"
}
MouseArea {
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
onClicked: {
settingsModal.allowFocusOverride = true;
settingsModal.shouldHaveFocus = false;
profileBrowser.open();
settingsModal.allowFocusOverride = true
settingsModal.shouldHaveFocus = false
profileBrowser.open(
)
}
}
}
Rectangle {
width: 28
height: 28
radius: 14
color: Qt.rgba(255, 255, 255, 0.9)
color: Qt.rgba(255, 255,
255, 0.9)
visible: profileImageContainer.hasImage
DankIcon {
anchors.centerIn: parent
name: "close"
size: 16
color: "black"
}
MouseArea {
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
onClicked: {
PortalService.setProfileImage("");
PortalService.setProfileImage(
"")
}
}
}
@@ -306,7 +312,8 @@ DankModal {
spacing: Theme.spacingXS
StyledText {
text: UserInfoService.fullName || "User"
text: UserInfoService.fullName
|| "User"
font.pixelSize: Theme.fontSizeLarge
font.weight: Font.Medium
color: Theme.surfaceText
@@ -315,7 +322,8 @@ DankModal {
}
StyledText {
text: DgopService.distribution || "Linux"
text: DgopService.distribution
|| "Linux"
font.pixelSize: Theme.fontSizeMedium
color: Theme.surfaceVariantText
elide: Text.ElideRight
@@ -341,33 +349,33 @@ DankModal {
id: sidebarRepeater
model: [{
"text": "Personalization",
"icon": "person"
}, {
"text": "Time & Date",
"icon": "schedule"
}, {
"text": "Weather",
"icon": "cloud"
}, {
"text": "Top Bar",
"icon": "toolbar"
}, {
"text": "Widgets",
"icon": "widgets"
}, {
"text": "Dock",
"icon": "dock_to_bottom"
}, {
"text": "Recent Apps",
"icon": "history"
}, {
"text": "Theme & Colors",
"icon": "palette"
}, {
"text": "About",
"icon": "info"
}]
"text": "Personalization",
"icon": "person"
}, {
"text": "Time & Date",
"icon": "schedule"
}, {
"text": "Weather",
"icon": "cloud"
}, {
"text": "Top Bar",
"icon": "toolbar"
}, {
"text": "Widgets",
"icon": "widgets"
}, {
"text": "Dock",
"icon": "dock_to_bottom"
}, {
"text": "Recent Apps",
"icon": "history"
}, {
"text": "Theme & Colors",
"icon": "palette"
}, {
"text": "About",
"icon": "info"
}]
Rectangle {
property bool isActive: sidebarContainer.currentIndex === index
@@ -397,7 +405,6 @@ DankModal {
font.weight: parent.parent.isActive ? Font.Medium : Font.Normal
anchors.verticalCenter: parent.verticalCenter
}
}
MouseArea {
@@ -407,7 +414,7 @@ DankModal {
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
sidebarContainer.currentIndex = index;
sidebarContainer.currentIndex = index
}
}
@@ -416,15 +423,10 @@ DankModal {
duration: Theme.shortDuration
easing.type: Theme.standardEasing
}
}
}
}
}
}
// Main content area
@@ -452,9 +454,7 @@ DankModal {
PersonalizationTab {
parentModal: settingsModal
}
}
}
Loader {
@@ -509,11 +509,8 @@ DankModal {
asynchronous: true
sourceComponent: Component {
DockTab {
}
DockTab {}
}
}
Loader {
@@ -545,210 +542,224 @@ DankModal {
asynchronous: true
sourceComponent: AboutTab {}
}
}
}
}
// Footer
Row {
anchors.horizontalCenter: parent.horizontalCenter
spacing: Theme.spacingXS
// Dank logo
Item {
width: 68
height: 16
anchors.verticalCenter: parent.verticalCenter
Image {
anchors.fill: parent
source: Qt.resolvedUrl(".").toString().replace("file://", "").replace("/Modals/", "") + "/assets/dank.svg"
source: Qt.resolvedUrl(".").toString().replace(
"file://",
"").replace("/Modals/",
"") + "/assets/dank.svg"
sourceSize: Qt.size(68, 16)
smooth: true
fillMode: Image.PreserveAspectFit
layer.enabled: true
layer.effect: MultiEffect {
colorization: 1
colorizationColor: Theme.primary
}
}
MouseArea {
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
onClicked: Qt.openUrlExternally("https://github.com/AvengeMedia/DankMaterialShell")
onClicked: Qt.openUrlExternally(
"https://github.com/AvengeMedia/DankMaterialShell")
}
}
StyledText {
text: "•"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
anchors.verticalCenter: parent.verticalCenter
}
Rectangle {
width: Theme.spacingXS
height: 1
color: "transparent"
}
// Niri logo
Item {
width: 24
height: 24
anchors.verticalCenter: parent.verticalCenter
Image {
anchors.fill: parent
source: Qt.resolvedUrl(".").toString().replace("file://", "").replace("/Modals/", "") + "/assets/niri.svg"
source: Qt.resolvedUrl(".").toString().replace(
"file://",
"").replace("/Modals/",
"") + "/assets/niri.svg"
sourceSize: Qt.size(24, 24)
smooth: true
fillMode: Image.PreserveAspectFit
}
MouseArea {
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
onClicked: Qt.openUrlExternally("https://github.com/YaLTeR/niri")
onClicked: Qt.openUrlExternally(
"https://github.com/YaLTeR/niri")
}
}
Rectangle {
width: Theme.spacingXS
height: 1
color: "transparent"
}
StyledText {
text: "•"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
anchors.verticalCenter: parent.verticalCenter
}
Rectangle {
width: Theme.spacingM
height: 1
color: "transparent"
}
// Matrix button
Item {
width: 32
height: 20
anchors.verticalCenter: parent.verticalCenter
Image {
anchors.fill: parent
source: Qt.resolvedUrl(".").toString().replace("file://", "").replace("/Modals/", "") + "/assets/matrix-logo-white.svg"
source: Qt.resolvedUrl(".").toString().replace(
"file://", "").replace(
"/Modals/",
"") + "/assets/matrix-logo-white.svg"
sourceSize: Qt.size(32, 20)
smooth: true
fillMode: Image.PreserveAspectFit
layer.enabled: true
layer.effect: MultiEffect {
colorization: 1
colorizationColor: Theme.surfaceText
}
}
MouseArea {
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
onClicked: Qt.openUrlExternally("https://matrix.to/#/#niri:matrix.org")
onClicked: Qt.openUrlExternally(
"https://matrix.to/#/#niri:matrix.org")
}
}
Rectangle {
width: Theme.spacingM
height: 1
color: "transparent"
}
StyledText {
text: "•"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
anchors.verticalCenter: parent.verticalCenter
}
Rectangle {
width: Theme.spacingM
height: 1
color: "transparent"
}
// Discord button
Item {
width: 16
height: 16
anchors.verticalCenter: parent.verticalCenter
Image {
anchors.fill: parent
source: Qt.resolvedUrl(".").toString().replace("file://", "").replace("/Modals/", "") + "/assets/discord.svg"
source: Qt.resolvedUrl(".").toString().replace(
"file://",
"").replace("/Modals/",
"") + "/assets/discord.svg"
sourceSize: Qt.size(16, 16)
smooth: true
fillMode: Image.PreserveAspectFit
}
MouseArea {
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
onClicked: Qt.openUrlExternally("https://discord.gg/vT8Sfjy7sx")
onClicked: Qt.openUrlExternally(
"https://discord.gg/vT8Sfjy7sx")
}
}
Rectangle {
width: Theme.spacingM
height: 1
color: "transparent"
}
StyledText {
text: "•"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
anchors.verticalCenter: parent.verticalCenter
}
Rectangle {
width: Theme.spacingM
height: 1
color: "transparent"
}
// Reddit button
Item {
width: 18
height: 18
anchors.verticalCenter: parent.verticalCenter
Image {
anchors.fill: parent
source: Qt.resolvedUrl(".").toString().replace("file://", "").replace("/Modals/", "") + "/assets/reddit.svg"
source: Qt.resolvedUrl(".").toString().replace(
"file://",
"").replace("/Modals/",
"") + "/assets/reddit.svg"
sourceSize: Qt.size(18, 18)
smooth: true
fillMode: Image.PreserveAspectFit
}
MouseArea {
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
onClicked: Qt.openUrlExternally("https://reddit.com/r/niri")
onClicked: Qt.openUrlExternally(
"https://reddit.com/r/niri")
}
}
}
}
}
}
FileBrowserModal {
@@ -758,18 +769,17 @@ DankModal {
browserIcon: "person"
browserType: "profile"
fileExtensions: ["*.jpg", "*.jpeg", "*.png", "*.bmp", "*.gif", "*.webp"]
onFileSelected: (path) => {
PortalService.setProfileImage(path);
close();
}
onFileSelected: path => {
PortalService.setProfileImage(path)
close()
}
onDialogClosed: {
if (settingsModal) {
settingsModal.allowFocusOverride = false;
settingsModal.allowFocusOverride = false
settingsModal.shouldHaveFocus = Qt.binding(() => {
return settingsModal.shouldBeVisible;
});
return settingsModal.shouldBeVisible
})
}
}
}
}

View File

@@ -16,41 +16,41 @@ DankModal {
property Component spotlightContent
function show() {
spotlightOpen = true;
open();
spotlightOpen = true
open()
if (contentLoader.item && contentLoader.item.appLauncher)
contentLoader.item.appLauncher.searchQuery = "";
contentLoader.item.appLauncher.searchQuery = ""
Qt.callLater(function() {
Qt.callLater(function () {
if (contentLoader.item && contentLoader.item.searchField)
contentLoader.item.searchField.forceActiveFocus();
});
contentLoader.item.searchField.forceActiveFocus()
})
}
function hide() {
spotlightOpen = false;
close();
spotlightOpen = false
close()
if (contentLoader.item && contentLoader.item.appLauncher) {
contentLoader.item.appLauncher.searchQuery = "";
contentLoader.item.appLauncher.selectedIndex = 0;
contentLoader.item.appLauncher.setCategory("All");
contentLoader.item.appLauncher.searchQuery = ""
contentLoader.item.appLauncher.selectedIndex = 0
contentLoader.item.appLauncher.setCategory("All")
}
}
function toggle() {
if (spotlightOpen)
hide();
hide()
else
show();
show()
}
shouldBeVisible: spotlightOpen
Connections {
target: ModalManager
function onCloseAllModalsExcept(excludedModal) {
if (excludedModal !== spotlightModal && !allowStacking && spotlightOpen) {
if (excludedModal !== spotlightModal && !allowStacking
&& spotlightOpen) {
spotlightOpen = false
}
}
@@ -64,43 +64,41 @@ DankModal {
enableShadow: true
onVisibleChanged: {
if (visible && !spotlightOpen)
show();
show()
if (visible && contentLoader.item)
Qt.callLater(function() {
Qt.callLater(function () {
if (contentLoader.item.searchField)
contentLoader.item.searchField.forceActiveFocus();
});
contentLoader.item.searchField.forceActiveFocus()
})
}
onBackgroundClicked: {
hide();
hide()
}
Component.onCompleted: {
}
content: spotlightContent
IpcHandler {
function open() {
spotlightModal.show();
return "SPOTLIGHT_OPEN_SUCCESS";
spotlightModal.show()
return "SPOTLIGHT_OPEN_SUCCESS"
}
function close() {
spotlightModal.hide();
return "SPOTLIGHT_CLOSE_SUCCESS";
spotlightModal.hide()
return "SPOTLIGHT_CLOSE_SUCCESS"
}
function toggle() {
spotlightModal.toggle();
return "SPOTLIGHT_TOGGLE_SUCCESS";
spotlightModal.toggle()
return "SPOTLIGHT_TOGGLE_SUCCESS"
}
target: "spotlight"
}
spotlightContent: Component {
Item {
id: spotlightKeyHandler
@@ -110,29 +108,34 @@ DankModal {
anchors.fill: parent
focus: true
Keys.onPressed: function(event) {
Keys.onPressed: function (event) {
if (event.key === Qt.Key_Escape) {
hide();
event.accepted = true;
hide()
event.accepted = true
} else if (event.key === Qt.Key_Down) {
appLauncher.selectNext();
event.accepted = true;
appLauncher.selectNext()
event.accepted = true
} else if (event.key === Qt.Key_Up) {
appLauncher.selectPrevious();
event.accepted = true;
} else if (event.key === Qt.Key_Right && appLauncher.viewMode === "grid") {
appLauncher.selectNextInRow();
event.accepted = true;
} else if (event.key === Qt.Key_Left && appLauncher.viewMode === "grid") {
appLauncher.selectPreviousInRow();
event.accepted = true;
} else if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter) {
appLauncher.launchSelected();
event.accepted = true;
} else if (!searchField.activeFocus && event.text && event.text.length > 0 && event.text.match(/[a-zA-Z0-9\\s]/)) {
searchField.forceActiveFocus();
searchField.insertText(event.text);
event.accepted = true;
appLauncher.selectPrevious()
event.accepted = true
} else if (event.key === Qt.Key_Right
&& appLauncher.viewMode === "grid") {
appLauncher.selectNextInRow()
event.accepted = true
} else if (event.key === Qt.Key_Left
&& appLauncher.viewMode === "grid") {
appLauncher.selectPreviousInRow()
event.accepted = true
} else if (event.key === Qt.Key_Return
|| event.key === Qt.Key_Enter) {
appLauncher.launchSelected()
event.accepted = true
} else if (!searchField.activeFocus && event.text
&& event.text.length > 0 && event.text.match(
/[a-zA-Z0-9\\s]/)) {
searchField.forceActiveFocus()
searchField.insertText(event.text)
event.accepted = true
}
}
@@ -142,8 +145,8 @@ DankModal {
viewMode: SettingsData.spotlightModalViewMode
gridColumns: 4
onAppLaunched: hide()
onViewModeSelected: function(mode) {
SettingsData.setSpotlightModalViewMode(mode);
onViewModeSelected: function (mode) {
SettingsData.setSpotlightModalViewMode(mode)
}
}
@@ -159,7 +162,8 @@ DankModal {
color: Theme.surfaceVariantAlpha
border.color: Theme.outlineMedium
border.width: 1
visible: appLauncher.categories.length > 1 || appLauncher.model.count > 0
visible: appLauncher.categories.length > 1
|| appLauncher.model.count > 0
CategorySelector {
id: categorySelector
@@ -169,11 +173,11 @@ DankModal {
categories: appLauncher.categories
selectedCategory: appLauncher.selectedCategory
compact: false
onCategorySelected: (category) => {
return appLauncher.setCategory(category);
}
onCategorySelected: category => {
return appLauncher.setCategory(
category)
}
}
}
Row {
@@ -183,10 +187,16 @@ DankModal {
DankTextField {
id: searchField
width: parent.width - 80 - Theme.spacingM // Leave space for view toggle buttons
width: parent.width - 80
- Theme.spacingM // Leave space for view toggle buttons
height: 56
cornerRadius: Theme.cornerRadius
backgroundColor: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, Theme.getContentBackgroundAlpha() * 0.7)
backgroundColor: Qt.rgba(
Theme.surfaceVariant.r,
Theme.surfaceVariant.g,
Theme.surfaceVariant.b,
Theme.getContentBackgroundAlpha(
) * 0.7)
normalBorderColor: Theme.outlineMedium
focusedBorderColor: Theme.primary
leftIconName: "search"
@@ -202,22 +212,26 @@ DankModal {
keyForwardTargets: [spotlightKeyHandler]
text: appLauncher.searchQuery
onTextEdited: {
appLauncher.searchQuery = text;
}
Keys.onPressed: (event) => {
if (event.key === Qt.Key_Escape) {
hide();
event.accepted = true;
} else if ((event.key === Qt.Key_Return || event.key === Qt.Key_Enter) && text.length > 0) {
if (appLauncher.keyboardNavigationActive && appLauncher.model.count > 0)
appLauncher.launchSelected();
else if (appLauncher.model.count > 0)
appLauncher.launchApp(appLauncher.model.get(0));
event.accepted = true;
} else if (event.key === Qt.Key_Down || event.key === Qt.Key_Up || event.key === Qt.Key_Left || event.key === Qt.Key_Right || ((event.key === Qt.Key_Return || event.key === Qt.Key_Enter) && text.length === 0)) {
event.accepted = false;
}
appLauncher.searchQuery = text
}
Keys.onPressed: event => {
if (event.key === Qt.Key_Escape) {
hide()
event.accepted = true
} else if ((event.key === Qt.Key_Return
|| event.key === Qt.Key_Enter)
&& text.length > 0) {
if (appLauncher.keyboardNavigationActive
&& appLauncher.model.count > 0)
appLauncher.launchSelected()
else if (appLauncher.model.count > 0)
appLauncher.launchApp(
appLauncher.model.get(0))
event.accepted = true
} else if (event.key === Qt.Key_Down || event.key === Qt.Key_Up || event.key === Qt.Key_Left || event.key === Qt.Key_Right || ((event.key === Qt.Key_Return || event.key === Qt.Key_Enter) && text.length === 0)) {
event.accepted = false
}
}
}
Row {
@@ -230,14 +244,16 @@ DankModal {
height: 36
radius: Theme.cornerRadius
color: appLauncher.viewMode === "list" ? Theme.primaryHover : listViewArea.containsMouse ? Theme.surfaceHover : "transparent"
border.color: appLauncher.viewMode === "list" ? Theme.primarySelected : "transparent"
border.color: appLauncher.viewMode
=== "list" ? Theme.primarySelected : "transparent"
border.width: 1
DankIcon {
anchors.centerIn: parent
name: "view_list"
size: 18
color: appLauncher.viewMode === "list" ? Theme.primary : Theme.surfaceText
color: appLauncher.viewMode
=== "list" ? Theme.primary : Theme.surfaceText
}
MouseArea {
@@ -247,10 +263,9 @@ DankModal {
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
appLauncher.setViewMode("list");
appLauncher.setViewMode("list")
}
}
}
Rectangle {
@@ -258,14 +273,16 @@ DankModal {
height: 36
radius: Theme.cornerRadius
color: appLauncher.viewMode === "grid" ? Theme.primaryHover : gridViewArea.containsMouse ? Theme.surfaceHover : "transparent"
border.color: appLauncher.viewMode === "grid" ? Theme.primarySelected : "transparent"
border.color: appLauncher.viewMode
=== "grid" ? Theme.primarySelected : "transparent"
border.width: 1
DankIcon {
anchors.centerIn: parent
name: "grid_view"
size: 18
color: appLauncher.viewMode === "grid" ? Theme.primary : Theme.surfaceText
color: appLauncher.viewMode
=== "grid" ? Theme.primary : Theme.surfaceText
}
MouseArea {
@@ -275,14 +292,11 @@ DankModal {
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
appLauncher.setViewMode("grid");
appLauncher.setViewMode("grid")
}
}
}
}
}
Rectangle {
@@ -305,20 +319,20 @@ DankModal {
property bool hoverUpdatesSelection: false
property bool keyboardNavigationActive: appLauncher.keyboardNavigationActive
signal keyboardNavigationReset()
signal keyboardNavigationReset
signal itemClicked(int index, var modelData)
signal itemRightClicked(int index, var modelData, real mouseX, real mouseY)
function ensureVisible(index) {
if (index < 0 || index >= count)
return ;
return
var itemY = index * (itemHeight + itemSpacing);
var itemBottom = itemY + itemHeight;
var itemY = index * (itemHeight + itemSpacing)
var itemBottom = itemY + itemHeight
if (itemY < contentY)
contentY = itemY;
contentY = itemY
else if (itemBottom > contentY + height)
contentY = itemBottom - height;
contentY = itemBottom - height
}
anchors.fill: parent
@@ -334,17 +348,16 @@ DankModal {
reuseItems: true
onCurrentIndexChanged: {
if (keyboardNavigationActive)
ensureVisible(currentIndex);
ensureVisible(currentIndex)
}
onItemClicked: function(index, modelData) {
appLauncher.launchApp(modelData);
onItemClicked: function (index, modelData) {
appLauncher.launchApp(modelData)
}
onItemRightClicked: function(index, modelData, mouseX, mouseY) {
contextMenu.show(mouseX, mouseY, modelData);
onItemRightClicked: function (index, modelData, mouseX, mouseY) {
contextMenu.show(mouseX, mouseY, modelData)
}
onKeyboardNavigationReset: {
appLauncher.keyboardNavigationActive = false;
appLauncher.keyboardNavigationActive = false
}
ScrollBar.vertical: ScrollBar {
@@ -377,7 +390,9 @@ DankModal {
id: listIconImg
anchors.fill: parent
source: (model.icon) ? Quickshell.iconPath(model.icon, SettingsData.iconTheme === "System Default" ? "" : SettingsData.iconTheme) : ""
source: (model.icon) ? Quickshell.iconPath(
model.icon,
SettingsData.iconTheme === "System Default" ? "" : SettingsData.iconTheme) : ""
smooth: true
asynchronous: true
visible: status === Image.Ready
@@ -393,14 +408,16 @@ DankModal {
StyledText {
anchors.centerIn: parent
text: (model.name && model.name.length > 0) ? model.name.charAt(0).toUpperCase() : "A"
text: (model.name
&& model.name.length
> 0) ? model.name.charAt(
0).toUpperCase(
) : "A"
font.pixelSize: resultsList.iconSize * 0.4
color: Theme.primary
font.weight: Font.Bold
}
}
}
Column {
@@ -423,11 +440,11 @@ DankModal {
font.pixelSize: Theme.fontSizeMedium
color: Theme.surfaceVariantText
elide: Text.ElideRight
visible: resultsList.showDescription && model.comment && model.comment.length > 0
visible: resultsList.showDescription
&& model.comment
&& model.comment.length > 0
}
}
}
MouseArea {
@@ -439,25 +456,28 @@ DankModal {
acceptedButtons: Qt.LeftButton | Qt.RightButton
z: 10
onEntered: {
if (resultsList.hoverUpdatesSelection && !resultsList.keyboardNavigationActive)
resultsList.currentIndex = index;
if (resultsList.hoverUpdatesSelection
&& !resultsList.keyboardNavigationActive)
resultsList.currentIndex = index
}
onPositionChanged: {
resultsList.keyboardNavigationReset();
}
onClicked: (mouse) => {
if (mouse.button === Qt.LeftButton) {
resultsList.itemClicked(index, model);
} else if (mouse.button === Qt.RightButton) {
var modalPos = mapToItem(spotlightKeyHandler, mouse.x, mouse.y);
resultsList.itemRightClicked(index, model, modalPos.x, modalPos.y);
}
resultsList.keyboardNavigationReset()
}
onClicked: mouse => {
if (mouse.button === Qt.LeftButton) {
resultsList.itemClicked(
index, model)
} else if (mouse.button === Qt.RightButton) {
var modalPos = mapToItem(
spotlightKeyHandler,
mouse.x, mouse.y)
resultsList.itemRightClicked(
index, model,
modalPos.x, modalPos.y)
}
}
}
}
}
DankGridView {
@@ -474,25 +494,30 @@ DankModal {
property int minIconSize: 32
property bool hoverUpdatesSelection: false
property bool keyboardNavigationActive: appLauncher.keyboardNavigationActive
property int baseCellWidth: adaptiveColumns ? Math.max(minCellWidth, Math.min(maxCellWidth, width / columns)) : (width - Theme.spacingS * 2) / columns
property int baseCellWidth: adaptiveColumns ? Math.max(
minCellWidth,
Math.min(maxCellWidth, width / columns)) : (width - Theme.spacingS * 2) / columns
property int baseCellHeight: baseCellWidth + 20
property int actualColumns: adaptiveColumns ? Math.floor(width / cellWidth) : columns
property int actualColumns: adaptiveColumns ? Math.floor(
width
/ cellWidth) : columns
property int remainingSpace: width - (actualColumns * cellWidth)
signal keyboardNavigationReset()
signal keyboardNavigationReset
signal itemClicked(int index, var modelData)
signal itemRightClicked(int index, var modelData, real mouseX, real mouseY)
function ensureVisible(index) {
if (index < 0 || index >= count)
return ;
return
var itemY = Math.floor(index / actualColumns) * cellHeight;
var itemBottom = itemY + cellHeight;
var itemY = Math.floor(
index / actualColumns) * cellHeight
var itemBottom = itemY + cellHeight
if (itemY < contentY)
contentY = itemY;
contentY = itemY
else if (itemBottom > contentY + height)
contentY = itemBottom - height;
contentY = itemBottom - height
}
anchors.fill: parent
@@ -510,17 +535,16 @@ DankModal {
reuseItems: true
onCurrentIndexChanged: {
if (keyboardNavigationActive)
ensureVisible(currentIndex);
ensureVisible(currentIndex)
}
onItemClicked: function(index, modelData) {
appLauncher.launchApp(modelData);
onItemClicked: function (index, modelData) {
appLauncher.launchApp(modelData)
}
onItemRightClicked: function(index, modelData, mouseX, mouseY) {
contextMenu.show(mouseX, mouseY, modelData);
onItemRightClicked: function (index, modelData, mouseX, mouseY) {
contextMenu.show(mouseX, mouseY, modelData)
}
onKeyboardNavigationReset: {
appLauncher.keyboardNavigationActive = false;
appLauncher.keyboardNavigationActive = false
}
ScrollBar.vertical: ScrollBar {
@@ -536,7 +560,8 @@ DankModal {
height: resultsGrid.cellHeight - resultsGrid.cellPadding
radius: Theme.cornerRadius
color: resultsGrid.currentIndex === index ? Theme.primaryPressed : gridMouseArea.containsMouse ? Theme.primaryHoverLight : Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.03)
border.color: resultsGrid.currentIndex === index ? Theme.primarySelected : Theme.outlineMedium
border.color: resultsGrid.currentIndex
=== index ? Theme.primarySelected : Theme.outlineMedium
border.width: resultsGrid.currentIndex === index ? 2 : 1
Column {
@@ -544,7 +569,12 @@ DankModal {
spacing: Theme.spacingS
Item {
property int iconSize: Math.min(resultsGrid.maxIconSize, Math.max(resultsGrid.minIconSize, resultsGrid.cellWidth * resultsGrid.iconSizeRatio))
property int iconSize: Math.min(
resultsGrid.maxIconSize,
Math.max(
resultsGrid.minIconSize,
resultsGrid.cellWidth
* resultsGrid.iconSizeRatio))
width: iconSize
height: iconSize
@@ -554,7 +584,9 @@ DankModal {
id: gridIconImg
anchors.fill: parent
source: (model.icon) ? Quickshell.iconPath(model.icon, SettingsData.iconTheme === "System Default" ? "" : SettingsData.iconTheme) : ""
source: (model.icon) ? Quickshell.iconPath(
model.icon,
SettingsData.iconTheme === "System Default" ? "" : SettingsData.iconTheme) : ""
smooth: true
asynchronous: true
visible: status === Image.Ready
@@ -570,14 +602,18 @@ DankModal {
StyledText {
anchors.centerIn: parent
text: (model.name && model.name.length > 0) ? model.name.charAt(0).toUpperCase() : "A"
font.pixelSize: Math.min(28, parent.width * 0.5)
text: (model.name
&& model.name.length
> 0) ? model.name.charAt(
0).toUpperCase(
) : "A"
font.pixelSize: Math.min(
28,
parent.width * 0.5)
color: Theme.primary
font.weight: Font.Bold
}
}
}
StyledText {
@@ -592,7 +628,6 @@ DankModal {
maximumLineCount: 2
wrapMode: Text.WordWrap
}
}
MouseArea {
@@ -604,29 +639,30 @@ DankModal {
acceptedButtons: Qt.LeftButton | Qt.RightButton
z: 10
onEntered: {
if (resultsGrid.hoverUpdatesSelection && !resultsGrid.keyboardNavigationActive)
resultsGrid.currentIndex = index;
if (resultsGrid.hoverUpdatesSelection
&& !resultsGrid.keyboardNavigationActive)
resultsGrid.currentIndex = index
}
onPositionChanged: {
resultsGrid.keyboardNavigationReset();
}
onClicked: (mouse) => {
if (mouse.button === Qt.LeftButton) {
resultsGrid.itemClicked(index, model);
} else if (mouse.button === Qt.RightButton) {
var modalPos = mapToItem(spotlightKeyHandler, mouse.x, mouse.y);
resultsGrid.itemRightClicked(index, model, modalPos.x, modalPos.y);
}
resultsGrid.keyboardNavigationReset()
}
onClicked: mouse => {
if (mouse.button === Qt.LeftButton) {
resultsGrid.itemClicked(
index, model)
} else if (mouse.button === Qt.RightButton) {
var modalPos = mapToItem(
spotlightKeyHandler,
mouse.x, mouse.y)
resultsGrid.itemRightClicked(
index, model,
modalPos.x, modalPos.y)
}
}
}
}
}
}
}
Rectangle {
@@ -637,23 +673,29 @@ DankModal {
function show(x, y, app) {
currentApp = app
const menuWidth = 180
const menuHeight = menuColumn.implicitHeight + Theme.spacingS * 2
let finalX = x + 8
let finalY = y + 8
if (finalX + menuWidth > spotlightKeyHandler.width) {
finalX = x - menuWidth - 8
}
if (finalY + menuHeight > spotlightKeyHandler.height) {
finalY = y - menuHeight - 8
}
finalX = Math.max(8, Math.min(finalX, spotlightKeyHandler.width - menuWidth - 8))
finalY = Math.max(8, Math.min(finalY, spotlightKeyHandler.height - menuHeight - 8))
finalX = Math.max(
8, Math.min(
finalX,
spotlightKeyHandler.width - menuWidth - 8))
finalY = Math.max(
8, Math.min(
finalY,
spotlightKeyHandler.height - menuHeight - 8))
contextMenu.x = finalX
contextMenu.y = finalY
contextMenu.visible = true
@@ -663,8 +705,8 @@ DankModal {
function close() {
contextMenu.menuVisible = false
Qt.callLater(() => {
contextMenu.visible = false
})
contextMenu.visible = false
})
}
visible: false
@@ -672,7 +714,8 @@ DankModal {
height: menuColumn.implicitHeight + Theme.spacingS * 2
radius: Theme.cornerRadius
color: Theme.popupBackground()
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08)
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g,
Theme.outline.b, 0.08)
border.width: 1
z: 1000
opacity: menuVisible ? 1 : 0
@@ -700,7 +743,11 @@ DankModal {
width: parent.width
height: 32
radius: Theme.cornerRadius
color: pinMouseArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent"
color: pinMouseArea.containsMouse ? Qt.rgba(
Theme.primary.r,
Theme.primary.g,
Theme.primary.b,
0.12) : "transparent"
Row {
anchors.left: parent.left
@@ -710,11 +757,15 @@ DankModal {
DankIcon {
name: {
if (!contextMenu.currentApp || !contextMenu.currentApp.desktopEntry)
if (!contextMenu.currentApp
|| !contextMenu.currentApp.desktopEntry)
return "push_pin"
var appId = contextMenu.currentApp.desktopEntry.id || contextMenu.currentApp.desktopEntry.execString || ""
return SessionData.isPinnedApp(appId) ? "keep_off" : "push_pin"
var appId = contextMenu.currentApp.desktopEntry.id
|| contextMenu.currentApp.desktopEntry.execString
|| ""
return SessionData.isPinnedApp(
appId) ? "keep_off" : "push_pin"
}
size: Theme.iconSize - 2
color: Theme.surfaceText
@@ -724,11 +775,15 @@ DankModal {
StyledText {
text: {
if (!contextMenu.currentApp || !contextMenu.currentApp.desktopEntry)
if (!contextMenu.currentApp
|| !contextMenu.currentApp.desktopEntry)
return "Pin to Dock"
var appId = contextMenu.currentApp.desktopEntry.id || contextMenu.currentApp.desktopEntry.execString || ""
return SessionData.isPinnedApp(appId) ? "Unpin from Dock" : "Pin to Dock"
var appId = contextMenu.currentApp.desktopEntry.id
|| contextMenu.currentApp.desktopEntry.execString
|| ""
return SessionData.isPinnedApp(
appId) ? "Unpin from Dock" : "Pin to Dock"
}
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceText
@@ -744,10 +799,13 @@ DankModal {
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
if (!contextMenu.currentApp || !contextMenu.currentApp.desktopEntry)
if (!contextMenu.currentApp
|| !contextMenu.currentApp.desktopEntry)
return
var appId = contextMenu.currentApp.desktopEntry.id || contextMenu.currentApp.desktopEntry.execString || ""
var appId = contextMenu.currentApp.desktopEntry.id
|| contextMenu.currentApp.desktopEntry.execString
|| ""
if (SessionData.isPinnedApp(appId))
SessionData.removePinnedApp(appId)
else
@@ -767,7 +825,8 @@ DankModal {
anchors.centerIn: parent
width: parent.width
height: 1
color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
color: Qt.rgba(Theme.outline.r, Theme.outline.g,
Theme.outline.b, 0.2)
}
}
@@ -775,7 +834,11 @@ DankModal {
width: parent.width
height: 32
radius: Theme.cornerRadius
color: launchMouseArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent"
color: launchMouseArea.containsMouse ? Qt.rgba(
Theme.primary.r,
Theme.primary.g,
Theme.primary.b,
0.12) : "transparent"
Row {
anchors.left: parent.left
@@ -808,7 +871,8 @@ DankModal {
cursorShape: Qt.PointingHandCursor
onClicked: {
if (contextMenu.currentApp)
appLauncher.launchApp(contextMenu.currentApp)
appLauncher.launchApp(
contextMenu.currentApp)
contextMenu.close()
}
@@ -845,13 +909,11 @@ DankModal {
width: contextMenu.width
height: contextMenu.height
onClicked: {
// Prevent closing when clicking on the menu itself
}
}
}
}
}
}

View File

@@ -5,300 +5,306 @@ import qs.Services
import qs.Widgets
DankModal {
id: root
id: root
property string wifiPasswordSSID: ""
property string wifiPasswordInput: ""
property string wifiPasswordSSID: ""
property string wifiPasswordInput: ""
function show(ssid) {
wifiPasswordSSID = ssid
wifiPasswordInput = ""
open()
Qt.callLater(function() {
if (contentLoader.item && contentLoader.item.passwordInput) {
contentLoader.item.passwordInput.forceActiveFocus()
}
})
}
shouldBeVisible: false
width: 420
height: 230
onShouldBeVisibleChanged: {
if (!shouldBeVisible)
wifiPasswordInput = ""
}
onOpened: {
Qt.callLater(function() {
if (contentLoader.item && contentLoader.item.passwordInput) {
contentLoader.item.passwordInput.forceActiveFocus()
}
})
}
onBackgroundClicked: {
close()
wifiPasswordInput = ""
}
Connections {
function onPasswordDialogShouldReopenChanged() {
if (NetworkService.passwordDialogShouldReopen
&& NetworkService.connectingSSID !== "") {
wifiPasswordSSID = NetworkService.connectingSSID
function show(ssid) {
wifiPasswordSSID = ssid
wifiPasswordInput = ""
open()
NetworkService.passwordDialogShouldReopen = false
}
Qt.callLater(function () {
if (contentLoader.item && contentLoader.item.passwordInput) {
contentLoader.item.passwordInput.forceActiveFocus()
}
})
}
target: NetworkService
}
content: Component {
FocusScope {
id: wifiContent
property alias passwordInput: passwordInput
anchors.fill: parent
focus: true
Keys.onEscapePressed: function(event) {
shouldBeVisible: false
width: 420
height: 230
onShouldBeVisibleChanged: {
if (!shouldBeVisible)
wifiPasswordInput = ""
}
onOpened: {
Qt.callLater(function () {
if (contentLoader.item && contentLoader.item.passwordInput) {
contentLoader.item.passwordInput.forceActiveFocus()
}
})
}
onBackgroundClicked: {
close()
wifiPasswordInput = ""
event.accepted = true
}
Column {
anchors.centerIn: parent
width: parent.width - Theme.spacingM * 2
spacing: Theme.spacingM
Row {
width: parent.width
Column {
width: parent.width - 40
spacing: Theme.spacingXS
StyledText {
text: "Connect to Wi-Fi"
font.pixelSize: Theme.fontSizeLarge
color: Theme.surfaceText
font.weight: Font.Medium
}
StyledText {
text: "Enter password for \"" + wifiPasswordSSID + "\""
font.pixelSize: Theme.fontSizeMedium
color: Theme.surfaceTextMedium
width: parent.width
elide: Text.ElideRight
}
}
DankActionButton {
iconName: "close"
iconSize: Theme.iconSize - 4
iconColor: Theme.surfaceText
hoverColor: Theme.errorHover
onClicked: {
close()
wifiPasswordInput = ""
}
}
}
Rectangle {
width: parent.width
height: 50
radius: Theme.cornerRadius
color: Theme.surfaceHover
border.color: passwordInput.activeFocus ? Theme.primary : Theme.outlineStrong
border.width: passwordInput.activeFocus ? 2 : 1
MouseArea {
anchors.fill: parent
onClicked: {
passwordInput.forceActiveFocus()
}
}
DankTextField {
id: passwordInput
anchors.fill: parent
font.pixelSize: Theme.fontSizeMedium
textColor: Theme.surfaceText
text: wifiPasswordInput
echoMode: showPasswordCheckbox.checked ? TextInput.Normal : TextInput.Password
placeholderText: ""
backgroundColor: "transparent"
focus: true
enabled: root.shouldBeVisible
onTextEdited: {
wifiPasswordInput = text
}
onAccepted: {
NetworkService.connectToWifiWithPassword(wifiPasswordSSID,
passwordInput.text)
close()
wifiPasswordInput = ""
passwordInput.text = ""
}
Component.onCompleted: {
if (root.shouldBeVisible) {
focusDelayTimer.start()
}
}
Timer {
id: focusDelayTimer
interval: 100
repeat: false
onTriggered: {
if (root.shouldBeVisible) {
passwordInput.forceActiveFocus()
}
}
}
Connections {
target: root
function onShouldBeVisibleChanged() {
if (root.shouldBeVisible) {
focusDelayTimer.start()
}
}
}
}
}
Row {
spacing: Theme.spacingS
Rectangle {
id: showPasswordCheckbox
property bool checked: false
width: 20
height: 20
radius: 4
color: checked ? Theme.primary : "transparent"
border.color: checked ? Theme.primary : Theme.outlineButton
border.width: 2
DankIcon {
anchors.centerIn: parent
name: "check"
size: 12
color: Theme.background
visible: parent.checked
}
MouseArea {
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
showPasswordCheckbox.checked = !showPasswordCheckbox.checked
}
}
}
StyledText {
text: "Show password"
font.pixelSize: Theme.fontSizeMedium
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
}
Item {
width: parent.width
height: 40
Row {
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
spacing: Theme.spacingM
Rectangle {
width: Math.max(70, cancelText.contentWidth + Theme.spacingM * 2)
height: 36
radius: Theme.cornerRadius
color: cancelArea.containsMouse ? Theme.surfaceTextHover : "transparent"
border.color: Theme.surfaceVariantAlpha
border.width: 1
StyledText {
id: cancelText
anchors.centerIn: parent
text: "Cancel"
font.pixelSize: Theme.fontSizeMedium
color: Theme.surfaceText
font.weight: Font.Medium
}
MouseArea {
id: cancelArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
close()
wifiPasswordInput = ""
}
}
}
Rectangle {
width: Math.max(80, connectText.contentWidth + Theme.spacingM * 2)
height: 36
radius: Theme.cornerRadius
color: connectArea.containsMouse ? Qt.darker(Theme.primary,
1.1) : Theme.primary
enabled: passwordInput.text.length > 0
opacity: enabled ? 1 : 0.5
StyledText {
id: connectText
anchors.centerIn: parent
text: "Connect"
font.pixelSize: Theme.fontSizeMedium
color: Theme.background
font.weight: Font.Medium
}
MouseArea {
id: connectArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
enabled: parent.enabled
onClicked: {
NetworkService.connectToWifiWithPassword(wifiPasswordSSID,
passwordInput.text)
close()
wifiPasswordInput = ""
passwordInput.text = ""
}
}
Behavior on color {
ColorAnimation {
duration: Theme.shortDuration
easing.type: Theme.standardEasing
}
}
}
}
}
}
}
}
Connections {
function onPasswordDialogShouldReopenChanged() {
if (NetworkService.passwordDialogShouldReopen
&& NetworkService.connectingSSID !== "") {
wifiPasswordSSID = NetworkService.connectingSSID
wifiPasswordInput = ""
open()
NetworkService.passwordDialogShouldReopen = false
}
}
target: NetworkService
}
content: Component {
FocusScope {
id: wifiContent
property alias passwordInput: passwordInput
anchors.fill: parent
focus: true
Keys.onEscapePressed: function (event) {
close()
wifiPasswordInput = ""
event.accepted = true
}
Column {
anchors.centerIn: parent
width: parent.width - Theme.spacingM * 2
spacing: Theme.spacingM
Row {
width: parent.width
Column {
width: parent.width - 40
spacing: Theme.spacingXS
StyledText {
text: "Connect to Wi-Fi"
font.pixelSize: Theme.fontSizeLarge
color: Theme.surfaceText
font.weight: Font.Medium
}
StyledText {
text: "Enter password for \"" + wifiPasswordSSID + "\""
font.pixelSize: Theme.fontSizeMedium
color: Theme.surfaceTextMedium
width: parent.width
elide: Text.ElideRight
}
}
DankActionButton {
iconName: "close"
iconSize: Theme.iconSize - 4
iconColor: Theme.surfaceText
hoverColor: Theme.errorHover
onClicked: {
close()
wifiPasswordInput = ""
}
}
}
Rectangle {
width: parent.width
height: 50
radius: Theme.cornerRadius
color: Theme.surfaceHover
border.color: passwordInput.activeFocus ? Theme.primary : Theme.outlineStrong
border.width: passwordInput.activeFocus ? 2 : 1
MouseArea {
anchors.fill: parent
onClicked: {
passwordInput.forceActiveFocus()
}
}
DankTextField {
id: passwordInput
anchors.fill: parent
font.pixelSize: Theme.fontSizeMedium
textColor: Theme.surfaceText
text: wifiPasswordInput
echoMode: showPasswordCheckbox.checked ? TextInput.Normal : TextInput.Password
placeholderText: ""
backgroundColor: "transparent"
focus: true
enabled: root.shouldBeVisible
onTextEdited: {
wifiPasswordInput = text
}
onAccepted: {
NetworkService.connectToWifiWithPassword(
wifiPasswordSSID, passwordInput.text)
close()
wifiPasswordInput = ""
passwordInput.text = ""
}
Component.onCompleted: {
if (root.shouldBeVisible) {
focusDelayTimer.start()
}
}
Timer {
id: focusDelayTimer
interval: 100
repeat: false
onTriggered: {
if (root.shouldBeVisible) {
passwordInput.forceActiveFocus()
}
}
}
Connections {
target: root
function onShouldBeVisibleChanged() {
if (root.shouldBeVisible) {
focusDelayTimer.start()
}
}
}
}
}
Row {
spacing: Theme.spacingS
Rectangle {
id: showPasswordCheckbox
property bool checked: false
width: 20
height: 20
radius: 4
color: checked ? Theme.primary : "transparent"
border.color: checked ? Theme.primary : Theme.outlineButton
border.width: 2
DankIcon {
anchors.centerIn: parent
name: "check"
size: 12
color: Theme.background
visible: parent.checked
}
MouseArea {
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
showPasswordCheckbox.checked = !showPasswordCheckbox.checked
}
}
}
StyledText {
text: "Show password"
font.pixelSize: Theme.fontSizeMedium
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
}
Item {
width: parent.width
height: 40
Row {
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
spacing: Theme.spacingM
Rectangle {
width: Math.max(
70,
cancelText.contentWidth + Theme.spacingM * 2)
height: 36
radius: Theme.cornerRadius
color: cancelArea.containsMouse ? Theme.surfaceTextHover : "transparent"
border.color: Theme.surfaceVariantAlpha
border.width: 1
StyledText {
id: cancelText
anchors.centerIn: parent
text: "Cancel"
font.pixelSize: Theme.fontSizeMedium
color: Theme.surfaceText
font.weight: Font.Medium
}
MouseArea {
id: cancelArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
close()
wifiPasswordInput = ""
}
}
}
Rectangle {
width: Math.max(
80,
connectText.contentWidth + Theme.spacingM * 2)
height: 36
radius: Theme.cornerRadius
color: connectArea.containsMouse ? Qt.darker(
Theme.primary,
1.1) : Theme.primary
enabled: passwordInput.text.length > 0
opacity: enabled ? 1 : 0.5
StyledText {
id: connectText
anchors.centerIn: parent
text: "Connect"
font.pixelSize: Theme.fontSizeMedium
color: Theme.background
font.weight: Font.Medium
}
MouseArea {
id: connectArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
enabled: parent.enabled
onClicked: {
NetworkService.connectToWifiWithPassword(
wifiPasswordSSID,
passwordInput.text)
close()
wifiPasswordInput = ""
passwordInput.text = ""
}
}
Behavior on color {
ColorAnimation {
duration: Theme.shortDuration
easing.type: Theme.standardEasing
}
}
}
}
}
}
}
}
}