1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2026-04-03 20:32:07 -04:00

uncomment toast, and format

This commit is contained in:
bbedward
2025-07-24 19:46:05 -04:00
parent 762785b27a
commit fc52aa2c7a
21 changed files with 575 additions and 427 deletions

View File

@@ -6,9 +6,9 @@ import Quickshell.Io
import Quickshell.Wayland
import Quickshell.Widgets
import qs.Common
import qs.Modules.AppDrawer
import qs.Services
import qs.Widgets
import qs.Modules.AppDrawer
PanelWindow {
id: appDrawerPopout
@@ -53,7 +53,6 @@ PanelWindow {
viewMode: Prefs.appLauncherViewMode
gridColumns: 4
onAppLaunched: appDrawerPopout.hide()
onViewModeSelected: function(mode) {
Prefs.setAppLauncherViewMode(mode);
@@ -67,24 +66,22 @@ PanelWindow {
onClicked: function(mouse) {
// Only close if click is outside the launcher panel
var localPos = mapToItem(launcherLoader, mouse.x, mouse.y);
if (localPos.x < 0 || localPos.x > launcherLoader.width ||
localPos.y < 0 || localPos.y > launcherLoader.height) {
if (localPos.x < 0 || localPos.x > launcherLoader.width || localPos.y < 0 || localPos.y > launcherLoader.height)
appDrawerPopout.hide();
}
}
}
// Main launcher panel with asynchronous loading
Loader {
id: launcherLoader
asynchronous: true
active: appDrawerPopout.isVisible
width: 520
height: 600
x: Theme.spacingL
y: Theme.barHeight + Theme.spacingXS
opacity: appDrawerPopout.isVisible ? 1 : 0
scale: appDrawerPopout.isVisible ? 1 : 0.9
@@ -94,6 +91,7 @@ PanelWindow {
easing.type: Easing.BezierSpline
easing.bezierCurve: Anims.emphasized
}
}
Behavior on scale {
@@ -102,13 +100,14 @@ PanelWindow {
easing.type: Easing.BezierSpline
easing.bezierCurve: Anims.emphasized
}
}
sourceComponent: Rectangle {
id: launcherPanel
color: Theme.popupBackground()
radius: Theme.cornerRadiusXLarge
// Remove layer rendering for better performance
antialiasing: true
smooth: true
@@ -146,13 +145,14 @@ PanelWindow {
// Content with focus management
Item {
id: keyHandler
anchors.fill: parent
focus: true
Component.onCompleted: {
if (appDrawerPopout.isVisible)
forceActiveFocus();
}
}
// Handle keyboard shortcuts
Keys.onPressed: function(event) {
if (event.key === Qt.Key_Escape) {
@@ -214,6 +214,7 @@ PanelWindow {
font.pixelSize: Theme.fontSizeMedium
color: Theme.surfaceVariantText
}
}
// Enhanced search field
@@ -252,26 +253,25 @@ PanelWindow {
event.accepted = false;
}
}
Component.onCompleted: {
if (appDrawerPopout.isVisible) {
if (appDrawerPopout.isVisible)
searchField.forceActiveFocus();
}
}
Connections {
function onIsVisibleChanged() {
if (appDrawerPopout.isVisible) {
if (appDrawerPopout.isVisible)
Qt.callLater(function() {
searchField.forceActiveFocus();
});
} else {
else
searchField.clearFocus();
}
}
target: appDrawerPopout
}
}
// Category filter and view mode controls
@@ -296,6 +296,7 @@ PanelWindow {
appLauncher.setCategory(value);
}
}
}
Item {
@@ -335,7 +336,9 @@ PanelWindow {
appLauncher.setViewMode("grid");
}
}
}
}
// App grid/list container
@@ -399,10 +402,15 @@ PanelWindow {
appLauncher.keyboardNavigationActive = false;
}
}
}
}
}
}
}
}

View File

