mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-04-03 20:32:07 -04:00
uncomment toast, and format
This commit is contained in:
@@ -6,9 +6,9 @@ import Quickshell.Io
|
||||
import Quickshell.Wayland
|
||||
import Quickshell.Widgets
|
||||
import qs.Common
|
||||
import qs.Modules.AppDrawer
|
||||
import qs.Services
|
||||
import qs.Widgets
|
||||
import qs.Modules.AppDrawer
|
||||
|
||||
PanelWindow {
|
||||
id: appDrawerPopout
|
||||
@@ -53,7 +53,6 @@ PanelWindow {
|
||||
|
||||
viewMode: Prefs.appLauncherViewMode
|
||||
gridColumns: 4
|
||||
|
||||
onAppLaunched: appDrawerPopout.hide()
|
||||
onViewModeSelected: function(mode) {
|
||||
Prefs.setAppLauncherViewMode(mode);
|
||||
@@ -67,24 +66,22 @@ PanelWindow {
|
||||
onClicked: function(mouse) {
|
||||
// Only close if click is outside the launcher panel
|
||||
var localPos = mapToItem(launcherLoader, mouse.x, mouse.y);
|
||||
if (localPos.x < 0 || localPos.x > launcherLoader.width ||
|
||||
localPos.y < 0 || localPos.y > launcherLoader.height) {
|
||||
if (localPos.x < 0 || localPos.x > launcherLoader.width || localPos.y < 0 || localPos.y > launcherLoader.height)
|
||||
appDrawerPopout.hide();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// Main launcher panel with asynchronous loading
|
||||
Loader {
|
||||
id: launcherLoader
|
||||
|
||||
asynchronous: true
|
||||
active: appDrawerPopout.isVisible
|
||||
|
||||
width: 520
|
||||
height: 600
|
||||
x: Theme.spacingL
|
||||
y: Theme.barHeight + Theme.spacingXS
|
||||
|
||||
opacity: appDrawerPopout.isVisible ? 1 : 0
|
||||
scale: appDrawerPopout.isVisible ? 1 : 0.9
|
||||
|
||||
@@ -94,6 +91,7 @@ PanelWindow {
|
||||
easing.type: Easing.BezierSpline
|
||||
easing.bezierCurve: Anims.emphasized
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Behavior on scale {
|
||||
@@ -102,13 +100,14 @@ PanelWindow {
|
||||
easing.type: Easing.BezierSpline
|
||||
easing.bezierCurve: Anims.emphasized
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
sourceComponent: Rectangle {
|
||||
id: launcherPanel
|
||||
|
||||
color: Theme.popupBackground()
|
||||
radius: Theme.cornerRadiusXLarge
|
||||
|
||||
// Remove layer rendering for better performance
|
||||
antialiasing: true
|
||||
smooth: true
|
||||
@@ -146,13 +145,14 @@ PanelWindow {
|
||||
// Content with focus management
|
||||
Item {
|
||||
id: keyHandler
|
||||
|
||||
anchors.fill: parent
|
||||
focus: true
|
||||
Component.onCompleted: {
|
||||
if (appDrawerPopout.isVisible)
|
||||
forceActiveFocus();
|
||||
}
|
||||
|
||||
}
|
||||
// Handle keyboard shortcuts
|
||||
Keys.onPressed: function(event) {
|
||||
if (event.key === Qt.Key_Escape) {
|
||||
@@ -214,6 +214,7 @@ PanelWindow {
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: Theme.surfaceVariantText
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Enhanced search field
|
||||
@@ -252,26 +253,25 @@ PanelWindow {
|
||||
event.accepted = false;
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
if (appDrawerPopout.isVisible) {
|
||||
if (appDrawerPopout.isVisible)
|
||||
searchField.forceActiveFocus();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Connections {
|
||||
function onIsVisibleChanged() {
|
||||
if (appDrawerPopout.isVisible) {
|
||||
if (appDrawerPopout.isVisible)
|
||||
Qt.callLater(function() {
|
||||
searchField.forceActiveFocus();
|
||||
});
|
||||
} else {
|
||||
else
|
||||
searchField.clearFocus();
|
||||
}
|
||||
}
|
||||
|
||||
target: appDrawerPopout
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Category filter and view mode controls
|
||||
@@ -296,6 +296,7 @@ PanelWindow {
|
||||
appLauncher.setCategory(value);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Item {
|
||||
@@ -335,7 +336,9 @@ PanelWindow {
|
||||
appLauncher.setViewMode("grid");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// App grid/list container
|
||||
@@ -399,10 +402,15 @@ PanelWindow {
|
||||
appLauncher.keyboardNavigationActive = false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -18,62 +18,35 @@ Item {
|
||||
property bool debounceSearch: true
|
||||
property int debounceInterval: 50
|
||||
property bool keyboardNavigationActive: false
|
||||
|
||||
// Categories (computed from AppSearchService)
|
||||
property var categories: {
|
||||
var allCategories = AppSearchService.getAllCategories().filter(cat => {
|
||||
var allCategories = AppSearchService.getAllCategories().filter((cat) => {
|
||||
return cat !== "Education" && cat !== "Science";
|
||||
});
|
||||
var result = ["All"];
|
||||
return result.concat(allCategories.filter(cat => {
|
||||
return result.concat(allCategories.filter((cat) => {
|
||||
return cat !== "All";
|
||||
}));
|
||||
}
|
||||
|
||||
// Category icons (computed from AppSearchService)
|
||||
property var categoryIcons: categories.map(category => AppSearchService.getCategoryIcon(category))
|
||||
|
||||
property var categoryIcons: categories.map((category) => {
|
||||
return AppSearchService.getCategoryIcon(category);
|
||||
})
|
||||
// App usage ranking helper
|
||||
property var appUsageRanking: Prefs.appUsageRanking
|
||||
// Internal model
|
||||
property alias model: filteredModel
|
||||
|
||||
// Signals
|
||||
signal appLaunched(var app)
|
||||
signal categorySelected(string category)
|
||||
signal viewModeSelected(string mode)
|
||||
|
||||
// Internal model
|
||||
property alias model: filteredModel
|
||||
|
||||
ListModel {
|
||||
id: filteredModel
|
||||
}
|
||||
|
||||
// Search debouncing
|
||||
Timer {
|
||||
id: searchDebounceTimer
|
||||
interval: root.debounceInterval
|
||||
repeat: false
|
||||
onTriggered: updateFilteredModel()
|
||||
}
|
||||
|
||||
// Watch for changes
|
||||
onSearchQueryChanged: {
|
||||
if (debounceSearch) {
|
||||
searchDebounceTimer.restart();
|
||||
} else {
|
||||
updateFilteredModel();
|
||||
}
|
||||
}
|
||||
onSelectedCategoryChanged: updateFilteredModel()
|
||||
onAppUsageRankingChanged: updateFilteredModel()
|
||||
|
||||
function updateFilteredModel() {
|
||||
filteredModel.clear();
|
||||
selectedIndex = 0;
|
||||
keyboardNavigationActive = false;
|
||||
|
||||
var apps = [];
|
||||
|
||||
if (searchQuery.length === 0) {
|
||||
// Show apps from category
|
||||
if (selectedCategory === "All") {
|
||||
@@ -90,8 +63,10 @@ Item {
|
||||
var categoryApps = AppSearchService.getAppsInCategory(selectedCategory);
|
||||
if (categoryApps.length > 0) {
|
||||
var allSearchResults = AppSearchService.searchApplications(searchQuery);
|
||||
var categoryNames = new Set(categoryApps.map(app => app.name));
|
||||
apps = allSearchResults.filter(searchApp => {
|
||||
var categoryNames = new Set(categoryApps.map((app) => {
|
||||
return app.name;
|
||||
}));
|
||||
apps = allSearchResults.filter((searchApp) => {
|
||||
return categoryNames.has(searchApp.name);
|
||||
}).slice(0, maxResults);
|
||||
} else {
|
||||
@@ -99,25 +74,20 @@ Item {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Sort apps by usage ranking, then alphabetically
|
||||
apps = apps.sort(function(a, b) {
|
||||
var aId = a.id || (a.execString || a.exec || "");
|
||||
var bId = b.id || (b.execString || b.exec || "");
|
||||
|
||||
var aUsage = appUsageRanking[aId] ? appUsageRanking[aId].usageCount : 0;
|
||||
var bUsage = appUsageRanking[bId] ? appUsageRanking[bId].usageCount : 0;
|
||||
|
||||
if (aUsage !== bUsage) {
|
||||
if (aUsage !== bUsage)
|
||||
return bUsage - aUsage; // Higher usage first
|
||||
}
|
||||
|
||||
return (a.name || "").localeCompare(b.name || ""); // Alphabetical fallback
|
||||
});
|
||||
|
||||
// Convert to model format and populate
|
||||
apps.forEach(app => {
|
||||
if (app) {
|
||||
apps.forEach((app) => {
|
||||
if (app)
|
||||
filteredModel.append({
|
||||
"name": app.name || "",
|
||||
"exec": app.execString || "",
|
||||
@@ -126,7 +96,7 @@ Item {
|
||||
"categories": app.categories || [],
|
||||
"desktopEntry": app
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
@@ -180,9 +150,8 @@ Item {
|
||||
function launchApp(appData) {
|
||||
if (!appData) {
|
||||
console.warn("AppLauncher: No app data provided");
|
||||
return;
|
||||
return ;
|
||||
}
|
||||
|
||||
appData.desktopEntry.execute();
|
||||
appLaunched(appData);
|
||||
Prefs.addAppUsage(appData.desktopEntry);
|
||||
@@ -200,8 +169,31 @@ Item {
|
||||
viewModeSelected(mode);
|
||||
}
|
||||
|
||||
// Watch for changes
|
||||
onSearchQueryChanged: {
|
||||
if (debounceSearch)
|
||||
searchDebounceTimer.restart();
|
||||
else
|
||||
updateFilteredModel();
|
||||
}
|
||||
onSelectedCategoryChanged: updateFilteredModel()
|
||||
onAppUsageRankingChanged: updateFilteredModel()
|
||||
// Initialize
|
||||
Component.onCompleted: {
|
||||
updateFilteredModel();
|
||||
}
|
||||
|
||||
ListModel {
|
||||
id: filteredModel
|
||||
}
|
||||
|
||||
// Search debouncing
|
||||
Timer {
|
||||
id: searchDebounceTimer
|
||||
|
||||
interval: root.debounceInterval
|
||||
repeat: false
|
||||
onTriggered: updateFilteredModel()
|
||||
}
|
||||
|
||||
}
|
||||
@@ -48,8 +48,11 @@ Item {
|
||||
categorySelected(modelData);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Two-row layout (for SpotlightModal organized style)
|
||||
@@ -66,7 +69,7 @@ Item {
|
||||
spacing: Theme.spacingS
|
||||
|
||||
Repeater {
|
||||
model: parent.topRowCategories.filter(cat => {
|
||||
model: parent.topRowCategories.filter((cat) => {
|
||||
return categories.includes(cat);
|
||||
})
|
||||
|
||||
@@ -95,8 +98,11 @@ Item {
|
||||
categorySelected(modelData);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Bottom row: Internet, Media, Office, Settings, System (5 items)
|
||||
@@ -107,7 +113,7 @@ Item {
|
||||
spacing: Theme.spacingS
|
||||
|
||||
Repeater {
|
||||
model: parent.bottomRowCategories.filter(cat => {
|
||||
model: parent.bottomRowCategories.filter((cat) => {
|
||||
return categories.includes(cat);
|
||||
})
|
||||
|
||||
@@ -136,8 +142,13 @@ Item {
|
||||
categorySelected(modelData);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -6,8 +6,8 @@ import Quickshell.Services.Mpris
|
||||
import Quickshell.Wayland
|
||||
import Quickshell.Widgets
|
||||
import qs.Common
|
||||
import qs.Services
|
||||
import qs.Modules.CentcomCenter
|
||||
import qs.Services
|
||||
|
||||
PanelWindow {
|
||||
id: root
|
||||
@@ -17,25 +17,25 @@ PanelWindow {
|
||||
property bool internalVisible: false
|
||||
|
||||
visible: internalVisible
|
||||
|
||||
onCalendarVisibleChanged: {
|
||||
if (calendarVisible) {
|
||||
internalVisible = true
|
||||
internalVisible = true;
|
||||
Qt.callLater(() => {
|
||||
// This ensures opacity changes after window is visible
|
||||
internalVisible = true // Force re-trigger if needed
|
||||
internalVisible = true;
|
||||
// Force re-trigger if needed
|
||||
// Ensure events are loaded for current display month
|
||||
calendarGrid.loadEventsForMonth()
|
||||
})
|
||||
calendarGrid.loadEventsForMonth();
|
||||
});
|
||||
} else {
|
||||
internalVisible = false
|
||||
internalVisible = false;
|
||||
}
|
||||
}
|
||||
onVisibleChanged: {
|
||||
if (visible && calendarGrid)
|
||||
calendarGrid.loadEventsForMonth();
|
||||
}
|
||||
|
||||
}
|
||||
implicitWidth: 480
|
||||
implicitHeight: 600
|
||||
WlrLayershell.layer: WlrLayershell.Overlay
|
||||
@@ -53,6 +53,8 @@ PanelWindow {
|
||||
Rectangle {
|
||||
id: mainContainer
|
||||
|
||||
readonly property real targetWidth: Math.min(Screen.width * 0.9, 600)
|
||||
|
||||
function calculateWidth() {
|
||||
let baseWidth = 320;
|
||||
if (leftWidgets.hasAnyWidgets)
|
||||
@@ -80,7 +82,6 @@ PanelWindow {
|
||||
return Math.min(contentHeight, parent.height * 0.9);
|
||||
}
|
||||
|
||||
readonly property real targetWidth: Math.min(Screen.width * 0.9, 600)
|
||||
width: targetWidth
|
||||
height: calculateHeight()
|
||||
color: Theme.surfaceContainer
|
||||
@@ -92,44 +93,27 @@ PanelWindow {
|
||||
scale: calendarVisible ? 1 : 0.9
|
||||
x: (Screen.width - targetWidth) / 2
|
||||
y: Theme.barHeight + 4
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
duration: Anims.durMed
|
||||
easing.type: Easing.BezierSpline
|
||||
easing.bezierCurve: Anims.emphasized
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on scale {
|
||||
NumberAnimation {
|
||||
duration: Anims.durMed
|
||||
easing.type: Easing.BezierSpline
|
||||
easing.bezierCurve: Anims.emphasized
|
||||
}
|
||||
}
|
||||
|
||||
// Only resize after animation is complete
|
||||
onOpacityChanged: {
|
||||
if (opacity === 1) {
|
||||
if (opacity === 1)
|
||||
// Animation finished, now we can safely resize
|
||||
Qt.callLater(() => {
|
||||
height = calculateHeight();
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Connections {
|
||||
function onEventsByDateChanged() {
|
||||
if (mainContainer.opacity === 1) {
|
||||
if (mainContainer.opacity === 1)
|
||||
mainContainer.height = mainContainer.calculateHeight();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function onKhalAvailableChanged() {
|
||||
if (mainContainer.opacity === 1) {
|
||||
if (mainContainer.opacity === 1)
|
||||
mainContainer.height = mainContainer.calculateHeight();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
target: CalendarService
|
||||
@@ -138,9 +122,9 @@ PanelWindow {
|
||||
|
||||
Connections {
|
||||
function onSelectedDateEventsChanged() {
|
||||
if (mainContainer.opacity === 1) {
|
||||
if (mainContainer.opacity === 1)
|
||||
mainContainer.height = mainContainer.calculateHeight();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
target: events
|
||||
@@ -172,8 +156,6 @@ PanelWindow {
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
Column {
|
||||
anchors.fill: parent
|
||||
anchors.margins: Theme.spacingM
|
||||
@@ -236,6 +218,24 @@ PanelWindow {
|
||||
|
||||
}
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
duration: Anims.durMed
|
||||
easing.type: Easing.BezierSpline
|
||||
easing.bezierCurve: Anims.emphasized
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Behavior on scale {
|
||||
NumberAnimation {
|
||||
duration: Anims.durMed
|
||||
easing.type: Easing.BezierSpline
|
||||
easing.bezierCurve: Anims.emphasized
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
layer.effect: MultiEffect {
|
||||
shadowEnabled: true
|
||||
shadowHorizontalOffset: 0
|
||||
@@ -245,8 +245,6 @@ PanelWindow {
|
||||
shadowOpacity: 0.15
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
@@ -256,10 +254,9 @@ PanelWindow {
|
||||
onClicked: function(mouse) {
|
||||
// Only close if click is outside the main container
|
||||
var localPos = mapToItem(mainContainer, mouse.x, mouse.y);
|
||||
if (localPos.x < 0 || localPos.x > mainContainer.width ||
|
||||
localPos.y < 0 || localPos.y > mainContainer.height) {
|
||||
if (localPos.x < 0 || localPos.x > mainContainer.width || localPos.y < 0 || localPos.y > mainContainer.height)
|
||||
calendarVisible = false;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ PanelWindow {
|
||||
|
||||
visible: notificationHistoryVisible
|
||||
implicitWidth: 400
|
||||
implicitHeight: Math.min(Screen.height * 0.60, Math.max(580, (notificationsList.contentHeight || 0) + 140))
|
||||
implicitHeight: Math.min(Screen.height * 0.6, Math.max(580, (notificationsList.contentHeight || 0) + 140))
|
||||
WlrLayershell.layer: WlrLayershell.Overlay
|
||||
WlrLayershell.exclusiveZone: -1
|
||||
WlrLayershell.keyboardFocus: WlrKeyboardFocus.None
|
||||
@@ -39,7 +39,7 @@ PanelWindow {
|
||||
|
||||
Rectangle {
|
||||
width: 400
|
||||
height: Math.min(Screen.height * 0.60, Math.max(580, (notificationsList.contentHeight || 0) + 140))
|
||||
height: Math.min(Screen.height * 0.6, Math.max(580, (notificationsList.contentHeight || 0) + 140))
|
||||
x: Screen.width - width - Theme.spacingL
|
||||
y: Theme.barHeight + Theme.spacingXS
|
||||
color: Theme.popupBackground()
|
||||
@@ -710,7 +710,6 @@ PanelWindow {
|
||||
|
||||
delegate: Rectangle {
|
||||
required property var modelData
|
||||
|
||||
readonly property bool messageExpanded: NotificationService.expandedMessages[modelData.notification.id] || false
|
||||
|
||||
width: parent.width
|
||||
@@ -830,7 +829,6 @@ PanelWindow {
|
||||
bodyText = bodyText.length > 500 ? bodyText.substring(0, 497) + "..." : bodyText;
|
||||
else
|
||||
bodyText = bodyText.length > 80 ? bodyText.substring(0, 77) + "..." : bodyText;
|
||||
|
||||
// Auto-detect and make URLs clickable
|
||||
const urlRegex = /(https?:\/\/[^\s]+)/g;
|
||||
return bodyText.replace(urlRegex, '<a href="$1" style="color: ' + Theme.primary + '; text-decoration: underline;">$1</a>');
|
||||
@@ -916,7 +914,6 @@ PanelWindow {
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1114,6 +1111,7 @@ PanelWindow {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.standardEasing
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Behavior on opacity {
|
||||
|
||||
@@ -16,7 +16,7 @@ PanelWindow {
|
||||
WlrLayershell.keyboardFocus: WlrKeyboardFocus.None
|
||||
color: "transparent"
|
||||
implicitWidth: 400
|
||||
implicitHeight: Math.min(Screen.height * 0.60, Math.max(400, (notificationsList.contentHeight || 0) + 32))
|
||||
implicitHeight: Math.min(Screen.height * 0.6, Math.max(400, (notificationsList.contentHeight || 0) + 32))
|
||||
|
||||
anchors {
|
||||
top: true
|
||||
@@ -35,18 +35,11 @@ PanelWindow {
|
||||
anchors.rightMargin: 16
|
||||
anchors.bottomMargin: 16
|
||||
width: 380
|
||||
height: Math.min(Screen.height * 0.60 - 32, Math.max(368, (notificationsList.contentHeight || 0) + 32))
|
||||
height: Math.min(Screen.height * 0.6 - 32, Math.max(368, (notificationsList.contentHeight || 0) + 32))
|
||||
color: "transparent"
|
||||
radius: 12
|
||||
clip: true
|
||||
|
||||
Behavior on height {
|
||||
NumberAnimation {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.standardEasing
|
||||
}
|
||||
}
|
||||
|
||||
ScrollView {
|
||||
anchors.fill: parent
|
||||
clip: true
|
||||
@@ -607,6 +600,7 @@ PanelWindow {
|
||||
// Body text with expand capability
|
||||
Text {
|
||||
id: bodyText
|
||||
|
||||
property bool hasUrls: {
|
||||
const urlRegex = /(https?:\/\/[^\s]+)/g;
|
||||
return urlRegex.test(modelData.body || "");
|
||||
@@ -908,6 +902,14 @@ PanelWindow {
|
||||
|
||||
}
|
||||
|
||||
Behavior on height {
|
||||
NumberAnimation {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.standardEasing
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Behavior on implicitHeight {
|
||||
|
||||
@@ -14,6 +14,7 @@ ScrollView {
|
||||
|
||||
Column {
|
||||
id: column
|
||||
|
||||
width: parent.width
|
||||
spacing: Theme.spacingXL
|
||||
topPadding: Theme.spacingL
|
||||
@@ -30,6 +31,7 @@ ScrollView {
|
||||
|
||||
Column {
|
||||
id: displaySection
|
||||
|
||||
anchors.fill: parent
|
||||
anchors.margins: Theme.spacingL
|
||||
spacing: Theme.spacingM
|
||||
@@ -52,6 +54,7 @@ ScrollView {
|
||||
color: Theme.surfaceText
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
DankToggle {
|
||||
@@ -89,7 +92,9 @@ ScrollView {
|
||||
Prefs.setIconTheme(value);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Transparency Settings Section
|
||||
@@ -103,6 +108,7 @@ ScrollView {
|
||||
|
||||
Column {
|
||||
id: transparencySection
|
||||
|
||||
anchors.fill: parent
|
||||
anchors.margins: Theme.spacingL
|
||||
spacing: Theme.spacingM
|
||||
@@ -125,6 +131,7 @@ ScrollView {
|
||||
color: Theme.surfaceText
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Column {
|
||||
@@ -150,6 +157,7 @@ ScrollView {
|
||||
Prefs.setTopBarTransparency(newValue / 100);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Column {
|
||||
@@ -175,8 +183,11 @@ ScrollView {
|
||||
Prefs.setPopupTransparency(newValue / 100);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Theme Picker Section
|
||||
@@ -190,6 +201,7 @@ ScrollView {
|
||||
|
||||
Column {
|
||||
id: themeSection
|
||||
|
||||
anchors.fill: parent
|
||||
anchors.margins: Theme.spacingL
|
||||
spacing: Theme.spacingM
|
||||
@@ -212,6 +224,7 @@ ScrollView {
|
||||
color: Theme.surfaceText
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Column {
|
||||
@@ -241,6 +254,7 @@ ScrollView {
|
||||
width: Math.min(parent.width, 400)
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Theme Grid
|
||||
@@ -280,15 +294,18 @@ ScrollView {
|
||||
|
||||
StyledText {
|
||||
id: nameText
|
||||
|
||||
text: Theme.themes[index].name
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceText
|
||||
anchors.centerIn: parent
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: mouseArea
|
||||
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
@@ -302,6 +319,7 @@ ScrollView {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.emphasizedEasing
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Behavior on border.width {
|
||||
@@ -309,9 +327,13 @@ ScrollView {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.emphasizedEasing
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Second row - Red, Cyan, Pink, Amber, Coral
|
||||
@@ -349,21 +371,25 @@ ScrollView {
|
||||
|
||||
StyledText {
|
||||
id: nameText2
|
||||
|
||||
text: themeIndex < Theme.themes.length ? Theme.themes[themeIndex].name : ""
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceText
|
||||
anchors.centerIn: parent
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: mouseArea2
|
||||
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
if (themeIndex < Theme.themes.length)
|
||||
Theme.switchTheme(themeIndex);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -372,6 +398,7 @@ ScrollView {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.emphasizedEasing
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Behavior on border.width {
|
||||
@@ -379,9 +406,13 @@ ScrollView {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.emphasizedEasing
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Spacer
|
||||
@@ -453,21 +484,22 @@ ScrollView {
|
||||
font.weight: Font.Medium
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: autoMouseArea
|
||||
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
if (ToastService.wallpaperErrorStatus === "matugen_missing") {
|
||||
if (ToastService.wallpaperErrorStatus === "matugen_missing")
|
||||
ToastService.showError("matugen not found - install matugen package for dynamic theming");
|
||||
} else if (ToastService.wallpaperErrorStatus === "error") {
|
||||
else if (ToastService.wallpaperErrorStatus === "error")
|
||||
ToastService.showError("Wallpaper processing failed - check wallpaper path");
|
||||
} else {
|
||||
else
|
||||
Theme.switchTheme(10, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -486,6 +518,7 @@ ScrollView {
|
||||
|
||||
StyledText {
|
||||
id: autoTooltipText
|
||||
|
||||
text: {
|
||||
if (ToastService.wallpaperErrorStatus === "error")
|
||||
return "Wallpaper symlink missing at ~/quickshell/current_wallpaper";
|
||||
@@ -501,6 +534,7 @@ ScrollView {
|
||||
width: Math.min(implicitWidth, 250)
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Behavior on scale {
|
||||
@@ -508,6 +542,7 @@ ScrollView {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.emphasizedEasing
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Behavior on color {
|
||||
@@ -515,6 +550,7 @@ ScrollView {
|
||||
duration: Theme.mediumDuration
|
||||
easing.type: Theme.standardEasing
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Behavior on border.color {
|
||||
@@ -522,16 +558,23 @@ ScrollView {
|
||||
duration: Theme.mediumDuration
|
||||
easing.type: Theme.standardEasing
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Night mode processes
|
||||
Process {
|
||||
id: nightModeEnableProcess
|
||||
|
||||
command: ["bash", "-c", "if command -v wlsunset > /dev/null; then pkill wlsunset; wlsunset -t 3000 & elif command -v redshift > /dev/null; then pkill redshift; redshift -P -O 3000 & else echo 'No night mode tool available'; fi"]
|
||||
running: false
|
||||
onExited: (exitCode) => {
|
||||
@@ -544,11 +587,14 @@ ScrollView {
|
||||
|
||||
Process {
|
||||
id: nightModeDisableProcess
|
||||
|
||||
command: ["bash", "-c", "pkill wlsunset; pkill redshift; if command -v wlsunset > /dev/null; then wlsunset -t 6500 -T 6500 & sleep 1; pkill wlsunset; elif command -v redshift > /dev/null; then redshift -P -O 6500; redshift -x; fi"]
|
||||
running: false
|
||||
onExited: (exitCode) => {
|
||||
if (exitCode !== 0)
|
||||
console.warn("Failed to disable night mode");
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -296,18 +296,26 @@ ScrollView {
|
||||
|
||||
StyledText {
|
||||
text: {
|
||||
if (!modelData.lastUsed) return "Never used";
|
||||
if (!modelData.lastUsed)
|
||||
return "Never used";
|
||||
|
||||
var date = new Date(modelData.lastUsed);
|
||||
var now = new Date();
|
||||
var diffMs = now - date;
|
||||
var diffMins = Math.floor(diffMs / (1000 * 60));
|
||||
var diffHours = Math.floor(diffMs / (1000 * 60 * 60));
|
||||
var diffDays = Math.floor(diffMs / (1000 * 60 * 60 * 24));
|
||||
if (diffMins < 1)
|
||||
return "Last launched just now";
|
||||
|
||||
if (diffMins < 1) return "Last launched just now";
|
||||
if (diffMins < 60) return "Last launched " + diffMins + " minute" + (diffMins === 1 ? "" : "s") + " ago";
|
||||
if (diffHours < 24) return "Last launched " + diffHours + " hour" + (diffHours === 1 ? "" : "s") + " ago";
|
||||
if (diffDays < 7) return "Last launched " + diffDays + " day" + (diffDays === 1 ? "" : "s") + " ago";
|
||||
if (diffMins < 60)
|
||||
return "Last launched " + diffMins + " minute" + (diffMins === 1 ? "" : "s") + " ago";
|
||||
|
||||
if (diffHours < 24)
|
||||
return "Last launched " + diffHours + " hour" + (diffHours === 1 ? "" : "s") + " ago";
|
||||
|
||||
if (diffDays < 7)
|
||||
return "Last launched " + diffDays + " day" + (diffDays === 1 ? "" : "s") + " ago";
|
||||
|
||||
return "Last launched " + date.toLocaleDateString();
|
||||
}
|
||||
@@ -329,7 +337,8 @@ ScrollView {
|
||||
iconColor: Theme.error
|
||||
hoverColor: Qt.rgba(Theme.error.r, Theme.error.g, Theme.error.b, 0.12)
|
||||
onClicked: {
|
||||
var currentRanking = Object.assign({}, Prefs.appUsageRanking);
|
||||
var currentRanking = Object.assign({
|
||||
}, Prefs.appUsageRanking);
|
||||
delete currentRanking[modelData.id];
|
||||
Prefs.appUsageRanking = currentRanking;
|
||||
Prefs.saveSettings();
|
||||
|
||||
@@ -3,19 +3,23 @@ import QtQuick.Controls
|
||||
import QtQuick.Effects
|
||||
import Quickshell
|
||||
import qs.Common
|
||||
import qs.Modals
|
||||
import qs.Services
|
||||
import qs.Widgets
|
||||
import qs.Modals
|
||||
|
||||
ScrollView {
|
||||
id: personalizationTab
|
||||
|
||||
property alias profileBrowser: profileBrowserLoader.item
|
||||
property alias wallpaperBrowser: wallpaperBrowserLoader.item
|
||||
|
||||
contentWidth: availableWidth
|
||||
contentHeight: column.implicitHeight
|
||||
clip: true
|
||||
|
||||
Column {
|
||||
id: column
|
||||
|
||||
width: parent.width
|
||||
spacing: Theme.spacingXL
|
||||
|
||||
@@ -30,6 +34,7 @@ ScrollView {
|
||||
|
||||
Column {
|
||||
id: profileSection
|
||||
|
||||
anchors.fill: parent
|
||||
anchors.margins: Theme.spacingL
|
||||
spacing: Theme.spacingM
|
||||
@@ -52,6 +57,7 @@ ScrollView {
|
||||
color: Theme.surfaceText
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Row {
|
||||
@@ -121,6 +127,7 @@ ScrollView {
|
||||
color: "black"
|
||||
antialiasing: true
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
@@ -135,6 +142,7 @@ ScrollView {
|
||||
size: Theme.iconSizeLarge + 8
|
||||
color: Theme.primaryText
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
DankIcon {
|
||||
@@ -144,6 +152,7 @@ ScrollView {
|
||||
color: Theme.error
|
||||
visible: Prefs.profileImage !== "" && avatarImageSource.status === Image.Error
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Column {
|
||||
@@ -194,6 +203,7 @@ ScrollView {
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
@@ -204,6 +214,7 @@ ScrollView {
|
||||
profileBrowser.visible = true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
StyledRect {
|
||||
@@ -211,7 +222,7 @@ ScrollView {
|
||||
height: 32
|
||||
radius: Theme.cornerRadius
|
||||
color: Theme.surfaceVariant
|
||||
opacity: Prefs.profileImage !== "" ? 1.0 : 0.5
|
||||
opacity: Prefs.profileImage !== "" ? 1 : 0.5
|
||||
|
||||
Row {
|
||||
anchors.centerIn: parent
|
||||
@@ -230,6 +241,7 @@ ScrollView {
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
@@ -240,11 +252,17 @@ ScrollView {
|
||||
Prefs.setProfileImage("");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Wallpaper Section
|
||||
@@ -258,6 +276,7 @@ ScrollView {
|
||||
|
||||
Column {
|
||||
id: wallpaperSection
|
||||
|
||||
anchors.fill: parent
|
||||
anchors.margins: Theme.spacingL
|
||||
spacing: Theme.spacingM
|
||||
@@ -280,6 +299,7 @@ ScrollView {
|
||||
color: Theme.surfaceText
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Row {
|
||||
@@ -303,16 +323,19 @@ ScrollView {
|
||||
visible: Prefs.wallpaperPath !== ""
|
||||
maxCacheSize: 160
|
||||
layer.enabled: true
|
||||
|
||||
layer.effect: MultiEffect {
|
||||
maskEnabled: true
|
||||
maskSource: wallpaperMask
|
||||
maskThresholdMin: 0.5
|
||||
maskSpreadAtMin: 1.0
|
||||
maskSpreadAtMin: 1
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: wallpaperMask
|
||||
|
||||
anchors.fill: parent
|
||||
anchors.margins: 1
|
||||
radius: Theme.cornerRadius - 1
|
||||
@@ -328,6 +351,7 @@ ScrollView {
|
||||
color: Theme.surfaceVariantText
|
||||
visible: Prefs.wallpaperPath === ""
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Column {
|
||||
@@ -378,6 +402,7 @@ ScrollView {
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
@@ -388,6 +413,7 @@ ScrollView {
|
||||
wallpaperBrowser.visible = true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
StyledRect {
|
||||
@@ -395,7 +421,7 @@ ScrollView {
|
||||
height: 32
|
||||
radius: Theme.cornerRadius
|
||||
color: Theme.surfaceVariant
|
||||
opacity: Prefs.wallpaperPath !== "" ? 1.0 : 0.5
|
||||
opacity: Prefs.wallpaperPath !== "" ? 1 : 0.5
|
||||
|
||||
Row {
|
||||
anchors.centerIn: parent
|
||||
@@ -414,6 +440,7 @@ ScrollView {
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
@@ -424,11 +451,17 @@ ScrollView {
|
||||
Prefs.setWallpaperPath("");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Dynamic Theming Section
|
||||
@@ -442,6 +475,7 @@ ScrollView {
|
||||
|
||||
Column {
|
||||
id: dynamicThemeSection
|
||||
|
||||
anchors.fill: parent
|
||||
anchors.margins: Theme.spacingL
|
||||
spacing: Theme.spacingM
|
||||
@@ -476,21 +510,23 @@ ScrollView {
|
||||
wrapMode: Text.WordWrap
|
||||
width: parent.width
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
DankToggle {
|
||||
id: toggle
|
||||
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
checked: Theme.isDynamicTheme
|
||||
enabled: ToastService.wallpaperErrorStatus !== "matugen_missing"
|
||||
onToggled: (toggled) => {
|
||||
if (toggled) {
|
||||
Theme.switchTheme(10, true)
|
||||
} else {
|
||||
Theme.switchTheme(0)
|
||||
}
|
||||
if (toggled)
|
||||
Theme.switchTheme(10, true);
|
||||
else
|
||||
Theme.switchTheme(0);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
StyledText {
|
||||
@@ -501,16 +537,21 @@ ScrollView {
|
||||
width: parent.width
|
||||
leftPadding: Theme.iconSize + Theme.spacingM
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
LazyLoader {
|
||||
id: profileBrowserLoader
|
||||
|
||||
active: false
|
||||
|
||||
FileBrowserModal {
|
||||
id: profileBrowser
|
||||
|
||||
browserTitle: "Select Profile Image"
|
||||
browserIcon: "person"
|
||||
browserType: "profile"
|
||||
@@ -520,14 +561,17 @@ ScrollView {
|
||||
visible = false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
LazyLoader {
|
||||
id: wallpaperBrowserLoader
|
||||
|
||||
active: false
|
||||
|
||||
FileBrowserModal {
|
||||
id: wallpaperBrowser
|
||||
|
||||
browserTitle: "Select Wallpaper"
|
||||
browserIcon: "wallpaper"
|
||||
browserType: "wallpaper"
|
||||
@@ -537,8 +581,7 @@ ScrollView {
|
||||
visible = false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
property alias profileBrowser: profileBrowserLoader.item
|
||||
property alias wallpaperBrowser: wallpaperBrowserLoader.item
|
||||
}
|
||||
@@ -16,6 +16,11 @@ Column {
|
||||
|
||||
width: parent.width
|
||||
spacing: expanded ? Theme.spacingM : 0
|
||||
Component.onCompleted: {
|
||||
if (!collapsible)
|
||||
expanded = true;
|
||||
|
||||
}
|
||||
|
||||
// Section header
|
||||
MouseArea {
|
||||
@@ -23,6 +28,11 @@ Column {
|
||||
height: headerRow.height
|
||||
enabled: collapsible
|
||||
hoverEnabled: collapsible
|
||||
onClicked: {
|
||||
if (collapsible)
|
||||
expanded = !expanded;
|
||||
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
@@ -50,7 +60,9 @@ Column {
|
||||
easing.type: Easing.BezierSpline
|
||||
easing.bezierCurve: Appearance.anim.curves.standard
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
DankIcon {
|
||||
@@ -68,13 +80,9 @@ Column {
|
||||
font.weight: Font.Medium
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
onClicked: {
|
||||
if (collapsible) {
|
||||
expanded = !expanded
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Divider
|
||||
@@ -93,6 +101,7 @@ Column {
|
||||
active: lazyLoad ? expanded || !collapsible : true
|
||||
visible: expanded || !collapsible
|
||||
asynchronous: true
|
||||
opacity: visible ? 1 : 0
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
@@ -100,14 +109,9 @@ Column {
|
||||
easing.type: Easing.BezierSpline
|
||||
easing.bezierCurve: Appearance.anim.curves.standard
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
opacity: visible ? 1 : 0
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
if (!collapsible) {
|
||||
expanded = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ ScrollView {
|
||||
|
||||
Column {
|
||||
id: column
|
||||
|
||||
width: parent.width
|
||||
spacing: Theme.spacingXL
|
||||
|
||||
@@ -26,6 +27,7 @@ ScrollView {
|
||||
|
||||
Column {
|
||||
id: timeSection
|
||||
|
||||
anchors.fill: parent
|
||||
anchors.margins: Theme.spacingL
|
||||
spacing: Theme.spacingM
|
||||
@@ -48,6 +50,7 @@ ScrollView {
|
||||
color: Theme.surfaceText
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
DankToggle {
|
||||
@@ -59,7 +62,9 @@ ScrollView {
|
||||
return Prefs.setClockFormat(checked);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Weather Settings Section
|
||||
@@ -73,6 +78,7 @@ ScrollView {
|
||||
|
||||
Column {
|
||||
id: weatherSection
|
||||
|
||||
anchors.fill: parent
|
||||
anchors.margins: Theme.spacingL
|
||||
spacing: Theme.spacingM
|
||||
@@ -95,6 +101,7 @@ ScrollView {
|
||||
color: Theme.surfaceText
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
DankToggle {
|
||||
@@ -153,9 +160,15 @@ ScrollView {
|
||||
duration: Theme.mediumDuration
|
||||
easing.type: Theme.emphasizedEasing
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -12,6 +12,7 @@ ScrollView {
|
||||
|
||||
Column {
|
||||
id: column
|
||||
|
||||
width: parent.width
|
||||
spacing: Theme.spacingXL
|
||||
topPadding: Theme.spacingL
|
||||
@@ -28,6 +29,7 @@ ScrollView {
|
||||
|
||||
Column {
|
||||
id: topBarSection
|
||||
|
||||
anchors.fill: parent
|
||||
anchors.margins: Theme.spacingL
|
||||
spacing: Theme.spacingM
|
||||
@@ -50,6 +52,7 @@ ScrollView {
|
||||
color: Theme.surfaceText
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
DankToggle {
|
||||
@@ -111,7 +114,9 @@ ScrollView {
|
||||
return Prefs.setShowSystemTray(checked);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Workspace Section
|
||||
@@ -125,6 +130,7 @@ ScrollView {
|
||||
|
||||
Column {
|
||||
id: workspaceSection
|
||||
|
||||
anchors.fill: parent
|
||||
anchors.margins: Theme.spacingL
|
||||
spacing: Theme.spacingM
|
||||
@@ -147,6 +153,7 @@ ScrollView {
|
||||
color: Theme.surfaceText
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
DankToggle {
|
||||
@@ -168,7 +175,11 @@ ScrollView {
|
||||
return Prefs.setShowWorkspacePadding(checked);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -115,12 +115,12 @@ PanelWindow {
|
||||
readonly property int availableWidth: width
|
||||
// Use estimated fixed widths to break circular dependencies
|
||||
readonly property int launcherButtonWidth: 40
|
||||
readonly property int workspaceSwitcherWidth: 120 // Approximate
|
||||
readonly property int workspaceSwitcherWidth: 120 // Approximate
|
||||
readonly property int focusedAppMaxWidth: focusedApp.visible ? 456 : 0
|
||||
readonly property int estimatedLeftSectionWidth: launcherButtonWidth + workspaceSwitcherWidth + focusedAppMaxWidth + (Theme.spacingXS * 2)
|
||||
readonly property int rightSectionWidth: rightSection.width
|
||||
readonly property int clockWidth: clock.width
|
||||
readonly property int mediaMaxWidth: media.visible ? 280 : 0 // Normal max width
|
||||
readonly property int mediaMaxWidth: media.visible ? 280 : 0 // Normal max width
|
||||
readonly property int weatherWidth: weather.visible ? weather.width : 0
|
||||
readonly property bool validLayout: availableWidth > 100 && estimatedLeftSectionWidth > 0 && rightSectionWidth > 0
|
||||
readonly property int clockLeftEdge: (availableWidth - clockWidth) / 2
|
||||
|
||||
@@ -11,7 +11,6 @@ Image {
|
||||
property string imagePath: ""
|
||||
property string imageHash: ""
|
||||
property int maxCacheSize: 512
|
||||
|
||||
readonly property string cachePath: imageHash ? `${Paths.stringify(Paths.imagecache)}/${imageHash}@${maxCacheSize}x${maxCacheSize}.png` : ""
|
||||
|
||||
asynchronous: true
|
||||
@@ -19,34 +18,33 @@ Image {
|
||||
sourceSize.width: maxCacheSize
|
||||
sourceSize.height: maxCacheSize
|
||||
smooth: true
|
||||
|
||||
onImagePathChanged: {
|
||||
if (imagePath) {
|
||||
hashProcess.command = ["sha256sum", Paths.strip(imagePath)]
|
||||
hashProcess.running = true
|
||||
hashProcess.command = ["sha256sum", Paths.strip(imagePath)];
|
||||
hashProcess.running = true;
|
||||
} else {
|
||||
source = ""
|
||||
imageHash = ""
|
||||
source = "";
|
||||
imageHash = "";
|
||||
}
|
||||
}
|
||||
|
||||
onCachePathChanged: {
|
||||
if (imageHash && cachePath) {
|
||||
// Ensure cache directory exists before trying to load from cache
|
||||
Paths.mkdir(Paths.imagecache)
|
||||
source = cachePath
|
||||
Paths.mkdir(Paths.imagecache);
|
||||
source = cachePath;
|
||||
}
|
||||
}
|
||||
|
||||
onStatusChanged: {
|
||||
if (source == cachePath && status === Image.Error) {
|
||||
source = imagePath
|
||||
source = imagePath;
|
||||
} else if (source == imagePath && status === Image.Ready && imageHash && cachePath) {
|
||||
Paths.mkdir(Paths.imagecache)
|
||||
const grabPath = cachePath
|
||||
if (visible && width > 0 && height > 0 && Window.window && Window.window.visible) {
|
||||
grabToImage(res => res.saveToFile(grabPath))
|
||||
}
|
||||
Paths.mkdir(Paths.imagecache);
|
||||
const grabPath = cachePath;
|
||||
if (visible && width > 0 && height > 0 && Window.window && Window.window.visible)
|
||||
grabToImage((res) => {
|
||||
return res.saveToFile(grabPath);
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,8 +53,10 @@ Image {
|
||||
|
||||
stdout: StdioCollector {
|
||||
onStreamFinished: {
|
||||
root.imageHash = text.split(" ")[0]
|
||||
root.imageHash = text.split(" ")[0];
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -18,11 +18,10 @@ Rectangle {
|
||||
height: 60
|
||||
radius: Theme.cornerRadius
|
||||
color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.08)
|
||||
|
||||
onVisibleChanged: {
|
||||
if (!visible && dropdownMenu.visible) {
|
||||
if (!visible && dropdownMenu.visible)
|
||||
dropdownMenu.close();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Column {
|
||||
@@ -48,6 +47,7 @@ Rectangle {
|
||||
wrapMode: Text.WordWrap
|
||||
width: parent.width
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
@@ -69,7 +69,6 @@ Rectangle {
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
|
||||
onClicked: {
|
||||
if (dropdownMenu.visible) {
|
||||
dropdownMenu.close();
|
||||
@@ -85,6 +84,7 @@ Rectangle {
|
||||
// Use a Row for the left-aligned content (icon + text)
|
||||
Row {
|
||||
id: contentRow
|
||||
|
||||
anchors.left: parent.left
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.leftMargin: Theme.spacingM
|
||||
@@ -108,11 +108,13 @@ Rectangle {
|
||||
width: dropdown.width - contentRow.x - expandIcon.width - Theme.spacingM - Theme.spacingS
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Anchor the expand icon to the right, outside of the Row
|
||||
DankIcon {
|
||||
id: expandIcon
|
||||
|
||||
name: "expand_more"
|
||||
size: 20
|
||||
color: Theme.surfaceVariantText
|
||||
@@ -120,18 +122,21 @@ Rectangle {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.rightMargin: Theme.spacingS
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Popup {
|
||||
id: dropdownMenu
|
||||
parent: Overlay.overlay
|
||||
|
||||
parent: Overlay.overlay
|
||||
width: 180
|
||||
height: Math.min(200, root.options.length * 36 + 16)
|
||||
|
||||
padding: 0
|
||||
closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutsideParent
|
||||
background: Rectangle { color: "transparent" }
|
||||
|
||||
background: Rectangle {
|
||||
color: "transparent"
|
||||
}
|
||||
|
||||
contentItem: Rectangle {
|
||||
color: Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, 1)
|
||||
@@ -174,10 +179,12 @@ Rectangle {
|
||||
color: root.currentValue === modelData ? Theme.primary : Theme.surfaceText
|
||||
font.weight: root.currentValue === modelData ? Font.Medium : Font.Normal
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: optionArea
|
||||
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
@@ -187,9 +194,15 @@ Rectangle {
|
||||
dropdownMenu.close();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -22,30 +22,27 @@ ScrollView {
|
||||
property bool keyboardNavigationActive: false
|
||||
|
||||
signal keyboardNavigationReset()
|
||||
|
||||
signal itemClicked(int index, var modelData)
|
||||
signal itemHovered(int index)
|
||||
|
||||
// Ensure the current item is visible
|
||||
function ensureVisible(index) {
|
||||
if (index < 0 || index >= grid.count) return;
|
||||
if (index < 0 || index >= grid.count)
|
||||
return ;
|
||||
|
||||
var itemY = Math.floor(index / grid.actualColumns) * grid.cellHeight;
|
||||
var itemBottom = itemY + grid.cellHeight;
|
||||
|
||||
if (itemY < grid.contentY) {
|
||||
if (itemY < grid.contentY)
|
||||
grid.contentY = itemY;
|
||||
} else if (itemBottom > grid.contentY + grid.height) {
|
||||
else if (itemBottom > grid.contentY + grid.height)
|
||||
grid.contentY = itemBottom - grid.height;
|
||||
}
|
||||
}
|
||||
|
||||
onCurrentIndexChanged: {
|
||||
if (keyboardNavigationActive) {
|
||||
if (keyboardNavigationActive)
|
||||
ensureVisible(currentIndex);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
clip: true
|
||||
ScrollBar.vertical.policy: ScrollBar.AsNeeded
|
||||
ScrollBar.horizontal.policy: ScrollBar.AlwaysOff
|
||||
@@ -157,9 +154,9 @@ ScrollView {
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
z: 10
|
||||
onEntered: {
|
||||
if (hoverUpdatesSelection && !keyboardNavigationActive) {
|
||||
if (hoverUpdatesSelection && !keyboardNavigationActive)
|
||||
currentIndex = index;
|
||||
}
|
||||
|
||||
itemHovered(index);
|
||||
}
|
||||
onPositionChanged: {
|
||||
|
||||
@@ -23,24 +23,22 @@ ScrollView {
|
||||
|
||||
// Ensure the current item is visible
|
||||
function ensureVisible(index) {
|
||||
if (index < 0 || index >= list.count) return;
|
||||
if (index < 0 || index >= list.count)
|
||||
return ;
|
||||
|
||||
var itemY = index * (itemHeight + itemSpacing);
|
||||
var itemBottom = itemY + itemHeight;
|
||||
|
||||
if (itemY < list.contentY) {
|
||||
if (itemY < list.contentY)
|
||||
list.contentY = itemY;
|
||||
} else if (itemBottom > list.contentY + list.height) {
|
||||
else if (itemBottom > list.contentY + list.height)
|
||||
list.contentY = itemBottom - list.height;
|
||||
}
|
||||
}
|
||||
|
||||
onCurrentIndexChanged: {
|
||||
if (keyboardNavigationActive) {
|
||||
if (keyboardNavigationActive)
|
||||
ensureVisible(currentIndex);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
clip: true
|
||||
ScrollBar.vertical.policy: ScrollBar.AlwaysOn
|
||||
ScrollBar.horizontal.policy: ScrollBar.AlwaysOff
|
||||
@@ -156,9 +154,9 @@ ScrollView {
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
z: 10
|
||||
onEntered: {
|
||||
if (hoverUpdatesSelection && !keyboardNavigationActive) {
|
||||
if (hoverUpdatesSelection && !keyboardNavigationActive)
|
||||
listView.currentIndex = index;
|
||||
}
|
||||
|
||||
itemHovered(index);
|
||||
}
|
||||
onPositionChanged: {
|
||||
|
||||
@@ -58,7 +58,9 @@ Item {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.standardEasing
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
StyledRect {
|
||||
@@ -85,15 +87,9 @@ Item {
|
||||
visible: sliderMouseArea.containsMouse && slider.enabled
|
||||
}
|
||||
|
||||
Behavior on scale {
|
||||
NumberAnimation {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.standardEasing
|
||||
}
|
||||
}
|
||||
|
||||
StyledRect {
|
||||
id: valueTooltip
|
||||
|
||||
width: tooltipText.contentWidth + Theme.spacingS * 2
|
||||
height: tooltipText.contentHeight + Theme.spacingXS * 2
|
||||
radius: Theme.cornerRadiusSmall
|
||||
@@ -108,6 +104,7 @@ Item {
|
||||
|
||||
Text {
|
||||
id: tooltipText
|
||||
|
||||
text: slider.value + slider.unit
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceText
|
||||
@@ -121,8 +118,19 @@ Item {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.standardEasing
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Behavior on scale {
|
||||
NumberAnimation {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.standardEasing
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Item {
|
||||
@@ -201,7 +209,9 @@ Item {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
DankIcon {
|
||||
@@ -211,6 +221,7 @@ Item {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
visible: slider.rightIcon.length > 0
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -38,7 +38,6 @@ Rectangle {
|
||||
readonly property real rightPadding: Theme.spacingM + (showClearButton && text.length > 0 ? 24 + Theme.spacingM : 0)
|
||||
property real topPadding: Theme.spacingM
|
||||
property real bottomPadding: Theme.spacingM
|
||||
|
||||
// Behavior control
|
||||
property bool ignoreLeftRightKeys: false
|
||||
property var keyForwardTargets: []
|
||||
@@ -133,19 +132,16 @@ Rectangle {
|
||||
onEditingFinished: root.editingFinished()
|
||||
onAccepted: root.accepted()
|
||||
onActiveFocusChanged: root.focusStateChanged(activeFocus)
|
||||
|
||||
Keys.forwardTo: root.ignoreLeftRightKeys ? root.keyForwardTargets : []
|
||||
|
||||
Keys.onLeftPressed: function(event) {
|
||||
if (root.ignoreLeftRightKeys) {
|
||||
if (root.ignoreLeftRightKeys)
|
||||
event.accepted = true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Keys.onRightPressed: function(event) {
|
||||
if (root.ignoreLeftRightKeys) {
|
||||
if (root.ignoreLeftRightKeys)
|
||||
event.accepted = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
|
||||
Reference in New Issue
Block a user