3 Commits

20 changed files with 858 additions and 733 deletions
+8 -1
View File
@@ -31,6 +31,13 @@ if("shell" IN_LIST ENABLE_MODULES)
foreach(dir assets scripts Components Config Modules Daemons Drawers Effects Helpers Paths) foreach(dir assets scripts Components Config Modules Daemons Drawers Effects Helpers Paths)
install(DIRECTORY ${dir} DESTINATION "${INSTALL_QSCONFDIR}") install(DIRECTORY ${dir} DESTINATION "${INSTALL_QSCONFDIR}")
endforeach() endforeach()
install(FILES shell.qml DESTINATION "${INSTALL_QSCONFDIR}")
# Disable watching for changes
file(READ shell.qml SHELL_QML)
string(REPLACE "settings.watchFiles: true" "settings.watchFiles: false" SHELL_QML "${SHELL_QML}")
file(WRITE "${CMAKE_BINARY_DIR}/qml/shell.qml" "${SHELL_QML}")
install(FILES "${CMAKE_BINARY_DIR}/qml/shell.qml" DESTINATION "${INSTALL_QSCONFDIR}")
# Greeter
install(DIRECTORY Greeter/ DESTINATION "${INSTALL_GREETERCONFDIR}") install(DIRECTORY Greeter/ DESTINATION "${INSTALL_GREETERCONFDIR}")
endif() endif()
+1
View File
@@ -15,6 +15,7 @@ Text {
color: DynamicColors.palette.m3onSurface color: DynamicColors.palette.m3onSurface
font.family: Appearance.font.family.sans font.family: Appearance.font.family.sans
font.pointSize: Appearance.font.size.normal font.pointSize: Appearance.font.size.normal
linkColor: DynamicColors.palette.m3onPrimaryFixedVariant
renderType: Text.NativeRendering renderType: Text.NativeRendering
textFormat: Text.PlainText textFormat: Text.PlainText
+12 -1
View File
@@ -22,6 +22,7 @@ Singleton {
property alias notifs: adapter.notifs property alias notifs: adapter.notifs
property alias osd: adapter.osd property alias osd: adapter.osd
property alias overview: adapter.overview property alias overview: adapter.overview
property alias plugins: adapter.plugins
property bool recentlySaved: false property bool recentlySaved: false
property alias screenshot: adapter.screenshot property alias screenshot: adapter.screenshot
property alias services: adapter.services property alias services: adapter.services
@@ -140,7 +141,8 @@ Singleton {
launcher: serializeLauncher(), launcher: serializeLauncher(),
colors: serializeColors(), colors: serializeColors(),
dock: serializeDock(), dock: serializeDock(),
screenshot: serializeScreenshot() screenshot: serializeScreenshot(),
plugins: serializePlugins()
}; };
} }
@@ -289,6 +291,13 @@ Singleton {
}; };
} }
function serializePlugins(): var {
return {
enabled: plugins.enabled,
entries: plugins.entries
};
}
function serializeScreenshot(): var { function serializeScreenshot(): var {
return { return {
enable_pp: screenshot.enable_pp, enable_pp: screenshot.enable_pp,
@@ -458,6 +467,8 @@ Singleton {
} }
property Overview overview: Overview { property Overview overview: Overview {
} }
property PluginConfig plugins: PluginConfig {
}
property Screenshot screenshot: Screenshot { property Screenshot screenshot: Screenshot {
} }
property Services services: Services { property Services services: Services {
+11
View File
@@ -0,0 +1,11 @@
import Quickshell.Io
JsonObject {
property bool enabled: false
property list<var> entries: [
{
id: "Plugin",
enabled: false
},
]
}
+18
View File
@@ -0,0 +1,18 @@
pragma Singleton
import Quickshell
import ZShell.Models
Singleton {
id: root
property alias plugins: plugins.entries
FileSystemModel {
id: plugins
nameFilters: ["*.qml"]
path: Quickshell.env("HOME") + "/.config/zshell"
recursive: false
}
}
+17
View File
@@ -0,0 +1,17 @@
import Quickshell
import QtQuick
import ZShell.Models
import qs.Config
Repeater {
model: FetchPlugins.plugins
LazyLoader {
required property FileSystemEntry modelData
activeAsync: Config.plugins.entries.some(p => {
return p.id === modelData.baseName && p.enabled;
})
source: modelData.path
}
}
+1 -1
View File
@@ -1,7 +1,7 @@
import Quickshell
import "../scripts/fzf.js" as Fzf import "../scripts/fzf.js" as Fzf
import "../scripts/fuzzysort.js" as Fuzzy import "../scripts/fuzzysort.js" as Fuzzy
import QtQuick import QtQuick
import Quickshell
Singleton { Singleton {
property var extraOpts: ({}) property var extraOpts: ({})
+3
View File
@@ -136,7 +136,10 @@ CustomRect {
wrapMode: Text.WordWrap wrapMode: Text.WordWrap
onLinkActivated: link => { onLinkActivated: link => {
if (Config.launcher.uwsm)
Quickshell.execDetached(["app2unit", "-O", "--", link]); Quickshell.execDetached(["app2unit", "-O", "--", link]);
else
Quickshell.execDetached(["xdg-open", link]);
root.visibilities.sidebar = false; root.visibilities.sidebar = false;
} }
} }
+5 -3
View File
@@ -100,13 +100,15 @@ Item {
icon: `brightness_${(Math.round(value * 6) + 1)}` icon: `brightness_${(Math.round(value * 6) + 1)}`
value: root.brightness value: root.brightness
onMoved: { onPressedChanged: {
if (!pressed) {
if (Config.osd.allMonBrightness) { if (Config.osd.allMonBrightness) {
root.monitor?.setBrightness(value);
} else {
for (const mon of Brightness.monitors) { for (const mon of Brightness.monitors) {
mon.setBrightness(value); mon.setBrightness(value);
} }
} else {
root.monitor?.setBrightness(value);
}
} }
} }
} }
+6
View File
@@ -116,6 +116,12 @@ Item {
key: "updates" key: "updates"
name: "Updates" name: "Updates"
} }
ListElement {
icon: "extension"
key: "plugins"
name: "Extensions"
}
} }
CustomClippingRect { CustomClippingRect {
+111 -111
View File
@@ -19,8 +19,8 @@ SettingsPage {
} }
SettingSpinBox { SettingSpinBox {
name: "Media update interval"
min: 0 min: 0
name: "Media update interval"
object: Config.dashboard object: Config.dashboard
setting: "mediaUpdateInterval" setting: "mediaUpdateInterval"
step: 50 step: 50
@@ -30,8 +30,8 @@ SettingsPage {
} }
SettingSpinBox { SettingSpinBox {
name: "Resource update interval"
min: 0 min: 0
name: "Resource update interval"
object: Config.dashboard object: Config.dashboard
setting: "resourceUpdateInterval" setting: "resourceUpdateInterval"
step: 50 step: 50
@@ -41,8 +41,8 @@ SettingsPage {
} }
SettingSpinBox { SettingSpinBox {
name: "Drag threshold"
min: 0 min: 0
name: "Drag threshold"
object: Config.dashboard object: Config.dashboard
setting: "dragThreshold" setting: "dragThreshold"
} }
@@ -107,112 +107,112 @@ SettingsPage {
} }
} }
SettingsSection { // SettingsSection {
sectionId: "Layout Sizes" // sectionId: "Layout Sizes"
//
SettingsHeader { // SettingsHeader {
name: "Layout Sizes" // name: "Layout Sizes"
} // }
//
SettingReadOnly { // SettingReadOnly {
name: "Tab indicator height" // name: "Tab indicator height"
value: String(Config.dashboard.sizes.tabIndicatorHeight) // value: String(Config.dashboard.sizes.tabIndicatorHeight)
} // }
//
Separator { // Separator {
} // }
//
SettingReadOnly { // SettingReadOnly {
name: "Tab indicator spacing" // name: "Tab indicator spacing"
value: String(Config.dashboard.sizes.tabIndicatorSpacing) // value: String(Config.dashboard.sizes.tabIndicatorSpacing)
} // }
//
Separator { // Separator {
} // }
//
SettingReadOnly { // SettingReadOnly {
name: "Info width" // name: "Info width"
value: String(Config.dashboard.sizes.infoWidth) // value: String(Config.dashboard.sizes.infoWidth)
} // }
//
Separator { // Separator {
} // }
//
SettingReadOnly { // SettingReadOnly {
name: "Info icon size" // name: "Info icon size"
value: String(Config.dashboard.sizes.infoIconSize) // value: String(Config.dashboard.sizes.infoIconSize)
} // }
//
Separator { // Separator {
} // }
//
SettingReadOnly { // SettingReadOnly {
name: "Date time width" // name: "Date time width"
value: String(Config.dashboard.sizes.dateTimeWidth) // value: String(Config.dashboard.sizes.dateTimeWidth)
} // }
//
Separator { // Separator {
} // }
//
SettingReadOnly { // SettingReadOnly {
name: "Media width" // name: "Media width"
value: String(Config.dashboard.sizes.mediaWidth) // value: String(Config.dashboard.sizes.mediaWidth)
} // }
//
Separator { // Separator {
} // }
//
SettingReadOnly { // SettingReadOnly {
name: "Media progress sweep" // name: "Media progress sweep"
value: String(Config.dashboard.sizes.mediaProgressSweep) // value: String(Config.dashboard.sizes.mediaProgressSweep)
} // }
//
Separator { // Separator {
} // }
//
SettingReadOnly { // SettingReadOnly {
name: "Media progress thickness" // name: "Media progress thickness"
value: String(Config.dashboard.sizes.mediaProgressThickness) // value: String(Config.dashboard.sizes.mediaProgressThickness)
} // }
//
Separator { // Separator {
} // }
//
SettingReadOnly { // SettingReadOnly {
name: "Resource progress thickness" // name: "Resource progress thickness"
value: String(Config.dashboard.sizes.resourceProgessThickness) // value: String(Config.dashboard.sizes.resourceProgessThickness)
} // }
//
Separator { // Separator {
} // }
//
SettingReadOnly { // SettingReadOnly {
name: "Weather width" // name: "Weather width"
value: String(Config.dashboard.sizes.weatherWidth) // value: String(Config.dashboard.sizes.weatherWidth)
} // }
//
Separator { // Separator {
} // }
//
SettingReadOnly { // SettingReadOnly {
name: "Media cover art size" // name: "Media cover art size"
value: String(Config.dashboard.sizes.mediaCoverArtSize) // value: String(Config.dashboard.sizes.mediaCoverArtSize)
} // }
//
Separator { // Separator {
} // }
//
SettingReadOnly { // SettingReadOnly {
name: "Media visualiser size" // name: "Media visualiser size"
value: String(Config.dashboard.sizes.mediaVisualiserSize) // value: String(Config.dashboard.sizes.mediaVisualiserSize)
} // }
//
Separator { // Separator {
} // }
//
SettingReadOnly { // SettingReadOnly {
name: "Resource size" // name: "Resource size"
value: String(Config.dashboard.sizes.resourceSize) // value: String(Config.dashboard.sizes.resourceSize)
} // }
} // }
} }
@@ -72,6 +72,8 @@ ColumnLayout {
SettingList { SettingList {
Layout.fillWidth: true Layout.fillWidth: true
anchors.left: undefined
anchors.right: undefined
onAddActiveActionRequested: { onAddActiveActionRequested: {
root.updateTimeoutEntry(index, "activeAction", ""); root.updateTimeoutEntry(index, "activeAction", "");
+18
View File
@@ -0,0 +1,18 @@
import qs.Modules.Settings.Controls
import qs.Config
SettingsPage {
SettingsSection {
sectionId: "Plugins"
SettingsHeader {
name: "Plugins"
}
SettingBarEntryList {
name: "Enable or disable plugins"
object: Config.plugins
setting: "entries"
}
}
}
+97 -97
View File
@@ -19,8 +19,8 @@ SettingsPage {
} }
SettingSpinBox { SettingSpinBox {
name: "Max toasts"
min: 1 min: 1
name: "Max toasts"
object: Config.utilities object: Config.utilities
setting: "maxToasts" setting: "maxToasts"
} }
@@ -29,8 +29,8 @@ SettingsPage {
} }
SettingSpinBox { SettingSpinBox {
name: "Panel width"
min: 1 min: 1
name: "Panel width"
object: Config.utilities.sizes object: Config.utilities.sizes
setting: "width" setting: "width"
} }
@@ -39,8 +39,8 @@ SettingsPage {
} }
SettingSpinBox { SettingSpinBox {
name: "Toast width"
min: 1 min: 1
name: "Toast width"
object: Config.utilities.sizes object: Config.utilities.sizes
setting: "toastWidth" setting: "toastWidth"
} }
@@ -77,100 +77,100 @@ SettingsPage {
setting: "gameModeChanged" setting: "gameModeChanged"
} }
Separator { // Separator {
// }
//
// SettingSwitch {
// name: "Do not disturb changed"
// object: Config.utilities.toasts
// setting: "dndChanged"
// }
//
// Separator {
// }
//
// SettingSwitch {
// name: "Audio output changed"
// object: Config.utilities.toasts
// setting: "audioOutputChanged"
// }
//
// Separator {
// }
//
// SettingSwitch {
// name: "Audio input changed"
// object: Config.utilities.toasts
// setting: "audioInputChanged"
// }
//
// Separator {
// }
//
// SettingSwitch {
// name: "Caps lock changed"
// object: Config.utilities.toasts
// setting: "capsLockChanged"
// }
//
// Separator {
// }
//
// SettingSwitch {
// name: "Num lock changed"
// object: Config.utilities.toasts
// setting: "numLockChanged"
// }
//
// Separator {
// }
//
// SettingSwitch {
// name: "Keyboard layout changed"
// object: Config.utilities.toasts
// setting: "kbLayoutChanged"
// }
//
// Separator {
// }
//
// SettingSwitch {
// name: "VPN changed"
// object: Config.utilities.toasts
// setting: "vpnChanged"
// }
//
// Separator {
// }
//
// SettingSwitch {
// name: "Now playing"
// object: Config.utilities.toasts
// setting: "nowPlaying"
// }
} }
SettingSwitch { // SettingsSection {
name: "Do not disturb changed" // sectionId: "VPN"
object: Config.utilities.toasts //
setting: "dndChanged" // SettingsHeader {
} // name: "VPN"
// }
Separator { //
} // SettingSwitch {
// name: "Enable VPN integration"
SettingSwitch { // object: Config.utilities.vpn
name: "Audio output changed" // setting: "enabled"
object: Config.utilities.toasts // }
setting: "audioOutputChanged" //
} // Separator {
// }
Separator { //
} // SettingStringList {
// name: "Provider"
SettingSwitch { // addLabel: qsTr("Add VPN provider")
name: "Audio input changed" // object: Config.utilities.vpn
object: Config.utilities.toasts // setting: "provider"
setting: "audioInputChanged" // }
} // }
Separator {
}
SettingSwitch {
name: "Caps lock changed"
object: Config.utilities.toasts
setting: "capsLockChanged"
}
Separator {
}
SettingSwitch {
name: "Num lock changed"
object: Config.utilities.toasts
setting: "numLockChanged"
}
Separator {
}
SettingSwitch {
name: "Keyboard layout changed"
object: Config.utilities.toasts
setting: "kbLayoutChanged"
}
Separator {
}
SettingSwitch {
name: "VPN changed"
object: Config.utilities.toasts
setting: "vpnChanged"
}
Separator {
}
SettingSwitch {
name: "Now playing"
object: Config.utilities.toasts
setting: "nowPlaying"
}
}
SettingsSection {
sectionId: "VPN"
SettingsHeader {
name: "VPN"
}
SettingSwitch {
name: "Enable VPN integration"
object: Config.utilities.vpn
setting: "enabled"
}
Separator {
}
SettingStringList {
name: "Provider"
addLabel: qsTr("Add VPN provider")
object: Config.utilities.vpn
setting: "provider"
}
}
} }
+9
View File
@@ -79,6 +79,8 @@ Item {
stack.push(screenshot); stack.push(screenshot);
else if (currentCategory === "updates") else if (currentCategory === "updates")
stack.push(updates); stack.push(updates);
else if (currentCategory === "plugins")
stack.push(plugins);
} }
target: root target: root
@@ -245,4 +247,11 @@ Item {
Cat.SystemUpdates { Cat.SystemUpdates {
} }
} }
Component {
id: plugins
Cat.Plugins {
}
}
} }
@@ -127,6 +127,9 @@ ColumnLayout {
} }
Separator { Separator {
Layout.fillWidth: true
anchors.left: undefined
anchors.right: undefined
} }
RowLayout { RowLayout {
@@ -207,6 +210,8 @@ ColumnLayout {
StringListEditor { StringListEditor {
Layout.fillWidth: true Layout.fillWidth: true
addLabel: qsTr("Add command argument") addLabel: qsTr("Add command argument")
anchors.left: undefined
anchors.right: undefined
values: [...(modelData.command ?? [])] values: [...(modelData.command ?? [])]
onListEdited: function (values) { onListEdited: function (values) {
@@ -215,6 +220,9 @@ ColumnLayout {
} }
Separator { Separator {
Layout.fillWidth: true
anchors.left: undefined
anchors.right: undefined
} }
RowLayout { RowLayout {
@@ -233,6 +241,9 @@ ColumnLayout {
} }
Separator { Separator {
Layout.fillWidth: true
anchors.left: undefined
anchors.right: undefined
} }
RowLayout { RowLayout {
+25 -13
View File
@@ -6,7 +6,7 @@ import qs.Components
import qs.Config import qs.Config
import qs.Helpers import qs.Helpers
ColumnLayout { CustomRect {
id: root id: root
readonly property bool highlighted: SettingsHighlight.highlightedSetting === name readonly property bool highlighted: SettingsHighlight.highlightedSetting === name
@@ -43,10 +43,9 @@ ColumnLayout {
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
height: shouldBeActive ? implicitHeight : 0 height: shouldBeActive ? layout.implicitHeight : 0
opacity: shouldBeActive ? 1 : 0 opacity: shouldBeActive ? 1 : 0
scale: shouldBeActive ? 1 : 0.8 scale: shouldBeActive ? 1 : 0.8
spacing: Appearance.spacing.smaller
visible: opacity > 0 visible: opacity > 0
Behavior on opacity { Behavior on opacity {
@@ -77,6 +76,14 @@ ColumnLayout {
} }
} }
ColumnLayout {
id: layout
anchors.left: parent.left
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
spacing: Appearance.spacing.smaller
CustomText { CustomText {
Layout.fillWidth: true Layout.fillWidth: true
font.pointSize: Appearance.font.size.larger font.pointSize: Appearance.font.size.larger
@@ -121,15 +128,17 @@ ColumnLayout {
} }
CustomRect { CustomRect {
Layout.fillWidth: true
Layout.preferredHeight: 33 Layout.preferredHeight: 33
Layout.preferredWidth: Math.max(Math.min(fromTextField.contentWidth + Appearance.padding.large * 2, 550), 50)
color: DynamicColors.tPalette.m3surfaceContainerHigh color: DynamicColors.tPalette.m3surfaceContainerHigh
radius: Appearance.rounding.full radius: Appearance.rounding.full
CustomTextField { CustomTextField {
anchors.fill: parent id: fromTextField
anchors.leftMargin: Appearance.padding.normal
anchors.rightMargin: Appearance.padding.normal anchors.centerIn: parent
horizontalAlignment: Text.AlignHCenter
implicitWidth: Math.min(contentWidth + Appearance.padding.normal * 2, 550)
text: modelData.from ?? "" text: modelData.from ?? ""
onEditingFinished: root.updateAlias(index, "from", text) onEditingFinished: root.updateAlias(index, "from", text)
@@ -154,15 +163,17 @@ ColumnLayout {
} }
CustomRect { CustomRect {
Layout.fillWidth: true
Layout.preferredHeight: 33 Layout.preferredHeight: 33
color: DynamicColors.tPalette.m3surface Layout.preferredWidth: Math.max(Math.min(toTextField.contentWidth + Appearance.padding.large * 2, 550), 50)
radius: Appearance.rounding.small color: DynamicColors.tPalette.m3surfaceContainerHigh
radius: Appearance.rounding.full
CustomTextField { CustomTextField {
anchors.fill: parent id: toTextField
anchors.leftMargin: Appearance.padding.normal
anchors.rightMargin: Appearance.padding.normal anchors.centerIn: parent
horizontalAlignment: Text.AlignHCenter
implicitWidth: Math.min(contentWidth + Appearance.padding.normal * 2, 550)
text: modelData.to ?? "" text: modelData.to ?? ""
onEditingFinished: root.updateAlias(index, "to", text) onEditingFinished: root.updateAlias(index, "to", text)
@@ -188,4 +199,5 @@ ColumnLayout {
text: qsTr("Add alias") text: qsTr("Add alias")
} }
} }
}
} }
+16 -25
View File
@@ -12,7 +12,8 @@ FileSystemEntry::FileSystemEntry(const QString& path, const QString& relativePat
, m_path(path) , m_path(path)
, m_relativePath(relativePath) , m_relativePath(relativePath)
, m_isImageInitialised(false) , m_isImageInitialised(false)
, m_mimeTypeInitialised(false) {} , m_mimeTypeInitialised(false) {
}
QString FileSystemEntry::path() const { QString FileSystemEntry::path() const {
return m_path; return m_path;
@@ -57,8 +58,8 @@ bool FileSystemEntry::isImage() const {
QString FileSystemEntry::mimeType() const { QString FileSystemEntry::mimeType() const {
if (!m_mimeTypeInitialised) { if (!m_mimeTypeInitialised) {
const QMimeDatabase db; static const QMimeDatabase s_db;
m_mimeType = db.mimeTypeForFile(m_path).name(); m_mimeType = s_db.mimeTypeForFile(m_path).name();
m_mimeTypeInitialised = true; m_mimeTypeInitialised = true;
} }
return m_mimeType; return m_mimeType;
@@ -219,7 +220,7 @@ void FileSystemModel::watchDirIfRecursive(const QString& path) {
if (m_recursive && m_watchChanges) { if (m_recursive && m_watchChanges) {
const auto currentDir = m_dir; const auto currentDir = m_dir;
const bool showHidden = m_showHidden; const bool showHidden = m_showHidden;
const auto future = QtConcurrent::run([showHidden, path]() { auto future = QtConcurrent::run([showHidden, path]() {
QDir::Filters filters = QDir::Dirs | QDir::NoDotAndDotDot; QDir::Filters filters = QDir::Dirs | QDir::NoDotAndDotDot;
if (showHidden) { if (showHidden) {
filters |= QDir::Hidden; filters |= QDir::Hidden;
@@ -232,16 +233,12 @@ void FileSystemModel::watchDirIfRecursive(const QString& path) {
} }
return dirs; return dirs;
}); });
const auto watcher = new QFutureWatcher<QStringList>(this); future.then(this, [currentDir, showHidden, this](const QStringList& paths) {
connect(watcher, &QFutureWatcher<QStringList>::finished, this, [currentDir, showHidden, watcher, this]() {
const auto paths = watcher->result();
if (currentDir == m_dir && showHidden == m_showHidden && !paths.isEmpty()) { if (currentDir == m_dir && showHidden == m_showHidden && !paths.isEmpty()) {
// Ignore if dir or showHidden has changed // Ignore if dir or showHidden has changed
m_watcher.addPaths(paths); m_watcher.addPaths(paths);
} }
watcher->deleteLater();
}); });
watcher->setFuture(future);
} }
} }
@@ -295,7 +292,7 @@ void FileSystemModel::updateEntriesForDir(const QString& dir) {
oldPaths << entry->path(); oldPaths << entry->path();
} }
const auto future = QtConcurrent::run([=](QPromise<QPair<QSet<QString>, QSet<QString>>>& promise) { auto future = QtConcurrent::run([=](QPromise<QPair<QSet<QString>, QSet<QString> > >& promise) {
const auto flags = recursive ? QDirIterator::Subdirectories : QDirIterator::NoIteratorFlags; const auto flags = recursive ? QDirIterator::Subdirectories : QDirIterator::NoIteratorFlags;
std::optional<QDirIterator> iter; std::optional<QDirIterator> iter;
@@ -353,7 +350,7 @@ void FileSystemModel::updateEntriesForDir(const QString& dir) {
newPaths.insert(path); newPaths.insert(path);
} }
if (promise.isCanceled() || newPaths == oldPaths) { if (promise.isCanceled()) {
return; return;
} }
@@ -365,23 +362,17 @@ void FileSystemModel::updateEntriesForDir(const QString& dir) {
} }
m_futures.insert(dir, future); m_futures.insert(dir, future);
const auto watcher = new QFutureWatcher<QPair<QSet<QString>, QSet<QString>>>(this); future
.then(this,
connect(watcher, &QFutureWatcher<QPair<QSet<QString>, QSet<QString>>>::finished, this, [dir, watcher, this]() { [dir, this](QPair<QSet<QString>, QSet<QString> > result) {
m_futures.remove(dir); m_futures.remove(dir);
if (!result.first.isEmpty() || !result.second.isEmpty()) {
if (!watcher->future().isResultReadyAt(0)) {
watcher->deleteLater();
return;
}
const auto result = watcher->result();
applyChanges(result.first, result.second); applyChanges(result.first, result.second);
}
watcher->deleteLater(); })
.onCanceled(this, [dir, this]() {
m_futures.remove(dir);
}); });
watcher->setFuture(future);
} }
void FileSystemModel::applyChanges(const QSet<QString>& removedPaths, const QSet<QString>& addedPaths) { void FileSystemModel::applyChanges(const QSet<QString>& removedPaths, const QSet<QString>& addedPaths) {
+90 -90
View File
@@ -13,136 +13,136 @@
namespace ZShell::models { namespace ZShell::models {
class FileSystemEntry : public QObject { class FileSystemEntry : public QObject {
Q_OBJECT Q_OBJECT
QML_ELEMENT QML_ELEMENT
QML_UNCREATABLE("FileSystemEntry instances can only be retrieved from a FileSystemModel") QML_UNCREATABLE("FileSystemEntry instances can only be retrieved from a FileSystemModel")
Q_PROPERTY(QString path READ path CONSTANT) Q_PROPERTY(QString path READ path CONSTANT)
Q_PROPERTY(QString relativePath READ relativePath NOTIFY relativePathChanged) Q_PROPERTY(QString relativePath READ relativePath NOTIFY relativePathChanged)
Q_PROPERTY(QString name READ name CONSTANT) Q_PROPERTY(QString name READ name CONSTANT)
Q_PROPERTY(QString baseName READ baseName CONSTANT) Q_PROPERTY(QString baseName READ baseName CONSTANT)
Q_PROPERTY(QString parentDir READ parentDir CONSTANT) Q_PROPERTY(QString parentDir READ parentDir CONSTANT)
Q_PROPERTY(QString suffix READ suffix CONSTANT) Q_PROPERTY(QString suffix READ suffix CONSTANT)
Q_PROPERTY(qint64 size READ size CONSTANT) Q_PROPERTY(qint64 size READ size CONSTANT)
Q_PROPERTY(bool isDir READ isDir CONSTANT) Q_PROPERTY(bool isDir READ isDir CONSTANT)
Q_PROPERTY(bool isImage READ isImage CONSTANT) Q_PROPERTY(bool isImage READ isImage CONSTANT)
Q_PROPERTY(QString mimeType READ mimeType CONSTANT) Q_PROPERTY(QString mimeType READ mimeType CONSTANT)
public: public:
explicit FileSystemEntry(const QString& path, const QString& relativePath, QObject* parent = nullptr); explicit FileSystemEntry(const QString& path, const QString& relativePath, QObject* parent = nullptr);
[[nodiscard]] QString path() const; [[nodiscard]] QString path() const;
[[nodiscard]] QString relativePath() const; [[nodiscard]] QString relativePath() const;
[[nodiscard]] QString name() const; [[nodiscard]] QString name() const;
[[nodiscard]] QString baseName() const; [[nodiscard]] QString baseName() const;
[[nodiscard]] QString parentDir() const; [[nodiscard]] QString parentDir() const;
[[nodiscard]] QString suffix() const; [[nodiscard]] QString suffix() const;
[[nodiscard]] qint64 size() const; [[nodiscard]] qint64 size() const;
[[nodiscard]] bool isDir() const; [[nodiscard]] bool isDir() const;
[[nodiscard]] bool isImage() const; [[nodiscard]] bool isImage() const;
[[nodiscard]] QString mimeType() const; [[nodiscard]] QString mimeType() const;
void updateRelativePath(const QDir& dir); void updateRelativePath(const QDir& dir);
signals: signals:
void relativePathChanged(); void relativePathChanged();
private: private:
const QFileInfo m_fileInfo; const QFileInfo m_fileInfo;
const QString m_path; const QString m_path;
QString m_relativePath; QString m_relativePath;
mutable bool m_isImage; mutable bool m_isImage;
mutable bool m_isImageInitialised; mutable bool m_isImageInitialised;
mutable QString m_mimeType; mutable QString m_mimeType;
mutable bool m_mimeTypeInitialised; mutable bool m_mimeTypeInitialised;
}; };
class FileSystemModel : public QAbstractListModel { class FileSystemModel : public QAbstractListModel {
Q_OBJECT Q_OBJECT
QML_ELEMENT QML_ELEMENT
Q_PROPERTY(QString path READ path WRITE setPath NOTIFY pathChanged) Q_PROPERTY(QString path READ path WRITE setPath NOTIFY pathChanged)
Q_PROPERTY(bool recursive READ recursive WRITE setRecursive NOTIFY recursiveChanged) Q_PROPERTY(bool recursive READ recursive WRITE setRecursive NOTIFY recursiveChanged)
Q_PROPERTY(bool watchChanges READ watchChanges WRITE setWatchChanges NOTIFY watchChangesChanged) Q_PROPERTY(bool watchChanges READ watchChanges WRITE setWatchChanges NOTIFY watchChangesChanged)
Q_PROPERTY(bool showHidden READ showHidden WRITE setShowHidden NOTIFY showHiddenChanged) Q_PROPERTY(bool showHidden READ showHidden WRITE setShowHidden NOTIFY showHiddenChanged)
Q_PROPERTY(bool sortReverse READ sortReverse WRITE setSortReverse NOTIFY sortReverseChanged) Q_PROPERTY(bool sortReverse READ sortReverse WRITE setSortReverse NOTIFY sortReverseChanged)
Q_PROPERTY(Filter filter READ filter WRITE setFilter NOTIFY filterChanged) Q_PROPERTY(Filter filter READ filter WRITE setFilter NOTIFY filterChanged)
Q_PROPERTY(QStringList nameFilters READ nameFilters WRITE setNameFilters NOTIFY nameFiltersChanged) Q_PROPERTY(QStringList nameFilters READ nameFilters WRITE setNameFilters NOTIFY nameFiltersChanged)
Q_PROPERTY(QQmlListProperty<ZShell::models::FileSystemEntry> entries READ entries NOTIFY entriesChanged) Q_PROPERTY(QQmlListProperty<ZShell::models::FileSystemEntry> entries READ entries NOTIFY entriesChanged)
public: public:
enum Filter { enum Filter {
NoFilter, NoFilter,
Images, Images,
Files, Files,
Dirs Dirs
}; };
Q_ENUM(Filter) Q_ENUM(Filter)
explicit FileSystemModel(QObject* parent = nullptr); explicit FileSystemModel(QObject* parent = nullptr);
int rowCount(const QModelIndex& parent = QModelIndex()) const override; int rowCount(const QModelIndex& parent = QModelIndex()) const override;
QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override; QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
QHash<int, QByteArray> roleNames() const override; QHash<int, QByteArray> roleNames() const override;
[[nodiscard]] QString path() const; [[nodiscard]] QString path() const;
void setPath(const QString& path); void setPath(const QString& path);
[[nodiscard]] bool recursive() const; [[nodiscard]] bool recursive() const;
void setRecursive(bool recursive); void setRecursive(bool recursive);
[[nodiscard]] bool watchChanges() const; [[nodiscard]] bool watchChanges() const;
void setWatchChanges(bool watchChanges); void setWatchChanges(bool watchChanges);
[[nodiscard]] bool showHidden() const; [[nodiscard]] bool showHidden() const;
void setShowHidden(bool showHidden); void setShowHidden(bool showHidden);
[[nodiscard]] bool sortReverse() const; [[nodiscard]] bool sortReverse() const;
void setSortReverse(bool sortReverse); void setSortReverse(bool sortReverse);
[[nodiscard]] Filter filter() const; [[nodiscard]] Filter filter() const;
void setFilter(Filter filter); void setFilter(Filter filter);
[[nodiscard]] QStringList nameFilters() const; [[nodiscard]] QStringList nameFilters() const;
void setNameFilters(const QStringList& nameFilters); void setNameFilters(const QStringList& nameFilters);
[[nodiscard]] QQmlListProperty<FileSystemEntry> entries(); [[nodiscard]] QQmlListProperty<FileSystemEntry> entries();
signals: signals:
void pathChanged(); void pathChanged();
void recursiveChanged(); void recursiveChanged();
void watchChangesChanged(); void watchChangesChanged();
void showHiddenChanged(); void showHiddenChanged();
void sortReverseChanged(); void sortReverseChanged();
void filterChanged(); void filterChanged();
void nameFiltersChanged(); void nameFiltersChanged();
void entriesChanged(); void entriesChanged();
private: private:
QDir m_dir; QDir m_dir;
QFileSystemWatcher m_watcher; QFileSystemWatcher m_watcher;
QList<FileSystemEntry*> m_entries; QList<FileSystemEntry*> m_entries;
QHash<QString, QFuture<QPair<QSet<QString>, QSet<QString>>>> m_futures; QHash<QString, QFuture<QPair<QSet<QString>, QSet<QString> > > > m_futures;
QString m_path; QString m_path;
bool m_recursive; bool m_recursive;
bool m_watchChanges; bool m_watchChanges;
bool m_showHidden; bool m_showHidden;
bool m_sortReverse; bool m_sortReverse = false;
Filter m_filter; Filter m_filter;
QStringList m_nameFilters; QStringList m_nameFilters;
void watchDirIfRecursive(const QString& path); void watchDirIfRecursive(const QString& path);
void update(); void update();
void updateWatcher(); void updateWatcher();
void updateEntries(); void updateEntries();
void updateEntriesForDir(const QString& dir); void updateEntriesForDir(const QString& dir);
void applyChanges(const QSet<QString>& removedPaths, const QSet<QString>& addedPaths); void applyChanges(const QSet<QString>& removedPaths, const QSet<QString>& addedPaths);
[[nodiscard]] bool compareEntries(const FileSystemEntry* a, const FileSystemEntry* b) const; [[nodiscard]] bool compareEntries(const FileSystemEntry* a, const FileSystemEntry* b) const;
}; };
} // namespace ZShell::models } // namespace ZShell::models
+7 -1
View File
@@ -1,11 +1,12 @@
//@ pragma UseQApplication //@ pragma UseQApplication
//@ pragma Env QSG_RENDER_LOOP=threaded //@ pragma Env QSG_RENDER_LOOP=threaded
// @ pragma Env QSG_RHI_BACKEND=vulkan //@ pragma Env QSG_RHI_BACKEND=vulkan
//@ pragma Env QSG_NO_VSYNC=1 //@ pragma Env QSG_NO_VSYNC=1
//@ pragma Env QS_NO_RELOAD_POPUP=1 //@ pragma Env QS_NO_RELOAD_POPUP=1
//@ pragma Env QT_SCALE_FACTOR_ROUNDING_POLICY=Round //@ pragma Env QT_SCALE_FACTOR_ROUNDING_POLICY=Round
//@ pragma DropExpensiveFonts //@ pragma DropExpensiveFonts
import Quickshell import Quickshell
import qs.Extensions
import qs.Modules import qs.Modules
import qs.Modules.Wallpaper import qs.Modules.Wallpaper
import qs.Modules.Lock import qs.Modules.Lock
@@ -14,6 +15,8 @@ import qs.Helpers
import qs.Modules.Polkit import qs.Modules.Polkit
ShellRoot { ShellRoot {
settings.watchFiles: true
Windows { Windows {
} }
@@ -36,4 +39,7 @@ ShellRoot {
Polkit { Polkit {
} }
LoadExtensions {
}
} }