mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2025-12-06 21:45:38 -05:00
launcher: sort by usage frequency
This commit is contained in:
399
Modules/Settings/LauncherTab.qml
Normal file
399
Modules/Settings/LauncherTab.qml
Normal file
@@ -0,0 +1,399 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import Quickshell.Widgets
|
||||
import qs.Common
|
||||
import qs.Widgets
|
||||
|
||||
ScrollView {
|
||||
id: launcherTab
|
||||
|
||||
contentWidth: availableWidth
|
||||
contentHeight: column.implicitHeight + Theme.spacingXL
|
||||
clip: true
|
||||
|
||||
Column {
|
||||
id: column
|
||||
|
||||
width: parent.width
|
||||
spacing: Theme.spacingXL
|
||||
topPadding: Theme.spacingL
|
||||
bottomPadding: Theme.spacingXL
|
||||
|
||||
StyledRect {
|
||||
width: parent.width
|
||||
height: appLauncherSection.implicitHeight + Theme.spacingL * 2
|
||||
radius: Theme.cornerRadiusLarge
|
||||
color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.3)
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
|
||||
border.width: 1
|
||||
|
||||
Column {
|
||||
id: appLauncherSection
|
||||
|
||||
anchors.fill: parent
|
||||
anchors.margins: Theme.spacingL
|
||||
spacing: Theme.spacingM
|
||||
|
||||
Row {
|
||||
width: parent.width
|
||||
spacing: Theme.spacingM
|
||||
|
||||
DankIcon {
|
||||
name: "apps"
|
||||
size: Theme.iconSize
|
||||
color: Theme.primary
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: "App Launcher"
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
font.weight: Font.Medium
|
||||
color: Theme.surfaceText
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
DankToggle {
|
||||
width: parent.width
|
||||
text: "Use OS Logo for App Launcher"
|
||||
description: "Display operating system logo instead of apps icon"
|
||||
checked: Prefs.useOSLogo
|
||||
onToggled: (checked) => {
|
||||
return Prefs.setUseOSLogo(checked);
|
||||
}
|
||||
}
|
||||
|
||||
StyledRect {
|
||||
width: parent.width
|
||||
height: logoCustomization.implicitHeight + Theme.spacingM * 2
|
||||
radius: Theme.cornerRadius
|
||||
color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.5)
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.3)
|
||||
border.width: 1
|
||||
visible: Prefs.useOSLogo
|
||||
opacity: visible ? 1 : 0
|
||||
|
||||
Column {
|
||||
id: logoCustomization
|
||||
|
||||
anchors.fill: parent
|
||||
anchors.margins: Theme.spacingM
|
||||
spacing: Theme.spacingM
|
||||
|
||||
StyledText {
|
||||
text: "OS Logo Customization"
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
}
|
||||
|
||||
Column {
|
||||
width: parent.width
|
||||
spacing: Theme.spacingS
|
||||
|
||||
StyledText {
|
||||
text: "Color Override"
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
}
|
||||
|
||||
DankTextField {
|
||||
width: 160
|
||||
height: 36
|
||||
placeholderText: "#ffffff"
|
||||
text: Prefs.osLogoColorOverride
|
||||
maximumLength: 7
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
topPadding: Theme.spacingS
|
||||
bottomPadding: Theme.spacingS
|
||||
onEditingFinished: {
|
||||
var color = text.trim();
|
||||
if (color === "" || /^#[0-9A-Fa-f]{6}$/.test(color))
|
||||
Prefs.setOSLogoColorOverride(color);
|
||||
else
|
||||
text = Prefs.osLogoColorOverride;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Column {
|
||||
width: parent.width
|
||||
spacing: Theme.spacingS
|
||||
|
||||
StyledText {
|
||||
text: "Brightness"
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
}
|
||||
|
||||
DankSlider {
|
||||
width: parent.width
|
||||
height: 24
|
||||
minimum: 0
|
||||
maximum: 100
|
||||
value: Math.round(Prefs.osLogoBrightness * 100)
|
||||
unit: ""
|
||||
showValue: true
|
||||
onSliderValueChanged: (newValue) => {
|
||||
Prefs.setOSLogoBrightness(newValue / 100);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Column {
|
||||
width: parent.width
|
||||
spacing: Theme.spacingS
|
||||
|
||||
StyledText {
|
||||
text: "Contrast"
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
}
|
||||
|
||||
DankSlider {
|
||||
width: parent.width
|
||||
height: 24
|
||||
minimum: 0
|
||||
maximum: 200
|
||||
value: Math.round(Prefs.osLogoContrast * 100)
|
||||
unit: ""
|
||||
showValue: true
|
||||
onSliderValueChanged: (newValue) => {
|
||||
Prefs.setOSLogoContrast(newValue / 100);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
duration: Theme.mediumDuration
|
||||
easing.type: Theme.emphasizedEasing
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
StyledRect {
|
||||
width: parent.width
|
||||
height: recentlyUsedSection.implicitHeight + Theme.spacingL * 2
|
||||
radius: Theme.cornerRadiusLarge
|
||||
color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.3)
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
|
||||
border.width: 1
|
||||
|
||||
Column {
|
||||
id: recentlyUsedSection
|
||||
|
||||
property var rankedAppsModel: {
|
||||
var apps = [];
|
||||
for (var appId in Prefs.appUsageRanking) {
|
||||
var appData = Prefs.appUsageRanking[appId];
|
||||
apps.push({
|
||||
"id": appId,
|
||||
"name": appData.name,
|
||||
"exec": appData.exec,
|
||||
"icon": appData.icon,
|
||||
"comment": appData.comment,
|
||||
"usageCount": appData.usageCount,
|
||||
"lastUsed": appData.lastUsed
|
||||
});
|
||||
}
|
||||
apps.sort(function(a, b) {
|
||||
if (a.usageCount !== b.usageCount)
|
||||
return b.usageCount - a.usageCount;
|
||||
|
||||
return a.name.localeCompare(b.name);
|
||||
});
|
||||
return apps.slice(0, 20);
|
||||
}
|
||||
|
||||
anchors.fill: parent
|
||||
anchors.margins: Theme.spacingL
|
||||
spacing: Theme.spacingM
|
||||
|
||||
Row {
|
||||
width: parent.width
|
||||
spacing: Theme.spacingM
|
||||
|
||||
DankIcon {
|
||||
name: "history"
|
||||
size: Theme.iconSize
|
||||
color: Theme.primary
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: "Recently Used Apps"
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
font.weight: Font.Medium
|
||||
color: Theme.surfaceText
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
Item {
|
||||
width: parent.width - parent.children[0].width - parent.children[1].width - clearAllButton.width - Theme.spacingM * 3
|
||||
height: 1
|
||||
}
|
||||
|
||||
DankActionButton {
|
||||
id: clearAllButton
|
||||
|
||||
iconName: "delete_sweep"
|
||||
iconSize: Theme.iconSize - 2
|
||||
iconColor: Theme.error
|
||||
hoverColor: Qt.rgba(Theme.error.r, Theme.error.g, Theme.error.b, 0.12)
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
onClicked: {
|
||||
Prefs.appUsageRanking = {
|
||||
};
|
||||
Prefs.saveSettings();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
StyledText {
|
||||
width: parent.width
|
||||
text: "Apps are ordered by usage frequency, then alphabetically."
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceVariantText
|
||||
wrapMode: Text.WordWrap
|
||||
}
|
||||
|
||||
Column {
|
||||
id: rankedAppsList
|
||||
|
||||
width: parent.width
|
||||
spacing: Theme.spacingS
|
||||
|
||||
Repeater {
|
||||
model: recentlyUsedSection.rankedAppsModel
|
||||
|
||||
delegate: Rectangle {
|
||||
width: rankedAppsList.width
|
||||
height: 48
|
||||
radius: Theme.cornerRadius
|
||||
color: Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, 0.3)
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.1)
|
||||
border.width: 1
|
||||
|
||||
Row {
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: Theme.spacingM
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: Theme.spacingM
|
||||
|
||||
StyledText {
|
||||
text: (index + 1).toString()
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
font.weight: Font.Medium
|
||||
color: Theme.primary
|
||||
width: 20
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
Image {
|
||||
width: 24
|
||||
height: 24
|
||||
source: modelData.icon ? "image://icon/" + modelData.icon : "image://icon/application-x-executable"
|
||||
sourceSize.width: 24
|
||||
sourceSize.height: 24
|
||||
fillMode: Image.PreserveAspectFit
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
onStatusChanged: {
|
||||
if (status === Image.Error)
|
||||
source = "image://icon/application-x-executable";
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: 2
|
||||
|
||||
StyledText {
|
||||
text: modelData.name || "Unknown App"
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
font.weight: Font.Medium
|
||||
color: Theme.surfaceText
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: {
|
||||
if (!modelData.lastUsed) return "Never used";
|
||||
var date = new Date(modelData.lastUsed);
|
||||
var now = new Date();
|
||||
var diffMs = now - date;
|
||||
var diffMins = Math.floor(diffMs / (1000 * 60));
|
||||
var diffHours = Math.floor(diffMs / (1000 * 60 * 60));
|
||||
var diffDays = Math.floor(diffMs / (1000 * 60 * 60 * 24));
|
||||
|
||||
if (diffMins < 1) return "Last launched just now";
|
||||
if (diffMins < 60) return "Last launched " + diffMins + " minute" + (diffMins === 1 ? "" : "s") + " ago";
|
||||
if (diffHours < 24) return "Last launched " + diffHours + " hour" + (diffHours === 1 ? "" : "s") + " ago";
|
||||
if (diffDays < 7) return "Last launched " + diffDays + " day" + (diffDays === 1 ? "" : "s") + " ago";
|
||||
|
||||
return "Last launched " + date.toLocaleDateString();
|
||||
}
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceVariantText
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
DankActionButton {
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: Theme.spacingM
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
circular: true
|
||||
iconName: "close"
|
||||
iconSize: 16
|
||||
iconColor: Theme.error
|
||||
hoverColor: Qt.rgba(Theme.error.r, Theme.error.g, Theme.error.b, 0.12)
|
||||
onClicked: {
|
||||
var currentRanking = Object.assign({}, Prefs.appUsageRanking);
|
||||
delete currentRanking[modelData.id];
|
||||
Prefs.appUsageRanking = currentRanking;
|
||||
Prefs.saveSettings();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
StyledText {
|
||||
width: parent.width
|
||||
text: recentlyUsedSection.rankedAppsModel.length === 0 ? "No apps have been launched yet." : ""
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: Theme.surfaceVariantText
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
visible: recentlyUsedSection.rankedAppsModel.length === 0
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -170,165 +170,5 @@ ScrollView {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// App Launcher Section
|
||||
StyledRect {
|
||||
width: parent.width
|
||||
height: appLauncherSection.implicitHeight + Theme.spacingL * 2
|
||||
radius: Theme.cornerRadiusLarge
|
||||
color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.3)
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
|
||||
border.width: 1
|
||||
|
||||
Column {
|
||||
id: appLauncherSection
|
||||
anchors.fill: parent
|
||||
anchors.margins: Theme.spacingL
|
||||
spacing: Theme.spacingM
|
||||
|
||||
Row {
|
||||
width: parent.width
|
||||
spacing: Theme.spacingM
|
||||
|
||||
DankIcon {
|
||||
name: "apps"
|
||||
size: Theme.iconSize
|
||||
color: Theme.primary
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: "App Launcher"
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
font.weight: Font.Medium
|
||||
color: Theme.surfaceText
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
}
|
||||
|
||||
DankToggle {
|
||||
width: parent.width
|
||||
text: "Use OS Logo for App Launcher"
|
||||
description: "Display operating system logo instead of apps icon"
|
||||
checked: Prefs.useOSLogo
|
||||
onToggled: (checked) => {
|
||||
return Prefs.setUseOSLogo(checked);
|
||||
}
|
||||
}
|
||||
|
||||
// OS Logo Customization - only visible when OS logo is enabled
|
||||
StyledRect {
|
||||
width: parent.width
|
||||
height: logoCustomization.implicitHeight + Theme.spacingM * 2
|
||||
radius: Theme.cornerRadius
|
||||
color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.5)
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.3)
|
||||
border.width: 1
|
||||
visible: Prefs.useOSLogo
|
||||
opacity: visible ? 1 : 0
|
||||
|
||||
Column {
|
||||
id: logoCustomization
|
||||
anchors.fill: parent
|
||||
anchors.margins: Theme.spacingM
|
||||
spacing: Theme.spacingM
|
||||
|
||||
StyledText {
|
||||
text: "OS Logo Customization"
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
}
|
||||
|
||||
Column {
|
||||
width: parent.width
|
||||
spacing: Theme.spacingS
|
||||
|
||||
StyledText {
|
||||
text: "Color Override"
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
}
|
||||
|
||||
DankTextField {
|
||||
width: 160
|
||||
height: 36
|
||||
placeholderText: "#ffffff"
|
||||
text: Prefs.osLogoColorOverride
|
||||
maximumLength: 7
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
topPadding: Theme.spacingS
|
||||
bottomPadding: Theme.spacingS
|
||||
onEditingFinished: {
|
||||
var color = text.trim();
|
||||
if (color === "" || /^#[0-9A-Fa-f]{6}$/.test(color))
|
||||
Prefs.setOSLogoColorOverride(color);
|
||||
else
|
||||
text = Prefs.osLogoColorOverride;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
width: parent.width
|
||||
spacing: Theme.spacingS
|
||||
|
||||
StyledText {
|
||||
text: "Brightness"
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
}
|
||||
|
||||
DankSlider {
|
||||
width: parent.width
|
||||
height: 24
|
||||
minimum: 0
|
||||
maximum: 100
|
||||
value: Math.round(Prefs.osLogoBrightness * 100)
|
||||
unit: ""
|
||||
showValue: true
|
||||
onSliderValueChanged: (newValue) => {
|
||||
Prefs.setOSLogoBrightness(newValue / 100);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
width: parent.width
|
||||
spacing: Theme.spacingS
|
||||
|
||||
StyledText {
|
||||
text: "Contrast"
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
}
|
||||
|
||||
DankSlider {
|
||||
width: parent.width
|
||||
height: 24
|
||||
minimum: 0
|
||||
maximum: 200
|
||||
value: Math.round(Prefs.osLogoContrast * 100)
|
||||
unit: ""
|
||||
showValue: true
|
||||
onSliderValueChanged: (newValue) => {
|
||||
Prefs.setOSLogoContrast(newValue / 100);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
duration: Theme.mediumDuration
|
||||
easing.type: Theme.emphasizedEasing
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user