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

View File

@@ -18,62 +18,35 @@ Item {
property bool debounceSearch: true property bool debounceSearch: true
property int debounceInterval: 50 property int debounceInterval: 50
property bool keyboardNavigationActive: false property bool keyboardNavigationActive: false
// Categories (computed from AppSearchService) // Categories (computed from AppSearchService)
property var categories: { property var categories: {
var allCategories = AppSearchService.getAllCategories().filter(cat => { var allCategories = AppSearchService.getAllCategories().filter((cat) => {
return cat !== "Education" && cat !== "Science"; return cat !== "Education" && cat !== "Science";
}); });
var result = ["All"]; var result = ["All"];
return result.concat(allCategories.filter(cat => { return result.concat(allCategories.filter((cat) => {
return cat !== "All"; return cat !== "All";
})); }));
} }
// Category icons (computed from AppSearchService) // 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 // App usage ranking helper
property var appUsageRanking: Prefs.appUsageRanking property var appUsageRanking: Prefs.appUsageRanking
// Internal model
property alias model: filteredModel
// Signals // Signals
signal appLaunched(var app) signal appLaunched(var app)
signal categorySelected(string category) signal categorySelected(string category)
signal viewModeSelected(string mode) 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() { function updateFilteredModel() {
filteredModel.clear(); filteredModel.clear();
selectedIndex = 0; selectedIndex = 0;
keyboardNavigationActive = false; keyboardNavigationActive = false;
var apps = []; var apps = [];
if (searchQuery.length === 0) { if (searchQuery.length === 0) {
// Show apps from category // Show apps from category
if (selectedCategory === "All") { if (selectedCategory === "All") {
@@ -90,8 +63,10 @@ Item {
var categoryApps = AppSearchService.getAppsInCategory(selectedCategory); var categoryApps = AppSearchService.getAppsInCategory(selectedCategory);
if (categoryApps.length > 0) { if (categoryApps.length > 0) {
var allSearchResults = AppSearchService.searchApplications(searchQuery); var allSearchResults = AppSearchService.searchApplications(searchQuery);
var categoryNames = new Set(categoryApps.map(app => app.name)); var categoryNames = new Set(categoryApps.map((app) => {
apps = allSearchResults.filter(searchApp => { return app.name;
}));
apps = allSearchResults.filter((searchApp) => {
return categoryNames.has(searchApp.name); return categoryNames.has(searchApp.name);
}).slice(0, maxResults); }).slice(0, maxResults);
} else { } else {
@@ -99,25 +74,20 @@ Item {
} }
} }
} }
// Sort apps by usage ranking, then alphabetically // Sort apps by usage ranking, then alphabetically
apps = apps.sort(function(a, b) { apps = apps.sort(function(a, b) {
var aId = a.id || (a.execString || a.exec || ""); var aId = a.id || (a.execString || a.exec || "");
var bId = b.id || (b.execString || b.exec || ""); var bId = b.id || (b.execString || b.exec || "");
var aUsage = appUsageRanking[aId] ? appUsageRanking[aId].usageCount : 0; var aUsage = appUsageRanking[aId] ? appUsageRanking[aId].usageCount : 0;
var bUsage = appUsageRanking[bId] ? appUsageRanking[bId].usageCount : 0; var bUsage = appUsageRanking[bId] ? appUsageRanking[bId].usageCount : 0;
if (aUsage !== bUsage)
if (aUsage !== bUsage) {
return bUsage - aUsage; // Higher usage first return bUsage - aUsage; // Higher usage first
}
return (a.name || "").localeCompare(b.name || ""); // Alphabetical fallback return (a.name || "").localeCompare(b.name || ""); // Alphabetical fallback
}); });
// Convert to model format and populate // Convert to model format and populate
apps.forEach(app => { apps.forEach((app) => {
if (app) { if (app)
filteredModel.append({ filteredModel.append({
"name": app.name || "", "name": app.name || "",
"exec": app.execString || "", "exec": app.execString || "",
@@ -126,7 +96,7 @@ Item {
"categories": app.categories || [], "categories": app.categories || [],
"desktopEntry": app "desktopEntry": app
}); });
}
}); });
} }
@@ -180,9 +150,8 @@ Item {
function launchApp(appData) { function launchApp(appData) {
if (!appData) { if (!appData) {
console.warn("AppLauncher: No app data provided"); console.warn("AppLauncher: No app data provided");
return; return ;
} }
appData.desktopEntry.execute(); appData.desktopEntry.execute();
appLaunched(appData); appLaunched(appData);
Prefs.addAppUsage(appData.desktopEntry); Prefs.addAppUsage(appData.desktopEntry);
@@ -200,8 +169,31 @@ Item {
viewModeSelected(mode); viewModeSelected(mode);
} }
// Watch for changes
onSearchQueryChanged: {
if (debounceSearch)
searchDebounceTimer.restart();
else
updateFilteredModel();
}
onSelectedCategoryChanged: updateFilteredModel()
onAppUsageRankingChanged: updateFilteredModel()
// Initialize // Initialize
Component.onCompleted: { Component.onCompleted: {
updateFilteredModel(); 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); categorySelected(modelData);
} }
} }
} }
} }
} }
// Two-row layout (for SpotlightModal organized style) // Two-row layout (for SpotlightModal organized style)
@@ -66,7 +69,7 @@ Item {
spacing: Theme.spacingS spacing: Theme.spacingS
Repeater { Repeater {
model: parent.topRowCategories.filter(cat => { model: parent.topRowCategories.filter((cat) => {
return categories.includes(cat); return categories.includes(cat);
}) })
@@ -95,8 +98,11 @@ Item {
categorySelected(modelData); categorySelected(modelData);
} }
} }
} }
} }
} }
// Bottom row: Internet, Media, Office, Settings, System (5 items) // Bottom row: Internet, Media, Office, Settings, System (5 items)
@@ -107,7 +113,7 @@ Item {
spacing: Theme.spacingS spacing: Theme.spacingS
Repeater { Repeater {
model: parent.bottomRowCategories.filter(cat => { model: parent.bottomRowCategories.filter((cat) => {
return categories.includes(cat); return categories.includes(cat);
}) })
@@ -136,8 +142,13 @@ Item {
categorySelected(modelData); categorySelected(modelData);
} }
} }
} }
} }
} }
} }
} }

