1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2026-08-10 07:28:30 -04:00

qs: launcher optimizations and weather tab optimizations

This commit is contained in:
bbedward
2026-07-07 21:15:51 -04:00
parent 1724aedd49
commit 93168ee073
5 changed files with 741 additions and 673 deletions
@@ -0,0 +1,324 @@
import QtQuick
import qs.Common
import qs.Services
import qs.Widgets
FocusScope {
id: root
property var editingApp: null
property string editAppId: ""
signal closeRequested
function loadOverride() {
var existing = SessionData.getAppOverride(editAppId);
editNameField.text = existing?.name || "";
editIconField.text = existing?.icon || "";
editCommentField.text = existing?.comment || "";
editEnvVarsField.text = existing?.envVars || "";
editExtraFlagsField.text = existing?.extraFlags || "";
Qt.callLater(() => editNameField.forceActiveFocus());
}
function saveAppOverride() {
var override = {};
if (editNameField.text.trim())
override.name = editNameField.text.trim();
if (editIconField.text.trim())
override.icon = editIconField.text.trim();
if (editCommentField.text.trim())
override.comment = editCommentField.text.trim();
if (editEnvVarsField.text.trim())
override.envVars = editEnvVarsField.text.trim();
if (editExtraFlagsField.text.trim())
override.extraFlags = editExtraFlagsField.text.trim();
SessionData.setAppOverride(editAppId, override);
closeRequested();
}
function resetAppOverride() {
SessionData.clearAppOverride(editAppId);
closeRequested();
}
Keys.onPressed: event => {
if (event.key === Qt.Key_Escape) {
closeRequested();
event.accepted = true;
} else if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter) {
if (event.modifiers & Qt.ControlModifier) {
saveAppOverride();
event.accepted = true;
}
} else if (event.key === Qt.Key_S && event.modifiers & Qt.ControlModifier) {
saveAppOverride();
event.accepted = true;
}
}
Column {
anchors.fill: parent
spacing: Theme.spacingM
Row {
width: parent.width
spacing: Theme.spacingM
Rectangle {
width: 40
height: 40
radius: Theme.cornerRadius
color: backButtonArea.containsMouse ? Theme.surfaceHover : Theme.withAlpha(Theme.surfaceHover, 0)
DankIcon {
anchors.centerIn: parent
name: "arrow_back"
size: 20
color: Theme.surfaceText
}
MouseArea {
id: backButtonArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: root.closeRequested()
}
}
Image {
width: 40
height: 40
source: Paths.resolveIconUrl(root.editingApp?.icon || "application-x-executable")
sourceSize.width: 40
sourceSize.height: 40
fillMode: Image.PreserveAspectFit
anchors.verticalCenter: parent.verticalCenter
}
Column {
anchors.verticalCenter: parent.verticalCenter
spacing: Theme.spacingXXS
StyledText {
text: I18n.tr("Edit App")
font.pixelSize: Theme.fontSizeLarge
color: Theme.surfaceText
font.weight: Font.Medium
}
StyledText {
text: root.editingApp?.name || ""
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
}
}
}
Rectangle {
width: parent.width
height: 1
color: Theme.outlineMedium
}
Flickable {
width: parent.width
height: parent.height - y - buttonsRow.height - Theme.spacingM
contentHeight: editFieldsColumn.height
clip: true
boundsBehavior: Flickable.StopAtBounds
Column {
id: editFieldsColumn
width: parent.width
spacing: Theme.spacingS
Column {
width: parent.width
spacing: Theme.spacingXS
StyledText {
text: I18n.tr("Name")
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceText
font.weight: Font.Medium
}
DankTextField {
id: editNameField
width: parent.width
placeholderText: root.editingApp?.name || ""
keyNavigationTab: editIconField
keyNavigationBacktab: editExtraFlagsField
}
}
Column {
width: parent.width
spacing: Theme.spacingXS
StyledText {
text: I18n.tr("Icon")
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceText
font.weight: Font.Medium
}
DankTextField {
id: editIconField
width: parent.width
placeholderText: root.editingApp?.icon || ""
keyNavigationTab: editCommentField
keyNavigationBacktab: editNameField
}
}
Column {
width: parent.width
spacing: Theme.spacingXS
StyledText {
text: I18n.tr("Description")
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceText
font.weight: Font.Medium
}
DankTextField {
id: editCommentField
width: parent.width
placeholderText: root.editingApp?.comment || ""
keyNavigationTab: editEnvVarsField
keyNavigationBacktab: editIconField
}
}
Column {
width: parent.width
spacing: Theme.spacingXS
StyledText {
text: I18n.tr("Environment Variables")
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceText
font.weight: Font.Medium
}
StyledText {
text: "KEY=value KEY2=value2"
font.pixelSize: Theme.fontSizeSmall - 1
color: Theme.surfaceVariantText
}
DankTextField {
id: editEnvVarsField
width: parent.width
placeholderText: "VAR=value"
keyNavigationTab: editExtraFlagsField
keyNavigationBacktab: editCommentField
}
}
Column {
width: parent.width
spacing: Theme.spacingXS
StyledText {
text: I18n.tr("Extra Arguments")
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceText
font.weight: Font.Medium
}
DankTextField {
id: editExtraFlagsField
width: parent.width
placeholderText: "--flag --option=value"
keyNavigationTab: editNameField
keyNavigationBacktab: editEnvVarsField
}
}
}
}
Row {
id: buttonsRow
anchors.horizontalCenter: parent.horizontalCenter
spacing: Theme.spacingM
Rectangle {
id: resetButton
width: 90
height: 40
radius: Theme.cornerRadius
color: resetButtonArea.containsMouse ? Theme.surfacePressed : Theme.surfaceVariantAlpha
visible: SessionData.getAppOverride(root.editAppId) !== null
StyledText {
text: I18n.tr("Reset")
font.pixelSize: Theme.fontSizeMedium
color: Theme.error
font.weight: Font.Medium
anchors.centerIn: parent
}
MouseArea {
id: resetButtonArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: root.resetAppOverride()
}
}
Rectangle {
id: cancelButton
width: 90
height: 40
radius: Theme.cornerRadius
color: cancelButtonArea.containsMouse ? Theme.surfacePressed : Theme.surfaceVariantAlpha
StyledText {
text: I18n.tr("Cancel")
font.pixelSize: Theme.fontSizeMedium
color: Theme.surfaceText
font.weight: Font.Medium
anchors.centerIn: parent
}
MouseArea {
id: cancelButtonArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: root.closeRequested()
}
}
Rectangle {
id: saveButton
width: 90
height: 40
radius: Theme.cornerRadius
color: saveButtonArea.containsMouse ? Theme.withAlpha(Theme.primary, 0.9) : Theme.primary
StyledText {
text: I18n.tr("Save")
font.pixelSize: Theme.fontSizeMedium
color: Theme.primaryText
font.weight: Font.Medium
anchors.centerIn: parent
}
MouseArea {
id: saveButtonArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: root.saveAppOverride()
}
}
}
}
}
+57 -44
View File
@@ -930,23 +930,10 @@ Item {
searchCompleted(); searchCompleted();
return; return;
} else if (!searchQuery) { } else if (!searchQuery) {
var emptyTriggerOrdered = getEmptyTriggerPluginsOrdered(); _pluginPhasePending = true;
for (var i = 0; i < emptyTriggerOrdered.length; i++) { _phase1Items = allItems.slice();
var plugin = emptyTriggerOrdered[i]; _pluginPhaseForceFirst = shouldResetSelection;
if (plugin.isBuiltIn) { pluginPhaseTimer.restart();
var blItems = AppSearchService.getBuiltInLauncherItems(plugin.id, searchQuery);
for (var j = 0; j < blItems.length; j++)
allItems.push(transformBuiltInSearchItem(blItems[j], plugin.id));
} else {
var pItems = getPluginItems(plugin.id, searchQuery);
for (var j = 0; j < pItems.length; j++)
allItems.push(pItems[j]);
}
}
var browseItems = getPluginBrowseItems();
for (var i = 0; i < browseItems.length; i++)
allItems.push(browseItems[i]);
} }
} }
@@ -977,11 +964,6 @@ Item {
flatModel = Scorer.flattenSections(newSections); flatModel = Scorer.flattenSections(newSections);
sections = newSections; sections = newSections;
if (!AppSearchService.isCacheValid() && !searchQuery && searchMode === "all" && !pluginFilter) {
AppSearchService.setCachedDefaultSections(sections, flatModel);
_saveDiskCache(sections);
}
selectedFlatIndex = restoreSelection(flatModel); selectedFlatIndex = restoreSelection(flatModel);
updateSelectedItem(); updateSelectedItem();
@@ -991,7 +973,9 @@ Item {
function _performPluginPhase() { function _performPluginPhase() {
_pluginPhasePending = false; _pluginPhasePending = false;
if (!searchQuery || searchQuery.length < 2 || searchMode !== "all") if (searchMode !== "all")
return;
if (searchQuery && searchQuery.length < 2)
return; return;
var currentVersion = _searchVersion; var currentVersion = _searchVersion;
@@ -999,27 +983,49 @@ Item {
var allItems = _phase1Items; var allItems = _phase1Items;
_phase1Items = []; _phase1Items = [];
var allPluginsOrdered = getAllVisiblePluginsOrdered(); if (!searchQuery) {
var maxPerPlugin = 10; var emptyTriggerOrdered = getEmptyTriggerPluginsOrdered();
for (var i = 0; i < allPluginsOrdered.length; i++) { for (var i = 0; i < emptyTriggerOrdered.length; i++) {
if (currentVersion !== _searchVersion) if (currentVersion !== _searchVersion)
return; return;
var plugin = allPluginsOrdered[i]; var plugin = emptyTriggerOrdered[i];
if (plugin.isBuiltIn && (plugin.id === "dms_settings_search" || plugin.id === "dms_clipboard_search")) if (plugin.isBuiltIn) {
continue; var blItems = AppSearchService.getBuiltInLauncherItems(plugin.id, searchQuery);
if (plugin.isBuiltIn) { for (var j = 0; j < blItems.length; j++)
var blItems = AppSearchService.getBuiltInLauncherItems(plugin.id, searchQuery); allItems.push(transformBuiltInSearchItem(blItems[j], plugin.id));
var blLimit = Math.min(blItems.length, maxPerPlugin); } else {
for (var j = 0; j < blLimit; j++) { var pItems = getPluginItems(plugin.id, searchQuery);
var item = transformBuiltInSearchItem(blItems[j], plugin.id); for (var j = 0; j < pItems.length; j++)
item._preScored = 900 - j; allItems.push(pItems[j]);
allItems.push(item);
} }
} else { }
var pItems = getPluginItems(plugin.id, searchQuery, maxPerPlugin);
for (var j = 0; j < pItems.length; j++) { var browseItems = getPluginBrowseItems();
pItems[j]._preScored = 900 - j; for (var i = 0; i < browseItems.length; i++)
allItems.push(pItems[j]); allItems.push(browseItems[i]);
} else {
var allPluginsOrdered = getAllVisiblePluginsOrdered();
var maxPerPlugin = 10;
for (var i = 0; i < allPluginsOrdered.length; i++) {
if (currentVersion !== _searchVersion)
return;
var plugin = allPluginsOrdered[i];
if (plugin.isBuiltIn && (plugin.id === "dms_settings_search" || plugin.id === "dms_clipboard_search"))
continue;
if (plugin.isBuiltIn) {
var blItems = AppSearchService.getBuiltInLauncherItems(plugin.id, searchQuery);
var blLimit = Math.min(blItems.length, maxPerPlugin);
for (var j = 0; j < blLimit; j++) {
var item = transformBuiltInSearchItem(blItems[j], plugin.id);
item._preScored = 900 - j;
allItems.push(item);
}
} else {
var pItems = getPluginItems(plugin.id, searchQuery, maxPerPlugin);
for (var j = 0; j < pItems.length; j++) {
pItems[j]._preScored = 900 - j;
allItems.push(pItems[j]);
}
} }
} }
} }
@@ -1029,7 +1035,8 @@ Item {
var dynamicDefs = buildDynamicSectionDefs(allItems); var dynamicDefs = buildDynamicSectionDefs(allItems);
var scoredItems = Scorer.scoreItems(allItems, searchQuery, getFrecencyForItem); var scoredItems = Scorer.scoreItems(allItems, searchQuery, getFrecencyForItem);
var newSections = Scorer.groupBySection(scoredItems, dynamicDefs, false, 50); var sortAlpha = !searchQuery && SettingsData.sortAppsAlphabetically;
var newSections = Scorer.groupBySection(scoredItems, dynamicDefs, sortAlpha, searchQuery ? 50 : 500);
if (currentVersion !== _searchVersion) if (currentVersion !== _searchVersion)
return; return;
@@ -1043,6 +1050,12 @@ Item {
_applyHighlights(newSections, searchQuery); _applyHighlights(newSections, searchQuery);
flatModel = Scorer.flattenSections(newSections); flatModel = Scorer.flattenSections(newSections);
sections = newSections; sections = newSections;
if (!AppSearchService.isCacheValid() && !searchQuery && !pluginFilter) {
AppSearchService.setCachedDefaultSections(sections, flatModel);
_saveDiskCache(sections);
}
selectedFlatIndex = restoreSelection(flatModel); selectedFlatIndex = restoreSelection(flatModel);
updateSelectedItem(); updateSelectedItem();
isSearching = false; isSearching = false;
@@ -54,14 +54,7 @@ FocusScope {
return; return;
editingApp = app; editingApp = app;
editAppId = app.id || app.execString || app.exec || ""; editAppId = app.id || app.execString || app.exec || "";
var existing = SessionData.getAppOverride(editAppId);
editNameField.text = existing?.name || "";
editIconField.text = existing?.icon || "";
editCommentField.text = existing?.comment || "";
editEnvVarsField.text = existing?.envVars || "";
editExtraFlagsField.text = existing?.extraFlags || "";
editMode = true; editMode = true;
Qt.callLater(() => editNameField.forceActiveFocus());
} }
function closeEditMode() { function closeEditMode() {
@@ -71,27 +64,6 @@ FocusScope {
Qt.callLater(() => searchField.forceActiveFocus()); Qt.callLater(() => searchField.forceActiveFocus());
} }
function saveAppOverride() {
var override = {};
if (editNameField.text.trim())
override.name = editNameField.text.trim();
if (editIconField.text.trim())
override.icon = editIconField.text.trim();
if (editCommentField.text.trim())
override.comment = editCommentField.text.trim();
if (editEnvVarsField.text.trim())
override.envVars = editEnvVarsField.text.trim();
if (editExtraFlagsField.text.trim())
override.extraFlags = editExtraFlagsField.text.trim();
SessionData.setAppOverride(editAppId, override);
closeEditMode();
}
function resetAppOverride() {
SessionData.clearAppOverride(editAppId);
closeEditMode();
}
function showContextMenu(item, x, y, fromKeyboard) { function showContextMenu(item, x, y, fromKeyboard) {
if (!item) if (!item)
return; return;
@@ -817,291 +789,21 @@ FocusScope {
} }
} }
FocusScope { Loader {
id: editView id: editLoader
anchors.fill: parent anchors.fill: parent
anchors.margins: Theme.spacingM anchors.margins: Theme.spacingM
visible: editMode active: root.editMode
focus: editMode visible: active
focus: root.editMode
Keys.onPressed: event => { sourceComponent: AppEditView {
if (event.key === Qt.Key_Escape) { focus: true
closeEditMode(); editingApp: root.editingApp
event.accepted = true; editAppId: root.editAppId
} else if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter) { onCloseRequested: root.closeEditMode()
if (event.modifiers & Qt.ControlModifier) {
saveAppOverride();
event.accepted = true;
}
} else if (event.key === Qt.Key_S && event.modifiers & Qt.ControlModifier) {
saveAppOverride();
event.accepted = true;
}
} }
Column { onLoaded: item.loadOverride()
anchors.fill: parent
spacing: Theme.spacingM
Row {
width: parent.width
spacing: Theme.spacingM
Rectangle {
width: 40
height: 40
radius: Theme.cornerRadius
color: backButtonArea.containsMouse ? Theme.surfaceHover : Theme.withAlpha(Theme.surfaceHover, 0)
DankIcon {
anchors.centerIn: parent
name: "arrow_back"
size: 20
color: Theme.surfaceText
}
MouseArea {
id: backButtonArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: closeEditMode()
}
}
Image {
width: 40
height: 40
source: Paths.resolveIconUrl(editingApp?.icon || "application-x-executable")
sourceSize.width: 40
sourceSize.height: 40
fillMode: Image.PreserveAspectFit
anchors.verticalCenter: parent.verticalCenter
}
Column {
anchors.verticalCenter: parent.verticalCenter
spacing: Theme.spacingXXS
StyledText {
text: I18n.tr("Edit App")
font.pixelSize: Theme.fontSizeLarge
color: Theme.surfaceText
font.weight: Font.Medium
}
StyledText {
text: editingApp?.name || ""
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
}
}
}
Rectangle {
width: parent.width
height: 1
color: Theme.outlineMedium
}
Flickable {
width: parent.width
height: parent.height - y - buttonsRow.height - Theme.spacingM
contentHeight: editFieldsColumn.height
clip: true
boundsBehavior: Flickable.StopAtBounds
Column {
id: editFieldsColumn
width: parent.width
spacing: Theme.spacingS
Column {
width: parent.width
spacing: Theme.spacingXS
StyledText {
text: I18n.tr("Name")
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceText
font.weight: Font.Medium
}
DankTextField {
id: editNameField
width: parent.width
placeholderText: editingApp?.name || ""
keyNavigationTab: editIconField
keyNavigationBacktab: editExtraFlagsField
}
}
Column {
width: parent.width
spacing: Theme.spacingXS
StyledText {
text: I18n.tr("Icon")
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceText
font.weight: Font.Medium
}
DankTextField {
id: editIconField
width: parent.width
placeholderText: editingApp?.icon || ""
keyNavigationTab: editCommentField
keyNavigationBacktab: editNameField
}
}
Column {
width: parent.width
spacing: Theme.spacingXS
StyledText {
text: I18n.tr("Description")
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceText
font.weight: Font.Medium
}
DankTextField {
id: editCommentField
width: parent.width
placeholderText: editingApp?.comment || ""
keyNavigationTab: editEnvVarsField
keyNavigationBacktab: editIconField
}
}
Column {
width: parent.width
spacing: Theme.spacingXS
StyledText {
text: I18n.tr("Environment Variables")
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceText
font.weight: Font.Medium
}
StyledText {
text: "KEY=value KEY2=value2"
font.pixelSize: Theme.fontSizeSmall - 1
color: Theme.surfaceVariantText
}
DankTextField {
id: editEnvVarsField
width: parent.width
placeholderText: "VAR=value"
keyNavigationTab: editExtraFlagsField
keyNavigationBacktab: editCommentField
}
}
Column {
width: parent.width
spacing: Theme.spacingXS
StyledText {
text: I18n.tr("Extra Arguments")
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceText
font.weight: Font.Medium
}
DankTextField {
id: editExtraFlagsField
width: parent.width
placeholderText: "--flag --option=value"
keyNavigationTab: editNameField
keyNavigationBacktab: editEnvVarsField
}
}
}
}
Row {
id: buttonsRow
anchors.horizontalCenter: parent.horizontalCenter
spacing: Theme.spacingM
Rectangle {
id: resetButton
width: 90
height: 40
radius: Theme.cornerRadius
color: resetButtonArea.containsMouse ? Theme.surfacePressed : Theme.surfaceVariantAlpha
visible: SessionData.getAppOverride(editAppId) !== null
StyledText {
text: I18n.tr("Reset")
font.pixelSize: Theme.fontSizeMedium
color: Theme.error
font.weight: Font.Medium
anchors.centerIn: parent
}
MouseArea {
id: resetButtonArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: resetAppOverride()
}
}
Rectangle {
id: cancelButton
width: 90
height: 40
radius: Theme.cornerRadius
color: cancelButtonArea.containsMouse ? Theme.surfacePressed : Theme.surfaceVariantAlpha
StyledText {
text: I18n.tr("Cancel")
font.pixelSize: Theme.fontSizeMedium
color: Theme.surfaceText
font.weight: Font.Medium
anchors.centerIn: parent
}
MouseArea {
id: cancelButtonArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: closeEditMode()
}
}
Rectangle {
id: saveButton
width: 90
height: 40
radius: Theme.cornerRadius
color: saveButtonArea.containsMouse ? Theme.withAlpha(Theme.primary, 0.9) : Theme.primary
StyledText {
text: I18n.tr("Save")
font.pixelSize: Theme.fontSizeMedium
color: Theme.primaryText
font.weight: Font.Medium
anchors.centerIn: parent
}
MouseArea {
id: saveButtonArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: saveAppOverride()
}
}
}
}
} }
} }
@@ -241,107 +241,124 @@ Item {
required property var modelData required property var modelData
required property int index required property int index
readonly property string rowType: modelData?.type ?? ""
width: mainListView.width width: mainListView.width
height: modelData?.height ?? 52 height: modelData?.height ?? 52
SectionHeader { Loader {
anchors.fill: parent anchors.fill: parent
visible: delegateRoot.modelData?.type === "header" active: delegateRoot.rowType === "header"
section: delegateRoot.modelData?.section ?? null visible: active
controller: root.controller sourceComponent: SectionHeader {
viewMode: { section: delegateRoot.modelData?.section ?? null
var vt = root.controller?.viewModeVersion ?? 0; controller: root.controller
void (vt); viewMode: {
return root.controller?.getSectionViewMode(delegateRoot.modelData?.sectionId ?? "") ?? "list"; var vt = root.controller?.viewModeVersion ?? 0;
void (vt);
return root.controller?.getSectionViewMode(delegateRoot.modelData?.sectionId ?? "") ?? "list";
}
canChangeViewMode: {
var vt = root.controller?.viewModeVersion ?? 0;
void (vt);
return root.controller?.canChangeSectionViewMode(delegateRoot.modelData?.sectionId ?? "") ?? false;
}
canCollapse: root.controller?.canCollapseSection(delegateRoot.modelData?.sectionId ?? "") ?? false
transientSurfaceTracker: root.transientSurfaceTracker
} }
canChangeViewMode: {
var vt = root.controller?.viewModeVersion ?? 0;
void (vt);
return root.controller?.canChangeSectionViewMode(delegateRoot.modelData?.sectionId ?? "") ?? false;
}
canCollapse: root.controller?.canCollapseSection(delegateRoot.modelData?.sectionId ?? "") ?? false
transientSurfaceTracker: root.transientSurfaceTracker
} }
ResultItem { Loader {
anchors.fill: parent anchors.fill: parent
anchors.topMargin: 2 anchors.topMargin: 2
anchors.bottomMargin: 2 anchors.bottomMargin: 2
visible: delegateRoot.modelData?.type === "list_item" active: delegateRoot.rowType === "list_item"
item: delegateRoot.modelData?.type === "list_item" ? (delegateRoot.modelData?.item ?? null) : null visible: active
isSelected: delegateRoot.modelData?.type === "list_item" && (delegateRoot.modelData?.flatIndex ?? -1) === root.controller?.selectedFlatIndex sourceComponent: ResultItem {
controller: root.controller item: delegateRoot.modelData?.item ?? null
flatIndex: delegateRoot.modelData?.type === "list_item" ? (delegateRoot.modelData?.flatIndex ?? -1) : -1 isSelected: (delegateRoot.modelData?.flatIndex ?? -1) === root.controller?.selectedFlatIndex
controller: root.controller
flatIndex: delegateRoot.modelData?.flatIndex ?? -1
onClicked: { onClicked: {
if (root.controller && delegateRoot.modelData?.item) { if (root.controller && delegateRoot.modelData?.item) {
root.controller.executeItem(delegateRoot.modelData.item); root.controller.executeItem(delegateRoot.modelData.item);
}
} }
}
onRightClicked: (mouseX, mouseY) => { onRightClicked: (mouseX, mouseY) => {
root.itemRightClicked(delegateRoot.modelData?.flatIndex ?? -1, delegateRoot.modelData?.item ?? null, mouseX, mouseY); root.itemRightClicked(delegateRoot.modelData?.flatIndex ?? -1, delegateRoot.modelData?.item ?? null, mouseX, mouseY);
}
} }
} }
Row { Loader {
id: gridRowContent
anchors.fill: parent anchors.fill: parent
visible: delegateRoot.modelData?.type === "grid_row" active: delegateRoot.rowType === "grid_row"
visible: active
sourceComponent: Row {
Repeater {
model: delegateRoot.modelData?.items ?? []
Repeater { Item {
model: delegateRoot.modelData?.type === "grid_row" ? (delegateRoot.modelData?.items ?? []) : [] id: gridCellDelegate
required property var modelData
required property int index
Item { readonly property bool isTile: delegateRoot.modelData?.viewMode === "tile"
id: gridCellDelegate readonly property real cellWidth: isTile ? Math.floor(delegateRoot.width / 3) : Math.floor(delegateRoot.width / (delegateRoot.modelData?.cols ?? root.gridColumns))
required property var modelData
required property int index
readonly property real cellWidth: delegateRoot.modelData?.viewMode === "tile" ? Math.floor(delegateRoot.width / 3) : Math.floor(delegateRoot.width / (delegateRoot.modelData?.cols ?? root.gridColumns)) width: cellWidth
height: delegateRoot.height
width: cellWidth Loader {
height: delegateRoot.height width: parent.width - 4
height: parent.height - 4
anchors.centerIn: parent
sourceComponent: gridCellDelegate.isTile ? tileCellComponent : gridCellComponent
GridItem { Component {
width: parent.width - 4 id: gridCellComponent
height: parent.height - 4
anchors.centerIn: parent
visible: delegateRoot.modelData?.viewMode === "grid"
item: gridCellDelegate.modelData?.item ?? null
isSelected: (gridCellDelegate.modelData?.flatIndex ?? -1) === root.controller?.selectedFlatIndex
controller: root.controller
flatIndex: gridCellDelegate.modelData?.flatIndex ?? -1
onClicked: { GridItem {
if (root.controller && gridCellDelegate.modelData?.item) { item: gridCellDelegate.modelData?.item ?? null
root.controller.executeItem(gridCellDelegate.modelData.item); isSelected: (gridCellDelegate.modelData?.flatIndex ?? -1) === root.controller?.selectedFlatIndex
controller: root.controller
flatIndex: gridCellDelegate.modelData?.flatIndex ?? -1
onClicked: {
if (root.controller && gridCellDelegate.modelData?.item) {
root.controller.executeItem(gridCellDelegate.modelData.item);
}
}
onRightClicked: (mouseX, mouseY) => {
root.itemRightClicked(gridCellDelegate.modelData?.flatIndex ?? -1, gridCellDelegate.modelData?.item ?? null, mouseX, mouseY);
}
}
} }
}
onRightClicked: (mouseX, mouseY) => { Component {
root.itemRightClicked(gridCellDelegate.modelData?.flatIndex ?? -1, gridCellDelegate.modelData?.item ?? null, mouseX, mouseY); id: tileCellComponent
}
}
TileItem { TileItem {
width: parent.width - 4 item: gridCellDelegate.modelData?.item ?? null
height: parent.height - 4 isSelected: (gridCellDelegate.modelData?.flatIndex ?? -1) === root.controller?.selectedFlatIndex
anchors.centerIn: parent controller: root.controller
visible: delegateRoot.modelData?.viewMode === "tile" flatIndex: gridCellDelegate.modelData?.flatIndex ?? -1
item: gridCellDelegate.modelData?.item ?? null
isSelected: (gridCellDelegate.modelData?.flatIndex ?? -1) === root.controller?.selectedFlatIndex
controller: root.controller
flatIndex: gridCellDelegate.modelData?.flatIndex ?? -1
onClicked: { onClicked: {
if (root.controller && gridCellDelegate.modelData?.item) { if (root.controller && gridCellDelegate.modelData?.item) {
root.controller.executeItem(gridCellDelegate.modelData.item); root.controller.executeItem(gridCellDelegate.modelData.item);
}
}
onRightClicked: (mouseX, mouseY) => {
root.itemRightClicked(gridCellDelegate.modelData?.flatIndex ?? -1, gridCellDelegate.modelData?.item ?? null, mouseX, mouseY);
}
}
} }
} }
onRightClicked: (mouseX, mouseY) => {
root.itemRightClicked(gridCellDelegate.modelData?.flatIndex ?? -1, gridCellDelegate.modelData?.item ?? null, mouseX, mouseY);
}
} }
} }
} }
+260 -248
View File
@@ -550,276 +550,288 @@ Item {
color: "transparent" color: "transparent"
Rectangle {
anchors.fill: parent
opacity: skyBox.backgroundOpacity
gradient: Gradient {
GradientStop {
position: 0.0
color: Theme.withAlpha(skyBox.blackColor, 0.0)
}
GradientStop {
position: 0.05
color: skyBox.topColor
}
GradientStop {
position: 0.3
color: skyBox.topColor
}
GradientStop {
position: 0.5
color: skyBox.topColor
}
GradientStop {
position: 0.501
color: skyBox.blackColor
}
GradientStop {
position: 0.9
color: skyBox.blackColor
}
GradientStop {
position: 1.0
color: Theme.withAlpha(skyBox.blackColor, 0.0)
}
}
}
property var currentDate: dateStepper.currentDate property var currentDate: dateStepper.currentDate
property var hMargin: 0 property var hMargin: 0
property var vMargin: Theme.spacingM property var vMargin: Theme.spacingM
property var effectiveHeight: skyBox.height - 2 * vMargin property var effectiveHeight: skyBox.height - 2 * vMargin
property var effectiveWidth: skyBox.width - 2 * hMargin property var effectiveWidth: skyBox.width - 2 * hMargin
StyledText {
text: parent.sunTime?.period ?? ""
font.pixelSize: Theme.fontSizeSmall
color: Theme.withAlpha(Theme.surfaceText, 0.7)
x: 0
y: 0
}
Shape {
id: skyShape
anchors.left: parent.left
anchors.top: parent.top
anchors.right: parent.right
height: parent.height / 2
opacity: skyBox.backgroundOpacity
ShapePath {
strokeColor: "transparent"
fillGradient: RadialGradient {
centerX: skyBox.hMargin + sun.x + sun.width / 2
centerY: skyBox.vMargin + sun.y + 30
centerRadius: {
const a = Math.abs((skyBox.sunTime?.dayPercent ?? 0) - 0.5);
const out = 200 * (0.5 - a * a);
return out;
}
focalX: skyBox.hMargin + sun.x + sun.width / 2
focalY: skyBox.vMargin + sun.y
GradientStop {
position: 0
color: skyBox.sunColor
}
GradientStop {
position: 0.3
color: Theme.blendAlpha(skyBox.sunColor, 0.5)
}
GradientStop {
position: 1
color: "transparent"
}
}
PathLine {
x: 0
y: 0
}
PathLine {
x: skyShape.width
y: 0
}
PathLine {
x: skyShape.width
y: skyShape.height
}
PathLine {
x: 0
y: skyShape.height
}
}
ShapePath {
strokeColor: "transparent"
fillGradient: RadialGradient {
centerX: sun.x
centerY: sun.y
centerRadius: 500
focalX: centerX
focalY: centerY + 0.99 * (centerRadius - focalRadius)
focalRadius: 10
GradientStop {
position: 0
color: skyBox.sunColor
}
GradientStop {
position: 0.45
color: skyBox.sunColor
}
GradientStop {
position: 0.55
color: "transparent"
}
GradientStop {
position: 1
color: "transparent"
}
}
PathLine {
x: 0
y: 0
}
PathLine {
x: skyShape.width
y: 0
}
PathLine {
x: skyShape.width
y: skyShape.height
}
PathLine {
x: 0
y: skyShape.height
}
}
}
Canvas {
id: ecliptic
anchors.fill: parent
property var points: WeatherService.getEcliptic(dateStepper.currentDate)
function getX(index) {
return points[index].h * skyBox.effectiveWidth + skyBox.hMargin;
}
function getY(index) {
return points[index].v * -(skyBox.effectiveHeight / 2) + skyBox.effectiveHeight / 2 + skyBox.vMargin;
}
onPointsChanged: requestPaint()
onPaint: {
var ctx = getContext("2d");
ctx.clearRect(0, 0, width, height);
if (!points || points.length === 0)
return;
ctx.beginPath();
ctx.moveTo(getX(0), getY(0));
for (var i = 1; i < points.length; i++) {
ctx.lineTo(getX(i), getY(i));
}
ctx.strokeStyle = Theme.withAlpha(Theme.outline, 0.2);
ctx.stroke();
}
}
property real latitude: WeatherService.getLocation()?.latitude ?? 0 property real latitude: WeatherService.getLocation()?.latitude ?? 0
property real sunDeclination: WeatherService.getSunDeclination(dateStepper.currentDate) property real sunDeclination: WeatherService.getSunDeclination(dateStepper.currentDate)
readonly property bool solarNoonIsSouth: latitude > sunDeclination readonly property bool solarNoonIsSouth: latitude > sunDeclination
StyledText { Loader {
id: middle anchors.fill: parent
text: skyBox.solarNoonIsSouth ? "S" : "N" asynchronous: true
font.pixelSize: Theme.fontSizeSmall sourceComponent: skyContentComponent
color: Theme.primary opacity: status === Loader.Ready ? 1 : 0
x: skyBox.width / 2 - middle.width / 2
y: skyBox.height / 2 - middle.height / 2 Behavior on opacity {
NumberAnimation {
duration: Theme.shortDuration
easing.type: Theme.standardEasing
}
}
} }
}
StyledText { Component {
id: left id: skyContentComponent
text: skyBox.solarNoonIsSouth ? "E" : "W"
font.pixelSize: Theme.fontSizeSmall
color: Theme.primary
x: skyBox.width / 4 - left.width / 2
y: skyBox.height / 2 - left.height / 2
}
StyledText { Item {
id: right Rectangle {
text: skyBox.solarNoonIsSouth ? "W" : "E" anchors.fill: parent
font.pixelSize: Theme.fontSizeSmall opacity: skyBox.backgroundOpacity
color: Theme.primary
x: 3 * skyBox.width / 4 - right.width / 2
y: skyBox.height / 2 - right.height / 2
}
Rectangle { gradient: Gradient {
height: 1 GradientStop {
anchors.leftMargin: Theme.spacingS position: 0.0
anchors.rightMargin: Theme.spacingS color: Theme.withAlpha(skyBox.blackColor, 0.0)
anchors.left: right.right }
anchors.right: skyBox.right GradientStop {
anchors.verticalCenter: middle.verticalCenter position: 0.05
color: Theme.outline color: skyBox.topColor
} }
GradientStop {
position: 0.3
color: skyBox.topColor
}
GradientStop {
position: 0.5
color: skyBox.topColor
}
GradientStop {
position: 0.501
color: skyBox.blackColor
}
GradientStop {
position: 0.9
color: skyBox.blackColor
}
GradientStop {
position: 1.0
color: Theme.withAlpha(skyBox.blackColor, 0.0)
}
}
}
Rectangle { StyledText {
height: 1 text: skyBox.sunTime?.period ?? ""
anchors.leftMargin: Theme.spacingS font.pixelSize: Theme.fontSizeSmall
anchors.rightMargin: Theme.spacingS color: Theme.withAlpha(Theme.surfaceText, 0.7)
anchors.left: middle.right x: 0
anchors.right: right.left y: 0
anchors.verticalCenter: middle.verticalCenter }
color: Theme.outline
}
Rectangle { Shape {
height: 1 id: skyShape
anchors.leftMargin: Theme.spacingS anchors.left: parent.left
anchors.rightMargin: Theme.spacingS anchors.top: parent.top
anchors.left: left.right anchors.right: parent.right
anchors.right: middle.left height: parent.height / 2
anchors.verticalCenter: middle.verticalCenter opacity: skyBox.backgroundOpacity
color: Theme.outline
}
Rectangle { ShapePath {
height: 1 strokeColor: "transparent"
anchors.leftMargin: Theme.spacingS fillGradient: RadialGradient {
anchors.rightMargin: Theme.spacingS centerX: skyBox.hMargin + sun.x + sun.width / 2
anchors.left: skyBox.left centerY: skyBox.vMargin + sun.y + 30
anchors.right: left.left centerRadius: {
anchors.verticalCenter: middle.verticalCenter const a = Math.abs((skyBox.sunTime?.dayPercent ?? 0) - 0.5);
color: Theme.outline const out = 200 * (0.5 - a * a);
} return out;
}
focalX: skyBox.hMargin + sun.x + sun.width / 2
focalY: skyBox.vMargin + sun.y
GradientStop {
position: 0
color: skyBox.sunColor
}
GradientStop {
position: 0.3
color: Theme.blendAlpha(skyBox.sunColor, 0.5)
}
GradientStop {
position: 1
color: "transparent"
}
}
PathLine {
x: 0
y: 0
}
PathLine {
x: skyShape.width
y: 0
}
PathLine {
x: skyShape.width
y: skyShape.height
}
PathLine {
x: 0
y: skyShape.height
}
}
DankNFIcon { ShapePath {
id: moonPhase strokeColor: "transparent"
name: WeatherService.getMoonPhase(skyBox.currentDate) || "" fillGradient: RadialGradient {
size: Theme.fontSizeXLarge centerX: sun.x
color: Theme.withAlpha(Theme.surfaceText, 0.7) centerY: sun.y
rotation: (WeatherService.getMoonAngle(skyBox.currentDate) || 0) / Math.PI * 180 centerRadius: 500
visible: !!pos focalX: centerX
focalY: centerY + 0.99 * (centerRadius - focalRadius)
focalRadius: 10
GradientStop {
position: 0
color: skyBox.sunColor
}
GradientStop {
position: 0.45
color: skyBox.sunColor
}
GradientStop {
position: 0.55
color: "transparent"
}
GradientStop {
position: 1
color: "transparent"
}
}
PathLine {
x: 0
y: 0
}
PathLine {
x: skyShape.width
y: 0
}
PathLine {
x: skyShape.width
y: skyShape.height
}
PathLine {
x: 0
y: skyShape.height
}
}
}
property var pos: WeatherService.getSkyArcPosition(skyBox.currentDate, false) Shape {
x: (pos?.h ?? 0) * skyBox.effectiveWidth - (moonPhase.width / 2) + skyBox.hMargin anchors.fill: parent
y: (pos?.v ?? 0) * -(skyBox.effectiveHeight / 2) + skyBox.effectiveHeight / 2 - (moonPhase.height / 2) + skyBox.vMargin
}
DankIcon { ShapePath {
id: sun strokeColor: Theme.withAlpha(Theme.outline, 0.2)
name: "light_mode" strokeWidth: 1
size: Theme.fontSizeXLarge fillColor: "transparent"
color: Theme.primary
visible: !!pos
property var pos: WeatherService.getSkyArcPosition(skyBox.currentDate, true) PathPolyline {
x: (pos?.h ?? 0) * skyBox.effectiveWidth - (sun.width / 2) + skyBox.hMargin path: {
y: (pos?.v ?? 0) * -(skyBox.effectiveHeight / 2) + skyBox.effectiveHeight / 2 - (sun.height / 2) + skyBox.vMargin const points = WeatherService.getEcliptic(dateStepper.currentDate) ?? [];
const out = [];
for (let i = 0; i < points.length; i++) {
out.push(Qt.point(points[i].h * skyBox.effectiveWidth + skyBox.hMargin, points[i].v * -(skyBox.effectiveHeight / 2) + skyBox.effectiveHeight / 2 + skyBox.vMargin));
}
return out;
}
}
}
}
StyledText {
id: middle
text: skyBox.solarNoonIsSouth ? "S" : "N"
font.pixelSize: Theme.fontSizeSmall
color: Theme.primary
x: skyBox.width / 2 - middle.width / 2
y: skyBox.height / 2 - middle.height / 2
}
StyledText {
id: left
text: skyBox.solarNoonIsSouth ? "E" : "W"
font.pixelSize: Theme.fontSizeSmall
color: Theme.primary
x: skyBox.width / 4 - left.width / 2
y: skyBox.height / 2 - left.height / 2
}
StyledText {
id: right
text: skyBox.solarNoonIsSouth ? "W" : "E"
font.pixelSize: Theme.fontSizeSmall
color: Theme.primary
x: 3 * skyBox.width / 4 - right.width / 2
y: skyBox.height / 2 - right.height / 2
}
Rectangle {
height: 1
anchors.leftMargin: Theme.spacingS
anchors.rightMargin: Theme.spacingS
anchors.left: right.right
anchors.right: parent.right
anchors.verticalCenter: middle.verticalCenter
color: Theme.outline
}
Rectangle {
height: 1
anchors.leftMargin: Theme.spacingS
anchors.rightMargin: Theme.spacingS
anchors.left: middle.right
anchors.right: right.left
anchors.verticalCenter: middle.verticalCenter
color: Theme.outline
}
Rectangle {
height: 1
anchors.leftMargin: Theme.spacingS
anchors.rightMargin: Theme.spacingS
anchors.left: left.right
anchors.right: middle.left
anchors.verticalCenter: middle.verticalCenter
color: Theme.outline
}
Rectangle {
height: 1
anchors.leftMargin: Theme.spacingS
anchors.rightMargin: Theme.spacingS
anchors.left: parent.left
anchors.right: left.left
anchors.verticalCenter: middle.verticalCenter
color: Theme.outline
}
DankNFIcon {
id: moonPhase
name: WeatherService.getMoonPhase(skyBox.currentDate) || ""
size: Theme.fontSizeXLarge
color: Theme.withAlpha(Theme.surfaceText, 0.7)
rotation: (WeatherService.getMoonAngle(skyBox.currentDate) || 0) / Math.PI * 180
visible: !!pos
property var pos: WeatherService.getSkyArcPosition(skyBox.currentDate, false)
x: (pos?.h ?? 0) * skyBox.effectiveWidth - (moonPhase.width / 2) + skyBox.hMargin
y: (pos?.v ?? 0) * -(skyBox.effectiveHeight / 2) + skyBox.effectiveHeight / 2 - (moonPhase.height / 2) + skyBox.vMargin
}
DankIcon {
id: sun
name: "light_mode"
size: Theme.fontSizeXLarge
color: Theme.primary
visible: !!pos
property var pos: WeatherService.getSkyArcPosition(skyBox.currentDate, true)
x: (pos?.h ?? 0) * skyBox.effectiveWidth - (sun.width / 2) + skyBox.hMargin
y: (pos?.v ?? 0) * -(skyBox.effectiveHeight / 2) + skyBox.effectiveHeight / 2 - (sun.height / 2) + skyBox.vMargin
}
} }
} }
} }