1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2026-01-28 15:32:50 -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
@@ -50,10 +50,9 @@ PanelWindow {
// App launcher logic // App launcher logic
AppLauncher { AppLauncher {
id: appLauncher id: appLauncher
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,48 +66,48 @@ 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
Behavior on opacity { Behavior on opacity {
NumberAnimation { NumberAnimation {
duration: Anims.durMed duration: Anims.durMed
easing.type: Easing.BezierSpline easing.type: Easing.BezierSpline
easing.bezierCurve: Anims.emphasized easing.bezierCurve: Anims.emphasized
} }
} }
Behavior on scale { Behavior on scale {
NumberAnimation { NumberAnimation {
duration: Anims.durMed duration: Anims.durMed
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
@@ -285,7 +285,7 @@ PanelWindow {
Item { Item {
width: 200 width: 200
height: 36 height: 36
DankDropdown { DankDropdown {
anchors.fill: parent anchors.fill: parent
text: "" text: ""
@@ -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

@@ -15,7 +15,7 @@ Rectangle {
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08) border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08)
border.width: 1 border.width: 1
layer.enabled: true layer.enabled: true
Ref { Ref {
service: WeatherService service: WeatherService
} }

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
@@ -726,7 +725,7 @@ PanelWindow {
Rectangle { Rectangle {
id: messageIcon id: messageIcon
readonly property bool hasNotificationImage: modelData.image && modelData.image !== "" readonly property bool hasNotificationImage: modelData.image && modelData.image !== ""
width: 32 width: 32
@@ -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

@@ -7,18 +7,19 @@ import qs.Widgets
ScrollView { ScrollView {
id: appearanceTab id: appearanceTab
contentWidth: availableWidth contentWidth: availableWidth
contentHeight: column.implicitHeight + Theme.spacingXL contentHeight: column.implicitHeight + Theme.spacingXL
clip: true clip: true
Column { Column {
id: column id: column
width: parent.width width: parent.width
spacing: Theme.spacingXL spacing: Theme.spacingXL
topPadding: Theme.spacingL topPadding: Theme.spacingL
bottomPadding: Theme.spacingXL bottomPadding: Theme.spacingXL
// Display Settings Section // Display Settings Section
StyledRect { StyledRect {
width: parent.width width: parent.width
@@ -27,24 +28,25 @@ ScrollView {
color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.3) color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.3)
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2) border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
border.width: 1 border.width: 1
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
Row { Row {
width: parent.width width: parent.width
spacing: Theme.spacingM spacing: Theme.spacingM
DankIcon { DankIcon {
name: "monitor" name: "monitor"
size: Theme.iconSize size: Theme.iconSize
color: Theme.primary color: Theme.primary
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
} }
StyledText { StyledText {
text: "Display Settings" text: "Display Settings"
font.pixelSize: Theme.fontSizeLarge font.pixelSize: Theme.fontSizeLarge
@@ -52,8 +54,9 @@ ScrollView {
color: Theme.surfaceText color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
} }
} }
DankToggle { DankToggle {
width: parent.width width: parent.width
text: "Night Mode" text: "Night Mode"
@@ -67,7 +70,7 @@ ScrollView {
nightModeDisableProcess.running = true; nightModeDisableProcess.running = true;
} }
} }
DankToggle { DankToggle {
width: parent.width width: parent.width
text: "Light Mode" text: "Light Mode"
@@ -78,7 +81,7 @@ ScrollView {
Theme.isLightMode = checked; Theme.isLightMode = checked;
} }
} }
DankDropdown { DankDropdown {
width: parent.width width: parent.width
text: "Icon Theme" text: "Icon Theme"
@@ -89,9 +92,11 @@ ScrollView {
Prefs.setIconTheme(value); Prefs.setIconTheme(value);
} }
} }
} }
} }
// Transparency Settings Section // Transparency Settings Section
StyledRect { StyledRect {
width: parent.width width: parent.width
@@ -100,24 +105,25 @@ ScrollView {
color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.3) color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.3)
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2) border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
border.width: 1 border.width: 1
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
Row { Row {
width: parent.width width: parent.width
spacing: Theme.spacingM spacing: Theme.spacingM
DankIcon { DankIcon {
name: "opacity" name: "opacity"
size: Theme.iconSize size: Theme.iconSize
color: Theme.primary color: Theme.primary
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
} }
StyledText { StyledText {
text: "Transparency Settings" text: "Transparency Settings"
font.pixelSize: Theme.fontSizeLarge font.pixelSize: Theme.fontSizeLarge
@@ -125,19 +131,20 @@ ScrollView {
color: Theme.surfaceText color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
} }
} }
Column { Column {
width: parent.width width: parent.width
spacing: Theme.spacingS spacing: Theme.spacingS
StyledText { StyledText {
text: "Top Bar Transparency" text: "Top Bar Transparency"
font.pixelSize: Theme.fontSizeSmall font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceText color: Theme.surfaceText
font.weight: Font.Medium font.weight: Font.Medium
} }
DankSlider { DankSlider {
width: parent.width width: parent.width
height: 24 height: 24
@@ -150,19 +157,20 @@ ScrollView {
Prefs.setTopBarTransparency(newValue / 100); Prefs.setTopBarTransparency(newValue / 100);
} }
} }
} }
Column { Column {
width: parent.width width: parent.width
spacing: Theme.spacingS spacing: Theme.spacingS
StyledText { StyledText {
text: "Popup Transparency" text: "Popup Transparency"
font.pixelSize: Theme.fontSizeSmall font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceText color: Theme.surfaceText
font.weight: Font.Medium font.weight: Font.Medium
} }
DankSlider { DankSlider {
width: parent.width width: parent.width
height: 24 height: 24
@@ -175,10 +183,13 @@ ScrollView {
Prefs.setPopupTransparency(newValue / 100); Prefs.setPopupTransparency(newValue / 100);
} }
} }
} }
} }
} }
// Theme Picker Section // Theme Picker Section
StyledRect { StyledRect {
width: parent.width width: parent.width
@@ -187,24 +198,25 @@ ScrollView {
color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.3) color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.3)
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2) border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
border.width: 1 border.width: 1
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
Row { Row {
width: parent.width width: parent.width
spacing: Theme.spacingM spacing: Theme.spacingM
DankIcon { DankIcon {
name: "palette" name: "palette"
size: Theme.iconSize size: Theme.iconSize
color: Theme.primary color: Theme.primary
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
} }
StyledText { StyledText {
text: "Theme Color" text: "Theme Color"
font.pixelSize: Theme.fontSizeLarge font.pixelSize: Theme.fontSizeLarge
@@ -212,12 +224,13 @@ ScrollView {
color: Theme.surfaceText color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
} }
} }
Column { Column {
width: parent.width width: parent.width
spacing: Theme.spacingS spacing: Theme.spacingS
StyledText { StyledText {
text: "Current Theme: " + (Theme.isDynamicTheme ? "Auto" : (Theme.currentThemeIndex < Theme.themes.length ? Theme.themes[Theme.currentThemeIndex].name : "Blue")) text: "Current Theme: " + (Theme.isDynamicTheme ? "Auto" : (Theme.currentThemeIndex < Theme.themes.length ? Theme.themes[Theme.currentThemeIndex].name : "Blue"))
font.pixelSize: Theme.fontSizeMedium font.pixelSize: Theme.fontSizeMedium
@@ -225,12 +238,12 @@ ScrollView {
font.weight: Font.Medium font.weight: Font.Medium
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
} }
StyledText { StyledText {
text: { text: {
if (Theme.isDynamicTheme) if (Theme.isDynamicTheme)
return "Wallpaper-based dynamic colors"; return "Wallpaper-based dynamic colors";
var descriptions = ["Material blue inspired by modern interfaces", "Deep blue inspired by material 3", "Rich purple tones for BB elegance", "Natural green for productivity", "Energetic orange for creativity", "Bold red for impact", "Cool cyan for tranquility", "Vibrant pink for expression", "Warm amber for comfort", "Soft coral for gentle warmth"]; var descriptions = ["Material blue inspired by modern interfaces", "Deep blue inspired by material 3", "Rich purple tones for BB elegance", "Natural green for productivity", "Energetic orange for creativity", "Bold red for impact", "Cool cyan for tranquility", "Vibrant pink for expression", "Warm amber for comfort", "Soft coral for gentle warmth"];
return descriptions[Theme.currentThemeIndex] || "Select a theme"; return descriptions[Theme.currentThemeIndex] || "Select a theme";
} }
@@ -241,21 +254,22 @@ ScrollView {
width: Math.min(parent.width, 400) width: Math.min(parent.width, 400)
horizontalAlignment: Text.AlignHCenter horizontalAlignment: Text.AlignHCenter
} }
} }
// Theme Grid // Theme Grid
Column { Column {
spacing: Theme.spacingS spacing: Theme.spacingS
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
// First row - Blue, Deep Blue, Purple, Green, Orange // First row - Blue, Deep Blue, Purple, Green, Orange
Row { Row {
spacing: Theme.spacingM spacing: Theme.spacingM
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
Repeater { Repeater {
model: 5 model: 5
Rectangle { Rectangle {
width: 32 width: 32
height: 32 height: 32
@@ -264,7 +278,7 @@ ScrollView {
border.color: Theme.outline border.color: Theme.outline
border.width: (Theme.currentThemeIndex === index && !Theme.isDynamicTheme) ? 2 : 1 border.width: (Theme.currentThemeIndex === index && !Theme.isDynamicTheme) ? 2 : 1
scale: (Theme.currentThemeIndex === index && !Theme.isDynamicTheme) ? 1.1 : 1 scale: (Theme.currentThemeIndex === index && !Theme.isDynamicTheme) ? 1.1 : 1
// Theme name tooltip // Theme name tooltip
Rectangle { Rectangle {
width: nameText.contentWidth + Theme.spacingS * 2 width: nameText.contentWidth + Theme.spacingS * 2
@@ -277,18 +291,21 @@ ScrollView {
anchors.bottomMargin: Theme.spacingXS anchors.bottomMargin: Theme.spacingXS
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
visible: mouseArea.containsMouse visible: mouseArea.containsMouse
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
@@ -296,35 +313,40 @@ ScrollView {
Theme.switchTheme(index, false); Theme.switchTheme(index, false);
} }
} }
Behavior on scale { Behavior on scale {
NumberAnimation { NumberAnimation {
duration: Theme.shortDuration duration: Theme.shortDuration
easing.type: Theme.emphasizedEasing easing.type: Theme.emphasizedEasing
} }
} }
Behavior on border.width { Behavior on border.width {
NumberAnimation { NumberAnimation {
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
Row { Row {
spacing: Theme.spacingM spacing: Theme.spacingM
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
Repeater { Repeater {
model: 5 model: 5
Rectangle { Rectangle {
property int themeIndex: index + 5 property int themeIndex: index + 5
width: 32 width: 32
height: 32 height: 32
radius: 16 radius: 16
@@ -333,7 +355,7 @@ ScrollView {
border.width: Theme.currentThemeIndex === themeIndex ? 2 : 1 border.width: Theme.currentThemeIndex === themeIndex ? 2 : 1
visible: themeIndex < Theme.themes.length visible: themeIndex < Theme.themes.length
scale: Theme.currentThemeIndex === themeIndex ? 1.1 : 1 scale: Theme.currentThemeIndex === themeIndex ? 1.1 : 1
// Theme name tooltip // Theme name tooltip
Rectangle { Rectangle {
width: nameText2.contentWidth + Theme.spacingS * 2 width: nameText2.contentWidth + Theme.spacingS * 2
@@ -346,50 +368,59 @@ ScrollView {
anchors.bottomMargin: Theme.spacingXS anchors.bottomMargin: Theme.spacingXS
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
visible: mouseArea2.containsMouse && themeIndex < Theme.themes.length visible: mouseArea2.containsMouse && themeIndex < Theme.themes.length
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);
} }
} }
Behavior on scale { Behavior on scale {
NumberAnimation { NumberAnimation {
duration: Theme.shortDuration duration: Theme.shortDuration
easing.type: Theme.emphasizedEasing easing.type: Theme.emphasizedEasing
} }
} }
Behavior on border.width { Behavior on border.width {
NumberAnimation { NumberAnimation {
duration: Theme.shortDuration duration: Theme.shortDuration
easing.type: Theme.emphasizedEasing easing.type: Theme.emphasizedEasing
} }
} }
} }
} }
} }
// Spacer // Spacer
Item { Item {
width: 1 width: 1
height: Theme.spacingM height: Theme.spacingM
} }
// Auto theme button // Auto theme button
Rectangle { Rectangle {
width: 120 width: 120
@@ -412,11 +443,11 @@ ScrollView {
} }
border.width: Theme.isDynamicTheme ? 2 : 1 border.width: Theme.isDynamicTheme ? 2 : 1
scale: Theme.isDynamicTheme ? 1.1 : (autoMouseArea.containsMouse ? 1.02 : 1) scale: Theme.isDynamicTheme ? 1.1 : (autoMouseArea.containsMouse ? 1.02 : 1)
Row { Row {
anchors.centerIn: parent anchors.centerIn: parent
spacing: Theme.spacingS spacing: Theme.spacingS
DankIcon { DankIcon {
name: { name: {
if (ToastService.wallpaperErrorStatus === "error" || ToastService.wallpaperErrorStatus === "matugen_missing") if (ToastService.wallpaperErrorStatus === "error" || ToastService.wallpaperErrorStatus === "matugen_missing")
@@ -433,7 +464,7 @@ ScrollView {
} }
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
} }
StyledText { StyledText {
text: { text: {
if (ToastService.wallpaperErrorStatus === "error") if (ToastService.wallpaperErrorStatus === "error")
@@ -453,24 +484,25 @@ 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);
}
} }
} }
// Tooltip for Auto button // Tooltip for Auto button
Rectangle { Rectangle {
width: autoTooltipText.contentWidth + Theme.spacingM * 2 width: autoTooltipText.contentWidth + Theme.spacingM * 2
@@ -483,9 +515,10 @@ ScrollView {
anchors.bottomMargin: Theme.spacingS anchors.bottomMargin: Theme.spacingS
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
visible: autoMouseArea.containsMouse && (!Theme.isDynamicTheme || ToastService.wallpaperErrorStatus === "error" || ToastService.wallpaperErrorStatus === "matugen_missing") visible: autoMouseArea.containsMouse && (!Theme.isDynamicTheme || ToastService.wallpaperErrorStatus === "error" || ToastService.wallpaperErrorStatus === "matugen_missing")
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,37 +534,47 @@ ScrollView {
width: Math.min(implicitWidth, 250) width: Math.min(implicitWidth, 250)
horizontalAlignment: Text.AlignHCenter horizontalAlignment: Text.AlignHCenter
} }
} }
Behavior on scale { Behavior on scale {
NumberAnimation { NumberAnimation {
duration: Theme.shortDuration duration: Theme.shortDuration
easing.type: Theme.emphasizedEasing easing.type: Theme.emphasizedEasing
} }
} }
Behavior on color { Behavior on color {
ColorAnimation { ColorAnimation {
duration: Theme.mediumDuration duration: Theme.mediumDuration
easing.type: Theme.standardEasing easing.type: Theme.standardEasing
} }
} }
Behavior on border.color { Behavior on border.color {
ColorAnimation { ColorAnimation {
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) => {
@@ -541,14 +584,17 @@ 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)
if (diffMins < 1) return "Last launched just now"; 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 (diffMins < 60)
if (diffDays < 7) return "Last launched " + diffDays + " day" + (diffDays === 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";
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,22 +3,26 @@ 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
// Profile Section // Profile Section
StyledRect { StyledRect {
width: parent.width width: parent.width
@@ -27,24 +31,25 @@ ScrollView {
color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.3) color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.3)
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2) border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
border.width: 1 border.width: 1
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
Row { Row {
width: parent.width width: parent.width
spacing: Theme.spacingM spacing: Theme.spacingM
DankIcon { DankIcon {
name: "person" name: "person"
size: Theme.iconSize size: Theme.iconSize
color: Theme.primary color: Theme.primary
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
} }
StyledText { StyledText {
text: "Profile Image" text: "Profile Image"
font.pixelSize: Theme.fontSizeLarge font.pixelSize: Theme.fontSizeLarge
@@ -52,21 +57,22 @@ ScrollView {
color: Theme.surfaceText color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
} }
} }
Row { Row {
width: parent.width width: parent.width
spacing: Theme.spacingL spacing: Theme.spacingL
// Circular profile image preview // Circular profile image preview
Item { Item {
id: avatarContainer id: avatarContainer
property bool hasImage: avatarImageSource.status === Image.Ready property bool hasImage: avatarImageSource.status === Image.Ready
width: 80 width: 80
height: 80 height: 80
Rectangle { Rectangle {
anchors.fill: parent anchors.fill: parent
radius: width / 2 radius: width / 2
@@ -75,17 +81,17 @@ ScrollView {
border.width: 1 border.width: 1
visible: parent.hasImage visible: parent.hasImage
} }
Image { Image {
id: avatarImageSource id: avatarImageSource
source: { source: {
if (Prefs.profileImage === "") if (Prefs.profileImage === "")
return ""; return "";
if (Prefs.profileImage.startsWith("/")) if (Prefs.profileImage.startsWith("/"))
return "file://" + Prefs.profileImage; return "file://" + Prefs.profileImage;
return Prefs.profileImage; return Prefs.profileImage;
} }
smooth: true smooth: true
@@ -94,7 +100,7 @@ ScrollView {
cache: true cache: true
visible: false visible: false
} }
MultiEffect { MultiEffect {
anchors.fill: parent anchors.fill: parent
anchors.margins: 5 anchors.margins: 5
@@ -105,38 +111,40 @@ ScrollView {
maskThresholdMin: 0.5 maskThresholdMin: 0.5
maskSpreadAtMin: 1 maskSpreadAtMin: 1
} }
Item { Item {
id: settingsCircularMask id: settingsCircularMask
width: 70 width: 70
height: 70 height: 70
layer.enabled: true layer.enabled: true
layer.smooth: true layer.smooth: true
visible: false visible: false
Rectangle { Rectangle {
anchors.fill: parent anchors.fill: parent
radius: width / 2 radius: width / 2
color: "black" color: "black"
antialiasing: true antialiasing: true
} }
} }
Rectangle { Rectangle {
anchors.fill: parent anchors.fill: parent
radius: width / 2 radius: width / 2
color: Theme.primary color: Theme.primary
visible: !parent.hasImage visible: !parent.hasImage
DankIcon { DankIcon {
anchors.centerIn: parent anchors.centerIn: parent
name: "person" name: "person"
size: Theme.iconSizeLarge + 8 size: Theme.iconSizeLarge + 8
color: Theme.primaryText color: Theme.primaryText
} }
} }
DankIcon { DankIcon {
anchors.centerIn: parent anchors.centerIn: parent
name: "warning" name: "warning"
@@ -144,13 +152,14 @@ ScrollView {
color: Theme.error color: Theme.error
visible: Prefs.profileImage !== "" && avatarImageSource.status === Image.Error visible: Prefs.profileImage !== "" && avatarImageSource.status === Image.Error
} }
} }
Column { Column {
width: parent.width - 80 - Theme.spacingL width: parent.width - 80 - Theme.spacingL
spacing: Theme.spacingS spacing: Theme.spacingS
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
StyledText { StyledText {
text: Prefs.profileImage ? Prefs.profileImage.split('/').pop() : "No profile image selected" text: Prefs.profileImage ? Prefs.profileImage.split('/').pop() : "No profile image selected"
font.pixelSize: Theme.fontSizeLarge font.pixelSize: Theme.fontSizeLarge
@@ -158,7 +167,7 @@ ScrollView {
elide: Text.ElideMiddle elide: Text.ElideMiddle
width: parent.width width: parent.width
} }
StyledText { StyledText {
text: Prefs.profileImage ? Prefs.profileImage : "" text: Prefs.profileImage ? Prefs.profileImage : ""
font.pixelSize: Theme.fontSizeSmall font.pixelSize: Theme.fontSizeSmall
@@ -167,35 +176,36 @@ ScrollView {
width: parent.width width: parent.width
visible: Prefs.profileImage !== "" visible: Prefs.profileImage !== ""
} }
Row { Row {
spacing: Theme.spacingS spacing: Theme.spacingS
StyledRect { StyledRect {
width: 100 width: 100
height: 32 height: 32
radius: Theme.cornerRadius radius: Theme.cornerRadius
color: Theme.primary color: Theme.primary
Row { Row {
anchors.centerIn: parent anchors.centerIn: parent
spacing: Theme.spacingXS spacing: Theme.spacingXS
DankIcon { DankIcon {
name: "folder_open" name: "folder_open"
size: Theme.iconSizeSmall size: Theme.iconSizeSmall
color: Theme.primaryText color: Theme.primaryText
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
} }
StyledText { StyledText {
text: "Browse" text: "Browse"
color: Theme.primaryText color: Theme.primaryText
font.pixelSize: Theme.fontSizeSmall font.pixelSize: Theme.fontSizeSmall
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
} }
} }
MouseArea { MouseArea {
anchors.fill: parent anchors.fill: parent
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
@@ -204,34 +214,36 @@ ScrollView {
profileBrowser.visible = true; profileBrowser.visible = true;
} }
} }
} }
StyledRect { StyledRect {
width: 80 width: 80
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
spacing: Theme.spacingXS spacing: Theme.spacingXS
DankIcon { DankIcon {
name: "clear" name: "clear"
size: Theme.iconSizeSmall size: Theme.iconSizeSmall
color: Theme.surfaceVariantText color: Theme.surfaceVariantText
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
} }
StyledText { StyledText {
text: "Clear" text: "Clear"
color: Theme.surfaceVariantText color: Theme.surfaceVariantText
font.pixelSize: Theme.fontSizeSmall font.pixelSize: Theme.fontSizeSmall
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
} }
} }
MouseArea { MouseArea {
anchors.fill: parent anchors.fill: parent
enabled: Prefs.profileImage !== "" enabled: Prefs.profileImage !== ""
@@ -240,13 +252,19 @@ ScrollView {
Prefs.setProfileImage(""); Prefs.setProfileImage("");
} }
} }
} }
} }
} }
} }
} }
} }
// Wallpaper Section // Wallpaper Section
StyledRect { StyledRect {
width: parent.width width: parent.width
@@ -255,24 +273,25 @@ ScrollView {
color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.3) color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.3)
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2) border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
border.width: 1 border.width: 1
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
Row { Row {
width: parent.width width: parent.width
spacing: Theme.spacingM spacing: Theme.spacingM
DankIcon { DankIcon {
name: "wallpaper" name: "wallpaper"
size: Theme.iconSize size: Theme.iconSize
color: Theme.primary color: Theme.primary
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
} }
StyledText { StyledText {
text: "Wallpaper" text: "Wallpaper"
font.pixelSize: Theme.fontSizeLarge font.pixelSize: Theme.fontSizeLarge
@@ -280,12 +299,13 @@ ScrollView {
color: Theme.surfaceText color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
} }
} }
Row { Row {
width: parent.width width: parent.width
spacing: Theme.spacingL spacing: Theme.spacingL
// Wallpaper Preview // Wallpaper Preview
StyledRect { StyledRect {
width: 160 width: 160
@@ -294,7 +314,7 @@ ScrollView {
color: Theme.surfaceVariant color: Theme.surfaceVariant
border.color: Theme.outline border.color: Theme.outline
border.width: 1 border.width: 1
CachingImage { CachingImage {
anchors.fill: parent anchors.fill: parent
anchors.margins: 1 anchors.margins: 1
@@ -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
@@ -320,7 +343,7 @@ ScrollView {
visible: false visible: false
layer.enabled: true layer.enabled: true
} }
DankIcon { DankIcon {
anchors.centerIn: parent anchors.centerIn: parent
name: "image" name: "image"
@@ -328,13 +351,14 @@ ScrollView {
color: Theme.surfaceVariantText color: Theme.surfaceVariantText
visible: Prefs.wallpaperPath === "" visible: Prefs.wallpaperPath === ""
} }
} }
Column { Column {
width: parent.width - 160 - Theme.spacingL width: parent.width - 160 - Theme.spacingL
spacing: Theme.spacingS spacing: Theme.spacingS
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
StyledText { StyledText {
text: Prefs.wallpaperPath ? Prefs.wallpaperPath.split('/').pop() : "No wallpaper selected" text: Prefs.wallpaperPath ? Prefs.wallpaperPath.split('/').pop() : "No wallpaper selected"
font.pixelSize: Theme.fontSizeLarge font.pixelSize: Theme.fontSizeLarge
@@ -342,7 +366,7 @@ ScrollView {
elide: Text.ElideMiddle elide: Text.ElideMiddle
width: parent.width width: parent.width
} }
StyledText { StyledText {
text: Prefs.wallpaperPath ? Prefs.wallpaperPath : "" text: Prefs.wallpaperPath ? Prefs.wallpaperPath : ""
font.pixelSize: Theme.fontSizeSmall font.pixelSize: Theme.fontSizeSmall
@@ -351,35 +375,36 @@ ScrollView {
width: parent.width width: parent.width
visible: Prefs.wallpaperPath !== "" visible: Prefs.wallpaperPath !== ""
} }
Row { Row {
spacing: Theme.spacingS spacing: Theme.spacingS
StyledRect { StyledRect {
width: 100 width: 100
height: 32 height: 32
radius: Theme.cornerRadius radius: Theme.cornerRadius
color: Theme.primary color: Theme.primary
Row { Row {
anchors.centerIn: parent anchors.centerIn: parent
spacing: Theme.spacingXS spacing: Theme.spacingXS
DankIcon { DankIcon {
name: "folder_open" name: "folder_open"
size: Theme.iconSizeSmall size: Theme.iconSizeSmall
color: Theme.primaryText color: Theme.primaryText
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
} }
StyledText { StyledText {
text: "Browse" text: "Browse"
color: Theme.primaryText color: Theme.primaryText
font.pixelSize: Theme.fontSizeSmall font.pixelSize: Theme.fontSizeSmall
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
} }
} }
MouseArea { MouseArea {
anchors.fill: parent anchors.fill: parent
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
@@ -388,34 +413,36 @@ ScrollView {
wallpaperBrowser.visible = true; wallpaperBrowser.visible = true;
} }
} }
} }
StyledRect { StyledRect {
width: 80 width: 80
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
spacing: Theme.spacingXS spacing: Theme.spacingXS
DankIcon { DankIcon {
name: "clear" name: "clear"
size: Theme.iconSizeSmall size: Theme.iconSizeSmall
color: Theme.surfaceVariantText color: Theme.surfaceVariantText
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
} }
StyledText { StyledText {
text: "Clear" text: "Clear"
color: Theme.surfaceVariantText color: Theme.surfaceVariantText
font.pixelSize: Theme.fontSizeSmall font.pixelSize: Theme.fontSizeSmall
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
} }
} }
MouseArea { MouseArea {
anchors.fill: parent anchors.fill: parent
enabled: Prefs.wallpaperPath !== "" enabled: Prefs.wallpaperPath !== ""
@@ -424,13 +451,19 @@ ScrollView {
Prefs.setWallpaperPath(""); Prefs.setWallpaperPath("");
} }
} }
} }
} }
} }
} }
} }
} }
// Dynamic Theming Section // Dynamic Theming Section
StyledRect { StyledRect {
width: parent.width width: parent.width
@@ -439,36 +472,37 @@ ScrollView {
color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.3) color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.3)
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2) border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
border.width: 1 border.width: 1
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
Row { Row {
width: parent.width width: parent.width
spacing: Theme.spacingM spacing: Theme.spacingM
DankIcon { DankIcon {
name: "palette" name: "palette"
size: Theme.iconSize size: Theme.iconSize
color: Theme.primary color: Theme.primary
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
} }
Column { Column {
width: parent.width - Theme.iconSize - Theme.spacingM - toggle.width - Theme.spacingM width: parent.width - Theme.iconSize - Theme.spacingM - toggle.width - Theme.spacingM
spacing: Theme.spacingXS spacing: Theme.spacingXS
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
StyledText { StyledText {
text: "Dynamic Theming" text: "Dynamic Theming"
font.pixelSize: Theme.fontSizeLarge font.pixelSize: Theme.fontSizeLarge
font.weight: Font.Medium font.weight: Font.Medium
color: Theme.surfaceText color: Theme.surfaceText
} }
StyledText { StyledText {
text: "Automatically extract colors from wallpaper" text: "Automatically extract colors from wallpaper"
font.pixelSize: Theme.fontSizeSmall font.pixelSize: Theme.fontSizeSmall
@@ -476,23 +510,25 @@ 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 {
text: "matugen not detected - dynamic theming unavailable" text: "matugen not detected - dynamic theming unavailable"
font.pixelSize: Theme.fontSizeSmall font.pixelSize: Theme.fontSizeSmall
@@ -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,7 +28,12 @@ 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
color: parent.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08) : "transparent" color: parent.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08) : "transparent"
@@ -32,7 +42,7 @@ Column {
Row { Row {
id: headerRow id: headerRow
width: parent.width width: parent.width
spacing: Theme.spacingS spacing: Theme.spacingS
topPadding: Theme.spacingS topPadding: Theme.spacingS
@@ -43,14 +53,16 @@ Column {
size: Theme.iconSize - 2 size: Theme.iconSize - 2
color: Theme.primary color: Theme.primary
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
Behavior on rotation { Behavior on rotation {
NumberAnimation { NumberAnimation {
duration: Appearance.anim.durations.fast duration: Appearance.anim.durations.fast
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,21 +101,17 @@ 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 {
duration: Appearance.anim.durations.normal duration: Appearance.anim.durations.normal
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

@@ -5,16 +5,17 @@ import qs.Widgets
ScrollView { ScrollView {
id: timeWeatherTab id: timeWeatherTab
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
// Time Settings Section // Time Settings Section
StyledRect { StyledRect {
width: parent.width width: parent.width
@@ -23,24 +24,25 @@ ScrollView {
color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.3) color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.3)
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2) border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
border.width: 1 border.width: 1
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
Row { Row {
width: parent.width width: parent.width
spacing: Theme.spacingM spacing: Theme.spacingM
DankIcon { DankIcon {
name: "schedule" name: "schedule"
size: Theme.iconSize size: Theme.iconSize
color: Theme.primary color: Theme.primary
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
} }
StyledText { StyledText {
text: "Time Format" text: "Time Format"
font.pixelSize: Theme.fontSizeLarge font.pixelSize: Theme.fontSizeLarge
@@ -48,8 +50,9 @@ ScrollView {
color: Theme.surfaceText color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
} }
} }
DankToggle { DankToggle {
width: parent.width width: parent.width
text: "24-Hour Format" text: "24-Hour Format"
@@ -59,9 +62,11 @@ ScrollView {
return Prefs.setClockFormat(checked); return Prefs.setClockFormat(checked);
} }
} }
} }
} }
// Weather Settings Section // Weather Settings Section
StyledRect { StyledRect {
width: parent.width width: parent.width
@@ -70,24 +75,25 @@ ScrollView {
color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.3) color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.3)
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2) border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
border.width: 1 border.width: 1
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
Row { Row {
width: parent.width width: parent.width
spacing: Theme.spacingM spacing: Theme.spacingM
DankIcon { DankIcon {
name: "cloud" name: "cloud"
size: Theme.iconSize size: Theme.iconSize
color: Theme.primary color: Theme.primary
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
} }
StyledText { StyledText {
text: "Weather" text: "Weather"
font.pixelSize: Theme.fontSizeLarge font.pixelSize: Theme.fontSizeLarge
@@ -95,8 +101,9 @@ ScrollView {
color: Theme.surfaceText color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
} }
} }
DankToggle { DankToggle {
width: parent.width width: parent.width
text: "Fahrenheit" text: "Fahrenheit"
@@ -106,7 +113,7 @@ ScrollView {
return Prefs.setTemperatureUnit(checked); return Prefs.setTemperatureUnit(checked);
} }
} }
DankToggle { DankToggle {
width: parent.width width: parent.width
text: "Override Location" text: "Override Location"
@@ -116,21 +123,21 @@ ScrollView {
return Prefs.setWeatherLocationOverrideEnabled(checked); return Prefs.setWeatherLocationOverrideEnabled(checked);
} }
} }
// Location input - only visible when override is enabled // Location input - only visible when override is enabled
Column { Column {
width: parent.width width: parent.width
spacing: Theme.spacingS spacing: Theme.spacingS
visible: Prefs.weatherLocationOverrideEnabled visible: Prefs.weatherLocationOverrideEnabled
opacity: visible ? 1 : 0 opacity: visible ? 1 : 0
StyledText { StyledText {
text: "Location" text: "Location"
font.pixelSize: Theme.fontSizeMedium font.pixelSize: Theme.fontSizeMedium
color: Theme.surfaceText color: Theme.surfaceText
font.weight: Font.Medium font.weight: Font.Medium
} }
DankLocationSearch { DankLocationSearch {
width: parent.width width: parent.width
currentLocation: Prefs.weatherLocationOverride currentLocation: Prefs.weatherLocationOverride
@@ -139,7 +146,7 @@ ScrollView {
Prefs.setWeatherLocationOverride(coordinates); Prefs.setWeatherLocationOverride(coordinates);
} }
} }
StyledText { StyledText {
text: "Examples: \"New York\", \"Tokyo\", \"90210\"" text: "Examples: \"New York\", \"Tokyo\", \"90210\""
font.pixelSize: Theme.fontSizeSmall font.pixelSize: Theme.fontSizeSmall
@@ -147,15 +154,21 @@ ScrollView {
wrapMode: Text.WordWrap wrapMode: Text.WordWrap
width: parent.width width: parent.width
} }
Behavior on opacity { Behavior on opacity {
NumberAnimation { NumberAnimation {
duration: Theme.mediumDuration duration: Theme.mediumDuration
easing.type: Theme.emphasizedEasing easing.type: Theme.emphasizedEasing
} }
} }
} }
} }
} }
} }
}
}

View File

@@ -5,18 +5,19 @@ import qs.Widgets
ScrollView { ScrollView {
id: widgetsTab id: widgetsTab
contentWidth: availableWidth contentWidth: availableWidth
contentHeight: column.implicitHeight + Theme.spacingXL contentHeight: column.implicitHeight + Theme.spacingXL
clip: true clip: true
Column { Column {
id: column id: column
width: parent.width width: parent.width
spacing: Theme.spacingXL spacing: Theme.spacingXL
topPadding: Theme.spacingL topPadding: Theme.spacingL
bottomPadding: Theme.spacingXL bottomPadding: Theme.spacingXL
// Top Bar Widgets Section // Top Bar Widgets Section
StyledRect { StyledRect {
width: parent.width width: parent.width
@@ -25,24 +26,25 @@ ScrollView {
color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.3) color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.3)
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2) border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
border.width: 1 border.width: 1
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
Row { Row {
width: parent.width width: parent.width
spacing: Theme.spacingM spacing: Theme.spacingM
DankIcon { DankIcon {
name: "widgets" name: "widgets"
size: Theme.iconSize size: Theme.iconSize
color: Theme.primary color: Theme.primary
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
} }
StyledText { StyledText {
text: "Top Bar Widgets" text: "Top Bar Widgets"
font.pixelSize: Theme.fontSizeLarge font.pixelSize: Theme.fontSizeLarge
@@ -50,8 +52,9 @@ ScrollView {
color: Theme.surfaceText color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
} }
} }
DankToggle { DankToggle {
width: parent.width width: parent.width
text: "Focused Window" text: "Focused Window"
@@ -61,7 +64,7 @@ ScrollView {
return Prefs.setShowFocusedWindow(checked); return Prefs.setShowFocusedWindow(checked);
} }
} }
DankToggle { DankToggle {
width: parent.width width: parent.width
text: "Weather Widget" text: "Weather Widget"
@@ -71,7 +74,7 @@ ScrollView {
return Prefs.setShowWeather(checked); return Prefs.setShowWeather(checked);
} }
} }
DankToggle { DankToggle {
width: parent.width width: parent.width
text: "Media Controls" text: "Media Controls"
@@ -81,7 +84,7 @@ ScrollView {
return Prefs.setShowMusic(checked); return Prefs.setShowMusic(checked);
} }
} }
DankToggle { DankToggle {
width: parent.width width: parent.width
text: "Clipboard Button" text: "Clipboard Button"
@@ -91,7 +94,7 @@ ScrollView {
return Prefs.setShowClipboard(checked); return Prefs.setShowClipboard(checked);
} }
} }
DankToggle { DankToggle {
width: parent.width width: parent.width
text: "System Resources" text: "System Resources"
@@ -101,7 +104,7 @@ ScrollView {
return Prefs.setShowSystemResources(checked); return Prefs.setShowSystemResources(checked);
} }
} }
DankToggle { DankToggle {
width: parent.width width: parent.width
text: "System Tray" text: "System Tray"
@@ -111,9 +114,11 @@ ScrollView {
return Prefs.setShowSystemTray(checked); return Prefs.setShowSystemTray(checked);
} }
} }
} }
} }
// Workspace Section // Workspace Section
StyledRect { StyledRect {
width: parent.width width: parent.width
@@ -122,24 +127,25 @@ ScrollView {
color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.3) color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.3)
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2) border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
border.width: 1 border.width: 1
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
Row { Row {
width: parent.width width: parent.width
spacing: Theme.spacingM spacing: Theme.spacingM
DankIcon { DankIcon {
name: "view_module" name: "view_module"
size: Theme.iconSize size: Theme.iconSize
color: Theme.primary color: Theme.primary
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
} }
StyledText { StyledText {
text: "Workspace Settings" text: "Workspace Settings"
font.pixelSize: Theme.fontSizeLarge font.pixelSize: Theme.fontSizeLarge
@@ -147,8 +153,9 @@ ScrollView {
color: Theme.surfaceText color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
} }
} }
DankToggle { DankToggle {
width: parent.width width: parent.width
text: "Workspace Index Numbers" text: "Workspace Index Numbers"
@@ -158,7 +165,7 @@ ScrollView {
return Prefs.setShowWorkspaceIndex(checked); return Prefs.setShowWorkspaceIndex(checked);
} }
} }
DankToggle { DankToggle {
width: parent.width width: parent.width
text: "Workspace Padding" text: "Workspace Padding"
@@ -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,44 +18,45 @@ 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);
});
} }
} }
Process { Process {
id: hashProcess id: hashProcess
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)
@@ -159,14 +164,14 @@ Rectangle {
anchors.leftMargin: Theme.spacingS anchors.leftMargin: Theme.spacingS
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
spacing: Theme.spacingS spacing: Theme.spacingS
DankIcon { DankIcon {
name: root.optionIcons.length > index ? root.optionIcons[index] : "" name: root.optionIcons.length > index ? root.optionIcons[index] : ""
size: 18 size: 18
color: root.currentValue === modelData ? Theme.primary : Theme.surfaceVariantText color: root.currentValue === modelData ? Theme.primary : Theme.surfaceVariantText
visible: name !== "" visible: name !== ""
} }
Text { Text {
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
text: modelData text: modelData
@@ -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

@@ -20,32 +20,29 @@ ScrollView {
property real wheelStepSize: 60 property real wheelStepSize: 60
property bool hoverUpdatesSelection: true property bool hoverUpdatesSelection: true
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

@@ -16,31 +16,29 @@ ScrollView {
property int itemSpacing: Theme.spacingS property int itemSpacing: Theme.spacingS
property bool hoverUpdatesSelection: true property bool hoverUpdatesSelection: true
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 >= 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
@@ -105,9 +101,10 @@ Item {
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
visible: (sliderMouseArea.containsMouse && slider.showValue) || (slider.isDragging && slider.showValue) visible: (sliderMouseArea.containsMouse && slider.showValue) || (slider.isDragging && slider.showValue)
opacity: visible ? 1 : 0 opacity: visible ? 1 : 0
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
@@ -115,14 +112,25 @@ Item {
anchors.centerIn: parent anchors.centerIn: parent
font.hintingPreference: Font.PreferFullHinting font.hintingPreference: Font.PreferFullHinting
} }
Behavior on opacity { Behavior on opacity {
NumberAnimation { NumberAnimation {
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,11 +38,10 @@ 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: []
// Signals // Signals
signal textEdited() signal textEdited()
signal editingFinished() signal editingFinished()
@@ -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
// } }
} }