View File

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

View File

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

View File

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

View File

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

View File

@@ -296,18 +296,26 @@ ScrollView {
StyledText { StyledText {
text: { text: {
if (!modelData.lastUsed) return "Never used"; if (!modelData.lastUsed)
return "Never used";
var date = new Date(modelData.lastUsed); var date = new Date(modelData.lastUsed);
var now = new Date(); var now = new Date();
var diffMs = now - date; var diffMs = now - date;
var diffMins = Math.floor(diffMs / (1000 * 60)); var diffMins = Math.floor(diffMs / (1000 * 60));
var diffHours = Math.floor(diffMs / (1000 * 60 * 60)); var diffHours = Math.floor(diffMs / (1000 * 60 * 60));
var diffDays = Math.floor(diffMs / (1000 * 60 * 60 * 24)); 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)
if (diffMins < 60) return "Last launched " + diffMins + " minute" + (diffMins === 1 ? "" : "s") + " ago"; 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 (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(); return "Last launched " + date.toLocaleDateString();
} }
@@ -329,7 +337,8 @@ ScrollView {
iconColor: Theme.error iconColor: Theme.error
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: {
var currentRanking = Object.assign({}, Prefs.appUsageRanking); var currentRanking = Object.assign({
}, Prefs.appUsageRanking);
delete currentRanking[modelData.id]; delete currentRanking[modelData.id];
Prefs.appUsageRanking = currentRanking; Prefs.appUsageRanking = currentRanking;
Prefs.saveSettings(); Prefs.saveSettings();

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -58,7 +58,9 @@ Item {
duration: Theme.shortDuration duration: Theme.shortDuration
easing.type: Theme.standardEasing easing.type: Theme.standardEasing
} }
} }
} }
StyledRect { StyledRect {
@@ -85,15 +87,9 @@ Item {
visible: sliderMouseArea.containsMouse && slider.enabled visible: sliderMouseArea.containsMouse && slider.enabled
} }
Behavior on scale {
NumberAnimation {
duration: Theme.shortDuration
easing.type: Theme.standardEasing
}
}
StyledRect { StyledRect {
id: valueTooltip id: valueTooltip
width: tooltipText.contentWidth + Theme.spacingS * 2 width: tooltipText.contentWidth + Theme.spacingS * 2
height: tooltipText.contentHeight + Theme.spacingXS * 2 height: tooltipText.contentHeight + Theme.spacingXS * 2
radius: Theme.cornerRadiusSmall radius: Theme.cornerRadiusSmall
@@ -108,6 +104,7 @@ Item {
Text { Text {
id: tooltipText id: tooltipText
text: slider.value + slider.unit text: slider.value + slider.unit
font.pixelSize: Theme.fontSizeSmall font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceText color: Theme.surfaceText
@@ -121,8 +118,19 @@ Item {
duration: Theme.shortDuration duration: Theme.shortDuration
easing.type: Theme.standardEasing easing.type: Theme.standardEasing
} }
} }
} }
Behavior on scale {
NumberAnimation {
duration: Theme.shortDuration
easing.type: Theme.standardEasing
}
}
} }
Item { Item {
@@ -201,7 +209,9 @@ Item {
} }
} }
} }
} }
} }
DankIcon { DankIcon {
@@ -211,6 +221,7 @@ Item {
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
visible: slider.rightIcon.length > 0 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) readonly property real rightPadding: Theme.spacingM + (showClearButton && text.length > 0 ? 24 + Theme.spacingM : 0)
property real topPadding: Theme.spacingM property real topPadding: Theme.spacingM
property real bottomPadding: Theme.spacingM property real bottomPadding: Theme.spacingM
// Behavior control // Behavior control
property bool ignoreLeftRightKeys: false property bool ignoreLeftRightKeys: false
property var keyForwardTargets: [] property var keyForwardTargets: []
@@ -133,19 +132,16 @@ Rectangle {
onEditingFinished: root.editingFinished() onEditingFinished: root.editingFinished()
onAccepted: root.accepted() onAccepted: root.accepted()
onActiveFocusChanged: root.focusStateChanged(activeFocus) onActiveFocusChanged: root.focusStateChanged(activeFocus)
Keys.forwardTo: root.ignoreLeftRightKeys ? root.keyForwardTargets : [] Keys.forwardTo: root.ignoreLeftRightKeys ? root.keyForwardTargets : []
Keys.onLeftPressed: function(event) { Keys.onLeftPressed: function(event) {
if (root.ignoreLeftRightKeys) { if (root.ignoreLeftRightKeys)
event.accepted = true; event.accepted = true;
}
}
}
Keys.onRightPressed: function(event) { Keys.onRightPressed: function(event) {
if (root.ignoreLeftRightKeys) { if (root.ignoreLeftRightKeys)
event.accepted = true; event.accepted = true;
}
} }
MouseArea { MouseArea {

View File

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