mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-01-29 16:02:51 -05:00
cleanup and qmlfmt remaining modals
- qmlfmt sucks I know, but what else can I do
This commit is contained in:
@@ -1,8 +1,5 @@
|
|||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Controls
|
import QtQuick.Controls
|
||||||
import Quickshell
|
|
||||||
import Quickshell.Io
|
|
||||||
import Quickshell.Widgets
|
|
||||||
import qs.Common
|
import qs.Common
|
||||||
import qs.Modals.Common
|
import qs.Modals.Common
|
||||||
import qs.Services
|
import qs.Services
|
||||||
@@ -14,7 +11,6 @@ DankModal {
|
|||||||
property bool networkInfoModalVisible: false
|
property bool networkInfoModalVisible: false
|
||||||
property string networkSSID: ""
|
property string networkSSID: ""
|
||||||
property var networkData: null
|
property var networkData: null
|
||||||
property string networkDetails: ""
|
|
||||||
|
|
||||||
function showNetworkInfo(ssid, data) {
|
function showNetworkInfo(ssid, data) {
|
||||||
networkSSID = ssid
|
networkSSID = ssid
|
||||||
@@ -29,21 +25,17 @@ DankModal {
|
|||||||
close()
|
close()
|
||||||
networkSSID = ""
|
networkSSID = ""
|
||||||
networkData = null
|
networkData = null
|
||||||
networkDetails = ""
|
|
||||||
}
|
}
|
||||||
|
|
||||||
visible: networkInfoModalVisible
|
visible: networkInfoModalVisible
|
||||||
width: 600
|
width: 600
|
||||||
height: 500
|
height: 500
|
||||||
enableShadow: true
|
enableShadow: true
|
||||||
onBackgroundClicked: {
|
onBackgroundClicked: hideDialog()
|
||||||
hideDialog()
|
|
||||||
}
|
|
||||||
onVisibleChanged: {
|
onVisibleChanged: {
|
||||||
if (!visible) {
|
if (!visible) {
|
||||||
networkSSID = ""
|
networkSSID = ""
|
||||||
networkData = null
|
networkData = null
|
||||||
networkDetails = ""
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -71,12 +63,13 @@ DankModal {
|
|||||||
}
|
}
|
||||||
|
|
||||||
StyledText {
|
StyledText {
|
||||||
text: "Details for \"" + networkSSID + "\""
|
text: `Details for "${networkSSID}"`
|
||||||
font.pixelSize: Theme.fontSizeMedium
|
font.pixelSize: Theme.fontSizeMedium
|
||||||
color: Theme.surfaceTextMedium
|
color: Theme.surfaceTextMedium
|
||||||
width: parent.width
|
width: parent.width
|
||||||
elide: Text.ElideRight
|
elide: Text.ElideRight
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DankActionButton {
|
DankActionButton {
|
||||||
@@ -84,36 +77,30 @@ DankModal {
|
|||||||
iconSize: Theme.iconSize - 4
|
iconSize: Theme.iconSize - 4
|
||||||
iconColor: Theme.surfaceText
|
iconColor: Theme.surfaceText
|
||||||
hoverColor: Theme.errorHover
|
hoverColor: Theme.errorHover
|
||||||
onClicked: {
|
onClicked: root.hideDialog()
|
||||||
root.hideDialog()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DankFlickable {
|
Rectangle {
|
||||||
id: flickableArea
|
id: detailsRect
|
||||||
|
|
||||||
width: parent.width
|
width: parent.width
|
||||||
height: parent.height - 140
|
height: parent.height - 140
|
||||||
|
radius: Theme.cornerRadius
|
||||||
|
color: Theme.surfaceHover
|
||||||
|
border.color: Theme.outlineStrong
|
||||||
|
border.width: 1
|
||||||
clip: true
|
clip: true
|
||||||
contentWidth: width
|
|
||||||
contentHeight: detailsRect.height
|
|
||||||
|
|
||||||
Rectangle {
|
ScrollView {
|
||||||
id: detailsRect
|
anchors.fill: parent
|
||||||
width: parent.width
|
anchors.margins: Theme.spacingM
|
||||||
height: detailsText.contentHeight + Theme.spacingM * 2
|
|
||||||
radius: Theme.cornerRadius
|
|
||||||
color: Theme.surfaceHover
|
|
||||||
border.color: Theme.outlineStrong
|
|
||||||
border.width: 1
|
|
||||||
|
|
||||||
TextArea {
|
TextArea {
|
||||||
id: detailsText
|
id: detailsText
|
||||||
anchors.fill: parent
|
|
||||||
anchors.margins: Theme.spacingM
|
text: NetworkService.networkInfoDetails && NetworkService.networkInfoDetails.replace(/\\n/g, '\n') || "No information available"
|
||||||
text: NetworkService.networkInfoDetails.replace(
|
|
||||||
/\\n/g,
|
|
||||||
'\n') || "No information available"
|
|
||||||
font.pixelSize: Theme.fontSizeMedium
|
font.pixelSize: Theme.fontSizeMedium
|
||||||
color: Theme.surfaceText
|
color: Theme.surfaceText
|
||||||
wrapMode: Text.WordWrap
|
wrapMode: Text.WordWrap
|
||||||
@@ -122,7 +109,9 @@ DankModal {
|
|||||||
background: null
|
background: null
|
||||||
padding: 0
|
padding: 0
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
@@ -132,14 +121,10 @@ DankModal {
|
|||||||
Rectangle {
|
Rectangle {
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
width: Math.max(
|
width: Math.max(70, closeText.contentWidth + Theme.spacingM * 2)
|
||||||
70,
|
|
||||||
closeText.contentWidth + Theme.spacingM * 2)
|
|
||||||
height: 36
|
height: 36
|
||||||
radius: Theme.cornerRadius
|
radius: Theme.cornerRadius
|
||||||
color: closeArea.containsMouse ? Qt.darker(
|
color: closeArea.containsMouse ? Qt.darker(Theme.primary, 1.1) : Theme.primary
|
||||||
Theme.primary,
|
|
||||||
1.1) : Theme.primary
|
|
||||||
|
|
||||||
StyledText {
|
StyledText {
|
||||||
id: closeText
|
id: closeText
|
||||||
@@ -157,9 +142,7 @@ DankModal {
|
|||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
hoverEnabled: true
|
hoverEnabled: true
|
||||||
cursorShape: Qt.PointingHandCursor
|
cursorShape: Qt.PointingHandCursor
|
||||||
onClicked: {
|
onClicked: root.hideDialog()
|
||||||
root.hideDialog()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Behavior on color {
|
Behavior on color {
|
||||||
@@ -167,10 +150,17 @@ DankModal {
|
|||||||
duration: Theme.shortDuration
|
duration: Theme.shortDuration
|
||||||
easing.type: Theme.standardEasing
|
easing.type: Theme.standardEasing
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,5 @@
|
|||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Controls
|
|
||||||
import QtQuick.Effects
|
|
||||||
import Quickshell
|
|
||||||
import Quickshell.Io
|
import Quickshell.Io
|
||||||
import Quickshell.Widgets
|
|
||||||
import qs.Common
|
import qs.Common
|
||||||
import qs.Modals.Common
|
import qs.Modals.Common
|
||||||
import qs.Modules.Notifications.Center
|
import qs.Modules.Notifications.Center
|
||||||
@@ -13,31 +9,6 @@ import qs.Widgets
|
|||||||
DankModal {
|
DankModal {
|
||||||
id: notificationModal
|
id: notificationModal
|
||||||
|
|
||||||
width: 500
|
|
||||||
height: 700
|
|
||||||
visible: false
|
|
||||||
onBackgroundClicked: hide()
|
|
||||||
onShouldBeVisibleChanged: (shouldBeVisible) => {
|
|
||||||
if (!shouldBeVisible) {
|
|
||||||
notificationModalOpen = false
|
|
||||||
modalKeyboardController.reset()
|
|
||||||
NotificationService.onOverlayClose()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
modalFocusScope.Keys.onPressed: function (event) {
|
|
||||||
modalKeyboardController.handleKey(event)
|
|
||||||
}
|
|
||||||
|
|
||||||
NotificationKeyboardController {
|
|
||||||
id: modalKeyboardController
|
|
||||||
listView: null
|
|
||||||
isOpen: notificationModal.notificationModalOpen
|
|
||||||
onClose: function () {
|
|
||||||
notificationModal.hide()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
property bool notificationModalOpen: false
|
property bool notificationModalOpen: false
|
||||||
property var notificationListRef: null
|
property var notificationListRef: null
|
||||||
|
|
||||||
@@ -46,7 +17,6 @@ DankModal {
|
|||||||
NotificationService.onOverlayOpen()
|
NotificationService.onOverlayOpen()
|
||||||
open()
|
open()
|
||||||
modalKeyboardController.reset()
|
modalKeyboardController.reset()
|
||||||
|
|
||||||
if (modalKeyboardController && notificationListRef) {
|
if (modalKeyboardController && notificationListRef) {
|
||||||
modalKeyboardController.listView = notificationListRef
|
modalKeyboardController.listView = notificationListRef
|
||||||
modalKeyboardController.rebuildFlatNavigation()
|
modalKeyboardController.rebuildFlatNavigation()
|
||||||
@@ -61,32 +31,54 @@ DankModal {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function toggle() {
|
function toggle() {
|
||||||
if (shouldBeVisible)
|
if (shouldBeVisible) {
|
||||||
hide()
|
hide()
|
||||||
else
|
} else {
|
||||||
show()
|
show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
width: 500
|
||||||
|
height: 700
|
||||||
|
visible: false
|
||||||
|
onBackgroundClicked: hide()
|
||||||
|
onShouldBeVisibleChanged: (shouldBeVisible) => {
|
||||||
|
if (!shouldBeVisible) {
|
||||||
|
notificationModalOpen = false
|
||||||
|
modalKeyboardController.reset()
|
||||||
|
NotificationService.onOverlayClose()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
modalFocusScope.Keys.onPressed: (event) => modalKeyboardController.handleKey(event)
|
||||||
|
|
||||||
|
NotificationKeyboardController {
|
||||||
|
id: modalKeyboardController
|
||||||
|
|
||||||
|
listView: null
|
||||||
|
isOpen: notificationModal.notificationModalOpen
|
||||||
|
onClose: () => notificationModal.hide()
|
||||||
}
|
}
|
||||||
|
|
||||||
IpcHandler {
|
IpcHandler {
|
||||||
function open() {
|
function open() {
|
||||||
notificationModal.show()
|
notificationModal.show();
|
||||||
return "NOTIFICATION_MODAL_OPEN_SUCCESS"
|
return "NOTIFICATION_MODAL_OPEN_SUCCESS";
|
||||||
}
|
}
|
||||||
|
|
||||||
function close() {
|
function close() {
|
||||||
notificationModal.hide()
|
notificationModal.hide();
|
||||||
return "NOTIFICATION_MODAL_CLOSE_SUCCESS"
|
return "NOTIFICATION_MODAL_CLOSE_SUCCESS";
|
||||||
}
|
}
|
||||||
|
|
||||||
function toggle() {
|
function toggle() {
|
||||||
notificationModal.toggle()
|
notificationModal.toggle();
|
||||||
return "NOTIFICATION_MODAL_TOGGLE_SUCCESS"
|
return "NOTIFICATION_MODAL_TOGGLE_SUCCESS";
|
||||||
}
|
}
|
||||||
|
|
||||||
target: "notifications"
|
target: "notifications"
|
||||||
}
|
}
|
||||||
|
|
||||||
property Component notificationContent: Component {
|
content: Component {
|
||||||
Item {
|
Item {
|
||||||
id: notificationKeyHandler
|
id: notificationKeyHandler
|
||||||
|
|
||||||
@@ -99,11 +91,13 @@ DankModal {
|
|||||||
|
|
||||||
NotificationHeader {
|
NotificationHeader {
|
||||||
id: notificationHeader
|
id: notificationHeader
|
||||||
|
|
||||||
keyboardController: modalKeyboardController
|
keyboardController: modalKeyboardController
|
||||||
}
|
}
|
||||||
|
|
||||||
NotificationSettings {
|
NotificationSettings {
|
||||||
id: notificationSettings
|
id: notificationSettings
|
||||||
|
|
||||||
expanded: notificationHeader.showSettings
|
expanded: notificationHeader.showSettings
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -113,7 +107,6 @@ DankModal {
|
|||||||
width: parent.width
|
width: parent.width
|
||||||
height: parent.height - y
|
height: parent.height - y
|
||||||
keyboardController: modalKeyboardController
|
keyboardController: modalKeyboardController
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
notificationModal.notificationListRef = notificationList
|
notificationModal.notificationListRef = notificationList
|
||||||
if (modalKeyboardController) {
|
if (modalKeyboardController) {
|
||||||
@@ -122,18 +115,21 @@ DankModal {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
NotificationKeyboardHints {
|
NotificationKeyboardHints {
|
||||||
id: keyboardHints
|
id: keyboardHints
|
||||||
|
|
||||||
anchors.bottom: parent.bottom
|
anchors.bottom: parent.bottom
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.margins: Theme.spacingL
|
anchors.margins: Theme.spacingL
|
||||||
showHints: modalKeyboardController.showKeyboardHints
|
showHints: modalKeyboardController.showKeyboardHints
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
content: notificationContent
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,6 @@
|
|||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Controls
|
|
||||||
import Quickshell
|
|
||||||
import Quickshell.Io
|
|
||||||
import qs.Common
|
import qs.Common
|
||||||
import qs.Modals.Common
|
import qs.Modals.Common
|
||||||
import qs.Services
|
|
||||||
import qs.Widgets
|
import qs.Widgets
|
||||||
|
|
||||||
DankModal {
|
DankModal {
|
||||||
@@ -16,53 +12,61 @@ DankModal {
|
|||||||
signal powerActionRequested(string action, string title, string message)
|
signal powerActionRequested(string action, string title, string message)
|
||||||
|
|
||||||
function selectOption() {
|
function selectOption() {
|
||||||
close()
|
close();
|
||||||
switch (selectedIndex) {
|
const actions = [{
|
||||||
case 0:
|
"action": "logout",
|
||||||
root.powerActionRequested("logout", "Log Out", "Are you sure you want to log out?")
|
"title": "Log Out",
|
||||||
break
|
"message": "Are you sure you want to log out?"
|
||||||
case 1:
|
}, {
|
||||||
root.powerActionRequested("suspend", "Suspend", "Are you sure you want to suspend the system?")
|
"action": "suspend",
|
||||||
break
|
"title": "Suspend",
|
||||||
case 2:
|
"message": "Are you sure you want to suspend the system?"
|
||||||
root.powerActionRequested("reboot", "Reboot", "Are you sure you want to reboot the system?")
|
}, {
|
||||||
break
|
"action": "reboot",
|
||||||
case 3:
|
"title": "Reboot",
|
||||||
root.powerActionRequested("poweroff", "Power Off", "Are you sure you want to power off the system?")
|
"message": "Are you sure you want to reboot the system?"
|
||||||
break
|
}, {
|
||||||
|
"action": "poweroff",
|
||||||
|
"title": "Power Off",
|
||||||
|
"message": "Are you sure you want to power off the system?"
|
||||||
|
}];
|
||||||
|
const selected = actions[selectedIndex];
|
||||||
|
if (selected) {
|
||||||
|
root.powerActionRequested(selected.action, selected.title, selected.message);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
shouldBeVisible: false
|
shouldBeVisible: false
|
||||||
width: 320
|
width: 320
|
||||||
height: 300
|
height: 300
|
||||||
enableShadow: true
|
enableShadow: true
|
||||||
onBackgroundClicked: {
|
onBackgroundClicked: () => {
|
||||||
close()
|
return close();
|
||||||
}
|
}
|
||||||
onOpened: {
|
onOpened: () => {
|
||||||
selectedIndex = 0
|
selectedIndex = 0;
|
||||||
modalFocusScope.forceActiveFocus()
|
modalFocusScope.forceActiveFocus();
|
||||||
}
|
}
|
||||||
modalFocusScope.Keys.onPressed: function(event) {
|
modalFocusScope.Keys.onPressed: (event) => {
|
||||||
switch (event.key) {
|
switch (event.key) {
|
||||||
case Qt.Key_Up:
|
case Qt.Key_Up:
|
||||||
selectedIndex = (selectedIndex - 1 + optionCount) % optionCount
|
selectedIndex = (selectedIndex - 1 + optionCount) % optionCount;
|
||||||
event.accepted = true
|
event.accepted = true;
|
||||||
break
|
break;
|
||||||
case Qt.Key_Down:
|
case Qt.Key_Down:
|
||||||
selectedIndex = (selectedIndex + 1) % optionCount
|
selectedIndex = (selectedIndex + 1) % optionCount;
|
||||||
event.accepted = true
|
event.accepted = true;
|
||||||
break
|
break;
|
||||||
case Qt.Key_Tab:
|
case Qt.Key_Tab:
|
||||||
selectedIndex = (selectedIndex + 1) % optionCount
|
selectedIndex = (selectedIndex + 1) % optionCount;
|
||||||
event.accepted = true
|
event.accepted = true;
|
||||||
break
|
break;
|
||||||
case Qt.Key_Return:
|
case Qt.Key_Return:
|
||||||
case Qt.Key_Enter:
|
case Qt.Key_Enter:
|
||||||
selectOption()
|
selectOption();
|
||||||
event.accepted = true
|
event.accepted = true;
|
||||||
break
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -96,8 +100,8 @@ DankModal {
|
|||||||
iconSize: Theme.iconSize - 4
|
iconSize: Theme.iconSize - 4
|
||||||
iconColor: Theme.surfaceText
|
iconColor: Theme.surfaceText
|
||||||
hoverColor: Qt.rgba(Theme.error.r, Theme.error.g, Theme.error.b, 0.12)
|
hoverColor: Qt.rgba(Theme.error.r, Theme.error.g, Theme.error.b, 0.12)
|
||||||
onClicked: {
|
onClicked: () => {
|
||||||
close()
|
return close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -112,12 +116,13 @@ DankModal {
|
|||||||
height: 50
|
height: 50
|
||||||
radius: Theme.cornerRadius
|
radius: Theme.cornerRadius
|
||||||
color: {
|
color: {
|
||||||
if (selectedIndex === 0)
|
if (selectedIndex === 0) {
|
||||||
return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12);
|
return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12);
|
||||||
else if (logoutArea.containsMouse)
|
} else if (logoutArea.containsMouse) {
|
||||||
return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08);
|
return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08);
|
||||||
else
|
} else {
|
||||||
return Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.08);
|
return Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.08);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
border.color: selectedIndex === 0 ? Theme.primary : "transparent"
|
border.color: selectedIndex === 0 ? Theme.primary : "transparent"
|
||||||
border.width: selectedIndex === 0 ? 1 : 0
|
border.width: selectedIndex === 0 ? 1 : 0
|
||||||
@@ -151,9 +156,9 @@ DankModal {
|
|||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
hoverEnabled: true
|
hoverEnabled: true
|
||||||
cursorShape: Qt.PointingHandCursor
|
cursorShape: Qt.PointingHandCursor
|
||||||
onClicked: {
|
onClicked: () => {
|
||||||
selectedIndex = 0
|
selectedIndex = 0;
|
||||||
selectOption()
|
selectOption();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -164,12 +169,13 @@ DankModal {
|
|||||||
height: 50
|
height: 50
|
||||||
radius: Theme.cornerRadius
|
radius: Theme.cornerRadius
|
||||||
color: {
|
color: {
|
||||||
if (selectedIndex === 1)
|
if (selectedIndex === 1) {
|
||||||
return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12);
|
return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12);
|
||||||
else if (suspendArea.containsMouse)
|
} else if (suspendArea.containsMouse) {
|
||||||
return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08);
|
return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08);
|
||||||
else
|
} else {
|
||||||
return Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.08);
|
return Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.08);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
border.color: selectedIndex === 1 ? Theme.primary : "transparent"
|
border.color: selectedIndex === 1 ? Theme.primary : "transparent"
|
||||||
border.width: selectedIndex === 1 ? 1 : 0
|
border.width: selectedIndex === 1 ? 1 : 0
|
||||||
@@ -203,9 +209,9 @@ DankModal {
|
|||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
hoverEnabled: true
|
hoverEnabled: true
|
||||||
cursorShape: Qt.PointingHandCursor
|
cursorShape: Qt.PointingHandCursor
|
||||||
onClicked: {
|
onClicked: () => {
|
||||||
selectedIndex = 1
|
selectedIndex = 1;
|
||||||
selectOption()
|
selectOption();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -216,12 +222,13 @@ DankModal {
|
|||||||
height: 50
|
height: 50
|
||||||
radius: Theme.cornerRadius
|
radius: Theme.cornerRadius
|
||||||
color: {
|
color: {
|
||||||
if (selectedIndex === 2)
|
if (selectedIndex === 2) {
|
||||||
return Qt.rgba(Theme.warning.r, Theme.warning.g, Theme.warning.b, 0.12);
|
return Qt.rgba(Theme.warning.r, Theme.warning.g, Theme.warning.b, 0.12);
|
||||||
else if (rebootArea.containsMouse)
|
} else if (rebootArea.containsMouse) {
|
||||||
return Qt.rgba(Theme.warning.r, Theme.warning.g, Theme.warning.b, 0.08);
|
return Qt.rgba(Theme.warning.r, Theme.warning.g, Theme.warning.b, 0.08);
|
||||||
else
|
} else {
|
||||||
return Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.08);
|
return Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.08);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
border.color: selectedIndex === 2 ? Theme.warning : "transparent"
|
border.color: selectedIndex === 2 ? Theme.warning : "transparent"
|
||||||
border.width: selectedIndex === 2 ? 1 : 0
|
border.width: selectedIndex === 2 ? 1 : 0
|
||||||
@@ -255,9 +262,9 @@ DankModal {
|
|||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
hoverEnabled: true
|
hoverEnabled: true
|
||||||
cursorShape: Qt.PointingHandCursor
|
cursorShape: Qt.PointingHandCursor
|
||||||
onClicked: {
|
onClicked: () => {
|
||||||
selectedIndex = 2
|
selectedIndex = 2;
|
||||||
selectOption()
|
selectOption();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -268,12 +275,13 @@ DankModal {
|
|||||||
height: 50
|
height: 50
|
||||||
radius: Theme.cornerRadius
|
radius: Theme.cornerRadius
|
||||||
color: {
|
color: {
|
||||||
if (selectedIndex === 3)
|
if (selectedIndex === 3) {
|
||||||
return Qt.rgba(Theme.error.r, Theme.error.g, Theme.error.b, 0.12);
|
return Qt.rgba(Theme.error.r, Theme.error.g, Theme.error.b, 0.12);
|
||||||
else if (powerOffArea.containsMouse)
|
} else if (powerOffArea.containsMouse) {
|
||||||
return Qt.rgba(Theme.error.r, Theme.error.g, Theme.error.b, 0.08);
|
return Qt.rgba(Theme.error.r, Theme.error.g, Theme.error.b, 0.08);
|
||||||
else
|
} else {
|
||||||
return Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.08);
|
return Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.08);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
border.color: selectedIndex === 3 ? Theme.error : "transparent"
|
border.color: selectedIndex === 3 ? Theme.error : "transparent"
|
||||||
border.width: selectedIndex === 3 ? 1 : 0
|
border.width: selectedIndex === 3 ? 1 : 0
|
||||||
@@ -307,9 +315,9 @@ DankModal {
|
|||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
hoverEnabled: true
|
hoverEnabled: true
|
||||||
cursorShape: Qt.PointingHandCursor
|
cursorShape: Qt.PointingHandCursor
|
||||||
onClicked: {
|
onClicked: () => {
|
||||||
selectedIndex = 3
|
selectedIndex = 3;
|
||||||
selectOption()
|
selectOption();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,5 @@
|
|||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Controls
|
|
||||||
import QtQuick.Effects
|
|
||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
import Quickshell
|
|
||||||
import Quickshell.Io
|
|
||||||
import Quickshell.Wayland
|
|
||||||
import Quickshell.Widgets
|
|
||||||
import qs.Common
|
import qs.Common
|
||||||
import qs.Modals.Common
|
import qs.Modals.Common
|
||||||
import qs.Modules.ProcessList
|
import qs.Modules.ProcessList
|
||||||
@@ -20,28 +14,31 @@ DankModal {
|
|||||||
|
|
||||||
function show() {
|
function show() {
|
||||||
if (!DgopService.dgopAvailable) {
|
if (!DgopService.dgopAvailable) {
|
||||||
console.warn("ProcessListModal: dgop is not available")
|
console.warn("ProcessListModal: dgop is not available");
|
||||||
return
|
return ;
|
||||||
}
|
}
|
||||||
open()
|
open();
|
||||||
UserInfoService.getUptime()
|
UserInfoService.getUptime();
|
||||||
}
|
}
|
||||||
|
|
||||||
function hide() {
|
function hide() {
|
||||||
close()
|
close();
|
||||||
if (processContextMenu.visible)
|
if (processContextMenu.visible) {
|
||||||
processContextMenu.close()
|
processContextMenu.close();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function toggle() {
|
function toggle() {
|
||||||
if (!DgopService.dgopAvailable) {
|
if (!DgopService.dgopAvailable) {
|
||||||
console.warn("ProcessListModal: dgop is not available")
|
console.warn("ProcessListModal: dgop is not available");
|
||||||
return
|
return ;
|
||||||
|
}
|
||||||
|
if (shouldBeVisible) {
|
||||||
|
hide();
|
||||||
|
} else {
|
||||||
|
show();
|
||||||
}
|
}
|
||||||
if (shouldBeVisible)
|
|
||||||
hide()
|
|
||||||
else
|
|
||||||
show()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
width: 900
|
width: 900
|
||||||
@@ -50,7 +47,9 @@ DankModal {
|
|||||||
backgroundColor: Theme.popupBackground()
|
backgroundColor: Theme.popupBackground()
|
||||||
cornerRadius: Theme.cornerRadius
|
cornerRadius: Theme.cornerRadius
|
||||||
enableShadow: true
|
enableShadow: true
|
||||||
onBackgroundClicked: hide()
|
onBackgroundClicked: () => {
|
||||||
|
return hide();
|
||||||
|
}
|
||||||
|
|
||||||
Component {
|
Component {
|
||||||
id: processesTabComponent
|
id: processesTabComponent
|
||||||
@@ -58,18 +57,23 @@ DankModal {
|
|||||||
ProcessesTab {
|
ProcessesTab {
|
||||||
contextMenu: processContextMenu
|
contextMenu: processContextMenu
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Component {
|
Component {
|
||||||
id: performanceTabComponent
|
id: performanceTabComponent
|
||||||
|
|
||||||
PerformanceTab {}
|
PerformanceTab {
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Component {
|
Component {
|
||||||
id: systemTabComponent
|
id: systemTabComponent
|
||||||
|
|
||||||
SystemTab {}
|
SystemTab {
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ProcessContextMenu {
|
ProcessContextMenu {
|
||||||
@@ -80,19 +84,19 @@ DankModal {
|
|||||||
Item {
|
Item {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
focus: true
|
focus: true
|
||||||
Keys.onPressed: function (event) {
|
Keys.onPressed: (event) => {
|
||||||
if (event.key === Qt.Key_Escape) {
|
if (event.key === Qt.Key_Escape) {
|
||||||
processListModal.hide()
|
processListModal.hide();
|
||||||
event.accepted = true
|
event.accepted = true;
|
||||||
} else if (event.key === Qt.Key_1) {
|
} else if (event.key === Qt.Key_1) {
|
||||||
currentTab = 0
|
currentTab = 0;
|
||||||
event.accepted = true
|
event.accepted = true;
|
||||||
} else if (event.key === Qt.Key_2) {
|
} else if (event.key === Qt.Key_2) {
|
||||||
currentTab = 1
|
currentTab = 1;
|
||||||
event.accepted = true
|
event.accepted = true;
|
||||||
} else if (event.key === Qt.Key_3) {
|
} else if (event.key === Qt.Key_3) {
|
||||||
currentTab = 2
|
currentTab = 2;
|
||||||
event.accepted = true
|
event.accepted = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -134,7 +138,9 @@ DankModal {
|
|||||||
horizontalAlignment: Text.AlignHCenter
|
horizontalAlignment: Text.AlignHCenter
|
||||||
wrapMode: Text.WordWrap
|
wrapMode: Text.WordWrap
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ColumnLayout {
|
ColumnLayout {
|
||||||
@@ -165,9 +171,12 @@ DankModal {
|
|||||||
iconSize: Theme.iconSize - 4
|
iconSize: Theme.iconSize - 4
|
||||||
iconColor: Theme.surfaceText
|
iconColor: Theme.surfaceText
|
||||||
hoverColor: Theme.errorHover
|
hoverColor: Theme.errorHover
|
||||||
onClicked: processListModal.hide()
|
onClicked: () => {
|
||||||
|
return processListModal.hide();
|
||||||
|
}
|
||||||
Layout.alignment: Qt.AlignVCenter
|
Layout.alignment: Qt.AlignVCenter
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
@@ -200,20 +209,11 @@ DankModal {
|
|||||||
|
|
||||||
DankIcon {
|
DankIcon {
|
||||||
name: {
|
name: {
|
||||||
switch (index) {
|
const tabIcons = ["list_alt", "analytics", "settings"];
|
||||||
case 0:
|
return tabIcons[index] || "tab";
|
||||||
return "list_alt"
|
|
||||||
case 1:
|
|
||||||
return "analytics"
|
|
||||||
case 2:
|
|
||||||
return "settings"
|
|
||||||
default:
|
|
||||||
return "tab"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
size: Theme.iconSize - 2
|
size: Theme.iconSize - 2
|
||||||
color: currentTab
|
color: currentTab === index ? Theme.primary : Theme.surfaceText
|
||||||
=== index ? Theme.primary : Theme.surfaceText
|
|
||||||
opacity: currentTab === index ? 1 : 0.7
|
opacity: currentTab === index ? 1 : 0.7
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
|
||||||
@@ -221,15 +221,16 @@ DankModal {
|
|||||||
ColorAnimation {
|
ColorAnimation {
|
||||||
duration: Theme.shortDuration
|
duration: Theme.shortDuration
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
StyledText {
|
StyledText {
|
||||||
text: modelData
|
text: modelData
|
||||||
font.pixelSize: Theme.fontSizeLarge
|
font.pixelSize: Theme.fontSizeLarge
|
||||||
font.weight: Font.Medium
|
font.weight: Font.Medium
|
||||||
color: currentTab
|
color: currentTab === index ? Theme.primary : Theme.surfaceText
|
||||||
=== index ? Theme.primary : Theme.surfaceText
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
anchors.verticalCenterOffset: -1
|
anchors.verticalCenterOffset: -1
|
||||||
|
|
||||||
@@ -237,8 +238,11 @@ DankModal {
|
|||||||
ColorAnimation {
|
ColorAnimation {
|
||||||
duration: Theme.shortDuration
|
duration: Theme.shortDuration
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MouseArea {
|
MouseArea {
|
||||||
@@ -247,8 +251,8 @@ DankModal {
|
|||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
hoverEnabled: true
|
hoverEnabled: true
|
||||||
cursorShape: Qt.PointingHandCursor
|
cursorShape: Qt.PointingHandCursor
|
||||||
onClicked: {
|
onClicked: () => {
|
||||||
currentTab = index
|
currentTab = index;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -256,16 +260,22 @@ DankModal {
|
|||||||
ColorAnimation {
|
ColorAnimation {
|
||||||
duration: Theme.shortDuration
|
duration: Theme.shortDuration
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Behavior on border.color {
|
Behavior on border.color {
|
||||||
ColorAnimation {
|
ColorAnimation {
|
||||||
duration: Theme.shortDuration
|
duration: Theme.shortDuration
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
@@ -291,7 +301,9 @@ DankModal {
|
|||||||
duration: Theme.mediumDuration
|
duration: Theme.mediumDuration
|
||||||
easing.type: Theme.emphasizedEasing
|
easing.type: Theme.emphasizedEasing
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Loader {
|
Loader {
|
||||||
@@ -309,7 +321,9 @@ DankModal {
|
|||||||
duration: Theme.mediumDuration
|
duration: Theme.mediumDuration
|
||||||
easing.type: Theme.emphasizedEasing
|
easing.type: Theme.emphasizedEasing
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Loader {
|
Loader {
|
||||||
@@ -327,10 +341,17 @@ DankModal {
|
|||||||
duration: Theme.mediumDuration
|
duration: Theme.mediumDuration
|
||||||
easing.type: Theme.emphasizedEasing
|
easing.type: Theme.emphasizedEasing
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
211
Modals/Settings/ProfileSection.qml
Normal file
211
Modals/Settings/ProfileSection.qml
Normal file
@@ -0,0 +1,211 @@
|
|||||||
|
import QtQuick
|
||||||
|
import QtQuick.Effects
|
||||||
|
import qs.Common
|
||||||
|
import qs.Services
|
||||||
|
import qs.Widgets
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property var parentModal: null
|
||||||
|
|
||||||
|
width: parent.width - Theme.spacingS * 2
|
||||||
|
height: 110
|
||||||
|
radius: Theme.cornerRadius
|
||||||
|
color: "transparent"
|
||||||
|
border.width: 0
|
||||||
|
|
||||||
|
Row {
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
anchors.leftMargin: Theme.spacingM
|
||||||
|
anchors.rightMargin: Theme.spacingM
|
||||||
|
spacing: Theme.spacingM
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: profileImageContainer
|
||||||
|
|
||||||
|
property bool hasImage: profileImageSource.status === Image.Ready
|
||||||
|
|
||||||
|
width: 80
|
||||||
|
height: 80
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
anchors.fill: parent
|
||||||
|
radius: width / 2
|
||||||
|
color: "transparent"
|
||||||
|
border.color: Theme.primary
|
||||||
|
border.width: 1
|
||||||
|
visible: parent.hasImage
|
||||||
|
}
|
||||||
|
|
||||||
|
Image {
|
||||||
|
id: profileImageSource
|
||||||
|
|
||||||
|
source: {
|
||||||
|
if (PortalService.profileImage === "") {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
if (PortalService.profileImage.startsWith("/")) {
|
||||||
|
return "file://" + PortalService.profileImage;
|
||||||
|
}
|
||||||
|
return PortalService.profileImage;
|
||||||
|
}
|
||||||
|
smooth: true
|
||||||
|
asynchronous: true
|
||||||
|
mipmap: true
|
||||||
|
cache: true
|
||||||
|
visible: false
|
||||||
|
}
|
||||||
|
|
||||||
|
MultiEffect {
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: 5
|
||||||
|
source: profileImageSource
|
||||||
|
maskEnabled: true
|
||||||
|
maskSource: profileCircularMask
|
||||||
|
visible: profileImageContainer.hasImage
|
||||||
|
maskThresholdMin: 0.5
|
||||||
|
maskSpreadAtMin: 1
|
||||||
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: profileCircularMask
|
||||||
|
|
||||||
|
width: 70
|
||||||
|
height: 70
|
||||||
|
layer.enabled: true
|
||||||
|
layer.smooth: true
|
||||||
|
visible: false
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
anchors.fill: parent
|
||||||
|
radius: width / 2
|
||||||
|
color: "black"
|
||||||
|
antialiasing: true
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
anchors.fill: parent
|
||||||
|
radius: width / 2
|
||||||
|
color: Theme.primary
|
||||||
|
visible: !parent.hasImage
|
||||||
|
|
||||||
|
DankIcon {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
name: "person"
|
||||||
|
size: Theme.iconSizeLarge
|
||||||
|
color: Theme.primaryText
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
anchors.fill: parent
|
||||||
|
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)
|
||||||
|
|
||||||
|
DankIcon {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
name: "edit"
|
||||||
|
size: 16
|
||||||
|
color: "black"
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
onClicked: () => {
|
||||||
|
if (root.parentModal) {
|
||||||
|
root.parentModal.allowFocusOverride = true;
|
||||||
|
root.parentModal.shouldHaveFocus = false;
|
||||||
|
if (root.parentModal.profileBrowser) {
|
||||||
|
root.parentModal.profileBrowser.open();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
width: 28
|
||||||
|
height: 28
|
||||||
|
radius: 14
|
||||||
|
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: () => {
|
||||||
|
return PortalService.setProfileImage("");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
id: profileMouseArea
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
hoverEnabled: true
|
||||||
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
propagateComposedEvents: true
|
||||||
|
acceptedButtons: Qt.NoButton
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Column {
|
||||||
|
width: 120
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
spacing: Theme.spacingXS
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
text: UserInfoService.fullName || "User"
|
||||||
|
font.pixelSize: Theme.fontSizeLarge
|
||||||
|
font.weight: Font.Medium
|
||||||
|
color: Theme.surfaceText
|
||||||
|
elide: Text.ElideRight
|
||||||
|
width: parent.width
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
text: DgopService.distribution || "Linux"
|
||||||
|
font.pixelSize: Theme.fontSizeMedium
|
||||||
|
color: Theme.surfaceVariantText
|
||||||
|
elide: Text.ElideRight
|
||||||
|
width: parent.width
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
158
Modals/Settings/SettingsContent.qml
Normal file
158
Modals/Settings/SettingsContent.qml
Normal file
@@ -0,0 +1,158 @@
|
|||||||
|
import QtQuick
|
||||||
|
import qs.Common
|
||||||
|
import qs.Modules.Settings
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property int currentIndex: 0
|
||||||
|
property var parentModal: null
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.leftMargin: 0
|
||||||
|
anchors.rightMargin: Theme.spacingS
|
||||||
|
anchors.bottomMargin: Theme.spacingM
|
||||||
|
anchors.topMargin: 0
|
||||||
|
color: "transparent"
|
||||||
|
|
||||||
|
Loader {
|
||||||
|
id: personalizationLoader
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
active: root.currentIndex === 0
|
||||||
|
visible: active
|
||||||
|
asynchronous: true
|
||||||
|
|
||||||
|
sourceComponent: Component {
|
||||||
|
PersonalizationTab {
|
||||||
|
parentModal: root.parentModal
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Loader {
|
||||||
|
id: timeLoader
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
active: root.currentIndex === 1
|
||||||
|
visible: active
|
||||||
|
asynchronous: true
|
||||||
|
|
||||||
|
sourceComponent: TimeTab {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Loader {
|
||||||
|
id: weatherLoader
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
active: root.currentIndex === 2
|
||||||
|
visible: active
|
||||||
|
asynchronous: true
|
||||||
|
|
||||||
|
sourceComponent: WeatherTab {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Loader {
|
||||||
|
id: topBarLoader
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
active: root.currentIndex === 3
|
||||||
|
visible: active
|
||||||
|
asynchronous: true
|
||||||
|
|
||||||
|
sourceComponent: TopBarTab {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Loader {
|
||||||
|
id: widgetsLoader
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
active: root.currentIndex === 4
|
||||||
|
visible: active
|
||||||
|
asynchronous: true
|
||||||
|
|
||||||
|
sourceComponent: WidgetTweaksTab {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Loader {
|
||||||
|
id: dockLoader
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
active: root.currentIndex === 5
|
||||||
|
visible: active
|
||||||
|
asynchronous: true
|
||||||
|
|
||||||
|
sourceComponent: Component {
|
||||||
|
DockTab {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Loader {
|
||||||
|
id: displaysLoader
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
active: root.currentIndex === 6
|
||||||
|
visible: active
|
||||||
|
asynchronous: true
|
||||||
|
|
||||||
|
sourceComponent: DisplaysTab {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Loader {
|
||||||
|
id: recentAppsLoader
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
active: root.currentIndex === 7
|
||||||
|
visible: active
|
||||||
|
asynchronous: true
|
||||||
|
|
||||||
|
sourceComponent: RecentAppsTab {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Loader {
|
||||||
|
id: themeColorsLoader
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
active: root.currentIndex === 8
|
||||||
|
visible: active
|
||||||
|
asynchronous: true
|
||||||
|
|
||||||
|
sourceComponent: ThemeColorsTab {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Loader {
|
||||||
|
id: aboutLoader
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
active: root.currentIndex === 9
|
||||||
|
visible: active
|
||||||
|
asynchronous: true
|
||||||
|
|
||||||
|
sourceComponent: AboutTab {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
199
Modals/Settings/SettingsModal.qml
Normal file
199
Modals/Settings/SettingsModal.qml
Normal file
@@ -0,0 +1,199 @@
|
|||||||
|
import QtQuick
|
||||||
|
import QtQuick.Effects
|
||||||
|
import Quickshell.Io
|
||||||
|
import qs.Common
|
||||||
|
import qs.Modals.Common
|
||||||
|
import qs.Modals.FileBrowser
|
||||||
|
import qs.Modules.Settings
|
||||||
|
import qs.Services
|
||||||
|
import qs.Widgets
|
||||||
|
|
||||||
|
DankModal {
|
||||||
|
id: settingsModal
|
||||||
|
|
||||||
|
property Component settingsContent
|
||||||
|
|
||||||
|
signal closingModal()
|
||||||
|
|
||||||
|
function show() {
|
||||||
|
open();
|
||||||
|
}
|
||||||
|
|
||||||
|
function hide() {
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggle() {
|
||||||
|
if (shouldBeVisible) {
|
||||||
|
hide();
|
||||||
|
} else {
|
||||||
|
show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
objectName: "settingsModal"
|
||||||
|
width: 800
|
||||||
|
height: 750
|
||||||
|
visible: false
|
||||||
|
onBackgroundClicked: () => {
|
||||||
|
return hide();
|
||||||
|
}
|
||||||
|
content: settingsContent
|
||||||
|
|
||||||
|
IpcHandler {
|
||||||
|
function open() {
|
||||||
|
settingsModal.show();
|
||||||
|
return "SETTINGS_OPEN_SUCCESS";
|
||||||
|
}
|
||||||
|
|
||||||
|
function close() {
|
||||||
|
settingsModal.hide();
|
||||||
|
return "SETTINGS_CLOSE_SUCCESS";
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggle() {
|
||||||
|
settingsModal.toggle();
|
||||||
|
return "SETTINGS_TOGGLE_SUCCESS";
|
||||||
|
}
|
||||||
|
|
||||||
|
target: "settings"
|
||||||
|
}
|
||||||
|
|
||||||
|
IpcHandler {
|
||||||
|
function browse(type: string) {
|
||||||
|
if (type === "wallpaper") {
|
||||||
|
wallpaperBrowser.allowStacking = false;
|
||||||
|
wallpaperBrowser.open();
|
||||||
|
} else if (type === "profile") {
|
||||||
|
profileBrowser.allowStacking = false;
|
||||||
|
profileBrowser.open();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
target: "file"
|
||||||
|
}
|
||||||
|
|
||||||
|
FileBrowserModal {
|
||||||
|
id: profileBrowser
|
||||||
|
|
||||||
|
allowStacking: true
|
||||||
|
browserTitle: "Select Profile Image"
|
||||||
|
browserIcon: "person"
|
||||||
|
browserType: "profile"
|
||||||
|
fileExtensions: ["*.jpg", "*.jpeg", "*.png", "*.bmp", "*.gif", "*.webp"]
|
||||||
|
onFileSelected: (path) => {
|
||||||
|
PortalService.setProfileImage(path);
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
onDialogClosed: () => {
|
||||||
|
if (settingsModal) {
|
||||||
|
settingsModal.allowFocusOverride = false;
|
||||||
|
settingsModal.shouldHaveFocus = Qt.binding(() => {
|
||||||
|
return settingsModal.shouldBeVisible;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
allowStacking = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FileBrowserModal {
|
||||||
|
id: wallpaperBrowser
|
||||||
|
|
||||||
|
allowStacking: true
|
||||||
|
browserTitle: "Select Wallpaper"
|
||||||
|
browserIcon: "wallpaper"
|
||||||
|
browserType: "wallpaper"
|
||||||
|
fileExtensions: ["*.jpg", "*.jpeg", "*.png", "*.bmp", "*.gif", "*.webp"]
|
||||||
|
onFileSelected: (path) => {
|
||||||
|
SessionData.setWallpaper(path);
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
onDialogClosed: () => {
|
||||||
|
allowStacking = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
settingsContent: Component {
|
||||||
|
Item {
|
||||||
|
anchors.fill: parent
|
||||||
|
focus: true
|
||||||
|
|
||||||
|
Column {
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.leftMargin: Theme.spacingL
|
||||||
|
anchors.rightMargin: Theme.spacingL
|
||||||
|
anchors.topMargin: Theme.spacingM
|
||||||
|
anchors.bottomMargin: Theme.spacingL
|
||||||
|
spacing: 0
|
||||||
|
|
||||||
|
Item {
|
||||||
|
width: parent.width
|
||||||
|
height: 35
|
||||||
|
|
||||||
|
Row {
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
spacing: Theme.spacingM
|
||||||
|
|
||||||
|
DankIcon {
|
||||||
|
name: "settings"
|
||||||
|
size: Theme.iconSize
|
||||||
|
color: Theme.primary
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
text: "Settings"
|
||||||
|
font.pixelSize: Theme.fontSizeXLarge
|
||||||
|
color: Theme.surfaceText
|
||||||
|
font.weight: Font.Medium
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
DankActionButton {
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
circular: false
|
||||||
|
iconName: "close"
|
||||||
|
iconSize: Theme.iconSize - 4
|
||||||
|
iconColor: Theme.surfaceText
|
||||||
|
hoverColor: Theme.errorHover
|
||||||
|
onClicked: () => {
|
||||||
|
return settingsModal.hide();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Row {
|
||||||
|
width: parent.width
|
||||||
|
height: parent.height - 35
|
||||||
|
spacing: 0
|
||||||
|
|
||||||
|
SettingsSidebar {
|
||||||
|
id: sidebar
|
||||||
|
|
||||||
|
parentModal: settingsModal
|
||||||
|
onCurrentIndexChanged: content.currentIndex = currentIndex
|
||||||
|
}
|
||||||
|
|
||||||
|
SettingsContent {
|
||||||
|
id: content
|
||||||
|
|
||||||
|
width: parent.width - sidebar.width
|
||||||
|
height: parent.height
|
||||||
|
parentModal: settingsModal
|
||||||
|
currentIndex: sidebar.currentIndex
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
133
Modals/Settings/SettingsSidebar.qml
Normal file
133
Modals/Settings/SettingsSidebar.qml
Normal file
@@ -0,0 +1,133 @@
|
|||||||
|
import QtQuick
|
||||||
|
import qs.Common
|
||||||
|
import qs.Modals.Settings
|
||||||
|
import qs.Widgets
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: sidebarContainer
|
||||||
|
|
||||||
|
property int currentIndex: 0
|
||||||
|
property var parentModal: null
|
||||||
|
readonly property var sidebarItems: [{
|
||||||
|
"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": "Displays",
|
||||||
|
"icon": "monitor"
|
||||||
|
}, {
|
||||||
|
"text": "Recent Apps",
|
||||||
|
"icon": "history"
|
||||||
|
}, {
|
||||||
|
"text": "Theme & Colors",
|
||||||
|
"icon": "palette"
|
||||||
|
}, {
|
||||||
|
"text": "About",
|
||||||
|
"icon": "info"
|
||||||
|
}]
|
||||||
|
|
||||||
|
width: 270
|
||||||
|
height: parent.height
|
||||||
|
color: Theme.surfaceContainer
|
||||||
|
radius: Theme.cornerRadius
|
||||||
|
|
||||||
|
Column {
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.leftMargin: Theme.spacingS
|
||||||
|
anchors.rightMargin: Theme.spacingS
|
||||||
|
anchors.bottomMargin: Theme.spacingS
|
||||||
|
anchors.topMargin: Theme.spacingM + 2
|
||||||
|
spacing: Theme.spacingXS
|
||||||
|
|
||||||
|
ProfileSection {
|
||||||
|
parentModal: sidebarContainer.parentModal
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
width: parent.width - Theme.spacingS * 2
|
||||||
|
height: 1
|
||||||
|
color: Theme.outline
|
||||||
|
opacity: 0.2
|
||||||
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
width: parent.width
|
||||||
|
height: Theme.spacingL
|
||||||
|
}
|
||||||
|
|
||||||
|
Repeater {
|
||||||
|
id: sidebarRepeater
|
||||||
|
|
||||||
|
model: sidebarContainer.sidebarItems
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
property bool isActive: sidebarContainer.currentIndex === index
|
||||||
|
|
||||||
|
width: parent.width - Theme.spacingS * 2
|
||||||
|
height: 44
|
||||||
|
radius: Theme.cornerRadius
|
||||||
|
color: isActive ? Theme.surfaceContainerHigh : tabMouseArea.containsMouse ? Theme.surfaceHover : "transparent"
|
||||||
|
|
||||||
|
Row {
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.leftMargin: Theme.spacingM
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
spacing: Theme.spacingM
|
||||||
|
|
||||||
|
DankIcon {
|
||||||
|
name: modelData.icon || ""
|
||||||
|
size: Theme.iconSize - 2
|
||||||
|
color: parent.parent.isActive ? Theme.primary : Theme.surfaceText
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
text: modelData.text || ""
|
||||||
|
font.pixelSize: Theme.fontSizeMedium
|
||||||
|
color: parent.parent.isActive ? Theme.primary : Theme.surfaceText
|
||||||
|
font.weight: parent.parent.isActive ? Font.Medium : Font.Normal
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
id: tabMouseArea
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
hoverEnabled: true
|
||||||
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
onClicked: () => {
|
||||||
|
sidebarContainer.currentIndex = index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Behavior on color {
|
||||||
|
ColorAnimation {
|
||||||
|
duration: Theme.shortDuration
|
||||||
|
easing.type: Theme.standardEasing
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,608 +0,0 @@
|
|||||||
import QtQuick
|
|
||||||
import QtQuick.Controls
|
|
||||||
import QtQuick.Effects
|
|
||||||
import Quickshell
|
|
||||||
import Quickshell.Io
|
|
||||||
import qs.Common
|
|
||||||
import qs.Modals.Common
|
|
||||||
import qs.Modals.FileBrowser
|
|
||||||
import qs.Modules.Settings
|
|
||||||
import qs.Services
|
|
||||||
import qs.Widgets
|
|
||||||
|
|
||||||
DankModal {
|
|
||||||
id: settingsModal
|
|
||||||
|
|
||||||
property Component settingsContent
|
|
||||||
|
|
||||||
signal closingModal
|
|
||||||
|
|
||||||
function show() {
|
|
||||||
open()
|
|
||||||
}
|
|
||||||
|
|
||||||
function hide() {
|
|
||||||
close()
|
|
||||||
}
|
|
||||||
|
|
||||||
function toggle() {
|
|
||||||
if (shouldBeVisible)
|
|
||||||
hide()
|
|
||||||
else
|
|
||||||
show()
|
|
||||||
}
|
|
||||||
|
|
||||||
objectName: "settingsModal"
|
|
||||||
width: 800
|
|
||||||
height: 750
|
|
||||||
visible: false
|
|
||||||
onBackgroundClicked: hide()
|
|
||||||
content: settingsContent
|
|
||||||
|
|
||||||
IpcHandler {
|
|
||||||
function open() {
|
|
||||||
settingsModal.show()
|
|
||||||
return "SETTINGS_OPEN_SUCCESS"
|
|
||||||
}
|
|
||||||
|
|
||||||
function close() {
|
|
||||||
settingsModal.hide()
|
|
||||||
return "SETTINGS_CLOSE_SUCCESS"
|
|
||||||
}
|
|
||||||
|
|
||||||
function toggle() {
|
|
||||||
settingsModal.toggle()
|
|
||||||
return "SETTINGS_TOGGLE_SUCCESS"
|
|
||||||
}
|
|
||||||
|
|
||||||
target: "settings"
|
|
||||||
}
|
|
||||||
|
|
||||||
IpcHandler {
|
|
||||||
function browse(type: string) {
|
|
||||||
if (type === "wallpaper") {
|
|
||||||
wallpaperBrowser.allowStacking = false
|
|
||||||
wallpaperBrowser.open()
|
|
||||||
} else if (type === "profile") {
|
|
||||||
profileBrowser.allowStacking = false
|
|
||||||
profileBrowser.open()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
target: "file"
|
|
||||||
}
|
|
||||||
|
|
||||||
settingsContent: Component {
|
|
||||||
Item {
|
|
||||||
anchors.fill: parent
|
|
||||||
focus: true
|
|
||||||
|
|
||||||
Column {
|
|
||||||
anchors.fill: parent
|
|
||||||
anchors.leftMargin: Theme.spacingL
|
|
||||||
anchors.rightMargin: Theme.spacingL
|
|
||||||
anchors.topMargin: Theme.spacingM
|
|
||||||
anchors.bottomMargin: Theme.spacingL
|
|
||||||
spacing: 0
|
|
||||||
|
|
||||||
Item {
|
|
||||||
width: parent.width
|
|
||||||
height: 35
|
|
||||||
|
|
||||||
Row {
|
|
||||||
anchors.left: parent.left
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
spacing: Theme.spacingM
|
|
||||||
|
|
||||||
DankIcon {
|
|
||||||
name: "settings"
|
|
||||||
size: Theme.iconSize
|
|
||||||
color: Theme.primary
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
}
|
|
||||||
|
|
||||||
StyledText {
|
|
||||||
text: "Settings"
|
|
||||||
font.pixelSize: Theme.fontSizeXLarge
|
|
||||||
color: Theme.surfaceText
|
|
||||||
font.weight: Font.Medium
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
DankActionButton {
|
|
||||||
anchors.right: parent.right
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
circular: false
|
|
||||||
iconName: "close"
|
|
||||||
iconSize: Theme.iconSize - 4
|
|
||||||
iconColor: Theme.surfaceText
|
|
||||||
hoverColor: Theme.errorHover
|
|
||||||
onClicked: settingsModal.hide()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Row {
|
|
||||||
width: parent.width
|
|
||||||
height: parent.height - 35
|
|
||||||
spacing: 0
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
id: sidebarContainer
|
|
||||||
|
|
||||||
property int currentIndex: 0
|
|
||||||
|
|
||||||
width: 270
|
|
||||||
height: parent.height
|
|
||||||
color: Theme.surfaceContainer
|
|
||||||
radius: Theme.cornerRadius
|
|
||||||
|
|
||||||
Column {
|
|
||||||
anchors.fill: parent
|
|
||||||
anchors.leftMargin: Theme.spacingS
|
|
||||||
anchors.rightMargin: Theme.spacingS
|
|
||||||
anchors.bottomMargin: Theme.spacingS
|
|
||||||
anchors.topMargin: Theme.spacingM + 2
|
|
||||||
spacing: Theme.spacingXS
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
width: parent.width - Theme.spacingS * 2
|
|
||||||
height: 110
|
|
||||||
radius: Theme.cornerRadius
|
|
||||||
color: "transparent"
|
|
||||||
border.width: 0
|
|
||||||
|
|
||||||
Row {
|
|
||||||
anchors.left: parent.left
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
anchors.leftMargin: Theme.spacingM
|
|
||||||
anchors.rightMargin: Theme.spacingM
|
|
||||||
spacing: Theme.spacingM
|
|
||||||
|
|
||||||
Item {
|
|
||||||
id: profileImageContainer
|
|
||||||
width: 80
|
|
||||||
height: 80
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
|
|
||||||
property bool hasImage: profileImageSource.status
|
|
||||||
=== Image.Ready
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
anchors.fill: parent
|
|
||||||
radius: width / 2
|
|
||||||
color: "transparent"
|
|
||||||
border.color: Theme.primary
|
|
||||||
border.width: 1
|
|
||||||
visible: parent.hasImage
|
|
||||||
}
|
|
||||||
|
|
||||||
Image {
|
|
||||||
id: profileImageSource
|
|
||||||
source: {
|
|
||||||
if (PortalService.profileImage === "")
|
|
||||||
return ""
|
|
||||||
if (PortalService.profileImage.startsWith(
|
|
||||||
"/"))
|
|
||||||
return "file://" + PortalService.profileImage
|
|
||||||
return PortalService.profileImage
|
|
||||||
}
|
|
||||||
smooth: true
|
|
||||||
asynchronous: true
|
|
||||||
mipmap: true
|
|
||||||
cache: true
|
|
||||||
visible: false
|
|
||||||
}
|
|
||||||
|
|
||||||
MultiEffect {
|
|
||||||
anchors.fill: parent
|
|
||||||
anchors.margins: 5
|
|
||||||
source: profileImageSource
|
|
||||||
maskEnabled: true
|
|
||||||
maskSource: profileCircularMask
|
|
||||||
visible: profileImageContainer.hasImage
|
|
||||||
maskThresholdMin: 0.5
|
|
||||||
maskSpreadAtMin: 1
|
|
||||||
}
|
|
||||||
|
|
||||||
Item {
|
|
||||||
id: profileCircularMask
|
|
||||||
width: 70
|
|
||||||
height: 70
|
|
||||||
layer.enabled: true
|
|
||||||
layer.smooth: true
|
|
||||||
visible: false
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
anchors.fill: parent
|
|
||||||
radius: width / 2
|
|
||||||
color: "black"
|
|
||||||
antialiasing: true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
anchors.fill: parent
|
|
||||||
radius: width / 2
|
|
||||||
color: Theme.primary
|
|
||||||
visible: !parent.hasImage
|
|
||||||
|
|
||||||
DankIcon {
|
|
||||||
anchors.centerIn: parent
|
|
||||||
name: "person"
|
|
||||||
size: Theme.iconSizeLarge
|
|
||||||
color: Theme.primaryText
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
anchors.fill: parent
|
|
||||||
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)
|
|
||||||
|
|
||||||
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(
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
width: 28
|
|
||||||
height: 28
|
|
||||||
radius: 14
|
|
||||||
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(
|
|
||||||
"")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
MouseArea {
|
|
||||||
id: profileMouseArea
|
|
||||||
anchors.fill: parent
|
|
||||||
hoverEnabled: true
|
|
||||||
cursorShape: Qt.PointingHandCursor
|
|
||||||
propagateComposedEvents: true
|
|
||||||
acceptedButtons: Qt.NoButton
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Column {
|
|
||||||
width: 120
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
spacing: Theme.spacingXS
|
|
||||||
|
|
||||||
StyledText {
|
|
||||||
text: UserInfoService.fullName
|
|
||||||
|| "User"
|
|
||||||
font.pixelSize: Theme.fontSizeLarge
|
|
||||||
font.weight: Font.Medium
|
|
||||||
color: Theme.surfaceText
|
|
||||||
elide: Text.ElideRight
|
|
||||||
width: parent.width
|
|
||||||
}
|
|
||||||
|
|
||||||
StyledText {
|
|
||||||
text: DgopService.distribution
|
|
||||||
|| "Linux"
|
|
||||||
font.pixelSize: Theme.fontSizeMedium
|
|
||||||
color: Theme.surfaceVariantText
|
|
||||||
elide: Text.ElideRight
|
|
||||||
width: parent.width
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
width: parent.width - Theme.spacingS * 2
|
|
||||||
height: 1
|
|
||||||
color: Theme.outline
|
|
||||||
opacity: 0.2
|
|
||||||
}
|
|
||||||
|
|
||||||
Item {
|
|
||||||
width: parent.width
|
|
||||||
height: Theme.spacingL
|
|
||||||
}
|
|
||||||
|
|
||||||
Repeater {
|
|
||||||
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": "Displays",
|
|
||||||
"icon": "monitor"
|
|
||||||
}, {
|
|
||||||
"text": "Recent Apps",
|
|
||||||
"icon": "history"
|
|
||||||
}, {
|
|
||||||
"text": "Theme & Colors",
|
|
||||||
"icon": "palette"
|
|
||||||
}, {
|
|
||||||
"text": "About",
|
|
||||||
"icon": "info"
|
|
||||||
}]
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
property bool isActive: sidebarContainer.currentIndex === index
|
|
||||||
|
|
||||||
width: parent.width - Theme.spacingS * 2
|
|
||||||
height: 44
|
|
||||||
radius: Theme.cornerRadius
|
|
||||||
color: isActive ? Theme.surfaceContainerHigh : tabMouseArea.containsMouse ? Theme.surfaceHover : "transparent"
|
|
||||||
|
|
||||||
Row {
|
|
||||||
anchors.left: parent.left
|
|
||||||
anchors.leftMargin: Theme.spacingM
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
spacing: Theme.spacingM
|
|
||||||
|
|
||||||
DankIcon {
|
|
||||||
name: modelData.icon || ""
|
|
||||||
size: Theme.iconSize - 2
|
|
||||||
color: parent.parent.isActive ? Theme.primary : Theme.surfaceText
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
}
|
|
||||||
|
|
||||||
StyledText {
|
|
||||||
text: modelData.text || ""
|
|
||||||
font.pixelSize: Theme.fontSizeMedium
|
|
||||||
color: parent.parent.isActive ? Theme.primary : Theme.surfaceText
|
|
||||||
font.weight: parent.parent.isActive ? Font.Medium : Font.Normal
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
MouseArea {
|
|
||||||
id: tabMouseArea
|
|
||||||
|
|
||||||
anchors.fill: parent
|
|
||||||
hoverEnabled: true
|
|
||||||
cursorShape: Qt.PointingHandCursor
|
|
||||||
onClicked: {
|
|
||||||
sidebarContainer.currentIndex = index
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Behavior on color {
|
|
||||||
ColorAnimation {
|
|
||||||
duration: Theme.shortDuration
|
|
||||||
easing.type: Theme.standardEasing
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Item {
|
|
||||||
width: parent.width - sidebarContainer.width
|
|
||||||
height: parent.height
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
anchors.fill: parent
|
|
||||||
anchors.leftMargin: 0
|
|
||||||
anchors.rightMargin: Theme.spacingS
|
|
||||||
anchors.bottomMargin: Theme.spacingM
|
|
||||||
anchors.topMargin: 0
|
|
||||||
color: "transparent"
|
|
||||||
|
|
||||||
Loader {
|
|
||||||
id: personalizationLoader
|
|
||||||
|
|
||||||
anchors.fill: parent
|
|
||||||
active: sidebarContainer.currentIndex === 0
|
|
||||||
visible: active
|
|
||||||
asynchronous: true
|
|
||||||
|
|
||||||
sourceComponent: Component {
|
|
||||||
PersonalizationTab {
|
|
||||||
parentModal: settingsModal
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Loader {
|
|
||||||
id: timeLoader
|
|
||||||
|
|
||||||
anchors.fill: parent
|
|
||||||
active: sidebarContainer.currentIndex === 1
|
|
||||||
visible: active
|
|
||||||
asynchronous: true
|
|
||||||
|
|
||||||
sourceComponent: TimeTab {}
|
|
||||||
}
|
|
||||||
|
|
||||||
Loader {
|
|
||||||
id: weatherLoader
|
|
||||||
|
|
||||||
anchors.fill: parent
|
|
||||||
active: sidebarContainer.currentIndex === 2
|
|
||||||
visible: active
|
|
||||||
asynchronous: true
|
|
||||||
|
|
||||||
sourceComponent: WeatherTab {}
|
|
||||||
}
|
|
||||||
|
|
||||||
Loader {
|
|
||||||
id: topBarLoader
|
|
||||||
|
|
||||||
anchors.fill: parent
|
|
||||||
active: sidebarContainer.currentIndex === 3
|
|
||||||
visible: active
|
|
||||||
asynchronous: true
|
|
||||||
|
|
||||||
sourceComponent: TopBarTab {}
|
|
||||||
}
|
|
||||||
|
|
||||||
Loader {
|
|
||||||
id: widgetsLoader
|
|
||||||
|
|
||||||
anchors.fill: parent
|
|
||||||
active: sidebarContainer.currentIndex === 4
|
|
||||||
visible: active
|
|
||||||
asynchronous: true
|
|
||||||
sourceComponent: WidgetTweaksTab {}
|
|
||||||
}
|
|
||||||
|
|
||||||
Loader {
|
|
||||||
id: dockLoader
|
|
||||||
|
|
||||||
anchors.fill: parent
|
|
||||||
active: sidebarContainer.currentIndex === 5
|
|
||||||
visible: active
|
|
||||||
asynchronous: true
|
|
||||||
|
|
||||||
sourceComponent: Component {
|
|
||||||
DockTab {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Loader {
|
|
||||||
id: displaysLoader
|
|
||||||
|
|
||||||
anchors.fill: parent
|
|
||||||
active: sidebarContainer.currentIndex === 6
|
|
||||||
visible: active
|
|
||||||
asynchronous: true
|
|
||||||
sourceComponent: DisplaysTab {}
|
|
||||||
}
|
|
||||||
|
|
||||||
Loader {
|
|
||||||
id: recentAppsLoader
|
|
||||||
|
|
||||||
anchors.fill: parent
|
|
||||||
active: sidebarContainer.currentIndex === 7
|
|
||||||
visible: active
|
|
||||||
asynchronous: true
|
|
||||||
sourceComponent: RecentAppsTab {}
|
|
||||||
}
|
|
||||||
|
|
||||||
Loader {
|
|
||||||
id: themeColorsLoader
|
|
||||||
|
|
||||||
anchors.fill: parent
|
|
||||||
active: sidebarContainer.currentIndex === 8
|
|
||||||
visible: active
|
|
||||||
asynchronous: true
|
|
||||||
sourceComponent: ThemeColorsTab {}
|
|
||||||
}
|
|
||||||
|
|
||||||
Loader {
|
|
||||||
id: aboutLoader
|
|
||||||
|
|
||||||
anchors.fill: parent
|
|
||||||
active: sidebarContainer.currentIndex === 9
|
|
||||||
visible: active
|
|
||||||
asynchronous: true
|
|
||||||
sourceComponent: AboutTab {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
FileBrowserModal {
|
|
||||||
id: profileBrowser
|
|
||||||
|
|
||||||
allowStacking: true
|
|
||||||
browserTitle: "Select Profile Image"
|
|
||||||
browserIcon: "person"
|
|
||||||
browserType: "profile"
|
|
||||||
fileExtensions: ["*.jpg", "*.jpeg", "*.png", "*.bmp", "*.gif", "*.webp"]
|
|
||||||
onFileSelected: path => {
|
|
||||||
PortalService.setProfileImage(path)
|
|
||||||
close()
|
|
||||||
}
|
|
||||||
onDialogClosed: {
|
|
||||||
if (settingsModal) {
|
|
||||||
settingsModal.allowFocusOverride = false
|
|
||||||
settingsModal.shouldHaveFocus = Qt.binding(() => {
|
|
||||||
return settingsModal.shouldBeVisible
|
|
||||||
})
|
|
||||||
}
|
|
||||||
allowStacking = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
FileBrowserModal {
|
|
||||||
id: wallpaperBrowser
|
|
||||||
|
|
||||||
allowStacking: true
|
|
||||||
browserTitle: "Select Wallpaper"
|
|
||||||
browserIcon: "wallpaper"
|
|
||||||
browserType: "wallpaper"
|
|
||||||
fileExtensions: ["*.jpg", "*.jpeg", "*.png", "*.bmp", "*.gif", "*.webp"]
|
|
||||||
onFileSelected: path => {
|
|
||||||
SessionData.setWallpaper(path)
|
|
||||||
close()
|
|
||||||
}
|
|
||||||
onDialogClosed: {
|
|
||||||
allowStacking = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
226
Modals/Spotlight/SpotlightContent.qml
Normal file
226
Modals/Spotlight/SpotlightContent.qml
Normal file
@@ -0,0 +1,226 @@
|
|||||||
|
import QtQuick
|
||||||
|
import QtQuick.Controls
|
||||||
|
import qs.Common
|
||||||
|
import qs.Modals.Spotlight
|
||||||
|
import qs.Modules.AppDrawer
|
||||||
|
import qs.Services
|
||||||
|
import qs.Widgets
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: spotlightKeyHandler
|
||||||
|
|
||||||
|
property alias appLauncher: appLauncher
|
||||||
|
property alias searchField: searchField
|
||||||
|
property var parentModal: null
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
focus: true
|
||||||
|
Keys.onPressed: event => {
|
||||||
|
if (event.key === Qt.Key_Escape) {
|
||||||
|
if (parentModal)
|
||||||
|
parentModal.hide()
|
||||||
|
|
||||||
|
event.accepted = true
|
||||||
|
} else if (event.key === Qt.Key_Down) {
|
||||||
|
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 {
|
||||||
|
id: appLauncher
|
||||||
|
|
||||||
|
viewMode: SettingsData.spotlightModalViewMode
|
||||||
|
gridColumns: 4
|
||||||
|
onAppLaunched: () => {
|
||||||
|
if (parentModal)
|
||||||
|
parentModal.hide()
|
||||||
|
}
|
||||||
|
onViewModeSelected: mode => {
|
||||||
|
SettingsData.setSpotlightModalViewMode(mode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Column {
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: Theme.spacingL
|
||||||
|
spacing: Theme.spacingL
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
width: parent.width
|
||||||
|
height: categorySelector.height + Theme.spacingM * 2
|
||||||
|
radius: Theme.cornerRadius
|
||||||
|
color: Theme.surfaceVariantAlpha
|
||||||
|
border.color: Theme.outlineMedium
|
||||||
|
border.width: 1
|
||||||
|
visible: appLauncher.categories.length > 1 || appLauncher.model.count > 0
|
||||||
|
|
||||||
|
CategorySelector {
|
||||||
|
id: categorySelector
|
||||||
|
|
||||||
|
anchors.centerIn: parent
|
||||||
|
width: parent.width - Theme.spacingM * 2
|
||||||
|
categories: appLauncher.categories
|
||||||
|
selectedCategory: appLauncher.selectedCategory
|
||||||
|
compact: false
|
||||||
|
onCategorySelected: category => {
|
||||||
|
appLauncher.setCategory(category)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Row {
|
||||||
|
width: parent.width
|
||||||
|
spacing: Theme.spacingM
|
||||||
|
|
||||||
|
DankTextField {
|
||||||
|
id: searchField
|
||||||
|
|
||||||
|
width: parent.width - 80 - Theme.spacingM
|
||||||
|
height: 56
|
||||||
|
cornerRadius: Theme.cornerRadius
|
||||||
|
backgroundColor: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, Theme.getContentBackgroundAlpha() * 0.7)
|
||||||
|
normalBorderColor: Theme.outlineMedium
|
||||||
|
focusedBorderColor: Theme.primary
|
||||||
|
leftIconName: "search"
|
||||||
|
leftIconSize: Theme.iconSize
|
||||||
|
leftIconColor: Theme.surfaceVariantText
|
||||||
|
leftIconFocusedColor: Theme.primary
|
||||||
|
showClearButton: true
|
||||||
|
textColor: Theme.surfaceText
|
||||||
|
font.pixelSize: Theme.fontSizeLarge
|
||||||
|
enabled: parentModal ? parentModal.spotlightOpen : true
|
||||||
|
placeholderText: ""
|
||||||
|
ignoreLeftRightKeys: true
|
||||||
|
keyForwardTargets: [spotlightKeyHandler]
|
||||||
|
text: appLauncher.searchQuery
|
||||||
|
onTextEdited: () => {
|
||||||
|
appLauncher.searchQuery = text
|
||||||
|
}
|
||||||
|
Keys.onPressed: event => {
|
||||||
|
if (event.key === Qt.Key_Escape) {
|
||||||
|
if (parentModal)
|
||||||
|
parentModal.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 {
|
||||||
|
spacing: Theme.spacingXS
|
||||||
|
visible: appLauncher.model.count > 0
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
width: 36
|
||||||
|
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.width: 1
|
||||||
|
|
||||||
|
DankIcon {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
name: "view_list"
|
||||||
|
size: 18
|
||||||
|
color: appLauncher.viewMode === "list" ? Theme.primary : Theme.surfaceText
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
id: listViewArea
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
hoverEnabled: true
|
||||||
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
onClicked: () => {
|
||||||
|
appLauncher.setViewMode("list")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
width: 36
|
||||||
|
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.width: 1
|
||||||
|
|
||||||
|
DankIcon {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
name: "grid_view"
|
||||||
|
size: 18
|
||||||
|
color: appLauncher.viewMode === "grid" ? Theme.primary : Theme.surfaceText
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
id: gridViewArea
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
hoverEnabled: true
|
||||||
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
onClicked: () => {
|
||||||
|
appLauncher.setViewMode("grid")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SpotlightResults {
|
||||||
|
appLauncher: spotlightKeyHandler.appLauncher
|
||||||
|
contextMenu: contextMenu
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SpotlightContextMenu {
|
||||||
|
id: contextMenu
|
||||||
|
|
||||||
|
appLauncher: spotlightKeyHandler.appLauncher
|
||||||
|
parentHandler: spotlightKeyHandler
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
visible: contextMenu.visible
|
||||||
|
z: 999
|
||||||
|
onClicked: () => {
|
||||||
|
contextMenu.close()
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
|
||||||
|
// Prevent closing when clicking on the menu itself
|
||||||
|
x: contextMenu.x
|
||||||
|
y: contextMenu.y
|
||||||
|
width: contextMenu.width
|
||||||
|
height: contextMenu.height
|
||||||
|
onClicked: () => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
205
Modals/Spotlight/SpotlightContextMenu.qml
Normal file
205
Modals/Spotlight/SpotlightContextMenu.qml
Normal file
@@ -0,0 +1,205 @@
|
|||||||
|
import QtQuick
|
||||||
|
import qs.Common
|
||||||
|
import qs.Services
|
||||||
|
import qs.Widgets
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: contextMenu
|
||||||
|
|
||||||
|
property var currentApp: null
|
||||||
|
property bool menuVisible: false
|
||||||
|
property var appLauncher: null
|
||||||
|
property var parentHandler: null
|
||||||
|
|
||||||
|
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 (parentHandler) {
|
||||||
|
if (finalX + menuWidth > parentHandler.width)
|
||||||
|
finalX = x - menuWidth - 8
|
||||||
|
|
||||||
|
if (finalY + menuHeight > parentHandler.height)
|
||||||
|
finalY = y - menuHeight - 8
|
||||||
|
|
||||||
|
finalX = Math.max(8, Math.min(finalX, parentHandler.width - menuWidth - 8))
|
||||||
|
finalY = Math.max(8, Math.min(finalY, parentHandler.height - menuHeight - 8))
|
||||||
|
}
|
||||||
|
contextMenu.x = finalX
|
||||||
|
contextMenu.y = finalY
|
||||||
|
contextMenu.visible = true
|
||||||
|
contextMenu.menuVisible = true
|
||||||
|
}
|
||||||
|
|
||||||
|
function close() {
|
||||||
|
contextMenu.menuVisible = false
|
||||||
|
Qt.callLater(() => {
|
||||||
|
contextMenu.visible = false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
visible: false
|
||||||
|
width: 180
|
||||||
|
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.width: 1
|
||||||
|
z: 1000
|
||||||
|
opacity: menuVisible ? 1 : 0
|
||||||
|
scale: menuVisible ? 1 : 0.85
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.topMargin: 4
|
||||||
|
anchors.leftMargin: 2
|
||||||
|
anchors.rightMargin: -2
|
||||||
|
anchors.bottomMargin: -4
|
||||||
|
radius: parent.radius
|
||||||
|
color: Qt.rgba(0, 0, 0, 0.15)
|
||||||
|
z: parent.z - 1
|
||||||
|
}
|
||||||
|
|
||||||
|
Column {
|
||||||
|
id: menuColumn
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: Theme.spacingS
|
||||||
|
spacing: 1
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
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"
|
||||||
|
|
||||||
|
Row {
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.leftMargin: Theme.spacingS
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
spacing: Theme.spacingS
|
||||||
|
|
||||||
|
DankIcon {
|
||||||
|
name: {
|
||||||
|
if (!contextMenu.currentApp || !contextMenu.currentApp.desktopEntry)
|
||||||
|
return "push_pin"
|
||||||
|
|
||||||
|
const appId = contextMenu.currentApp.desktopEntry.id || contextMenu.currentApp.desktopEntry.execString || ""
|
||||||
|
return SessionData.isPinnedApp(appId) ? "keep_off" : "push_pin"
|
||||||
|
}
|
||||||
|
size: Theme.iconSize - 2
|
||||||
|
color: Theme.surfaceText
|
||||||
|
opacity: 0.7
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
text: {
|
||||||
|
if (!contextMenu.currentApp || !contextMenu.currentApp.desktopEntry)
|
||||||
|
return "Pin to Dock"
|
||||||
|
|
||||||
|
const 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
|
||||||
|
font.weight: Font.Normal
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
id: pinMouseArea
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
hoverEnabled: true
|
||||||
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
onClicked: () => {
|
||||||
|
if (!contextMenu.currentApp || !contextMenu.currentApp.desktopEntry)
|
||||||
|
return
|
||||||
|
|
||||||
|
const appId = contextMenu.currentApp.desktopEntry.id || contextMenu.currentApp.desktopEntry.execString || ""
|
||||||
|
if (SessionData.isPinnedApp(appId))
|
||||||
|
SessionData.removePinnedApp(appId)
|
||||||
|
else
|
||||||
|
SessionData.addPinnedApp(appId)
|
||||||
|
contextMenu.close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
width: parent.width - Theme.spacingS * 2
|
||||||
|
height: 5
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
color: "transparent"
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
width: parent.width
|
||||||
|
height: 1
|
||||||
|
color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
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"
|
||||||
|
|
||||||
|
Row {
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.leftMargin: Theme.spacingS
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
spacing: Theme.spacingS
|
||||||
|
|
||||||
|
DankIcon {
|
||||||
|
name: "launch"
|
||||||
|
size: Theme.iconSize - 2
|
||||||
|
color: Theme.surfaceText
|
||||||
|
opacity: 0.7
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
text: "Launch"
|
||||||
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
|
color: Theme.surfaceText
|
||||||
|
font.weight: Font.Normal
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
id: launchMouseArea
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
hoverEnabled: true
|
||||||
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
onClicked: () => {
|
||||||
|
if (contextMenu.currentApp && appLauncher)
|
||||||
|
appLauncher.launchApp(contextMenu.currentApp)
|
||||||
|
|
||||||
|
contextMenu.close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Behavior on opacity {
|
||||||
|
NumberAnimation {
|
||||||
|
duration: Theme.mediumDuration
|
||||||
|
easing.type: Theme.emphasizedEasing
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Behavior on scale {
|
||||||
|
NumberAnimation {
|
||||||
|
duration: Theme.mediumDuration
|
||||||
|
easing.type: Theme.emphasizedEasing
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
109
Modals/Spotlight/SpotlightModal.qml
Normal file
109
Modals/Spotlight/SpotlightModal.qml
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
import QtQuick
|
||||||
|
import QtQuick.Controls
|
||||||
|
import Quickshell
|
||||||
|
import Quickshell.Io
|
||||||
|
import Quickshell.Widgets
|
||||||
|
import qs.Common
|
||||||
|
import qs.Modals.Common
|
||||||
|
import qs.Modules.AppDrawer
|
||||||
|
import qs.Services
|
||||||
|
import qs.Widgets
|
||||||
|
|
||||||
|
DankModal {
|
||||||
|
id: spotlightModal
|
||||||
|
|
||||||
|
property bool spotlightOpen: false
|
||||||
|
property Component spotlightContent
|
||||||
|
|
||||||
|
function show() {
|
||||||
|
spotlightOpen = true
|
||||||
|
open()
|
||||||
|
if (contentLoader.item && contentLoader.item.appLauncher) {
|
||||||
|
contentLoader.item.appLauncher.searchQuery = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
Qt.callLater(() => {
|
||||||
|
if (contentLoader.item && contentLoader.item.searchField) {
|
||||||
|
contentLoader.item.searchField.forceActiveFocus()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function hide() {
|
||||||
|
spotlightOpen = false
|
||||||
|
close()
|
||||||
|
if (contentLoader.item && contentLoader.item.appLauncher) {
|
||||||
|
contentLoader.item.appLauncher.searchQuery = ""
|
||||||
|
contentLoader.item.appLauncher.selectedIndex = 0
|
||||||
|
contentLoader.item.appLauncher.setCategory("All")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggle() {
|
||||||
|
if (spotlightOpen) {
|
||||||
|
hide()
|
||||||
|
} else {
|
||||||
|
show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
shouldBeVisible: spotlightOpen
|
||||||
|
width: 550
|
||||||
|
height: 600
|
||||||
|
backgroundColor: Theme.popupBackground()
|
||||||
|
cornerRadius: Theme.cornerRadius
|
||||||
|
borderColor: Theme.outlineMedium
|
||||||
|
borderWidth: 1
|
||||||
|
enableShadow: true
|
||||||
|
onVisibleChanged: () => {
|
||||||
|
if (visible && !spotlightOpen) {
|
||||||
|
show()
|
||||||
|
}
|
||||||
|
if (visible && contentLoader.item) {
|
||||||
|
Qt.callLater(() => {
|
||||||
|
if (contentLoader.item.searchField) {
|
||||||
|
contentLoader.item.searchField.forceActiveFocus()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
onBackgroundClicked: () => {
|
||||||
|
return hide()
|
||||||
|
}
|
||||||
|
content: spotlightContent
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
function onCloseAllModalsExcept(excludedModal) {
|
||||||
|
if (excludedModal !== spotlightModal && !allowStacking && spotlightOpen) {
|
||||||
|
spotlightOpen = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
target: ModalManager
|
||||||
|
}
|
||||||
|
|
||||||
|
IpcHandler {
|
||||||
|
function open() {
|
||||||
|
spotlightModal.show()
|
||||||
|
return "SPOTLIGHT_OPEN_SUCCESS"
|
||||||
|
}
|
||||||
|
|
||||||
|
function close() {
|
||||||
|
spotlightModal.hide()
|
||||||
|
return "SPOTLIGHT_CLOSE_SUCCESS"
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggle() {
|
||||||
|
spotlightModal.toggle()
|
||||||
|
return "SPOTLIGHT_TOGGLE_SUCCESS"
|
||||||
|
}
|
||||||
|
|
||||||
|
target: "spotlight"
|
||||||
|
}
|
||||||
|
|
||||||
|
spotlightContent: Component {
|
||||||
|
SpotlightContent {
|
||||||
|
parentModal: spotlightModal
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
340
Modals/Spotlight/SpotlightResults.qml
Normal file
340
Modals/Spotlight/SpotlightResults.qml
Normal file
@@ -0,0 +1,340 @@
|
|||||||
|
import QtQuick
|
||||||
|
import QtQuick.Controls
|
||||||
|
import Quickshell
|
||||||
|
import Quickshell.Widgets
|
||||||
|
import qs.Common
|
||||||
|
import qs.Widgets
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: resultsContainer
|
||||||
|
|
||||||
|
property var appLauncher: null
|
||||||
|
property var contextMenu: null
|
||||||
|
|
||||||
|
width: parent.width
|
||||||
|
height: parent.height - y
|
||||||
|
radius: Theme.cornerRadius
|
||||||
|
color: Theme.surfaceLight
|
||||||
|
border.color: Theme.outlineLight
|
||||||
|
border.width: 1
|
||||||
|
|
||||||
|
DankListView {
|
||||||
|
id: resultsList
|
||||||
|
|
||||||
|
property int itemHeight: 60
|
||||||
|
property int iconSize: 40
|
||||||
|
property bool showDescription: true
|
||||||
|
property int itemSpacing: Theme.spacingS
|
||||||
|
property bool hoverUpdatesSelection: false
|
||||||
|
property bool keyboardNavigationActive: appLauncher ? appLauncher.keyboardNavigationActive : false
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
const itemY = index * (itemHeight + itemSpacing)
|
||||||
|
const itemBottom = itemY + itemHeight
|
||||||
|
if (itemY < contentY)
|
||||||
|
contentY = itemY
|
||||||
|
else if (itemBottom > contentY + height)
|
||||||
|
contentY = itemBottom - height
|
||||||
|
}
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: Theme.spacingS
|
||||||
|
visible: appLauncher && appLauncher.viewMode === "list"
|
||||||
|
model: appLauncher ? appLauncher.model : null
|
||||||
|
currentIndex: appLauncher ? appLauncher.selectedIndex : -1
|
||||||
|
clip: true
|
||||||
|
spacing: itemSpacing
|
||||||
|
focus: true
|
||||||
|
interactive: true
|
||||||
|
cacheBuffer: Math.max(0, Math.min(height * 2, 1000))
|
||||||
|
reuseItems: true
|
||||||
|
onCurrentIndexChanged: {
|
||||||
|
if (keyboardNavigationActive)
|
||||||
|
ensureVisible(currentIndex)
|
||||||
|
}
|
||||||
|
onItemClicked: (index, modelData) => {
|
||||||
|
if (appLauncher)
|
||||||
|
appLauncher.launchApp(modelData)
|
||||||
|
}
|
||||||
|
onItemRightClicked: (index, modelData, mouseX, mouseY) => {
|
||||||
|
if (contextMenu)
|
||||||
|
contextMenu.show(mouseX, mouseY, modelData)
|
||||||
|
}
|
||||||
|
onKeyboardNavigationReset: () => {
|
||||||
|
if (appLauncher)
|
||||||
|
appLauncher.keyboardNavigationActive = false
|
||||||
|
}
|
||||||
|
|
||||||
|
ScrollBar.vertical: ScrollBar {
|
||||||
|
policy: ScrollBar.AlwaysOn
|
||||||
|
}
|
||||||
|
|
||||||
|
ScrollBar.horizontal: ScrollBar {
|
||||||
|
policy: ScrollBar.AlwaysOff
|
||||||
|
}
|
||||||
|
|
||||||
|
delegate: Rectangle {
|
||||||
|
width: ListView.view.width
|
||||||
|
height: resultsList.itemHeight
|
||||||
|
radius: Theme.cornerRadius
|
||||||
|
color: ListView.isCurrentItem ? Theme.primaryPressed : listMouseArea.containsMouse ? Theme.primaryHoverLight : Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.03)
|
||||||
|
border.color: ListView.isCurrentItem ? Theme.primarySelected : Theme.outlineMedium
|
||||||
|
border.width: ListView.isCurrentItem ? 2 : 1
|
||||||
|
|
||||||
|
Row {
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: Theme.spacingM
|
||||||
|
spacing: Theme.spacingL
|
||||||
|
|
||||||
|
Item {
|
||||||
|
width: resultsList.iconSize
|
||||||
|
height: resultsList.iconSize
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
|
||||||
|
IconImage {
|
||||||
|
id: listIconImg
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
source: Quickshell.iconPath(model.icon, true)
|
||||||
|
asynchronous: true
|
||||||
|
visible: status === Image.Ready
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
anchors.fill: parent
|
||||||
|
visible: !listIconImg.visible
|
||||||
|
color: Theme.surfaceLight
|
||||||
|
radius: Theme.cornerRadius
|
||||||
|
border.width: 1
|
||||||
|
border.color: Theme.primarySelected
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
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 {
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
width: parent.width - resultsList.iconSize - Theme.spacingL
|
||||||
|
spacing: Theme.spacingXS
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
width: parent.width
|
||||||
|
text: model.name || ""
|
||||||
|
font.pixelSize: Theme.fontSizeLarge
|
||||||
|
color: Theme.surfaceText
|
||||||
|
font.weight: Font.Medium
|
||||||
|
elide: Text.ElideRight
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
width: parent.width
|
||||||
|
text: model.comment || "Application"
|
||||||
|
font.pixelSize: Theme.fontSizeMedium
|
||||||
|
color: Theme.surfaceVariantText
|
||||||
|
elide: Text.ElideRight
|
||||||
|
visible: resultsList.showDescription && model.comment && model.comment.length > 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
id: listMouseArea
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
hoverEnabled: true
|
||||||
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
||||||
|
z: 10
|
||||||
|
onEntered: () => {
|
||||||
|
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) {
|
||||||
|
const modalPos = mapToItem(resultsContainer.parent, mouse.x, mouse.y)
|
||||||
|
resultsList.itemRightClicked(index, model, modalPos.x, modalPos.y)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DankGridView {
|
||||||
|
id: resultsGrid
|
||||||
|
|
||||||
|
property int currentIndex: appLauncher ? appLauncher.selectedIndex : -1
|
||||||
|
property int columns: 4
|
||||||
|
property bool adaptiveColumns: false
|
||||||
|
property int minCellWidth: 120
|
||||||
|
property int maxCellWidth: 160
|
||||||
|
property int cellPadding: 8
|
||||||
|
property real iconSizeRatio: 0.55
|
||||||
|
property int maxIconSize: 48
|
||||||
|
property int minIconSize: 32
|
||||||
|
property bool hoverUpdatesSelection: false
|
||||||
|
property bool keyboardNavigationActive: appLauncher ? appLauncher.keyboardNavigationActive : false
|
||||||
|
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 remainingSpace: width - (actualColumns * cellWidth)
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
const itemY = Math.floor(index / actualColumns) * cellHeight
|
||||||
|
const itemBottom = itemY + cellHeight
|
||||||
|
if (itemY < contentY)
|
||||||
|
contentY = itemY
|
||||||
|
else if (itemBottom > contentY + height)
|
||||||
|
contentY = itemBottom - height
|
||||||
|
}
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: Theme.spacingS
|
||||||
|
visible: appLauncher && appLauncher.viewMode === "grid"
|
||||||
|
model: appLauncher ? appLauncher.model : null
|
||||||
|
clip: true
|
||||||
|
cellWidth: baseCellWidth
|
||||||
|
cellHeight: baseCellHeight
|
||||||
|
leftMargin: Math.max(Theme.spacingS, remainingSpace / 2)
|
||||||
|
rightMargin: leftMargin
|
||||||
|
focus: true
|
||||||
|
interactive: true
|
||||||
|
cacheBuffer: Math.max(0, Math.min(height * 2, 1000))
|
||||||
|
reuseItems: true
|
||||||
|
onCurrentIndexChanged: {
|
||||||
|
if (keyboardNavigationActive)
|
||||||
|
ensureVisible(currentIndex)
|
||||||
|
}
|
||||||
|
onItemClicked: (index, modelData) => {
|
||||||
|
if (appLauncher)
|
||||||
|
appLauncher.launchApp(modelData)
|
||||||
|
}
|
||||||
|
onItemRightClicked: (index, modelData, mouseX, mouseY) => {
|
||||||
|
if (contextMenu)
|
||||||
|
contextMenu.show(mouseX, mouseY, modelData)
|
||||||
|
}
|
||||||
|
onKeyboardNavigationReset: () => {
|
||||||
|
if (appLauncher)
|
||||||
|
appLauncher.keyboardNavigationActive = false
|
||||||
|
}
|
||||||
|
|
||||||
|
ScrollBar.vertical: ScrollBar {
|
||||||
|
policy: ScrollBar.AsNeeded
|
||||||
|
}
|
||||||
|
|
||||||
|
ScrollBar.horizontal: ScrollBar {
|
||||||
|
policy: ScrollBar.AlwaysOff
|
||||||
|
}
|
||||||
|
|
||||||
|
delegate: Rectangle {
|
||||||
|
width: resultsGrid.cellWidth - resultsGrid.cellPadding
|
||||||
|
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.width: resultsGrid.currentIndex === index ? 2 : 1
|
||||||
|
|
||||||
|
Column {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
spacing: Theme.spacingS
|
||||||
|
|
||||||
|
Item {
|
||||||
|
property int iconSize: Math.min(resultsGrid.maxIconSize, Math.max(resultsGrid.minIconSize, resultsGrid.cellWidth * resultsGrid.iconSizeRatio))
|
||||||
|
|
||||||
|
width: iconSize
|
||||||
|
height: iconSize
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
|
||||||
|
IconImage {
|
||||||
|
id: gridIconImg
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
source: Quickshell.iconPath(model.icon, true)
|
||||||
|
smooth: true
|
||||||
|
asynchronous: true
|
||||||
|
visible: status === Image.Ready
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
anchors.fill: parent
|
||||||
|
visible: !gridIconImg.visible
|
||||||
|
color: Theme.surfaceLight
|
||||||
|
radius: Theme.cornerRadius
|
||||||
|
border.width: 1
|
||||||
|
border.color: Theme.primarySelected
|
||||||
|
|
||||||
|
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)
|
||||||
|
color: Theme.primary
|
||||||
|
font.weight: Font.Bold
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
width: resultsGrid.cellWidth - 12
|
||||||
|
text: model.name || ""
|
||||||
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
|
color: Theme.surfaceText
|
||||||
|
font.weight: Font.Medium
|
||||||
|
elide: Text.ElideRight
|
||||||
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
maximumLineCount: 2
|
||||||
|
wrapMode: Text.WordWrap
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
id: gridMouseArea
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
hoverEnabled: true
|
||||||
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
||||||
|
z: 10
|
||||||
|
onEntered: () => {
|
||||||
|
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) {
|
||||||
|
const modalPos = mapToItem(resultsContainer.parent, mouse.x, mouse.y)
|
||||||
|
resultsGrid.itemRightClicked(index, model, modalPos.x, modalPos.y)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,915 +0,0 @@
|
|||||||
import QtQuick
|
|
||||||
import QtQuick.Controls
|
|
||||||
import QtQuick.Effects
|
|
||||||
import Quickshell
|
|
||||||
import Quickshell.Io
|
|
||||||
import Quickshell.Widgets
|
|
||||||
import qs.Common
|
|
||||||
import qs.Modals.Common
|
|
||||||
import qs.Modules.AppDrawer
|
|
||||||
import qs.Services
|
|
||||||
import qs.Widgets
|
|
||||||
|
|
||||||
DankModal {
|
|
||||||
id: spotlightModal
|
|
||||||
|
|
||||||
property bool spotlightOpen: false
|
|
||||||
property Component spotlightContent
|
|
||||||
|
|
||||||
function show() {
|
|
||||||
spotlightOpen = true
|
|
||||||
open()
|
|
||||||
if (contentLoader.item && contentLoader.item.appLauncher)
|
|
||||||
contentLoader.item.appLauncher.searchQuery = ""
|
|
||||||
|
|
||||||
Qt.callLater(function () {
|
|
||||||
if (contentLoader.item && contentLoader.item.searchField)
|
|
||||||
contentLoader.item.searchField.forceActiveFocus()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
function hide() {
|
|
||||||
spotlightOpen = false
|
|
||||||
close()
|
|
||||||
if (contentLoader.item && contentLoader.item.appLauncher) {
|
|
||||||
contentLoader.item.appLauncher.searchQuery = ""
|
|
||||||
contentLoader.item.appLauncher.selectedIndex = 0
|
|
||||||
contentLoader.item.appLauncher.setCategory("All")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function toggle() {
|
|
||||||
if (spotlightOpen)
|
|
||||||
hide()
|
|
||||||
else
|
|
||||||
show()
|
|
||||||
}
|
|
||||||
|
|
||||||
shouldBeVisible: spotlightOpen
|
|
||||||
|
|
||||||
Connections {
|
|
||||||
target: ModalManager
|
|
||||||
function onCloseAllModalsExcept(excludedModal) {
|
|
||||||
if (excludedModal !== spotlightModal && !allowStacking
|
|
||||||
&& spotlightOpen) {
|
|
||||||
spotlightOpen = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
width: 550
|
|
||||||
height: 600
|
|
||||||
backgroundColor: Theme.popupBackground()
|
|
||||||
cornerRadius: Theme.cornerRadius
|
|
||||||
borderColor: Theme.outlineMedium
|
|
||||||
borderWidth: 1
|
|
||||||
enableShadow: true
|
|
||||||
onVisibleChanged: {
|
|
||||||
if (visible && !spotlightOpen)
|
|
||||||
show()
|
|
||||||
|
|
||||||
if (visible && contentLoader.item)
|
|
||||||
Qt.callLater(function () {
|
|
||||||
if (contentLoader.item.searchField)
|
|
||||||
contentLoader.item.searchField.forceActiveFocus()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
onBackgroundClicked: {
|
|
||||||
hide()
|
|
||||||
}
|
|
||||||
Component.onCompleted: {
|
|
||||||
|
|
||||||
}
|
|
||||||
content: spotlightContent
|
|
||||||
|
|
||||||
IpcHandler {
|
|
||||||
function open() {
|
|
||||||
spotlightModal.show()
|
|
||||||
return "SPOTLIGHT_OPEN_SUCCESS"
|
|
||||||
}
|
|
||||||
|
|
||||||
function close() {
|
|
||||||
spotlightModal.hide()
|
|
||||||
return "SPOTLIGHT_CLOSE_SUCCESS"
|
|
||||||
}
|
|
||||||
|
|
||||||
function toggle() {
|
|
||||||
spotlightModal.toggle()
|
|
||||||
return "SPOTLIGHT_TOGGLE_SUCCESS"
|
|
||||||
}
|
|
||||||
|
|
||||||
target: "spotlight"
|
|
||||||
}
|
|
||||||
|
|
||||||
spotlightContent: Component {
|
|
||||||
Item {
|
|
||||||
id: spotlightKeyHandler
|
|
||||||
|
|
||||||
property alias appLauncher: appLauncher
|
|
||||||
property alias searchField: searchField
|
|
||||||
|
|
||||||
anchors.fill: parent
|
|
||||||
focus: true
|
|
||||||
Keys.onPressed: function (event) {
|
|
||||||
if (event.key === Qt.Key_Escape) {
|
|
||||||
hide()
|
|
||||||
event.accepted = true
|
|
||||||
} else if (event.key === Qt.Key_Down) {
|
|
||||||
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 {
|
|
||||||
id: appLauncher
|
|
||||||
|
|
||||||
viewMode: SettingsData.spotlightModalViewMode
|
|
||||||
gridColumns: 4
|
|
||||||
onAppLaunched: hide()
|
|
||||||
onViewModeSelected: function (mode) {
|
|
||||||
SettingsData.setSpotlightModalViewMode(mode)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Column {
|
|
||||||
anchors.fill: parent
|
|
||||||
anchors.margins: Theme.spacingL
|
|
||||||
spacing: Theme.spacingL
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
width: parent.width
|
|
||||||
height: categorySelector.height + Theme.spacingM * 2
|
|
||||||
radius: Theme.cornerRadius
|
|
||||||
color: Theme.surfaceVariantAlpha
|
|
||||||
border.color: Theme.outlineMedium
|
|
||||||
border.width: 1
|
|
||||||
visible: appLauncher.categories.length > 1
|
|
||||||
|| appLauncher.model.count > 0
|
|
||||||
|
|
||||||
CategorySelector {
|
|
||||||
id: categorySelector
|
|
||||||
|
|
||||||
anchors.centerIn: parent
|
|
||||||
width: parent.width - Theme.spacingM * 2
|
|
||||||
categories: appLauncher.categories
|
|
||||||
selectedCategory: appLauncher.selectedCategory
|
|
||||||
compact: false
|
|
||||||
onCategorySelected: category => {
|
|
||||||
return appLauncher.setCategory(
|
|
||||||
category)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Row {
|
|
||||||
width: parent.width
|
|
||||||
spacing: Theme.spacingM
|
|
||||||
|
|
||||||
DankTextField {
|
|
||||||
id: searchField
|
|
||||||
|
|
||||||
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)
|
|
||||||
normalBorderColor: Theme.outlineMedium
|
|
||||||
focusedBorderColor: Theme.primary
|
|
||||||
leftIconName: "search"
|
|
||||||
leftIconSize: Theme.iconSize
|
|
||||||
leftIconColor: Theme.surfaceVariantText
|
|
||||||
leftIconFocusedColor: Theme.primary
|
|
||||||
showClearButton: true
|
|
||||||
textColor: Theme.surfaceText
|
|
||||||
font.pixelSize: Theme.fontSizeLarge
|
|
||||||
enabled: spotlightOpen
|
|
||||||
placeholderText: ""
|
|
||||||
ignoreLeftRightKeys: true
|
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Row {
|
|
||||||
spacing: Theme.spacingXS
|
|
||||||
visible: appLauncher.model.count > 0
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
width: 36
|
|
||||||
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.width: 1
|
|
||||||
|
|
||||||
DankIcon {
|
|
||||||
anchors.centerIn: parent
|
|
||||||
name: "view_list"
|
|
||||||
size: 18
|
|
||||||
color: appLauncher.viewMode
|
|
||||||
=== "list" ? Theme.primary : Theme.surfaceText
|
|
||||||
}
|
|
||||||
|
|
||||||
MouseArea {
|
|
||||||
id: listViewArea
|
|
||||||
|
|
||||||
anchors.fill: parent
|
|
||||||
hoverEnabled: true
|
|
||||||
cursorShape: Qt.PointingHandCursor
|
|
||||||
onClicked: {
|
|
||||||
appLauncher.setViewMode("list")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
width: 36
|
|
||||||
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.width: 1
|
|
||||||
|
|
||||||
DankIcon {
|
|
||||||
anchors.centerIn: parent
|
|
||||||
name: "grid_view"
|
|
||||||
size: 18
|
|
||||||
color: appLauncher.viewMode
|
|
||||||
=== "grid" ? Theme.primary : Theme.surfaceText
|
|
||||||
}
|
|
||||||
|
|
||||||
MouseArea {
|
|
||||||
id: gridViewArea
|
|
||||||
|
|
||||||
anchors.fill: parent
|
|
||||||
hoverEnabled: true
|
|
||||||
cursorShape: Qt.PointingHandCursor
|
|
||||||
onClicked: {
|
|
||||||
appLauncher.setViewMode("grid")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
id: resultsContainer
|
|
||||||
|
|
||||||
width: parent.width
|
|
||||||
height: parent.height - y
|
|
||||||
radius: Theme.cornerRadius
|
|
||||||
color: Theme.surfaceLight
|
|
||||||
border.color: Theme.outlineLight
|
|
||||||
border.width: 1
|
|
||||||
|
|
||||||
DankListView {
|
|
||||||
id: resultsList
|
|
||||||
|
|
||||||
property int itemHeight: 60
|
|
||||||
property int iconSize: 40
|
|
||||||
property bool showDescription: true
|
|
||||||
property int itemSpacing: Theme.spacingS
|
|
||||||
property bool hoverUpdatesSelection: false
|
|
||||||
property bool keyboardNavigationActive: appLauncher.keyboardNavigationActive
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
var itemY = index * (itemHeight + itemSpacing)
|
|
||||||
var itemBottom = itemY + itemHeight
|
|
||||||
if (itemY < contentY)
|
|
||||||
contentY = itemY
|
|
||||||
else if (itemBottom > contentY + height)
|
|
||||||
contentY = itemBottom - height
|
|
||||||
}
|
|
||||||
|
|
||||||
anchors.fill: parent
|
|
||||||
anchors.margins: Theme.spacingS
|
|
||||||
visible: appLauncher.viewMode === "list"
|
|
||||||
model: appLauncher.model
|
|
||||||
currentIndex: appLauncher.selectedIndex
|
|
||||||
clip: true
|
|
||||||
spacing: itemSpacing
|
|
||||||
focus: true
|
|
||||||
interactive: true
|
|
||||||
cacheBuffer: Math.max(0, Math.min(height * 2, 1000))
|
|
||||||
reuseItems: true
|
|
||||||
onCurrentIndexChanged: {
|
|
||||||
if (keyboardNavigationActive)
|
|
||||||
ensureVisible(currentIndex)
|
|
||||||
}
|
|
||||||
onItemClicked: function (index, modelData) {
|
|
||||||
appLauncher.launchApp(modelData)
|
|
||||||
}
|
|
||||||
onItemRightClicked: function (index, modelData, mouseX, mouseY) {
|
|
||||||
contextMenu.show(mouseX, mouseY, modelData)
|
|
||||||
}
|
|
||||||
onKeyboardNavigationReset: {
|
|
||||||
appLauncher.keyboardNavigationActive = false
|
|
||||||
}
|
|
||||||
|
|
||||||
ScrollBar.vertical: ScrollBar {
|
|
||||||
policy: ScrollBar.AlwaysOn
|
|
||||||
}
|
|
||||||
|
|
||||||
ScrollBar.horizontal: ScrollBar {
|
|
||||||
policy: ScrollBar.AlwaysOff
|
|
||||||
}
|
|
||||||
|
|
||||||
delegate: Rectangle {
|
|
||||||
width: ListView.view.width
|
|
||||||
height: resultsList.itemHeight
|
|
||||||
radius: Theme.cornerRadius
|
|
||||||
color: ListView.isCurrentItem ? Theme.primaryPressed : listMouseArea.containsMouse ? Theme.primaryHoverLight : Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.03)
|
|
||||||
border.color: ListView.isCurrentItem ? Theme.primarySelected : Theme.outlineMedium
|
|
||||||
border.width: ListView.isCurrentItem ? 2 : 1
|
|
||||||
|
|
||||||
Row {
|
|
||||||
anchors.fill: parent
|
|
||||||
anchors.margins: Theme.spacingM
|
|
||||||
spacing: Theme.spacingL
|
|
||||||
|
|
||||||
Item {
|
|
||||||
width: resultsList.iconSize
|
|
||||||
height: resultsList.iconSize
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
|
|
||||||
IconImage {
|
|
||||||
id: listIconImg
|
|
||||||
|
|
||||||
anchors.fill: parent
|
|
||||||
source: Quickshell.iconPath(model.icon, true)
|
|
||||||
asynchronous: true
|
|
||||||
visible: status === Image.Ready
|
|
||||||
}
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
anchors.fill: parent
|
|
||||||
visible: !listIconImg.visible
|
|
||||||
color: Theme.surfaceLight
|
|
||||||
radius: Theme.cornerRadius
|
|
||||||
border.width: 1
|
|
||||||
border.color: Theme.primarySelected
|
|
||||||
|
|
||||||
StyledText {
|
|
||||||
anchors.centerIn: parent
|
|
||||||
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 {
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
width: parent.width - resultsList.iconSize - Theme.spacingL
|
|
||||||
spacing: Theme.spacingXS
|
|
||||||
|
|
||||||
StyledText {
|
|
||||||
width: parent.width
|
|
||||||
text: model.name || ""
|
|
||||||
font.pixelSize: Theme.fontSizeLarge
|
|
||||||
color: Theme.surfaceText
|
|
||||||
font.weight: Font.Medium
|
|
||||||
elide: Text.ElideRight
|
|
||||||
}
|
|
||||||
|
|
||||||
StyledText {
|
|
||||||
width: parent.width
|
|
||||||
text: model.comment || "Application"
|
|
||||||
font.pixelSize: Theme.fontSizeMedium
|
|
||||||
color: Theme.surfaceVariantText
|
|
||||||
elide: Text.ElideRight
|
|
||||||
visible: resultsList.showDescription
|
|
||||||
&& model.comment
|
|
||||||
&& model.comment.length > 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
MouseArea {
|
|
||||||
id: listMouseArea
|
|
||||||
|
|
||||||
anchors.fill: parent
|
|
||||||
hoverEnabled: true
|
|
||||||
cursorShape: Qt.PointingHandCursor
|
|
||||||
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
|
||||||
z: 10
|
|
||||||
onEntered: {
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
DankGridView {
|
|
||||||
id: resultsGrid
|
|
||||||
|
|
||||||
property int currentIndex: appLauncher.selectedIndex
|
|
||||||
property int columns: 4
|
|
||||||
property bool adaptiveColumns: false
|
|
||||||
property int minCellWidth: 120
|
|
||||||
property int maxCellWidth: 160
|
|
||||||
property int cellPadding: 8
|
|
||||||
property real iconSizeRatio: 0.55
|
|
||||||
property int maxIconSize: 48
|
|
||||||
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 baseCellHeight: baseCellWidth + 20
|
|
||||||
property int actualColumns: adaptiveColumns ? Math.floor(
|
|
||||||
width
|
|
||||||
/ cellWidth) : columns
|
|
||||||
property int remainingSpace: width - (actualColumns * cellWidth)
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
var itemY = Math.floor(
|
|
||||||
index / actualColumns) * cellHeight
|
|
||||||
var itemBottom = itemY + cellHeight
|
|
||||||
if (itemY < contentY)
|
|
||||||
contentY = itemY
|
|
||||||
else if (itemBottom > contentY + height)
|
|
||||||
contentY = itemBottom - height
|
|
||||||
}
|
|
||||||
|
|
||||||
anchors.fill: parent
|
|
||||||
anchors.margins: Theme.spacingS
|
|
||||||
visible: appLauncher.viewMode === "grid"
|
|
||||||
model: appLauncher.model
|
|
||||||
clip: true
|
|
||||||
cellWidth: baseCellWidth
|
|
||||||
cellHeight: baseCellHeight
|
|
||||||
leftMargin: Math.max(Theme.spacingS, remainingSpace / 2)
|
|
||||||
rightMargin: leftMargin
|
|
||||||
focus: true
|
|
||||||
interactive: true
|
|
||||||
cacheBuffer: Math.max(0, Math.min(height * 2, 1000))
|
|
||||||
reuseItems: true
|
|
||||||
onCurrentIndexChanged: {
|
|
||||||
if (keyboardNavigationActive)
|
|
||||||
ensureVisible(currentIndex)
|
|
||||||
}
|
|
||||||
onItemClicked: function (index, modelData) {
|
|
||||||
appLauncher.launchApp(modelData)
|
|
||||||
}
|
|
||||||
onItemRightClicked: function (index, modelData, mouseX, mouseY) {
|
|
||||||
contextMenu.show(mouseX, mouseY, modelData)
|
|
||||||
}
|
|
||||||
onKeyboardNavigationReset: {
|
|
||||||
appLauncher.keyboardNavigationActive = false
|
|
||||||
}
|
|
||||||
|
|
||||||
ScrollBar.vertical: ScrollBar {
|
|
||||||
policy: ScrollBar.AsNeeded
|
|
||||||
}
|
|
||||||
|
|
||||||
ScrollBar.horizontal: ScrollBar {
|
|
||||||
policy: ScrollBar.AlwaysOff
|
|
||||||
}
|
|
||||||
|
|
||||||
delegate: Rectangle {
|
|
||||||
width: resultsGrid.cellWidth - resultsGrid.cellPadding
|
|
||||||
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.width: resultsGrid.currentIndex === index ? 2 : 1
|
|
||||||
|
|
||||||
Column {
|
|
||||||
anchors.centerIn: parent
|
|
||||||
spacing: Theme.spacingS
|
|
||||||
|
|
||||||
Item {
|
|
||||||
property int iconSize: Math.min(
|
|
||||||
resultsGrid.maxIconSize,
|
|
||||||
Math.max(
|
|
||||||
resultsGrid.minIconSize,
|
|
||||||
resultsGrid.cellWidth
|
|
||||||
* resultsGrid.iconSizeRatio))
|
|
||||||
|
|
||||||
width: iconSize
|
|
||||||
height: iconSize
|
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
|
||||||
|
|
||||||
IconImage {
|
|
||||||
id: gridIconImg
|
|
||||||
|
|
||||||
anchors.fill: parent
|
|
||||||
source: Quickshell.iconPath(model.icon, true)
|
|
||||||
smooth: true
|
|
||||||
asynchronous: true
|
|
||||||
visible: status === Image.Ready
|
|
||||||
}
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
anchors.fill: parent
|
|
||||||
visible: !gridIconImg.visible
|
|
||||||
color: Theme.surfaceLight
|
|
||||||
radius: Theme.cornerRadius
|
|
||||||
border.width: 1
|
|
||||||
border.color: Theme.primarySelected
|
|
||||||
|
|
||||||
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)
|
|
||||||
color: Theme.primary
|
|
||||||
font.weight: Font.Bold
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
StyledText {
|
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
|
||||||
width: resultsGrid.cellWidth - 12
|
|
||||||
text: model.name || ""
|
|
||||||
font.pixelSize: Theme.fontSizeSmall
|
|
||||||
color: Theme.surfaceText
|
|
||||||
font.weight: Font.Medium
|
|
||||||
elide: Text.ElideRight
|
|
||||||
horizontalAlignment: Text.AlignHCenter
|
|
||||||
maximumLineCount: 2
|
|
||||||
wrapMode: Text.WordWrap
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
MouseArea {
|
|
||||||
id: gridMouseArea
|
|
||||||
|
|
||||||
anchors.fill: parent
|
|
||||||
hoverEnabled: true
|
|
||||||
cursorShape: Qt.PointingHandCursor
|
|
||||||
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
|
||||||
z: 10
|
|
||||||
onEntered: {
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
id: contextMenu
|
|
||||||
|
|
||||||
property var currentApp: null
|
|
||||||
property bool menuVisible: false
|
|
||||||
|
|
||||||
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))
|
|
||||||
|
|
||||||
contextMenu.x = finalX
|
|
||||||
contextMenu.y = finalY
|
|
||||||
contextMenu.visible = true
|
|
||||||
contextMenu.menuVisible = true
|
|
||||||
}
|
|
||||||
|
|
||||||
function close() {
|
|
||||||
contextMenu.menuVisible = false
|
|
||||||
Qt.callLater(() => {
|
|
||||||
contextMenu.visible = false
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
visible: false
|
|
||||||
width: 180
|
|
||||||
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.width: 1
|
|
||||||
z: 1000
|
|
||||||
opacity: menuVisible ? 1 : 0
|
|
||||||
scale: menuVisible ? 1 : 0.85
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
anchors.fill: parent
|
|
||||||
anchors.topMargin: 4
|
|
||||||
anchors.leftMargin: 2
|
|
||||||
anchors.rightMargin: -2
|
|
||||||
anchors.bottomMargin: -4
|
|
||||||
radius: parent.radius
|
|
||||||
color: Qt.rgba(0, 0, 0, 0.15)
|
|
||||||
z: parent.z - 1
|
|
||||||
}
|
|
||||||
|
|
||||||
Column {
|
|
||||||
id: menuColumn
|
|
||||||
|
|
||||||
anchors.fill: parent
|
|
||||||
anchors.margins: Theme.spacingS
|
|
||||||
spacing: 1
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
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"
|
|
||||||
|
|
||||||
Row {
|
|
||||||
anchors.left: parent.left
|
|
||||||
anchors.leftMargin: Theme.spacingS
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
spacing: Theme.spacingS
|
|
||||||
|
|
||||||
DankIcon {
|
|
||||||
name: {
|
|
||||||
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"
|
|
||||||
}
|
|
||||||
size: Theme.iconSize - 2
|
|
||||||
color: Theme.surfaceText
|
|
||||||
opacity: 0.7
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
}
|
|
||||||
|
|
||||||
StyledText {
|
|
||||||
text: {
|
|
||||||
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"
|
|
||||||
}
|
|
||||||
font.pixelSize: Theme.fontSizeSmall
|
|
||||||
color: Theme.surfaceText
|
|
||||||
font.weight: Font.Normal
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
MouseArea {
|
|
||||||
id: pinMouseArea
|
|
||||||
|
|
||||||
anchors.fill: parent
|
|
||||||
hoverEnabled: true
|
|
||||||
cursorShape: Qt.PointingHandCursor
|
|
||||||
onClicked: {
|
|
||||||
if (!contextMenu.currentApp
|
|
||||||
|| !contextMenu.currentApp.desktopEntry)
|
|
||||||
return
|
|
||||||
|
|
||||||
var appId = contextMenu.currentApp.desktopEntry.id
|
|
||||||
|| contextMenu.currentApp.desktopEntry.execString
|
|
||||||
|| ""
|
|
||||||
if (SessionData.isPinnedApp(appId))
|
|
||||||
SessionData.removePinnedApp(appId)
|
|
||||||
else
|
|
||||||
SessionData.addPinnedApp(appId)
|
|
||||||
contextMenu.close()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
width: parent.width - Theme.spacingS * 2
|
|
||||||
height: 5
|
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
|
||||||
color: "transparent"
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
anchors.centerIn: parent
|
|
||||||
width: parent.width
|
|
||||||
height: 1
|
|
||||||
color: Qt.rgba(Theme.outline.r, Theme.outline.g,
|
|
||||||
Theme.outline.b, 0.2)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
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"
|
|
||||||
|
|
||||||
Row {
|
|
||||||
anchors.left: parent.left
|
|
||||||
anchors.leftMargin: Theme.spacingS
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
spacing: Theme.spacingS
|
|
||||||
|
|
||||||
DankIcon {
|
|
||||||
name: "launch"
|
|
||||||
size: Theme.iconSize - 2
|
|
||||||
color: Theme.surfaceText
|
|
||||||
opacity: 0.7
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
}
|
|
||||||
|
|
||||||
StyledText {
|
|
||||||
text: "Launch"
|
|
||||||
font.pixelSize: Theme.fontSizeSmall
|
|
||||||
color: Theme.surfaceText
|
|
||||||
font.weight: Font.Normal
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
MouseArea {
|
|
||||||
id: launchMouseArea
|
|
||||||
|
|
||||||
anchors.fill: parent
|
|
||||||
hoverEnabled: true
|
|
||||||
cursorShape: Qt.PointingHandCursor
|
|
||||||
onClicked: {
|
|
||||||
if (contextMenu.currentApp)
|
|
||||||
appLauncher.launchApp(
|
|
||||||
contextMenu.currentApp)
|
|
||||||
|
|
||||||
contextMenu.close()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Behavior on opacity {
|
|
||||||
NumberAnimation {
|
|
||||||
duration: Theme.mediumDuration
|
|
||||||
easing.type: Theme.emphasizedEasing
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Behavior on scale {
|
|
||||||
NumberAnimation {
|
|
||||||
duration: Theme.mediumDuration
|
|
||||||
easing.type: Theme.emphasizedEasing
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
MouseArea {
|
|
||||||
anchors.fill: parent
|
|
||||||
visible: contextMenu.visible
|
|
||||||
z: 999
|
|
||||||
onClicked: {
|
|
||||||
contextMenu.close()
|
|
||||||
}
|
|
||||||
|
|
||||||
MouseArea {
|
|
||||||
x: contextMenu.x
|
|
||||||
y: contextMenu.y
|
|
||||||
width: contextMenu.width
|
|
||||||
height: contextMenu.height
|
|
||||||
onClicked: {
|
|
||||||
|
|
||||||
// Prevent closing when clicking on the menu itself
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Controls
|
|
||||||
import qs.Common
|
import qs.Common
|
||||||
import qs.Modals.Common
|
import qs.Modals.Common
|
||||||
import qs.Services
|
import qs.Services
|
||||||
@@ -15,58 +14,56 @@ DankModal {
|
|||||||
wifiPasswordSSID = ssid
|
wifiPasswordSSID = ssid
|
||||||
wifiPasswordInput = ""
|
wifiPasswordInput = ""
|
||||||
open()
|
open()
|
||||||
Qt.callLater(function () {
|
Qt.callLater(() => {
|
||||||
if (contentLoader.item && contentLoader.item.passwordInput) {
|
if (contentLoader.item && contentLoader.item.passwordInput)
|
||||||
contentLoader.item.passwordInput.forceActiveFocus()
|
contentLoader.item.passwordInput.forceActiveFocus()
|
||||||
}
|
})
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
shouldBeVisible: false
|
shouldBeVisible: false
|
||||||
width: 420
|
width: 420
|
||||||
height: 230
|
height: 230
|
||||||
onShouldBeVisibleChanged: {
|
onShouldBeVisibleChanged: () => {
|
||||||
if (!shouldBeVisible)
|
if (!shouldBeVisible)
|
||||||
wifiPasswordInput = ""
|
wifiPasswordInput = ""
|
||||||
}
|
}
|
||||||
onOpened: {
|
onOpened: {
|
||||||
Qt.callLater(function () {
|
Qt.callLater(() => {
|
||||||
if (contentLoader.item && contentLoader.item.passwordInput) {
|
if (contentLoader.item && contentLoader.item.passwordInput)
|
||||||
contentLoader.item.passwordInput.forceActiveFocus()
|
contentLoader.item.passwordInput.forceActiveFocus()
|
||||||
}
|
})
|
||||||
})
|
|
||||||
}
|
|
||||||
onBackgroundClicked: {
|
|
||||||
close()
|
|
||||||
wifiPasswordInput = ""
|
|
||||||
}
|
}
|
||||||
|
onBackgroundClicked: () => {
|
||||||
|
close()
|
||||||
|
wifiPasswordInput = ""
|
||||||
|
}
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
|
target: NetworkService
|
||||||
|
|
||||||
function onPasswordDialogShouldReopenChanged() {
|
function onPasswordDialogShouldReopenChanged() {
|
||||||
if (NetworkService.passwordDialogShouldReopen
|
if (NetworkService.passwordDialogShouldReopen && NetworkService.connectingSSID !== "") {
|
||||||
&& NetworkService.connectingSSID !== "") {
|
|
||||||
wifiPasswordSSID = NetworkService.connectingSSID
|
wifiPasswordSSID = NetworkService.connectingSSID
|
||||||
wifiPasswordInput = ""
|
wifiPasswordInput = ""
|
||||||
open()
|
open()
|
||||||
NetworkService.passwordDialogShouldReopen = false
|
NetworkService.passwordDialogShouldReopen = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
target: NetworkService
|
|
||||||
}
|
}
|
||||||
|
|
||||||
content: Component {
|
content: Component {
|
||||||
FocusScope {
|
FocusScope {
|
||||||
id: wifiContent
|
id: wifiContent
|
||||||
|
|
||||||
property alias passwordInput: passwordInput
|
property alias passwordInput: passwordInput
|
||||||
|
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
focus: true
|
focus: true
|
||||||
Keys.onEscapePressed: function (event) {
|
Keys.onEscapePressed: event => {
|
||||||
close()
|
close()
|
||||||
wifiPasswordInput = ""
|
wifiPasswordInput = ""
|
||||||
event.accepted = true
|
event.accepted = true
|
||||||
}
|
}
|
||||||
|
|
||||||
Column {
|
Column {
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
@@ -88,7 +85,7 @@ DankModal {
|
|||||||
}
|
}
|
||||||
|
|
||||||
StyledText {
|
StyledText {
|
||||||
text: "Enter password for \"" + wifiPasswordSSID + "\""
|
text: `Enter password for "${wifiPasswordSSID}"`
|
||||||
font.pixelSize: Theme.fontSizeMedium
|
font.pixelSize: Theme.fontSizeMedium
|
||||||
color: Theme.surfaceTextMedium
|
color: Theme.surfaceTextMedium
|
||||||
width: parent.width
|
width: parent.width
|
||||||
@@ -101,10 +98,10 @@ DankModal {
|
|||||||
iconSize: Theme.iconSize - 4
|
iconSize: Theme.iconSize - 4
|
||||||
iconColor: Theme.surfaceText
|
iconColor: Theme.surfaceText
|
||||||
hoverColor: Theme.errorHover
|
hoverColor: Theme.errorHover
|
||||||
onClicked: {
|
onClicked: () => {
|
||||||
close()
|
close()
|
||||||
wifiPasswordInput = ""
|
wifiPasswordInput = ""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -118,9 +115,9 @@ DankModal {
|
|||||||
|
|
||||||
MouseArea {
|
MouseArea {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
onClicked: {
|
onClicked: () => {
|
||||||
passwordInput.forceActiveFocus()
|
passwordInput.forceActiveFocus()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DankTextField {
|
DankTextField {
|
||||||
@@ -135,40 +132,37 @@ DankModal {
|
|||||||
backgroundColor: "transparent"
|
backgroundColor: "transparent"
|
||||||
focus: true
|
focus: true
|
||||||
enabled: root.shouldBeVisible
|
enabled: root.shouldBeVisible
|
||||||
onTextEdited: {
|
onTextEdited: () => {
|
||||||
wifiPasswordInput = text
|
wifiPasswordInput = text
|
||||||
}
|
}
|
||||||
onAccepted: {
|
onAccepted: () => {
|
||||||
NetworkService.connectToWifi(
|
NetworkService.connectToWifi(wifiPasswordSSID, passwordInput.text)
|
||||||
wifiPasswordSSID, passwordInput.text)
|
close()
|
||||||
close()
|
wifiPasswordInput = ""
|
||||||
wifiPasswordInput = ""
|
passwordInput.text = ""
|
||||||
passwordInput.text = ""
|
}
|
||||||
}
|
Component.onCompleted: () => {
|
||||||
|
if (root.shouldBeVisible)
|
||||||
Component.onCompleted: {
|
focusDelayTimer.start()
|
||||||
if (root.shouldBeVisible) {
|
}
|
||||||
focusDelayTimer.start()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Timer {
|
Timer {
|
||||||
id: focusDelayTimer
|
id: focusDelayTimer
|
||||||
|
|
||||||
interval: 100
|
interval: 100
|
||||||
repeat: false
|
repeat: false
|
||||||
onTriggered: {
|
onTriggered: () => {
|
||||||
if (root.shouldBeVisible) {
|
if (root.shouldBeVisible)
|
||||||
passwordInput.forceActiveFocus()
|
passwordInput.forceActiveFocus()
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
target: root
|
target: root
|
||||||
|
|
||||||
function onShouldBeVisibleChanged() {
|
function onShouldBeVisibleChanged() {
|
||||||
if (root.shouldBeVisible) {
|
if (root.shouldBeVisible)
|
||||||
focusDelayTimer.start()
|
focusDelayTimer.start()
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -201,9 +195,9 @@ DankModal {
|
|||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
hoverEnabled: true
|
hoverEnabled: true
|
||||||
cursorShape: Qt.PointingHandCursor
|
cursorShape: Qt.PointingHandCursor
|
||||||
onClicked: {
|
onClicked: () => {
|
||||||
showPasswordCheckbox.checked = !showPasswordCheckbox.checked
|
showPasswordCheckbox.checked = !showPasswordCheckbox.checked
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -225,9 +219,7 @@ DankModal {
|
|||||||
spacing: Theme.spacingM
|
spacing: Theme.spacingM
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
width: Math.max(
|
width: Math.max(70, cancelText.contentWidth + Theme.spacingM * 2)
|
||||||
70,
|
|
||||||
cancelText.contentWidth + Theme.spacingM * 2)
|
|
||||||
height: 36
|
height: 36
|
||||||
radius: Theme.cornerRadius
|
radius: Theme.cornerRadius
|
||||||
color: cancelArea.containsMouse ? Theme.surfaceTextHover : "transparent"
|
color: cancelArea.containsMouse ? Theme.surfaceTextHover : "transparent"
|
||||||
@@ -250,22 +242,18 @@ DankModal {
|
|||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
hoverEnabled: true
|
hoverEnabled: true
|
||||||
cursorShape: Qt.PointingHandCursor
|
cursorShape: Qt.PointingHandCursor
|
||||||
onClicked: {
|
onClicked: () => {
|
||||||
close()
|
close()
|
||||||
wifiPasswordInput = ""
|
wifiPasswordInput = ""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
width: Math.max(
|
width: Math.max(80, connectText.contentWidth + Theme.spacingM * 2)
|
||||||
80,
|
|
||||||
connectText.contentWidth + Theme.spacingM * 2)
|
|
||||||
height: 36
|
height: 36
|
||||||
radius: Theme.cornerRadius
|
radius: Theme.cornerRadius
|
||||||
color: connectArea.containsMouse ? Qt.darker(
|
color: connectArea.containsMouse ? Qt.darker(Theme.primary, 1.1) : Theme.primary
|
||||||
Theme.primary,
|
|
||||||
1.1) : Theme.primary
|
|
||||||
enabled: passwordInput.text.length > 0
|
enabled: passwordInput.text.length > 0
|
||||||
opacity: enabled ? 1 : 0.5
|
opacity: enabled ? 1 : 0.5
|
||||||
|
|
||||||
@@ -286,14 +274,12 @@ DankModal {
|
|||||||
hoverEnabled: true
|
hoverEnabled: true
|
||||||
cursorShape: Qt.PointingHandCursor
|
cursorShape: Qt.PointingHandCursor
|
||||||
enabled: parent.enabled
|
enabled: parent.enabled
|
||||||
onClicked: {
|
onClicked: () => {
|
||||||
NetworkService.connectToWifi(
|
NetworkService.connectToWifi(wifiPasswordSSID, passwordInput.text)
|
||||||
wifiPasswordSSID,
|
close()
|
||||||
passwordInput.text)
|
wifiPasswordInput = ""
|
||||||
close()
|
passwordInput.text = ""
|
||||||
wifiPasswordInput = ""
|
}
|
||||||
passwordInput.text = ""
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Behavior on color {
|
Behavior on color {
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ import qs.Common
|
|||||||
import qs.Modals
|
import qs.Modals
|
||||||
import qs.Modals.Common
|
import qs.Modals.Common
|
||||||
import qs.Modals.Clipboard
|
import qs.Modals.Clipboard
|
||||||
|
import qs.Modals.Settings
|
||||||
|
import qs.Modals.Spotlight
|
||||||
import qs.Modules
|
import qs.Modules
|
||||||
import qs.Modules.AppDrawer
|
import qs.Modules.AppDrawer
|
||||||
import qs.Modules.CentcomCenter
|
import qs.Modules.CentcomCenter
|
||||||
|
|||||||
Reference in New Issue
Block a user