@@ -18,62 +18,35 @@ Item {
property bool debounceSearch: true
property int debounceInterval: 50
property bool keyboardNavigationActive: false
// Categories (computed from AppSearchService)
property var categories: {
var allCategories = AppSearchService.getAllCategories().filter(cat => {
var allCategories = AppSearchService.getAllCategories().filter((cat) => {
return cat !== "Education" && cat !== "Science";
});
var result = ["All"];
return result.concat(allCategories.filter(cat => {
return result.concat(allCategories.filter((cat) => {
return cat !== "All";
}));
}
// Category icons (computed from AppSearchService)
property var categoryIcons: categories.map(category => AppSearchService.getCategoryIcon(category))
property var categoryIcons: categories.map((category) => {
return AppSearchService.getCategoryIcon(category);
})
// App usage ranking helper
property var appUsageRanking: Prefs.appUsageRanking
// Internal model
property alias model: filteredModel
// Signals
signal appLaunched(var app)
signal categorySelected(string category)
signal viewModeSelected(string mode)
// Internal model
property alias model: filteredModel
ListModel {
id: filteredModel
}
// Search debouncing
Timer {
id: searchDebounceTimer
interval: root.debounceInterval
repeat: false
onTriggered: updateFilteredModel()
}
// Watch for changes
onSearchQueryChanged: {
if (debounceSearch) {
searchDebounceTimer.restart();
} else {
updateFilteredModel();
}
}
onSelectedCategoryChanged: updateFilteredModel()
onAppUsageRankingChanged: updateFilteredModel()
function updateFilteredModel() {
filteredModel.clear();
selectedIndex = 0;
keyboardNavigationActive = false;
var apps = [];
if (searchQuery.length === 0) {
// Show apps from category
if (selectedCategory === "All") {
@@ -90,8 +63,10 @@ Item {
var categoryApps = AppSearchService.getAppsInCategory(selectedCategory);
if (categoryApps.length > 0) {
var allSearchResults = AppSearchService.searchApplications(searchQuery);
var categoryNames = new Set(categoryApps.map(app => app.name));
apps = allSearchResults.filter(searchApp => {
var categoryNames = new Set(categoryApps.map((app) => {
return app.name;
}));
apps = allSearchResults.filter((searchApp) => {
return categoryNames.has(searchApp.name);
}).slice(0, maxResults);
} else {
@@ -99,25 +74,20 @@ Item {
}
}
}
// Sort apps by usage ranking, then alphabetically
apps = apps.sort(function(a, b) {
var aId = a.id || (a.execString || a.exec || "");
var bId = b.id || (b.execString || b.exec || "");
var aUsage = appUsageRanking[aId] ? appUsageRanking[aId].usageCount : 0;
var bUsage = appUsageRanking[bId] ? appUsageRanking[bId].usageCount : 0;
if (aUsage !== bUsage) {
if (aUsage !== bUsage)
return bUsage - aUsage; // Higher usage first
}
return (a.name || "").localeCompare(b.name || ""); // Alphabetical fallback
});
// Convert to model format and populate
apps.forEach(app => {
if (app) {
apps.forEach((app) => {
if (app)
filteredModel.append({
"name": app.name || "",
"exec": app.execString || "",
@@ -126,7 +96,7 @@ Item {
"categories": app.categories || [],
"desktopEntry": app
});
}
});
}
@@ -180,9 +150,8 @@ Item {
function launchApp(appData) {
if (!appData) {
console.warn("AppLauncher: No app data provided");
return;
return ;
}
appData.desktopEntry.execute();
appLaunched(appData);
Prefs.addAppUsage(appData.desktopEntry);
@@ -200,8 +169,31 @@ Item {
viewModeSelected(mode);
}
// Watch for changes
onSearchQueryChanged: {
if (debounceSearch)
searchDebounceTimer.restart();
else
updateFilteredModel();
}
onSelectedCategoryChanged: updateFilteredModel()
onAppUsageRankingChanged: updateFilteredModel()
// Initialize
Component.onCompleted: {
updateFilteredModel();
}
ListModel {
id: filteredModel
}
// Search debouncing
Timer {
id: searchDebounceTimer
interval: root.debounceInterval
repeat: false
onTriggered: updateFilteredModel()
}
}

View File

@@ -48,8 +48,11 @@ Item {
categorySelected(modelData);
}
}
}
}
}
// Two-row layout (for SpotlightModal organized style)
@@ -66,7 +69,7 @@ Item {
spacing: Theme.spacingS
Repeater {
model: parent.topRowCategories.filter(cat => {
model: parent.topRowCategories.filter((cat) => {
return categories.includes(cat);
})
@@ -95,8 +98,11 @@ Item {
categorySelected(modelData);
}
}
}
}
}
// Bottom row: Internet, Media, Office, Settings, System (5 items)
@@ -107,7 +113,7 @@ Item {
spacing: Theme.spacingS
Repeater {
model: parent.bottomRowCategories.filter(cat => {
model: parent.bottomRowCategories.filter((cat) => {
return categories.includes(cat);
})
@@ -136,8 +142,13 @@ Item {
categorySelected(modelData);
}
}
}
}
}
}
}

View File

@@ -6,8 +6,8 @@ import Quickshell.Services.Mpris
import Quickshell.Wayland
import Quickshell.Widgets
import qs.Common
import qs.Services
import qs.Modules.CentcomCenter
import qs.Services
PanelWindow {
id: root
@@ -17,25 +17,25 @@ PanelWindow {
property bool internalVisible: false
visible: internalVisible
onCalendarVisibleChanged: {
if (calendarVisible) {
internalVisible = true
internalVisible = true;
Qt.callLater(() => {
// This ensures opacity changes after window is visible
internalVisible = true // Force re-trigger if needed
internalVisible = true;
// Force re-trigger if needed
// Ensure events are loaded for current display month
calendarGrid.loadEventsForMonth()
})
calendarGrid.loadEventsForMonth();
});
} else {
internalVisible = false
internalVisible = false;
}
}
onVisibleChanged: {
if (visible && calendarGrid)
calendarGrid.loadEventsForMonth();
}
}
implicitWidth: 480
implicitHeight: 600
WlrLayershell.layer: WlrLayershell.Overlay
@@ -53,6 +53,8 @@ PanelWindow {
Rectangle {
id: mainContainer
readonly property real targetWidth: Math.min(Screen.width * 0.9, 600)
function calculateWidth() {
let baseWidth = 320;
if (leftWidgets.hasAnyWidgets)
@@ -80,7 +82,6 @@ PanelWindow {
return Math.min(contentHeight, parent.height * 0.9);
}
readonly property real targetWidth: Math.min(Screen.width * 0.9, 600)
width: targetWidth
height: calculateHeight()
color: Theme.surfaceContainer
@@ -92,44 +93,27 @@ PanelWindow {
scale: calendarVisible ? 1 : 0.9
x: (Screen.width - targetWidth) / 2
y: Theme.barHeight + 4
Behavior on opacity {
NumberAnimation {
duration: Anims.durMed
easing.type: Easing.BezierSpline
easing.bezierCurve: Anims.emphasized
}
}
Behavior on scale {
NumberAnimation {
duration: Anims.durMed
easing.type: Easing.BezierSpline
easing.bezierCurve: Anims.emphasized
}
}
// Only resize after animation is complete
onOpacityChanged: {
if (opacity === 1) {
if (opacity === 1)
// Animation finished, now we can safely resize
Qt.callLater(() => {
height = calculateHeight();
});
}
}
Connections {
function onEventsByDateChanged() {
if (mainContainer.opacity === 1) {
if (mainContainer.opacity === 1)
mainContainer.height = mainContainer.calculateHeight();
}
}
function onKhalAvailableChanged() {
if (mainContainer.opacity === 1) {
if (mainContainer.opacity === 1)
mainContainer.height = mainContainer.calculateHeight();
}
}
target: CalendarService
@@ -138,9 +122,9 @@ PanelWindow {
Connections {
function onSelectedDateEventsChanged() {
if (mainContainer.opacity === 1) {
if (mainContainer.opacity === 1)
mainContainer.height = mainContainer.calculateHeight();
}
}
target: events
@@ -172,8 +156,6 @@ PanelWindow {
}
Column {
anchors.fill: parent
anchors.margins: Theme.spacingM
@@ -236,6 +218,24 @@ PanelWindow {
}
Behavior on opacity {
NumberAnimation {
duration: Anims.durMed
easing.type: Easing.BezierSpline
easing.bezierCurve: Anims.emphasized
}
}
Behavior on scale {
NumberAnimation {
duration: Anims.durMed
easing.type: Easing.BezierSpline
easing.bezierCurve: Anims.emphasized
}
}
layer.effect: MultiEffect {
shadowEnabled: true
shadowHorizontalOffset: 0
@@ -245,8 +245,6 @@ PanelWindow {
shadowOpacity: 0.15
}
}
MouseArea {
@@ -256,10 +254,9 @@ PanelWindow {
onClicked: function(mouse) {
// Only close if click is outside the main container
var localPos = mapToItem(mainContainer, mouse.x, mouse.y);
if (localPos.x < 0 || localPos.x > mainContainer.width ||
localPos.y < 0 || localPos.y > mainContainer.height) {
if (localPos.x < 0 || localPos.x > mainContainer.width || localPos.y < 0 || localPos.y > mainContainer.height)
calendarVisible = false;
}
}
}

View File

@@ -16,7 +16,7 @@ PanelWindow {
visible: notificationHistoryVisible
implicitWidth: 400
implicitHeight: Math.min(Screen.height * 0.60, Math.max(580, (notificationsList.contentHeight || 0) + 140))
implicitHeight: Math.min(Screen.height * 0.6, Math.max(580, (notificationsList.contentHeight || 0) + 140))
WlrLayershell.layer: WlrLayershell.Overlay
WlrLayershell.exclusiveZone: -1
WlrLayershell.keyboardFocus: WlrKeyboardFocus.None
@@ -39,7 +39,7 @@ PanelWindow {
Rectangle {
width: 400
height: Math.min(Screen.height * 0.60, Math.max(580, (notificationsList.contentHeight || 0) + 140))
height: Math.min(Screen.height * 0.6, Math.max(580, (notificationsList.contentHeight || 0) + 140))
x: Screen.width - width - Theme.spacingL
y: Theme.barHeight + Theme.spacingXS
color: Theme.popupBackground()
@@ -710,7 +710,6 @@ PanelWindow {
delegate: Rectangle {
required property var modelData
readonly property bool messageExpanded: NotificationService.expandedMessages[modelData.notification.id] || false
width: parent.width
@@ -830,7 +829,6 @@ PanelWindow {
bodyText = bodyText.length > 500 ? bodyText.substring(0, 497) + "..." : bodyText;
else
bodyText = bodyText.length > 80 ? bodyText.substring(0, 77) + "..." : bodyText;
// Auto-detect and make URLs clickable
const urlRegex = /(https?:\/\/[^\s]+)/g;
return bodyText.replace(urlRegex, '<a href="$1" style="color: ' + Theme.primary + '; text-decoration: underline;">$1</a>');
@@ -916,7 +914,6 @@ PanelWindow {
}
}
}
@@ -1114,6 +1111,7 @@ PanelWindow {
duration: Theme.shortDuration
easing.type: Theme.standardEasing
}
}
Behavior on opacity {

View File

@@ -16,7 +16,7 @@ PanelWindow {
WlrLayershell.keyboardFocus: WlrKeyboardFocus.None
color: "transparent"
implicitWidth: 400
implicitHeight: Math.min(Screen.height * 0.60, Math.max(400, (notificationsList.contentHeight || 0) + 32))
implicitHeight: Math.min(Screen.height * 0.6, Math.max(400, (notificationsList.contentHeight || 0) + 32))
anchors {
top: true
@@ -35,18 +35,11 @@ PanelWindow {
anchors.rightMargin: 16
anchors.bottomMargin: 16
width: 380
height: Math.min(Screen.height * 0.60 - 32, Math.max(368, (notificationsList.contentHeight || 0) + 32))
height: Math.min(Screen.height * 0.6 - 32, Math.max(368, (notificationsList.contentHeight || 0) + 32))
color: "transparent"
radius: 12
clip: true
Behavior on height {
NumberAnimation {
duration: Theme.shortDuration
easing.type: Theme.standardEasing
}
}
ScrollView {
anchors.fill: parent
clip: true
@@ -607,6 +600,7 @@ PanelWindow {
// Body text with expand capability
Text {
id: bodyText
property bool hasUrls: {
const urlRegex = /(https?:\/\/[^\s]+)/g;
return urlRegex.test(modelData.body || "");
@@ -908,6 +902,14 @@ PanelWindow {
}
Behavior on height {
NumberAnimation {
duration: Theme.shortDuration
easing.type: Theme.standardEasing
}
}
}
Behavior on implicitHeight {

View File

@@ -14,6 +14,7 @@ ScrollView {
Column {
id: column
width: parent.width
spacing: Theme.spacingXL
topPadding: Theme.spacingL
@@ -30,6 +31,7 @@ ScrollView {
Column {
id: displaySection
anchors.fill: parent
anchors.margins: Theme.spacingL
spacing: Theme.spacingM
@@ -52,6 +54,7 @@ ScrollView {
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
}
DankToggle {
@@ -89,7 +92,9 @@ ScrollView {
Prefs.setIconTheme(value);
}
}
}
}
// Transparency Settings Section
@@ -103,6 +108,7 @@ ScrollView {
Column {
id: transparencySection
anchors.fill: parent
anchors.margins: Theme.spacingL
spacing: Theme.spacingM
@@ -125,6 +131,7 @@ ScrollView {
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
}
Column {
@@ -150,6 +157,7 @@ ScrollView {
Prefs.setTopBarTransparency(newValue / 100);
}
}
}
Column {
@@ -175,8 +183,11 @@ ScrollView {
Prefs.setPopupTransparency(newValue / 100);
}
}
}
}
}
// Theme Picker Section
@@ -190,6 +201,7 @@ ScrollView {
Column {
id: themeSection
anchors.fill: parent
anchors.margins: Theme.spacingL
spacing: Theme.spacingM
@@ -212,6 +224,7 @@ ScrollView {
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
}
Column {
@@ -241,6 +254,7 @@ ScrollView {
width: Math.min(parent.width, 400)
horizontalAlignment: Text.AlignHCenter
}
}
// Theme Grid
@@ -280,15 +294,18 @@ ScrollView {
StyledText {
id: nameText
text: Theme.themes[index].name
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceText
anchors.centerIn: parent
}
}
MouseArea {
id: mouseArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
@@ -302,6 +319,7 @@ ScrollView {
duration: Theme.shortDuration
easing.type: Theme.emphasizedEasing
}
}
Behavior on border.width {
@@ -309,9 +327,13 @@ ScrollView {
duration: Theme.shortDuration
easing.type: Theme.emphasizedEasing
}
}
}
}
}
// Second row - Red, Cyan, Pink, Amber, Coral
@@ -349,21 +371,25 @@ ScrollView {
StyledText {
id: nameText2
text: themeIndex < Theme.themes.length ? Theme.themes[themeIndex].name : ""
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceText
anchors.centerIn: parent
}
}
MouseArea {
id: mouseArea2
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
if (themeIndex < Theme.themes.length)
Theme.switchTheme(themeIndex);
}
}
@@ -372,6 +398,7 @@ ScrollView {
duration: Theme.shortDuration
easing.type: Theme.emphasizedEasing
}
}
Behavior on border.width {
@@ -379,9 +406,13 @@ ScrollView {
duration: Theme.shortDuration
easing.type: Theme.emphasizedEasing
}
}
}
}
}
// Spacer
@@ -453,21 +484,22 @@ ScrollView {
font.weight: Font.Medium
anchors.verticalCenter: parent.verticalCenter
}
}
MouseArea {
id: autoMouseArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
if (ToastService.wallpaperErrorStatus === "matugen_missing") {
if (ToastService.wallpaperErrorStatus === "matugen_missing")
ToastService.showError("matugen not found - install matugen package for dynamic theming");
} else if (ToastService.wallpaperErrorStatus === "error") {
else if (ToastService.wallpaperErrorStatus === "error")
ToastService.showError("Wallpaper processing failed - check wallpaper path");
} else {
else
Theme.switchTheme(10, true);
}
}
}
@@ -486,6 +518,7 @@ ScrollView {
StyledText {
id: autoTooltipText
text: {
if (ToastService.wallpaperErrorStatus === "error")
return "Wallpaper symlink missing at ~/quickshell/current_wallpaper";
@@ -501,6 +534,7 @@ ScrollView {
width: Math.min(implicitWidth, 250)
horizontalAlignment: Text.AlignHCenter
}
}
Behavior on scale {
@@ -508,6 +542,7 @@ ScrollView {
duration: Theme.shortDuration
easing.type: Theme.emphasizedEasing
}
}
Behavior on color {
@@ -515,6 +550,7 @@ ScrollView {
duration: Theme.mediumDuration
easing.type: Theme.standardEasing
}
}
Behavior on border.color {
@@ -522,16 +558,23 @@ ScrollView {
duration: Theme.mediumDuration
easing.type: Theme.standardEasing
}
}
}
}
}
}
}
// Night mode processes
Process {
id: nightModeEnableProcess
command: ["bash", "-c", "if command -v wlsunset > /dev/null; then pkill wlsunset; wlsunset -t 3000 & elif command -v redshift > /dev/null; then pkill redshift; redshift -P -O 3000 & else echo 'No night mode tool available'; fi"]
running: false
onExited: (exitCode) => {
@@ -544,11 +587,14 @@ ScrollView {
Process {
id: nightModeDisableProcess
command: ["bash", "-c", "pkill wlsunset; pkill redshift; if command -v wlsunset > /dev/null; then wlsunset -t 6500 -T 6500 & sleep 1; pkill wlsunset; elif command -v redshift > /dev/null; then redshift -P -O 6500; redshift -x; fi"]
running: false
onExited: (exitCode) => {
if (exitCode !== 0)
console.warn("Failed to disable night mode");
}
}
}

View File

@@ -296,18 +296,26 @@ ScrollView {
StyledText {
text: {
if (!modelData.lastUsed) return "Never used";
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 < 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";
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();
}
@@ -329,7 +337,8 @@ ScrollView {
iconColor: Theme.error
hoverColor: Qt.rgba(Theme.error.r, Theme.error.g, Theme.error.b, 0.12)
onClicked: {
var currentRanking = Object.assign({}, Prefs.appUsageRanking);
var currentRanking = Object.assign({
}, Prefs.appUsageRanking);
delete currentRanking[modelData.id];
Prefs.appUsageRanking = currentRanking;
Prefs.saveSettings();

View File

@@ -3,19 +3,23 @@ import QtQuick.Controls
import QtQuick.Effects
import Quickshell
import qs.Common
import qs.Modals
import qs.Services
import qs.Widgets
import qs.Modals
ScrollView {
id: personalizationTab
property alias profileBrowser: profileBrowserLoader.item
property alias wallpaperBrowser: wallpaperBrowserLoader.item
contentWidth: availableWidth
contentHeight: column.implicitHeight
clip: true
Column {
id: column
width: parent.width
spacing: Theme.spacingXL
@@ -30,6 +34,7 @@ ScrollView {
Column {
id: profileSection
anchors.fill: parent
anchors.margins: Theme.spacingL
spacing: Theme.spacingM
@@ -52,6 +57,7 @@ ScrollView {
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
}
Row {
@@ -121,6 +127,7 @@ ScrollView {
color: "black"
antialiasing: true
}
}
Rectangle {
@@ -135,6 +142,7 @@ ScrollView {
size: Theme.iconSizeLarge + 8
color: Theme.primaryText
}
}
DankIcon {
@@ -144,6 +152,7 @@ ScrollView {
color: Theme.error
visible: Prefs.profileImage !== "" && avatarImageSource.status === Image.Error
}
}
Column {
@@ -194,6 +203,7 @@ ScrollView {
font.pixelSize: Theme.fontSizeSmall
anchors.verticalCenter: parent.verticalCenter
}
}
MouseArea {
@@ -204,6 +214,7 @@ ScrollView {
profileBrowser.visible = true;
}
}
}
StyledRect {
@@ -211,7 +222,7 @@ ScrollView {
height: 32
radius: Theme.cornerRadius
color: Theme.surfaceVariant
opacity: Prefs.profileImage !== "" ? 1.0 : 0.5
opacity: Prefs.profileImage !== "" ? 1 : 0.5
Row {
anchors.centerIn: parent
@@ -230,6 +241,7 @@ ScrollView {
font.pixelSize: Theme.fontSizeSmall
anchors.verticalCenter: parent.verticalCenter
}
}
MouseArea {
@@ -240,11 +252,17 @@ ScrollView {
Prefs.setProfileImage("");
}
}
}
}
}
}
}
}
// Wallpaper Section
@@ -258,6 +276,7 @@ ScrollView {
Column {
id: wallpaperSection
anchors.fill: parent
anchors.margins: Theme.spacingL
spacing: Theme.spacingM
@@ -280,6 +299,7 @@ ScrollView {
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
}
Row {
@@ -303,16 +323,19 @@ ScrollView {
visible: Prefs.wallpaperPath !== ""
maxCacheSize: 160
layer.enabled: true
layer.effect: MultiEffect {
maskEnabled: true
maskSource: wallpaperMask
maskThresholdMin: 0.5
maskSpreadAtMin: 1.0
maskSpreadAtMin: 1
}
}
Rectangle {
id: wallpaperMask
anchors.fill: parent
anchors.margins: 1
radius: Theme.cornerRadius - 1
@@ -328,6 +351,7 @@ ScrollView {
color: Theme.surfaceVariantText
visible: Prefs.wallpaperPath === ""
}
}
Column {
@@ -378,6 +402,7 @@ ScrollView {
font.pixelSize: Theme.fontSizeSmall
anchors.verticalCenter: parent.verticalCenter
}
}
MouseArea {
@@ -388,6 +413,7 @@ ScrollView {
wallpaperBrowser.visible = true;
}
}
}
StyledRect {
@@ -395,7 +421,7 @@ ScrollView {
height: 32
radius: Theme.cornerRadius
color: Theme.surfaceVariant
opacity: Prefs.wallpaperPath !== "" ? 1.0 : 0.5
opacity: Prefs.wallpaperPath !== "" ? 1 : 0.5
Row {
anchors.centerIn: parent
@@ -414,6 +440,7 @@ ScrollView {
font.pixelSize: Theme.fontSizeSmall
anchors.verticalCenter: parent.verticalCenter
}
}
MouseArea {
@@ -424,11 +451,17 @@ ScrollView {
Prefs.setWallpaperPath("");
}
}
}
}
}
}
}
}
// Dynamic Theming Section
@@ -442,6 +475,7 @@ ScrollView {
Column {
id: dynamicThemeSection
anchors.fill: parent
anchors.margins: Theme.spacingL
spacing: Theme.spacingM
@@ -476,21 +510,23 @@ ScrollView {
wrapMode: Text.WordWrap
width: parent.width
}
}
DankToggle {
id: toggle
anchors.verticalCenter: parent.verticalCenter
checked: Theme.isDynamicTheme
enabled: ToastService.wallpaperErrorStatus !== "matugen_missing"
onToggled: (toggled) => {
if (toggled) {
Theme.switchTheme(10, true)
} else {
Theme.switchTheme(0)
}
if (toggled)
Theme.switchTheme(10, true);
else
Theme.switchTheme(0);
}
}
}
StyledText {
@@ -501,16 +537,21 @@ ScrollView {
width: parent.width
leftPadding: Theme.iconSize + Theme.spacingM
}
}
}
}
LazyLoader {
id: profileBrowserLoader
active: false
FileBrowserModal {
id: profileBrowser
browserTitle: "Select Profile Image"
browserIcon: "person"
browserType: "profile"
@@ -520,14 +561,17 @@ ScrollView {
visible = false;
}
}
}
LazyLoader {
id: wallpaperBrowserLoader
active: false
FileBrowserModal {
id: wallpaperBrowser
browserTitle: "Select Wallpaper"
browserIcon: "wallpaper"
browserType: "wallpaper"
@@ -537,8 +581,7 @@ ScrollView {
visible = false;
}
}
}
property alias profileBrowser: profileBrowserLoader.item
property alias wallpaperBrowser: wallpaperBrowserLoader.item
}

View File

@@ -16,6 +16,11 @@ Column {
width: parent.width
spacing: expanded ? Theme.spacingM : 0
Component.onCompleted: {
if (!collapsible)
expanded = true;
}
// Section header
MouseArea {
@@ -23,6 +28,11 @@ Column {
height: headerRow.height
enabled: collapsible
hoverEnabled: collapsible
onClicked: {
if (collapsible)
expanded = !expanded;
}
Rectangle {
anchors.fill: parent
@@ -50,7 +60,9 @@ Column {
easing.type: Easing.BezierSpline
easing.bezierCurve: Appearance.anim.curves.standard
}
}
}
DankIcon {
@@ -68,13 +80,9 @@ Column {
font.weight: Font.Medium
anchors.verticalCenter: parent.verticalCenter
}
}
onClicked: {
if (collapsible) {
expanded = !expanded
}
}
}
// Divider
@@ -93,6 +101,7 @@ Column {
active: lazyLoad ? expanded || !collapsible : true
visible: expanded || !collapsible
asynchronous: true
opacity: visible ? 1 : 0
Behavior on opacity {
NumberAnimation {
@@ -100,14 +109,9 @@ Column {
easing.type: Easing.BezierSpline
easing.bezierCurve: Appearance.anim.curves.standard
}
}
opacity: visible ? 1 : 0
}
Component.onCompleted: {
if (!collapsible) {
expanded = true
}
}
}

View File

@@ -12,6 +12,7 @@ ScrollView {
Column {
id: column
width: parent.width
spacing: Theme.spacingXL
@@ -26,6 +27,7 @@ ScrollView {
Column {
id: timeSection
anchors.fill: parent
anchors.margins: Theme.spacingL
spacing: Theme.spacingM
@@ -48,6 +50,7 @@ ScrollView {
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
}
DankToggle {
@@ -59,7 +62,9 @@ ScrollView {
return Prefs.setClockFormat(checked);
}
}
}
}
// Weather Settings Section
@@ -73,6 +78,7 @@ ScrollView {
Column {
id: weatherSection
anchors.fill: parent
anchors.margins: Theme.spacingL
spacing: Theme.spacingM
@@ -95,6 +101,7 @@ ScrollView {
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
}
DankToggle {
@@ -153,9 +160,15 @@ ScrollView {
duration: Theme.mediumDuration
easing.type: Theme.emphasizedEasing
}
}
}
}
}
}
}

View File

@@ -12,6 +12,7 @@ ScrollView {
Column {
id: column
width: parent.width
spacing: Theme.spacingXL
topPadding: Theme.spacingL
@@ -28,6 +29,7 @@ ScrollView {
Column {
id: topBarSection
anchors.fill: parent
anchors.margins: Theme.spacingL
spacing: Theme.spacingM
@@ -50,6 +52,7 @@ ScrollView {
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
}
DankToggle {
@@ -111,7 +114,9 @@ ScrollView {
return Prefs.setShowSystemTray(checked);
}
}
}
}
// Workspace Section
@@ -125,6 +130,7 @@ ScrollView {
Column {
id: workspaceSection
anchors.fill: parent
anchors.margins: Theme.spacingL
spacing: Theme.spacingM
@@ -147,6 +153,7 @@ ScrollView {
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
}
DankToggle {
@@ -168,7 +175,11 @@ ScrollView {
return Prefs.setShowWorkspacePadding(checked);
}
}
}
}
}
}

View File

@@ -115,12 +115,12 @@ PanelWindow {
readonly property int availableWidth: width
// Use estimated fixed widths to break circular dependencies
readonly property int launcherButtonWidth: 40
readonly property int workspaceSwitcherWidth: 120 // Approximate
readonly property int workspaceSwitcherWidth: 120 // Approximate
readonly property int focusedAppMaxWidth: focusedApp.visible ? 456 : 0
readonly property int estimatedLeftSectionWidth: launcherButtonWidth + workspaceSwitcherWidth + focusedAppMaxWidth + (Theme.spacingXS * 2)
readonly property int rightSectionWidth: rightSection.width
readonly property int clockWidth: clock.width
readonly property int mediaMaxWidth: media.visible ? 280 : 0 // Normal max width
readonly property int mediaMaxWidth: media.visible ? 280 : 0 // Normal max width
readonly property int weatherWidth: weather.visible ? weather.width : 0
readonly property bool validLayout: availableWidth > 100 && estimatedLeftSectionWidth > 0 && rightSectionWidth > 0
readonly property int clockLeftEdge: (availableWidth - clockWidth) / 2

View File

@@ -11,7 +11,6 @@ Image {
property string imagePath: ""
property string imageHash: ""
property int maxCacheSize: 512
readonly property string cachePath: imageHash ? `${Paths.stringify(Paths.imagecache)}/${imageHash}@${maxCacheSize}x${maxCacheSize}.png` : ""
asynchronous: true
@@ -19,34 +18,33 @@ Image {
sourceSize.width: maxCacheSize
sourceSize.height: maxCacheSize
smooth: true
onImagePathChanged: {
if (imagePath) {
hashProcess.command = ["sha256sum", Paths.strip(imagePath)]
hashProcess.running = true
hashProcess.command = ["sha256sum", Paths.strip(imagePath)];
hashProcess.running = true;
} else {
source = ""
imageHash = ""
source = "";
imageHash = "";
}
}
onCachePathChanged: {
if (imageHash && cachePath) {
// Ensure cache directory exists before trying to load from cache
Paths.mkdir(Paths.imagecache)
source = cachePath
Paths.mkdir(Paths.imagecache);
source = cachePath;
}
}
onStatusChanged: {
if (source == cachePath && status === Image.Error) {
source = imagePath
source = imagePath;
} else if (source == imagePath && status === Image.Ready && imageHash && cachePath) {
Paths.mkdir(Paths.imagecache)
const grabPath = cachePath
if (visible && width > 0 && height > 0 && Window.window && Window.window.visible) {
grabToImage(res => res.saveToFile(grabPath))
}
Paths.mkdir(Paths.imagecache);
const grabPath = cachePath;
if (visible && width > 0 && height > 0 && Window.window && Window.window.visible)
grabToImage((res) => {
return res.saveToFile(grabPath);
});
}
}
@@ -55,8 +53,10 @@ Image {
stdout: StdioCollector {
onStreamFinished: {
root.imageHash = text.split(" ")[0]
root.imageHash = text.split(" ")[0];
}
}
}
}

View File

@@ -18,11 +18,10 @@ Rectangle {
height: 60
radius: Theme.cornerRadius
color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.08)
onVisibleChanged: {
if (!visible && dropdownMenu.visible) {
if (!visible && dropdownMenu.visible)
dropdownMenu.close();
}
}
Column {
@@ -48,6 +47,7 @@ Rectangle {
wrapMode: Text.WordWrap
width: parent.width
}
}
Rectangle {
@@ -69,7 +69,6 @@ Rectangle {
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
if (dropdownMenu.visible) {
dropdownMenu.close();
@@ -85,6 +84,7 @@ Rectangle {
// Use a Row for the left-aligned content (icon + text)
Row {
id: contentRow
anchors.left: parent.left
anchors.verticalCenter: parent.verticalCenter
anchors.leftMargin: Theme.spacingM
@@ -108,11 +108,13 @@ Rectangle {
width: dropdown.width - contentRow.x - expandIcon.width - Theme.spacingM - Theme.spacingS
elide: Text.ElideRight
}
}
// Anchor the expand icon to the right, outside of the Row
DankIcon {
id: expandIcon
name: "expand_more"
size: 20
color: Theme.surfaceVariantText
@@ -120,18 +122,21 @@ Rectangle {
anchors.verticalCenter: parent.verticalCenter
anchors.rightMargin: Theme.spacingS
}
}
Popup {
id: dropdownMenu
parent: Overlay.overlay
parent: Overlay.overlay
width: 180
height: Math.min(200, root.options.length * 36 + 16)
padding: 0
closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutsideParent
background: Rectangle { color: "transparent" }
background: Rectangle {
color: "transparent"
}
contentItem: Rectangle {
color: Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, 1)
@@ -174,10 +179,12 @@ Rectangle {
color: root.currentValue === modelData ? Theme.primary : Theme.surfaceText
font.weight: root.currentValue === modelData ? Font.Medium : Font.Normal
}
}
MouseArea {
id: optionArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
@@ -187,9 +194,15 @@ Rectangle {
dropdownMenu.close();
}
}
}
}
}
}
}
}

View File

@@ -22,30 +22,27 @@ ScrollView {
property bool keyboardNavigationActive: false
signal keyboardNavigationReset()
signal itemClicked(int index, var modelData)
signal itemHovered(int index)
// Ensure the current item is visible
function ensureVisible(index) {
if (index < 0 || index >= grid.count) return;
if (index < 0 || index >= grid.count)
return ;
var itemY = Math.floor(index / grid.actualColumns) * grid.cellHeight;
var itemBottom = itemY + grid.cellHeight;
if (itemY < grid.contentY) {
if (itemY < grid.contentY)
grid.contentY = itemY;
} else if (itemBottom > grid.contentY + grid.height) {
else if (itemBottom > grid.contentY + grid.height)
grid.contentY = itemBottom - grid.height;
}
}
onCurrentIndexChanged: {
if (keyboardNavigationActive) {
if (keyboardNavigationActive)
ensureVisible(currentIndex);
}
}
}
clip: true
ScrollBar.vertical.policy: ScrollBar.AsNeeded
ScrollBar.horizontal.policy: ScrollBar.AlwaysOff
@@ -157,9 +154,9 @@ ScrollView {
cursorShape: Qt.PointingHandCursor
z: 10
onEntered: {
if (hoverUpdatesSelection && !keyboardNavigationActive) {
if (hoverUpdatesSelection && !keyboardNavigationActive)
currentIndex = index;
}
itemHovered(index);
}
onPositionChanged: {

View File

@@ -23,24 +23,22 @@ ScrollView {
// Ensure the current item is visible
function ensureVisible(index) {
if (index < 0 || index >= list.count) return;
if (index < 0 || index >= list.count)
return ;
var itemY = index * (itemHeight + itemSpacing);
var itemBottom = itemY + itemHeight;
if (itemY < list.contentY) {
if (itemY < list.contentY)
list.contentY = itemY;
} else if (itemBottom > list.contentY + list.height) {
else if (itemBottom > list.contentY + list.height)
list.contentY = itemBottom - list.height;
}
}
onCurrentIndexChanged: {
if (keyboardNavigationActive) {
if (keyboardNavigationActive)
ensureVisible(currentIndex);
}
}
}
clip: true
ScrollBar.vertical.policy: ScrollBar.AlwaysOn
ScrollBar.horizontal.policy: ScrollBar.AlwaysOff
@@ -156,9 +154,9 @@ ScrollView {
cursorShape: Qt.PointingHandCursor
z: 10
onEntered: {
if (hoverUpdatesSelection && !keyboardNavigationActive) {
if (hoverUpdatesSelection && !keyboardNavigationActive)
listView.currentIndex = index;
}
itemHovered(index);
}
onPositionChanged: {

View File

@@ -58,7 +58,9 @@ Item {
duration: Theme.shortDuration
easing.type: Theme.standardEasing
}
}
}
StyledRect {
@@ -85,15 +87,9 @@ Item {
visible: sliderMouseArea.containsMouse && slider.enabled
}
Behavior on scale {
NumberAnimation {
duration: Theme.shortDuration
easing.type: Theme.standardEasing
}
}
StyledRect {
id: valueTooltip
width: tooltipText.contentWidth + Theme.spacingS * 2
height: tooltipText.contentHeight + Theme.spacingXS * 2
radius: Theme.cornerRadiusSmall
@@ -108,6 +104,7 @@ Item {
Text {
id: tooltipText
text: slider.value + slider.unit
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceText
@@ -121,8 +118,19 @@ Item {
duration: Theme.shortDuration
easing.type: Theme.standardEasing
}
}
}
Behavior on scale {
NumberAnimation {
duration: Theme.shortDuration
easing.type: Theme.standardEasing
}
}
}
Item {
@@ -201,7 +209,9 @@ Item {
}
}
}
}
}
DankIcon {
@@ -211,6 +221,7 @@ Item {
anchors.verticalCenter: parent.verticalCenter
visible: slider.rightIcon.length > 0
}
}
}

View File

@@ -38,7 +38,6 @@ Rectangle {
readonly property real rightPadding: Theme.spacingM + (showClearButton && text.length > 0 ? 24 + Theme.spacingM : 0)
property real topPadding: Theme.spacingM
property real bottomPadding: Theme.spacingM
// Behavior control
property bool ignoreLeftRightKeys: false
property var keyForwardTargets: []
@@ -133,19 +132,16 @@ Rectangle {
onEditingFinished: root.editingFinished()
onAccepted: root.accepted()
onActiveFocusChanged: root.focusStateChanged(activeFocus)
Keys.forwardTo: root.ignoreLeftRightKeys ? root.keyForwardTargets : []
Keys.onLeftPressed: function(event) {
if (root.ignoreLeftRightKeys) {
if (root.ignoreLeftRightKeys)
event.accepted = true;
}
}
}
Keys.onRightPressed: function(event) {
if (root.ignoreLeftRightKeys) {
if (root.ignoreLeftRightKeys)
event.accepted = true;
}
}
MouseArea {

View File

@@ -139,8 +139,7 @@ ShellRoot {
target: "processlist"
}
// Toast {
// id: toastWidget
// }
Toast {
id: toastWidget
}
}