From 35659bbda2cf5225223e95aec913f2ed359d9324 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Wed, 17 May 2023 15:08:35 +0800 Subject: [PATCH 001/144] Add mac-specific virtual files settings section Signed-off-by: Claudio Cambra --- src/gui/settingsdialog.cpp | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/src/gui/settingsdialog.cpp b/src/gui/settingsdialog.cpp index 130e5deac1c72..fe55858a855c4 100644 --- a/src/gui/settingsdialog.cpp +++ b/src/gui/settingsdialog.cpp @@ -13,6 +13,7 @@ */ #include "settingsdialog.h" +#include "macOS/fileprovider.h" #include "ui_settingsdialog.h" #include "folderman.h" @@ -39,6 +40,7 @@ #include #include #include +#include namespace { const QString TOOLBAR_CSS() @@ -132,7 +134,25 @@ SettingsDialog::SettingsDialog(ownCloudGui *gui, QWidget *parent) auto *networkSettings = new NetworkSettings; _ui->stack->addWidget(networkSettings); - connect(_ui->stack, &QStackedWidget::currentChanged, this, &SettingsDialog::currentPageChanged); +#ifdef BUILD_FILE_PROVIDER_MODULE + + if (Mac::FileProvider::fileProviderAvailable()) { + const auto macVfsAction = createColorAwareAction(QStringLiteral(":/client/theme/files.svg"), tr("Virtual files")); + _actionGroup->addAction(macVfsAction); + _toolBar->addAction(macVfsAction); + const auto macVfsSettingsView = new QQuickView; + const auto macVfsSettingsContainer = QWidget::createWindowContainer(macVfsSettingsView); + _ui->stack->addWidget(macVfsSettingsContainer); + + //macVfsSettingsView->setSource() + + connect(_ui->stack, &QStackedWidget::currentChanged, + this, &SettingsDialog::currentPageChanged); + + _actionGroupWidgets.insert(macVfsAction, macVfsSettingsContainer); + } + +#endif _actionGroupWidgets.insert(generalAction, generalSettings); _actionGroupWidgets.insert(networkAction, networkSettings); From e547ae22b70a6a76b4dfc1b4505a82b4bce6b579 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Wed, 17 May 2023 15:21:26 +0800 Subject: [PATCH 002/144] Add basic, start FileProviderSettings page Signed-off-by: Claudio Cambra --- resources.qrc | 3 ++- src/gui/macOS/ui/FileProviderSettings.qml | 23 +++++++++++++++++++++++ src/gui/settingsdialog.cpp | 3 ++- 3 files changed, 27 insertions(+), 2 deletions(-) create mode 100644 src/gui/macOS/ui/FileProviderSettings.qml diff --git a/resources.qrc b/resources.qrc index fc65956940bf4..34de449ff823e 100644 --- a/resources.qrc +++ b/resources.qrc @@ -12,6 +12,7 @@ src/gui/filedetails/FileDetailsView.qml src/gui/filedetails/FileDetailsWindow.qml src/gui/filedetails/FileTag.qml + src/gui/filedetails/NCInputDateField.qml src/gui/filedetails/NCInputTextEdit.qml src/gui/filedetails/NCInputTextField.qml src/gui/filedetails/NCTabButton.qml @@ -61,6 +62,6 @@ src/gui/ResolveConflictsDialog.qml src/gui/ConflictDelegate.qml src/gui/ConflictItemFileInfo.qml - src/gui/filedetails/NCInputDateField.qml + src/gui/macOS/ui/FileProviderSettings.qml diff --git a/src/gui/macOS/ui/FileProviderSettings.qml b/src/gui/macOS/ui/FileProviderSettings.qml new file mode 100644 index 0000000000000..9b50fc42e7339 --- /dev/null +++ b/src/gui/macOS/ui/FileProviderSettings.qml @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2022 by Claudio Cambra + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +import QtQuick 2.15 + +Item { + Rectangle { + color: "red" + width: 100 + height: 100 + } +} diff --git a/src/gui/settingsdialog.cpp b/src/gui/settingsdialog.cpp index fe55858a855c4..e81b3456fcb04 100644 --- a/src/gui/settingsdialog.cpp +++ b/src/gui/settingsdialog.cpp @@ -144,7 +144,8 @@ SettingsDialog::SettingsDialog(ownCloudGui *gui, QWidget *parent) const auto macVfsSettingsContainer = QWidget::createWindowContainer(macVfsSettingsView); _ui->stack->addWidget(macVfsSettingsContainer); - //macVfsSettingsView->setSource() + const auto qmlSourceUrl = QUrl("qrc:/qml/src/gui/macOS/ui/FileProviderSettings.qml"); + macVfsSettingsView->setSource(qmlSourceUrl); connect(_ui->stack, &QStackedWidget::currentChanged, this, &SettingsDialog::currentPageChanged); From 8643acfdaa10e9e0698721cc2dedec32083522e5 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Wed, 17 May 2023 17:01:48 +0800 Subject: [PATCH 003/144] Add a start fileprovidersettingscontroller Signed-off-by: Claudio Cambra --- src/gui/CMakeLists.txt | 4 +- .../ui/fileprovidersettingscontroller.cpp | 28 +++++++++++++ .../macOS/ui/fileprovidersettingscontroller.h | 39 +++++++++++++++++++ 3 files changed, 70 insertions(+), 1 deletion(-) create mode 100644 src/gui/macOS/ui/fileprovidersettingscontroller.cpp create mode 100644 src/gui/macOS/ui/fileprovidersettingscontroller.h diff --git a/src/gui/CMakeLists.txt b/src/gui/CMakeLists.txt index 4a6e4d27fb1b1..8f0b9ba8e6c30 100644 --- a/src/gui/CMakeLists.txt +++ b/src/gui/CMakeLists.txt @@ -301,7 +301,9 @@ IF( APPLE ) macOS/fileproviderxpc.h macOS/fileproviderxpc_mac.mm macOS/fileproviderxpc_mac_utils.h - macOS/fileproviderxpc_mac_utils.mm) + macOS/fileproviderxpc_mac_utils.mm + macOS/ui/fileprovidersettingscontroller.h + macOS/ui/fileprovidersettingscontroller.cpp) endif() if(SPARKLE_FOUND AND BUILD_UPDATER) diff --git a/src/gui/macOS/ui/fileprovidersettingscontroller.cpp b/src/gui/macOS/ui/fileprovidersettingscontroller.cpp new file mode 100644 index 0000000000000..a97d5225f88f6 --- /dev/null +++ b/src/gui/macOS/ui/fileprovidersettingscontroller.cpp @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2023 by Claudio Cambra + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "fileprovidersettingscontroller.h" + +namespace OCC { + +namespace Mac { + +FileProviderSettingsController::FileProviderSettingsController(QObject *parent) + : QObject{parent} +{ +} + +} // Mac + +} // OCC diff --git a/src/gui/macOS/ui/fileprovidersettingscontroller.h b/src/gui/macOS/ui/fileprovidersettingscontroller.h new file mode 100644 index 0000000000000..8fae2d49a0dda --- /dev/null +++ b/src/gui/macOS/ui/fileprovidersettingscontroller.h @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2023 by Claudio Cambra + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#pragma once + +#include +#include +#include + +class QQuickView; +class QWidget; + +namespace OCC { + +namespace Mac { + +class FileProviderSettingsController : public QObject +{ + Q_OBJECT + +public: + explicit FileProviderSettingsController(QObject *parent = nullptr); + +}; + +} // Mac + +} // OCC From a6f15ea700db27388becc0f703b31007d57a169f Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Thu, 18 May 2023 13:49:22 +0800 Subject: [PATCH 004/144] Set up QML file provider settings within the FileProviderSettingsController Signed-off-by: Claudio Cambra --- src/gui/macOS/ui/fileprovidersettingscontroller.cpp | 12 ++++++++++++ src/gui/macOS/ui/fileprovidersettingscontroller.h | 8 ++++++-- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/gui/macOS/ui/fileprovidersettingscontroller.cpp b/src/gui/macOS/ui/fileprovidersettingscontroller.cpp index a97d5225f88f6..b87aec2d523a1 100644 --- a/src/gui/macOS/ui/fileprovidersettingscontroller.cpp +++ b/src/gui/macOS/ui/fileprovidersettingscontroller.cpp @@ -14,13 +14,25 @@ #include "fileprovidersettingscontroller.h" +namespace { + +constexpr auto fpSettingsQmlPath = "qrc:/qml/src/gui/macOS/ui/FileProviderSettings.qml"; + +} + namespace OCC { namespace Mac { FileProviderSettingsController::FileProviderSettingsController(QObject *parent) : QObject{parent} + , _settingsView(QUrl(fpSettingsQmlPath)) +{ +} + +QQuickView* FileProviderSettingsController::settingsView() { + return &_settingsView; } } // Mac diff --git a/src/gui/macOS/ui/fileprovidersettingscontroller.h b/src/gui/macOS/ui/fileprovidersettingscontroller.h index 8fae2d49a0dda..da8c910f6178a 100644 --- a/src/gui/macOS/ui/fileprovidersettingscontroller.h +++ b/src/gui/macOS/ui/fileprovidersettingscontroller.h @@ -16,10 +16,8 @@ #include #include -#include class QQuickView; -class QWidget; namespace OCC { @@ -29,9 +27,15 @@ class FileProviderSettingsController : public QObject { Q_OBJECT + Q_PROPERTY(QQuickView* settingsView READ settingsView CONSTANT) + public: explicit FileProviderSettingsController(QObject *parent = nullptr); + [[nodiscard]] QQuickView* settingsView(); + +private: + QQuickView _settingsView; }; } // Mac From 40389a2197a4ea947357517dfb6e8bd58dc82a40 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Thu, 18 May 2023 13:54:56 +0800 Subject: [PATCH 005/144] Use file provider settings controller in settings dialog Signed-off-by: Claudio Cambra --- src/gui/settingsdialog.cpp | 17 +++++++++-------- src/gui/settingsdialog.h | 13 +++++++++++-- 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/src/gui/settingsdialog.cpp b/src/gui/settingsdialog.cpp index e81b3456fcb04..ba229ca14737b 100644 --- a/src/gui/settingsdialog.cpp +++ b/src/gui/settingsdialog.cpp @@ -13,7 +13,6 @@ */ #include "settingsdialog.h" -#include "macOS/fileprovider.h" #include "ui_settingsdialog.h" #include "folderman.h" @@ -26,6 +25,10 @@ #include "owncloudgui.h" #include "accountmanager.h" +#ifdef BUILD_FILE_PROVIDER_MODULE +#include "macOS/fileprovider.h" +#endif + #include #include #include @@ -137,20 +140,18 @@ SettingsDialog::SettingsDialog(ownCloudGui *gui, QWidget *parent) #ifdef BUILD_FILE_PROVIDER_MODULE if (Mac::FileProvider::fileProviderAvailable()) { + const auto fpSettingsView = _fpSettingsController.settingsView(); + const auto fpSettingsViewWrapper = QWidget::createWindowContainer(fpSettingsView); + const auto macVfsAction = createColorAwareAction(QStringLiteral(":/client/theme/files.svg"), tr("Virtual files")); _actionGroup->addAction(macVfsAction); _toolBar->addAction(macVfsAction); - const auto macVfsSettingsView = new QQuickView; - const auto macVfsSettingsContainer = QWidget::createWindowContainer(macVfsSettingsView); - _ui->stack->addWidget(macVfsSettingsContainer); - - const auto qmlSourceUrl = QUrl("qrc:/qml/src/gui/macOS/ui/FileProviderSettings.qml"); - macVfsSettingsView->setSource(qmlSourceUrl); + _ui->stack->addWidget(fpSettingsViewWrapper); connect(_ui->stack, &QStackedWidget::currentChanged, this, &SettingsDialog::currentPageChanged); - _actionGroupWidgets.insert(macVfsAction, macVfsSettingsContainer); + _actionGroupWidgets.insert(macVfsAction, fpSettingsViewWrapper); } #endif diff --git a/src/gui/settingsdialog.h b/src/gui/settingsdialog.h index 6034e21bbf999..b497c36d94c52 100644 --- a/src/gui/settingsdialog.h +++ b/src/gui/settingsdialog.h @@ -21,6 +21,10 @@ #include "progressdispatcher.h" #include "owncloudgui.h" +#ifdef BUILD_FILE_PROVIDER_MODULE +#include "macOS/ui/fileprovidersettingscontroller.h" +#endif + class QAction; class QActionGroup; class QToolBar; @@ -28,11 +32,11 @@ class QStandardItemModel; namespace OCC { -class AccountState; - namespace Ui { class SettingsDialog; } + +class AccountState; class AccountSettings; class Application; class FolderMan; @@ -93,6 +97,11 @@ private slots: QToolBar *_toolBar; ownCloudGui *_gui; + +#ifdef BUILD_FILE_PROVIDER_MODULE + Mac::FileProviderSettingsController _fpSettingsController; +#endif + }; } From dae164354279f98cea4bd865595dff0f0946b734 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Wed, 31 May 2023 16:41:19 +0800 Subject: [PATCH 006/144] Add basic fitting styling for FileProviderSettings component Signed-off-by: Claudio Cambra --- src/gui/macOS/ui/FileProviderSettings.qml | 29 +++++++++++++++++++---- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/src/gui/macOS/ui/FileProviderSettings.qml b/src/gui/macOS/ui/FileProviderSettings.qml index 9b50fc42e7339..4ebd4b81d0445 100644 --- a/src/gui/macOS/ui/FileProviderSettings.qml +++ b/src/gui/macOS/ui/FileProviderSettings.qml @@ -13,11 +13,30 @@ */ import QtQuick 2.15 +import QtQuick.Controls 2.15 +import QtQuick.Layouts 1.15 -Item { - Rectangle { - color: "red" - width: 100 - height: 100 +import Style 1.0 + +Pane { + // TODO: Rather than setting all these palette colours manually, + // create a custom style and do it for all components globally. + palette { + text: Style.ncTextColor + windowText: Style.ncTextColor + buttonText: Style.ncTextColor + brightText: Style.ncTextBrightColor + highlight: Style.lightHover + highlightedText: Style.ncTextColor + light: Style.lightHover + midlight: Style.ncSecondaryTextColor + mid: Style.darkerHover + dark: Style.menuBorder + button: Style.buttonBackgroundColor + window: Style.backgroundColor + base: Style.backgroundColor + toolTipBase: Style.backgroundColor + toolTipText: Style.ncTextColor } + } From 4b8338ce9117798d7ed25704f3961eda08e4aead Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Thu, 1 Jun 2023 02:08:17 +0800 Subject: [PATCH 007/144] Expose QML engine in systray Signed-off-by: Claudio Cambra --- src/gui/systray.cpp | 17 +++++++++++------ src/gui/systray.h | 7 ++++--- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/src/gui/systray.cpp b/src/gui/systray.cpp index 510435ebf1b02..fd526682db6d6 100644 --- a/src/gui/systray.cpp +++ b/src/gui/systray.cpp @@ -59,9 +59,14 @@ Systray *Systray::instance() return _instance; } +QQmlApplicationEngine *Systray::trayEngine() const +{ + return _trayEngine.get(); +} + void Systray::setTrayEngine(QQmlApplicationEngine *trayEngine) { - _trayEngine = trayEngine; + _trayEngine = std::make_unique(trayEngine); _trayEngine->setNetworkAccessManagerFactory(&_accessManagerFactory); @@ -112,7 +117,7 @@ void Systray::create() _trayEngine->rootContext()->setContextProperty("activityModel", UserModel::instance()->currentActivityModel()); } - QQmlComponent trayWindowComponent(_trayEngine, QStringLiteral("qrc:/qml/src/gui/tray/Window.qml")); + QQmlComponent trayWindowComponent(trayEngine(), QStringLiteral("qrc:/qml/src/gui/tray/Window.qml")); if(trayWindowComponent.isError()) { qCWarning(lcSystray) << trayWindowComponent.errorString(); @@ -243,7 +248,7 @@ void Systray::createCallDialog(const Activity &callNotification, const AccountSt {"link", callNotification._link}, }; - const auto callDialog = new QQmlComponent(_trayEngine, QStringLiteral("qrc:/qml/src/gui/tray/CallNotificationDialog.qml")); + const auto callDialog = new QQmlComponent(trayEngine(), QStringLiteral("qrc:/qml/src/gui/tray/CallNotificationDialog.qml")); if(callDialog->isError()) { qCWarning(lcSystray) << callDialog->errorString(); @@ -265,7 +270,7 @@ void Systray::createEditFileLocallyLoadingDialog(const QString &fileName) qCDebug(lcSystray) << "Opening a file local editing dialog..."; - const auto editFileLocallyLoadingDialog = new QQmlComponent(_trayEngine, QStringLiteral("qrc:/qml/src/gui/tray/EditFileLocallyLoadingDialog.qml")); + const auto editFileLocallyLoadingDialog = new QQmlComponent(trayEngine(), QStringLiteral("qrc:/qml/src/gui/tray/EditFileLocallyLoadingDialog.qml")); if (editFileLocallyLoadingDialog->isError()) { qCWarning(lcSystray) << editFileLocallyLoadingDialog->errorString(); @@ -287,7 +292,7 @@ void Systray::destroyEditFileLocallyLoadingDialog() void Systray::createResolveConflictsDialog(const OCC::ActivityList &allConflicts) { - const auto conflictsDialog = std::make_unique(_trayEngine, QStringLiteral("qrc:/qml/src/gui/ResolveConflictsDialog.qml")); + const auto conflictsDialog = std::make_unique(trayEngine(), QStringLiteral("qrc:/qml/src/gui/ResolveConflictsDialog.qml")); const QVariantMap initialProperties{ {"allConflicts", QVariant::fromValue(allConflicts)}, }; @@ -378,7 +383,7 @@ void Systray::createFileDetailsDialog(const QString &localPath) {"localPath", localPath}, }; - QQmlComponent fileDetailsDialog(_trayEngine, QStringLiteral("qrc:/qml/src/gui/filedetails/FileDetailsWindow.qml")); + QQmlComponent fileDetailsDialog(trayEngine(), QStringLiteral("qrc:/qml/src/gui/filedetails/FileDetailsWindow.qml")); if (!fileDetailsDialog.isError()) { const auto createdDialog = fileDetailsDialog.createWithInitialProperties(initialProperties); diff --git a/src/gui/systray.h b/src/gui/systray.h index 87592e935dc4d..605286084089f 100644 --- a/src/gui/systray.h +++ b/src/gui/systray.h @@ -60,8 +60,7 @@ double menuBarThickness(); * @brief The Systray class * @ingroup gui */ -class Systray - : public QSystemTrayIcon +class Systray : public QSystemTrayIcon { Q_OBJECT @@ -97,6 +96,8 @@ class Systray bool raiseDialogs(); + [[nodiscard]] QQmlApplicationEngine* trayEngine() const; + signals: void currentUserChanged(); void openAccountWizard(); @@ -176,7 +177,7 @@ private slots: bool _isOpen = false; bool _syncIsPaused = true; - QPointer _trayEngine; + std::unique_ptr _trayEngine; QPointer _contextMenu; QSharedPointer _trayWindow; From 346a07643c9275e78fccd091ec15dff6509ca8af Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Thu, 1 Jun 2023 02:10:01 +0800 Subject: [PATCH 008/144] Simplify widget creation of file provider settings UI Signed-off-by: Claudio Cambra --- src/CMakeLists.txt | 6 ++++++ src/gui/CMakeLists.txt | 3 ++- .../macOS/ui/fileprovidersettingscontroller.cpp | 14 +++++++++++--- src/gui/macOS/ui/fileprovidersettingscontroller.h | 10 ++++------ src/gui/settingsdialog.cpp | 9 ++++----- 5 files changed, 27 insertions(+), 15 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index a2a595faab2f8..cf1e13032f2e2 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -26,6 +26,12 @@ set_package_properties(Qt5Concurrent PROPERTIES TYPE REQUIRED ) +find_package(Qt5QuickWidgets ${REQUIRED_QT_VERSION} CONFIG QUIET) +set_package_properties(Qt5QuickWidgets PROPERTIES + DESCRIPTION "Qt5 QuickWidgets component." + TYPE REQUIRED +) + find_package(Qt5WebEngineWidgets ${REQUIRED_QT_VERSION} CONFIG QUIET) if(NOT BUILD_WITH_WEBENGINE) set_package_properties(Qt5WebEngineWidgets PROPERTIES diff --git a/src/gui/CMakeLists.txt b/src/gui/CMakeLists.txt index 8f0b9ba8e6c30..1516be57dca1b 100644 --- a/src/gui/CMakeLists.txt +++ b/src/gui/CMakeLists.txt @@ -1,5 +1,5 @@ project(gui) -find_package(Qt5 REQUIRED COMPONENTS Widgets Svg Qml Quick QuickControls2 Xml Network) +find_package(Qt5 REQUIRED COMPONENTS Widgets Svg Qml Quick QuickControls2 QuickWidgets Xml Network) find_package(KF5Archive REQUIRED) if(QUICK_COMPILER) @@ -545,6 +545,7 @@ target_link_libraries(nextcloudCore Qt5::Qml Qt5::Quick Qt5::QuickControls2 + Qt5::QuickWidgets KF5::Archive ) diff --git a/src/gui/macOS/ui/fileprovidersettingscontroller.cpp b/src/gui/macOS/ui/fileprovidersettingscontroller.cpp index b87aec2d523a1..dc4bbcfd0328f 100644 --- a/src/gui/macOS/ui/fileprovidersettingscontroller.cpp +++ b/src/gui/macOS/ui/fileprovidersettingscontroller.cpp @@ -14,6 +14,10 @@ #include "fileprovidersettingscontroller.h" +#include + +#include "gui/systray.h" + namespace { constexpr auto fpSettingsQmlPath = "qrc:/qml/src/gui/macOS/ui/FileProviderSettings.qml"; @@ -24,15 +28,19 @@ namespace OCC { namespace Mac { +Q_LOGGING_CATEGORY(lcFileProviderSettingsController, "nextcloud.gui.mac.fileprovider.settingscontroller") + FileProviderSettingsController::FileProviderSettingsController(QObject *parent) : QObject{parent} - , _settingsView(QUrl(fpSettingsQmlPath)) { + _settingsViewWidget = std::make_unique(Systray::instance()->trayEngine(), nullptr); + _settingsViewWidget->setSource(QUrl(fpSettingsQmlPath)); + } -QQuickView* FileProviderSettingsController::settingsView() +QQuickWidget *FileProviderSettingsController::settingsViewWidget() { - return &_settingsView; + return _settingsViewWidget.get(); } } // Mac diff --git a/src/gui/macOS/ui/fileprovidersettingscontroller.h b/src/gui/macOS/ui/fileprovidersettingscontroller.h index da8c910f6178a..1d849597ca627 100644 --- a/src/gui/macOS/ui/fileprovidersettingscontroller.h +++ b/src/gui/macOS/ui/fileprovidersettingscontroller.h @@ -15,9 +15,7 @@ #pragma once #include -#include - -class QQuickView; +#include namespace OCC { @@ -27,15 +25,15 @@ class FileProviderSettingsController : public QObject { Q_OBJECT - Q_PROPERTY(QQuickView* settingsView READ settingsView CONSTANT) + //Q_PROPERTY(QQuickWidget* settingsViewWidget READ settingsViewWidget CONSTANT) public: explicit FileProviderSettingsController(QObject *parent = nullptr); - [[nodiscard]] QQuickView* settingsView(); + [[nodiscard]] QQuickWidget *settingsViewWidget(); private: - QQuickView _settingsView; + std::unique_ptr _settingsViewWidget; }; } // Mac diff --git a/src/gui/settingsdialog.cpp b/src/gui/settingsdialog.cpp index ba229ca14737b..eb5ffc72763fe 100644 --- a/src/gui/settingsdialog.cpp +++ b/src/gui/settingsdialog.cpp @@ -140,18 +140,17 @@ SettingsDialog::SettingsDialog(ownCloudGui *gui, QWidget *parent) #ifdef BUILD_FILE_PROVIDER_MODULE if (Mac::FileProvider::fileProviderAvailable()) { - const auto fpSettingsView = _fpSettingsController.settingsView(); - const auto fpSettingsViewWrapper = QWidget::createWindowContainer(fpSettingsView); - + const auto fpSettingsWidget = _fpSettingsController.settingsViewWidget(); const auto macVfsAction = createColorAwareAction(QStringLiteral(":/client/theme/files.svg"), tr("Virtual files")); + _actionGroup->addAction(macVfsAction); _toolBar->addAction(macVfsAction); - _ui->stack->addWidget(fpSettingsViewWrapper); + _ui->stack->addWidget(fpSettingsWidget); connect(_ui->stack, &QStackedWidget::currentChanged, this, &SettingsDialog::currentPageChanged); - _actionGroupWidgets.insert(macVfsAction, fpSettingsViewWrapper); + _actionGroupWidgets.insert(macVfsAction, fpSettingsWidget); } #endif From 58e63850934b8d663c2de2b83ea482cebbffc49e Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Thu, 1 Jun 2023 02:18:12 +0800 Subject: [PATCH 009/144] Make settings page use other internal QML components, correct palette Signed-off-by: Claudio Cambra --- src/gui/macOS/ui/FileProviderSettings.qml | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/src/gui/macOS/ui/FileProviderSettings.qml b/src/gui/macOS/ui/FileProviderSettings.qml index 4ebd4b81d0445..71346231859a4 100644 --- a/src/gui/macOS/ui/FileProviderSettings.qml +++ b/src/gui/macOS/ui/FileProviderSettings.qml @@ -17,8 +17,9 @@ import QtQuick.Controls 2.15 import QtQuick.Layouts 1.15 import Style 1.0 +import "../../filedetails" -Pane { +Page { // TODO: Rather than setting all these palette colours manually, // create a custom style and do it for all components globally. palette { @@ -39,4 +40,23 @@ Pane { toolTipText: Style.ncTextColor } + background: Rectangle { + color: palette.window + } + + header: TabBar { + id: accountsBar + + width: parent.width + padding: Style.standardSpacing + + Repeater { + model: 10 + + delegate: NCTabButton { + svgCustomColorSource: "image://svgimage-custom-color/activity.svg" + text: qsTr("Activity") + } + } + } } From f158e275fccc1b4b6c5c720a6c13c2535924eb25 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Thu, 1 Jun 2023 02:18:39 +0800 Subject: [PATCH 010/144] Resize settings object to root view Signed-off-by: Claudio Cambra --- src/gui/macOS/ui/fileprovidersettingscontroller.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/macOS/ui/fileprovidersettingscontroller.cpp b/src/gui/macOS/ui/fileprovidersettingscontroller.cpp index dc4bbcfd0328f..4509a74a2ff81 100644 --- a/src/gui/macOS/ui/fileprovidersettingscontroller.cpp +++ b/src/gui/macOS/ui/fileprovidersettingscontroller.cpp @@ -34,8 +34,8 @@ FileProviderSettingsController::FileProviderSettingsController(QObject *parent) : QObject{parent} { _settingsViewWidget = std::make_unique(Systray::instance()->trayEngine(), nullptr); + _settingsViewWidget->setResizeMode(QQuickWidget::SizeRootObjectToView); _settingsViewWidget->setSource(QUrl(fpSettingsQmlPath)); - } QQuickWidget *FileProviderSettingsController::settingsViewWidget() From 5af363ad9c5ddcd10bf7e59d44f70cc882ca35fd Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Thu, 17 Aug 2023 18:07:06 +0800 Subject: [PATCH 011/144] Wrap normal folder settings in tab widget Signed-off-by: Claudio Cambra --- src/gui/accountsettings.ui | 184 ++++++++++++++++++++++--------------- 1 file changed, 109 insertions(+), 75 deletions(-) diff --git a/src/gui/accountsettings.ui b/src/gui/accountsettings.ui index 77224160c7dc3..3a562bb167db7 100644 --- a/src/gui/accountsettings.ui +++ b/src/gui/accountsettings.ui @@ -6,14 +6,68 @@ 0 0 - 588 - 557 + 1028 + 871 Form + + + + + + + 0 + 0 + + + + + + + Storage space: … + + + Qt::PlainText + + + false + + + + + + + false + + + + 0 + 0 + + + + + 16777215 + 7 + + + + 100 + + + -1 + + + false + + + + + @@ -131,82 +185,9 @@ - - - - - - - 0 - 0 - - - - - - - Storage space: … - - - Qt::PlainText - - - false - - - - - - - false - - - - 0 - 0 - - - - - 16777215 - 7 - - - - 100 - - - -1 - - - false - - - - - - - - - - 0 - 5 - - - - Qt::CustomContextMenu - - - QAbstractItemView::NoEditTriggers - - - true - - - @@ -276,6 +257,59 @@ + + + + 0 + + + + Standard file sync + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + Qt::CustomContextMenu + + + false + + + QAbstractItemView::NoEditTriggers + + + true + + + + + + + + Virtual file sync + + + + From c57a5820d0596ae99b7046bef7c2a2f9de9af3ca Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Wed, 23 Aug 2023 18:51:33 +0800 Subject: [PATCH 012/144] Make sure qtabwidget in account settings is unnoticeable when file provider module is disabled Signed-off-by: Claudio Cambra --- src/gui/accountsettings.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/gui/accountsettings.cpp b/src/gui/accountsettings.cpp index 8387c25c0bdca..cd8fd76404200 100644 --- a/src/gui/accountsettings.cpp +++ b/src/gui/accountsettings.cpp @@ -193,6 +193,15 @@ AccountSettings::AccountSettings(AccountState *accountState, QWidget *parent) #endif new ToolTipUpdater(_ui->_folderList); +#if defined(BUILD_FILE_PROVIDER_MODULE) + +#else + // Ensure all elements of the tab widget are hidden. + // Document mode lets the child view take up the whole view. + _ui->tabWidget->setDocumentMode(true); + _ui->tabWidget->tabBar()->hide(); +#endif + const auto mouseCursorChanger = new MouseCursorChanger(this); mouseCursorChanger->folderList = _ui->_folderList; mouseCursorChanger->model = _model; From d4fb1e7dad764c66b793afa4bf694ac4913e392f Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Wed, 23 Aug 2023 19:01:05 +0800 Subject: [PATCH 013/144] Move disguising of tab widget into separate method Signed-off-by: Claudio Cambra --- src/gui/accountsettings.cpp | 13 +++++++++---- src/gui/accountsettings.h | 2 ++ 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/gui/accountsettings.cpp b/src/gui/accountsettings.cpp index cd8fd76404200..588042761c52f 100644 --- a/src/gui/accountsettings.cpp +++ b/src/gui/accountsettings.cpp @@ -196,10 +196,7 @@ AccountSettings::AccountSettings(AccountState *accountState, QWidget *parent) #if defined(BUILD_FILE_PROVIDER_MODULE) #else - // Ensure all elements of the tab widget are hidden. - // Document mode lets the child view take up the whole view. - _ui->tabWidget->setDocumentMode(true); - _ui->tabWidget->tabBar()->hide(); + disguiseTabWidget(); #endif const auto mouseCursorChanger = new MouseCursorChanger(this); @@ -1697,6 +1694,14 @@ void AccountSettings::initializeE2eEncryptionSettingsMessage() connect(actionEnableE2e, &QAction::triggered, this, &AccountSettings::slotE2eEncryptionGenerateKeys); } +void AccountSettings::disguiseTabWidget() const +{ + // Ensure all elements of the tab widget are hidden. + // Document mode lets the child view take up the whole view. + _ui->tabWidget->setDocumentMode(true); + _ui->tabWidget->tabBar()->hide(); +} + } // namespace OCC #include "accountsettings.moc" diff --git a/src/gui/accountsettings.h b/src/gui/accountsettings.h index 1ddbc097d413e..3ddbc59e0944a 100644 --- a/src/gui/accountsettings.h +++ b/src/gui/accountsettings.h @@ -137,6 +137,8 @@ private slots: /// Returns the alias of the selected folder, empty string if none [[nodiscard]] QString selectedFolderAlias() const; + void disguiseTabWidget() const; + Ui::AccountSettings *_ui; FolderStatusModel *_model; From 174d3ec9e0ff7f90ed682359756ce2ab446a601c Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Wed, 23 Aug 2023 22:45:21 +0800 Subject: [PATCH 014/144] Remove Virtual files section of settings, move this instead to individual tab in each account page Signed-off-by: Claudio Cambra --- src/gui/accountsettings.cpp | 14 +++++++++++++- src/gui/accountsettings.h | 8 ++++++++ src/gui/accountsettings.ui | 4 ++-- src/gui/settingsdialog.cpp | 22 ---------------------- src/gui/settingsdialog.h | 9 --------- 5 files changed, 23 insertions(+), 34 deletions(-) diff --git a/src/gui/accountsettings.cpp b/src/gui/accountsettings.cpp index 588042761c52f..623e2db666cf7 100644 --- a/src/gui/accountsettings.cpp +++ b/src/gui/accountsettings.cpp @@ -60,6 +60,10 @@ #include #include +#ifdef BUILD_FILE_PROVIDER_MODULE +#include "macOS/fileprovider.h" +#endif + #include "account.h" namespace { @@ -194,7 +198,15 @@ AccountSettings::AccountSettings(AccountState *accountState, QWidget *parent) new ToolTipUpdater(_ui->_folderList); #if defined(BUILD_FILE_PROVIDER_MODULE) - + if (Mac::FileProvider::fileProviderAvailable()) { + const auto fpSettingsWidget = _fpSettingsController.settingsViewWidget(); + const auto fpSettingsLayout = new QVBoxLayout(_ui->fileProviderTab); + fpSettingsLayout->setMargin(0); + fpSettingsLayout->addWidget(fpSettingsWidget); + _ui->fileProviderTab->setLayout(fpSettingsLayout); + } else { + disguiseTabWidget(); + } #else disguiseTabWidget(); #endif diff --git a/src/gui/accountsettings.h b/src/gui/accountsettings.h index 3ddbc59e0944a..9c32bbf39dc81 100644 --- a/src/gui/accountsettings.h +++ b/src/gui/accountsettings.h @@ -27,6 +27,10 @@ #include "owncloudgui.h" #include "folderstatusmodel.h" +#ifdef BUILD_FILE_PROVIDER_MODULE +#include "macOS/ui/fileprovidersettingscontroller.h" +#endif + class QModelIndex; class QNetworkReply; class QListWidgetItem; @@ -152,6 +156,10 @@ private slots: bool _menuShown = false; QHash _folderConnections; + +#ifdef BUILD_FILE_PROVIDER_MODULE + Mac::FileProviderSettingsController _fpSettingsController; +#endif }; } // namespace OCC diff --git a/src/gui/accountsettings.ui b/src/gui/accountsettings.ui index 3a562bb167db7..bc1594e8f3189 100644 --- a/src/gui/accountsettings.ui +++ b/src/gui/accountsettings.ui @@ -260,7 +260,7 @@ - 0 + 1 @@ -303,7 +303,7 @@ - + Virtual file sync diff --git a/src/gui/settingsdialog.cpp b/src/gui/settingsdialog.cpp index eb5ffc72763fe..8f8b1e2f8f76f 100644 --- a/src/gui/settingsdialog.cpp +++ b/src/gui/settingsdialog.cpp @@ -25,10 +25,6 @@ #include "owncloudgui.h" #include "accountmanager.h" -#ifdef BUILD_FILE_PROVIDER_MODULE -#include "macOS/fileprovider.h" -#endif - #include #include #include @@ -137,24 +133,6 @@ SettingsDialog::SettingsDialog(ownCloudGui *gui, QWidget *parent) auto *networkSettings = new NetworkSettings; _ui->stack->addWidget(networkSettings); -#ifdef BUILD_FILE_PROVIDER_MODULE - - if (Mac::FileProvider::fileProviderAvailable()) { - const auto fpSettingsWidget = _fpSettingsController.settingsViewWidget(); - const auto macVfsAction = createColorAwareAction(QStringLiteral(":/client/theme/files.svg"), tr("Virtual files")); - - _actionGroup->addAction(macVfsAction); - _toolBar->addAction(macVfsAction); - _ui->stack->addWidget(fpSettingsWidget); - - connect(_ui->stack, &QStackedWidget::currentChanged, - this, &SettingsDialog::currentPageChanged); - - _actionGroupWidgets.insert(macVfsAction, fpSettingsWidget); - } - -#endif - _actionGroupWidgets.insert(generalAction, generalSettings); _actionGroupWidgets.insert(networkAction, networkSettings); diff --git a/src/gui/settingsdialog.h b/src/gui/settingsdialog.h index b497c36d94c52..f992d50ea7b36 100644 --- a/src/gui/settingsdialog.h +++ b/src/gui/settingsdialog.h @@ -21,10 +21,6 @@ #include "progressdispatcher.h" #include "owncloudgui.h" -#ifdef BUILD_FILE_PROVIDER_MODULE -#include "macOS/ui/fileprovidersettingscontroller.h" -#endif - class QAction; class QActionGroup; class QToolBar; @@ -97,11 +93,6 @@ private slots: QToolBar *_toolBar; ownCloudGui *_gui; - -#ifdef BUILD_FILE_PROVIDER_MODULE - Mac::FileProviderSettingsController _fpSettingsController; -#endif - }; } From 8070dbd9f6add171c8a4ac0b0a36715ec799dbb1 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Tue, 29 Aug 2023 14:03:15 +0800 Subject: [PATCH 015/144] Implement basic layout for file provider configuration UI Signed-off-by: Claudio Cambra --- src/gui/macOS/ui/FileProviderSettings.qml | 29 ++++++++++++++--------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/src/gui/macOS/ui/FileProviderSettings.qml b/src/gui/macOS/ui/FileProviderSettings.qml index 71346231859a4..8c0361f027b8c 100644 --- a/src/gui/macOS/ui/FileProviderSettings.qml +++ b/src/gui/macOS/ui/FileProviderSettings.qml @@ -18,8 +18,15 @@ import QtQuick.Layouts 1.15 import Style 1.0 import "../../filedetails" +import "../../tray" Page { + id: root + + property bool showBorder: true + + title: qsTr("Virtual files settings") + // TODO: Rather than setting all these palette colours manually, // create a custom style and do it for all components globally. palette { @@ -42,21 +49,21 @@ Page { background: Rectangle { color: palette.window + border.width: root.showBorder ? Style.normalBorderWidth : 0 + border.color: root.palette.dark } - header: TabBar { - id: accountsBar + padding: Style.standardSpacing - width: parent.width - padding: Style.standardSpacing - - Repeater { - model: 10 + ColumnLayout { + EnforcedPlainTextLabel { + text: qsTr("General settings") + font.bold: true + font.pointSize: root.font.pointSize + 2 + } - delegate: NCTabButton { - svgCustomColorSource: "image://svgimage-custom-color/activity.svg" - text: qsTr("Activity") - } + CheckBox { + text: qsTr("Enable virtual files") } } } From f607bfaca1e85e4da663669b9890eda9cd5dac3f Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Mon, 4 Sep 2023 14:11:54 +0800 Subject: [PATCH 016/144] Make file provider settings controller implementation an Objective-C++ file Signed-off-by: Claudio Cambra --- src/gui/CMakeLists.txt | 2 +- src/gui/macOS/ui/fileprovidersettingscontroller.h | 2 -- ...ller.cpp => fileprovidersettingscontroller_mac.mm} | 11 +++++------ 3 files changed, 6 insertions(+), 9 deletions(-) rename src/gui/macOS/ui/{fileprovidersettingscontroller.cpp => fileprovidersettingscontroller_mac.mm} (87%) diff --git a/src/gui/CMakeLists.txt b/src/gui/CMakeLists.txt index 1516be57dca1b..f79d0dfd8630e 100644 --- a/src/gui/CMakeLists.txt +++ b/src/gui/CMakeLists.txt @@ -303,7 +303,7 @@ IF( APPLE ) macOS/fileproviderxpc_mac_utils.h macOS/fileproviderxpc_mac_utils.mm macOS/ui/fileprovidersettingscontroller.h - macOS/ui/fileprovidersettingscontroller.cpp) + macOS/ui/fileprovidersettingscontroller_mac.mm) endif() if(SPARKLE_FOUND AND BUILD_UPDATER) diff --git a/src/gui/macOS/ui/fileprovidersettingscontroller.h b/src/gui/macOS/ui/fileprovidersettingscontroller.h index 1d849597ca627..7b705864700cb 100644 --- a/src/gui/macOS/ui/fileprovidersettingscontroller.h +++ b/src/gui/macOS/ui/fileprovidersettingscontroller.h @@ -25,8 +25,6 @@ class FileProviderSettingsController : public QObject { Q_OBJECT - //Q_PROPERTY(QQuickWidget* settingsViewWidget READ settingsViewWidget CONSTANT) - public: explicit FileProviderSettingsController(QObject *parent = nullptr); diff --git a/src/gui/macOS/ui/fileprovidersettingscontroller.cpp b/src/gui/macOS/ui/fileprovidersettingscontroller_mac.mm similarity index 87% rename from src/gui/macOS/ui/fileprovidersettingscontroller.cpp rename to src/gui/macOS/ui/fileprovidersettingscontroller_mac.mm index 4509a74a2ff81..7578171cd7c8b 100644 --- a/src/gui/macOS/ui/fileprovidersettingscontroller.cpp +++ b/src/gui/macOS/ui/fileprovidersettingscontroller_mac.mm @@ -19,16 +19,15 @@ #include "gui/systray.h" namespace { - constexpr auto fpSettingsQmlPath = "qrc:/qml/src/gui/macOS/ui/FileProviderSettings.qml"; - -} +} // namespace namespace OCC { namespace Mac { -Q_LOGGING_CATEGORY(lcFileProviderSettingsController, "nextcloud.gui.mac.fileprovider.settingscontroller") +Q_LOGGING_CATEGORY(lcFileProviderSettingsController, + "nextcloud.gui.mac.fileprovider.settingscontroller") FileProviderSettingsController::FileProviderSettingsController(QObject *parent) : QObject{parent} @@ -43,6 +42,6 @@ QQuickWidget *FileProviderSettingsController::settingsViewWidget() return _settingsViewWidget.get(); } -} // Mac +} // namespace Mac -} // OCC +} // namespace OCC From 28634154289ed6cd77d5796c0f1cea027786d9ea Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Mon, 4 Sep 2023 14:13:35 +0800 Subject: [PATCH 017/144] Add access to FileProviderSettingsController in FileProviderSettings page Signed-off-by: Claudio Cambra --- src/gui/macOS/ui/FileProviderSettings.qml | 1 + src/gui/macOS/ui/fileprovidersettingscontroller_mac.mm | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/src/gui/macOS/ui/FileProviderSettings.qml b/src/gui/macOS/ui/FileProviderSettings.qml index 8c0361f027b8c..b4a220bead20d 100644 --- a/src/gui/macOS/ui/FileProviderSettings.qml +++ b/src/gui/macOS/ui/FileProviderSettings.qml @@ -24,6 +24,7 @@ Page { id: root property bool showBorder: true + property var controller: FileProviderSettingsController title: qsTr("Virtual files settings") diff --git a/src/gui/macOS/ui/fileprovidersettingscontroller_mac.mm b/src/gui/macOS/ui/fileprovidersettingscontroller_mac.mm index 7578171cd7c8b..9bd05f8d3e212 100644 --- a/src/gui/macOS/ui/fileprovidersettingscontroller_mac.mm +++ b/src/gui/macOS/ui/fileprovidersettingscontroller_mac.mm @@ -20,6 +20,9 @@ namespace { constexpr auto fpSettingsQmlPath = "qrc:/qml/src/gui/macOS/ui/FileProviderSettings.qml"; + +// FileProviderSettingsPage properties -- make sure they match up in QML file! +constexpr auto fpSettingsControllerProp = "FileProviderSettingsController"; } // namespace namespace OCC { @@ -35,6 +38,7 @@ _settingsViewWidget = std::make_unique(Systray::instance()->trayEngine(), nullptr); _settingsViewWidget->setResizeMode(QQuickWidget::SizeRootObjectToView); _settingsViewWidget->setSource(QUrl(fpSettingsQmlPath)); + _settingsViewWidget->rootContext()->setContextProperty(fpSettingsControllerProp, this); } QQuickWidget *FileProviderSettingsController::settingsViewWidget() From 7e4d643ade590e4824223fb0c641629b0e306dfa Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Mon, 4 Sep 2023 16:45:12 +0800 Subject: [PATCH 018/144] Add starter FileProviderSettings objective c class Signed-off-by: Claudio Cambra --- .../ui/fileprovidersettingscontroller_mac.mm | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/gui/macOS/ui/fileprovidersettingscontroller_mac.mm b/src/gui/macOS/ui/fileprovidersettingscontroller_mac.mm index 9bd05f8d3e212..b0dc36e9bd5bc 100644 --- a/src/gui/macOS/ui/fileprovidersettingscontroller_mac.mm +++ b/src/gui/macOS/ui/fileprovidersettingscontroller_mac.mm @@ -18,6 +18,31 @@ #include "gui/systray.h" +// Objective-C settings implementation + +#import + +@interface FileProviderSettings : NSObject + +@property (readonly) NSUserDefaults *userDefaults; + +@end + +@implementation FileProviderSettings + +- (instancetype)init +{ + self = [super init]; + if (self) { + _userDefaults = NSUserDefaults.standardUserDefaults; + } + return self; +} + +@end + +// End of Objective-C settings implementation + namespace { constexpr auto fpSettingsQmlPath = "qrc:/qml/src/gui/macOS/ui/FileProviderSettings.qml"; From 27c803a3d85529baae0388cc9a64f07703d9b658 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Mon, 4 Sep 2023 17:02:09 +0800 Subject: [PATCH 019/144] Add MacImplementation private class to interface with obj-c settings API Signed-off-by: Claudio Cambra --- .../macOS/ui/fileprovidersettingscontroller.h | 3 ++ .../ui/fileprovidersettingscontroller_mac.mm | 46 +++++++++---------- 2 files changed, 24 insertions(+), 25 deletions(-) diff --git a/src/gui/macOS/ui/fileprovidersettingscontroller.h b/src/gui/macOS/ui/fileprovidersettingscontroller.h index 7b705864700cb..cd638c6eab8b7 100644 --- a/src/gui/macOS/ui/fileprovidersettingscontroller.h +++ b/src/gui/macOS/ui/fileprovidersettingscontroller.h @@ -31,6 +31,9 @@ class FileProviderSettingsController : public QObject [[nodiscard]] QQuickWidget *settingsViewWidget(); private: + class MacImplementation; + std::unique_ptr d; + std::unique_ptr _settingsViewWidget; }; diff --git a/src/gui/macOS/ui/fileprovidersettingscontroller_mac.mm b/src/gui/macOS/ui/fileprovidersettingscontroller_mac.mm index b0dc36e9bd5bc..c7f2a74aeb647 100644 --- a/src/gui/macOS/ui/fileprovidersettingscontroller_mac.mm +++ b/src/gui/macOS/ui/fileprovidersettingscontroller_mac.mm @@ -18,30 +18,9 @@ #include "gui/systray.h" -// Objective-C settings implementation - +// Objective-C imports #import - -@interface FileProviderSettings : NSObject - -@property (readonly) NSUserDefaults *userDefaults; - -@end - -@implementation FileProviderSettings - -- (instancetype)init -{ - self = [super init]; - if (self) { - _userDefaults = NSUserDefaults.standardUserDefaults; - } - return self; -} - -@end - -// End of Objective-C settings implementation +// End of Objective-C imports namespace { constexpr auto fpSettingsQmlPath = "qrc:/qml/src/gui/macOS/ui/FileProviderSettings.qml"; @@ -54,8 +33,25 @@ - (instancetype)init namespace Mac { -Q_LOGGING_CATEGORY(lcFileProviderSettingsController, - "nextcloud.gui.mac.fileprovider.settingscontroller") +Q_LOGGING_CATEGORY(lcFileProviderSettingsController, "nextcloud.gui.mac.fileprovider.settingscontroller") + +class FileProviderSettingsController::MacImplementation +{ +public: + MacImplementation() + { + _userDefaults = NSUserDefaults.standardUserDefaults; + }; + + ~MacImplementation() + { + [_userDefaults release]; + }; + +private: + NSUserDefaults *_userDefaults; +}; + FileProviderSettingsController::FileProviderSettingsController(QObject *parent) : QObject{parent} From d80962b634cb615acda761d0fe85a536261b67e5 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Mon, 4 Sep 2023 17:11:14 +0800 Subject: [PATCH 020/144] Instantiate internal MacImplementation in file provider settings controller Signed-off-by: Claudio Cambra --- src/gui/macOS/ui/fileprovidersettingscontroller.h | 1 + src/gui/macOS/ui/fileprovidersettingscontroller_mac.mm | 9 +++++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/gui/macOS/ui/fileprovidersettingscontroller.h b/src/gui/macOS/ui/fileprovidersettingscontroller.h index cd638c6eab8b7..74fa86fc8931e 100644 --- a/src/gui/macOS/ui/fileprovidersettingscontroller.h +++ b/src/gui/macOS/ui/fileprovidersettingscontroller.h @@ -27,6 +27,7 @@ class FileProviderSettingsController : public QObject public: explicit FileProviderSettingsController(QObject *parent = nullptr); + ~FileProviderSettingsController() override; [[nodiscard]] QQuickWidget *settingsViewWidget(); diff --git a/src/gui/macOS/ui/fileprovidersettingscontroller_mac.mm b/src/gui/macOS/ui/fileprovidersettingscontroller_mac.mm index c7f2a74aeb647..39028d8722f53 100644 --- a/src/gui/macOS/ui/fileprovidersettingscontroller_mac.mm +++ b/src/gui/macOS/ui/fileprovidersettingscontroller_mac.mm @@ -38,8 +38,9 @@ class FileProviderSettingsController::MacImplementation { public: - MacImplementation() + MacImplementation(FileProviderSettingsController *const parent) { + q = parent; _userDefaults = NSUserDefaults.standardUserDefaults; }; @@ -49,13 +50,17 @@ }; private: - NSUserDefaults *_userDefaults; + FileProviderSettingsController *q = nullptr; + NSUserDefaults *_userDefaults = nil; }; +FileProviderSettingsController::~FileProviderSettingsController() = default; FileProviderSettingsController::FileProviderSettingsController(QObject *parent) : QObject{parent} { + d = std::make_unique(this); + _settingsViewWidget = std::make_unique(Systray::instance()->trayEngine(), nullptr); _settingsViewWidget->setResizeMode(QQuickWidget::SizeRootObjectToView); _settingsViewWidget->setSource(QUrl(fpSettingsQmlPath)); From 0e02a64c5eacbc72a21880613b50d60c2dc25768 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Mon, 4 Sep 2023 17:59:58 +0800 Subject: [PATCH 021/144] Lazily load settings view widget Signed-off-by: Claudio Cambra --- src/gui/macOS/ui/fileprovidersettingscontroller.h | 2 ++ src/gui/macOS/ui/fileprovidersettingscontroller_mac.mm | 7 +++++++ 2 files changed, 9 insertions(+) diff --git a/src/gui/macOS/ui/fileprovidersettingscontroller.h b/src/gui/macOS/ui/fileprovidersettingscontroller.h index 74fa86fc8931e..cf3fccfc29535 100644 --- a/src/gui/macOS/ui/fileprovidersettingscontroller.h +++ b/src/gui/macOS/ui/fileprovidersettingscontroller.h @@ -32,6 +32,8 @@ class FileProviderSettingsController : public QObject [[nodiscard]] QQuickWidget *settingsViewWidget(); private: + void instantiateSettingsWidget(); + class MacImplementation; std::unique_ptr d; diff --git a/src/gui/macOS/ui/fileprovidersettingscontroller_mac.mm b/src/gui/macOS/ui/fileprovidersettingscontroller_mac.mm index 39028d8722f53..fb02c31476ab7 100644 --- a/src/gui/macOS/ui/fileprovidersettingscontroller_mac.mm +++ b/src/gui/macOS/ui/fileprovidersettingscontroller_mac.mm @@ -60,7 +60,10 @@ : QObject{parent} { d = std::make_unique(this); +} +void FileProviderSettingsController::instantiateSettingsWidget() +{ _settingsViewWidget = std::make_unique(Systray::instance()->trayEngine(), nullptr); _settingsViewWidget->setResizeMode(QQuickWidget::SizeRootObjectToView); _settingsViewWidget->setSource(QUrl(fpSettingsQmlPath)); @@ -69,6 +72,10 @@ QQuickWidget *FileProviderSettingsController::settingsViewWidget() { + if (!_settingsViewWidget) { + instantiateSettingsWidget(); + } + return _settingsViewWidget.get(); } From 20f89c6999fcdb5d64c404e651e93ee120ac98cb Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Mon, 4 Sep 2023 18:27:27 +0800 Subject: [PATCH 022/144] Make the fp settings controller static Signed-off-by: Claudio Cambra --- src/gui/accountsettings.cpp | 2 +- src/gui/accountsettings.h | 4 ---- src/gui/macOS/ui/fileprovidersettingscontroller.h | 6 ++++-- src/gui/macOS/ui/fileprovidersettingscontroller_mac.mm | 6 ++++++ 4 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/gui/accountsettings.cpp b/src/gui/accountsettings.cpp index 623e2db666cf7..da03b52d20f4a 100644 --- a/src/gui/accountsettings.cpp +++ b/src/gui/accountsettings.cpp @@ -199,7 +199,7 @@ AccountSettings::AccountSettings(AccountState *accountState, QWidget *parent) #if defined(BUILD_FILE_PROVIDER_MODULE) if (Mac::FileProvider::fileProviderAvailable()) { - const auto fpSettingsWidget = _fpSettingsController.settingsViewWidget(); + const auto fpSettingsWidget = Mac::FileProviderSettingsController::instance()->settingsViewWidget(); const auto fpSettingsLayout = new QVBoxLayout(_ui->fileProviderTab); fpSettingsLayout->setMargin(0); fpSettingsLayout->addWidget(fpSettingsWidget); diff --git a/src/gui/accountsettings.h b/src/gui/accountsettings.h index 9c32bbf39dc81..ddb7ff66a6b3d 100644 --- a/src/gui/accountsettings.h +++ b/src/gui/accountsettings.h @@ -156,10 +156,6 @@ private slots: bool _menuShown = false; QHash _folderConnections; - -#ifdef BUILD_FILE_PROVIDER_MODULE - Mac::FileProviderSettingsController _fpSettingsController; -#endif }; } // namespace OCC diff --git a/src/gui/macOS/ui/fileprovidersettingscontroller.h b/src/gui/macOS/ui/fileprovidersettingscontroller.h index cf3fccfc29535..a8742d792eba1 100644 --- a/src/gui/macOS/ui/fileprovidersettingscontroller.h +++ b/src/gui/macOS/ui/fileprovidersettingscontroller.h @@ -26,12 +26,14 @@ class FileProviderSettingsController : public QObject Q_OBJECT public: - explicit FileProviderSettingsController(QObject *parent = nullptr); - ~FileProviderSettingsController() override; + static FileProviderSettingsController *instance(); [[nodiscard]] QQuickWidget *settingsViewWidget(); private: + explicit FileProviderSettingsController(QObject *parent = nullptr); + ~FileProviderSettingsController() override; + void instantiateSettingsWidget(); class MacImplementation; diff --git a/src/gui/macOS/ui/fileprovidersettingscontroller_mac.mm b/src/gui/macOS/ui/fileprovidersettingscontroller_mac.mm index fb02c31476ab7..a14cfa851aaf9 100644 --- a/src/gui/macOS/ui/fileprovidersettingscontroller_mac.mm +++ b/src/gui/macOS/ui/fileprovidersettingscontroller_mac.mm @@ -54,6 +54,12 @@ NSUserDefaults *_userDefaults = nil; }; +FileProviderSettingsController *FileProviderSettingsController::instance() +{ + static FileProviderSettingsController controller; + return &controller; +} + FileProviderSettingsController::~FileProviderSettingsController() = default; FileProviderSettingsController::FileProviderSettingsController(QObject *parent) From 94ce3da9c5037b08f71849d33816a72af59319d9 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Mon, 4 Sep 2023 18:28:41 +0800 Subject: [PATCH 023/144] Treat FileProviderSettingsController::settingsViewWidget as a factory method Signed-off-by: Claudio Cambra --- src/gui/accountsettings.cpp | 7 ++++--- .../macOS/ui/fileprovidersettingscontroller.h | 7 ++----- .../ui/fileprovidersettingscontroller_mac.mm | 20 ++++++------------- 3 files changed, 12 insertions(+), 22 deletions(-) diff --git a/src/gui/accountsettings.cpp b/src/gui/accountsettings.cpp index da03b52d20f4a..7117cdf5a10d7 100644 --- a/src/gui/accountsettings.cpp +++ b/src/gui/accountsettings.cpp @@ -199,11 +199,12 @@ AccountSettings::AccountSettings(AccountState *accountState, QWidget *parent) #if defined(BUILD_FILE_PROVIDER_MODULE) if (Mac::FileProvider::fileProviderAvailable()) { - const auto fpSettingsWidget = Mac::FileProviderSettingsController::instance()->settingsViewWidget(); - const auto fpSettingsLayout = new QVBoxLayout(_ui->fileProviderTab); + const auto fileProviderTab = _ui->fileProviderTab; + const auto fpSettingsLayout = new QVBoxLayout(fileProviderTab); + const auto fpSettingsWidget = Mac::FileProviderSettingsController::instance()->settingsViewWidget(fileProviderTab); fpSettingsLayout->setMargin(0); fpSettingsLayout->addWidget(fpSettingsWidget); - _ui->fileProviderTab->setLayout(fpSettingsLayout); + fileProviderTab->setLayout(fpSettingsLayout); } else { disguiseTabWidget(); } diff --git a/src/gui/macOS/ui/fileprovidersettingscontroller.h b/src/gui/macOS/ui/fileprovidersettingscontroller.h index a8742d792eba1..a8f0f876e772a 100644 --- a/src/gui/macOS/ui/fileprovidersettingscontroller.h +++ b/src/gui/macOS/ui/fileprovidersettingscontroller.h @@ -28,18 +28,15 @@ class FileProviderSettingsController : public QObject public: static FileProviderSettingsController *instance(); - [[nodiscard]] QQuickWidget *settingsViewWidget(); + [[nodiscard]] QQuickWidget *settingsViewWidget(QWidget *const parent = nullptr, + const QQuickWidget::ResizeMode resizeMode = QQuickWidget::SizeRootObjectToView); private: explicit FileProviderSettingsController(QObject *parent = nullptr); ~FileProviderSettingsController() override; - void instantiateSettingsWidget(); - class MacImplementation; std::unique_ptr d; - - std::unique_ptr _settingsViewWidget; }; } // Mac diff --git a/src/gui/macOS/ui/fileprovidersettingscontroller_mac.mm b/src/gui/macOS/ui/fileprovidersettingscontroller_mac.mm index a14cfa851aaf9..2d34b2c442de6 100644 --- a/src/gui/macOS/ui/fileprovidersettingscontroller_mac.mm +++ b/src/gui/macOS/ui/fileprovidersettingscontroller_mac.mm @@ -68,21 +68,13 @@ d = std::make_unique(this); } -void FileProviderSettingsController::instantiateSettingsWidget() +QQuickWidget *FileProviderSettingsController::settingsViewWidget(QWidget *const parent, const QQuickWidget::ResizeMode resizeMode) { - _settingsViewWidget = std::make_unique(Systray::instance()->trayEngine(), nullptr); - _settingsViewWidget->setResizeMode(QQuickWidget::SizeRootObjectToView); - _settingsViewWidget->setSource(QUrl(fpSettingsQmlPath)); - _settingsViewWidget->rootContext()->setContextProperty(fpSettingsControllerProp, this); -} - -QQuickWidget *FileProviderSettingsController::settingsViewWidget() -{ - if (!_settingsViewWidget) { - instantiateSettingsWidget(); - } - - return _settingsViewWidget.get(); + const auto settingsViewWidget = new QQuickWidget(Systray::instance()->trayEngine(), parent); + settingsViewWidget->setResizeMode(resizeMode); + settingsViewWidget->setSource(QUrl(fpSettingsQmlPath)); + settingsViewWidget->rootContext()->setContextProperty(fpSettingsControllerProp, this); + return settingsViewWidget; } } // namespace Mac From c69bb4375c82949ab4cf22481bfc6b1c245248e1 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Mon, 4 Sep 2023 18:49:12 +0800 Subject: [PATCH 024/144] Make it possible to check whether an account has vfs enabled or not Signed-off-by: Claudio Cambra --- .../macOS/ui/fileprovidersettingscontroller.h | 2 ++ .../ui/fileprovidersettingscontroller_mac.mm | 30 +++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/src/gui/macOS/ui/fileprovidersettingscontroller.h b/src/gui/macOS/ui/fileprovidersettingscontroller.h index a8f0f876e772a..15ff403fb7db8 100644 --- a/src/gui/macOS/ui/fileprovidersettingscontroller.h +++ b/src/gui/macOS/ui/fileprovidersettingscontroller.h @@ -31,6 +31,8 @@ class FileProviderSettingsController : public QObject [[nodiscard]] QQuickWidget *settingsViewWidget(QWidget *const parent = nullptr, const QQuickWidget::ResizeMode resizeMode = QQuickWidget::SizeRootObjectToView); + [[nodiscard]] Q_INVOKABLE bool vfsEnabledForAccount(const QString &userIdAtHost); + private: explicit FileProviderSettingsController(QObject *parent = nullptr); ~FileProviderSettingsController() override; diff --git a/src/gui/macOS/ui/fileprovidersettingscontroller_mac.mm b/src/gui/macOS/ui/fileprovidersettingscontroller_mac.mm index 2d34b2c442de6..512eb7f11ff66 100644 --- a/src/gui/macOS/ui/fileprovidersettingscontroller_mac.mm +++ b/src/gui/macOS/ui/fileprovidersettingscontroller_mac.mm @@ -27,6 +27,9 @@ // FileProviderSettingsPage properties -- make sure they match up in QML file! constexpr auto fpSettingsControllerProp = "FileProviderSettingsController"; + +// NSUserDefaults entries +constexpr auto enabledAccountsSettingsKey = "enabledAccounts"; } // namespace namespace OCC { @@ -49,7 +52,29 @@ [_userDefaults release]; }; + QStringList enabledAccounts() const + { + QStringList qEnabledAccounts; + NSArray *const enabledAccounts = nsEnabledAccounts(); + for (NSString *const userIdAtHostString in enabledAccounts) { + qEnabledAccounts.append(QString::fromNSString(userIdAtHostString)); + } + return qEnabledAccounts; + } + + bool vfsEnabledForAccount(const QString &userIdAtHost) const + { + NSArray *const vfsEnabledAccounts = nsEnabledAccounts(); + return [vfsEnabledAccounts containsObject:userIdAtHost.toNSString()]; + } + private: + NSArray *nsEnabledAccounts() const + { + NSString *const accsKey = [NSString stringWithUTF8String:enabledAccountsSettingsKey]; + return (NSArray *)[_userDefaults objectForKey:accsKey]; + } + FileProviderSettingsController *q = nullptr; NSUserDefaults *_userDefaults = nil; }; @@ -77,6 +102,11 @@ return settingsViewWidget; } +bool FileProviderSettingsController::vfsEnabledForAccount(const QString &userIdAtHost) +{ + return d->vfsEnabledForAccount(userIdAtHost); +} + } // namespace Mac } // namespace OCC From 9a880f419911b8bee9c68e4a07625a4e3ed78f5a Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Tue, 5 Sep 2023 10:43:01 +0800 Subject: [PATCH 025/144] Implement modification of file provider enabled for account Signed-off-by: Claudio Cambra --- .../macOS/ui/fileprovidersettingscontroller.h | 5 +++- .../ui/fileprovidersettingscontroller_mac.mm | 30 ++++++++++++++++++- 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/src/gui/macOS/ui/fileprovidersettingscontroller.h b/src/gui/macOS/ui/fileprovidersettingscontroller.h index 15ff403fb7db8..4bf463493371c 100644 --- a/src/gui/macOS/ui/fileprovidersettingscontroller.h +++ b/src/gui/macOS/ui/fileprovidersettingscontroller.h @@ -31,7 +31,10 @@ class FileProviderSettingsController : public QObject [[nodiscard]] QQuickWidget *settingsViewWidget(QWidget *const parent = nullptr, const QQuickWidget::ResizeMode resizeMode = QQuickWidget::SizeRootObjectToView); - [[nodiscard]] Q_INVOKABLE bool vfsEnabledForAccount(const QString &userIdAtHost); + [[nodiscard]] Q_INVOKABLE bool vfsEnabledForAccount(const QString &userIdAtHost) const; + +public slots: + void setVfsEnabledForAccount(const QString &userIdAtHost, const bool setEnabled); private: explicit FileProviderSettingsController(QObject *parent = nullptr); diff --git a/src/gui/macOS/ui/fileprovidersettingscontroller_mac.mm b/src/gui/macOS/ui/fileprovidersettingscontroller_mac.mm index 512eb7f11ff66..1b1ee9f8abded 100644 --- a/src/gui/macOS/ui/fileprovidersettingscontroller_mac.mm +++ b/src/gui/macOS/ui/fileprovidersettingscontroller_mac.mm @@ -68,6 +68,29 @@ bool vfsEnabledForAccount(const QString &userIdAtHost) const return [vfsEnabledAccounts containsObject:userIdAtHost.toNSString()]; } + void setVfsEnabledForAccount(const QString &userIdAtHost, const bool setEnabled) const + { + NSArray *const vfsEnabledAccounts = nsEnabledAccounts(); + NSString *const nsUserIdAtHost = userIdAtHost.toNSString(); + const BOOL accountEnabled = [vfsEnabledAccounts containsObject:nsUserIdAtHost]; + + if (accountEnabled == setEnabled) { + return; + } + + NSMutableArray *const mutableVfsAccounts = vfsEnabledAccounts.mutableCopy; + + if (setEnabled) { + [mutableVfsAccounts addObject:nsUserIdAtHost]; + } else { + [mutableVfsAccounts removeObject:nsUserIdAtHost]; + } + + NSArray *const modifiedVfsAccounts = mutableVfsAccounts.copy; + NSString *const accsKey = [NSString stringWithUTF8String:enabledAccountsSettingsKey]; + [_userDefaults setObject:modifiedVfsAccounts forKey:accsKey]; + } + private: NSArray *nsEnabledAccounts() const { @@ -102,11 +125,16 @@ bool vfsEnabledForAccount(const QString &userIdAtHost) const return settingsViewWidget; } -bool FileProviderSettingsController::vfsEnabledForAccount(const QString &userIdAtHost) +bool FileProviderSettingsController::vfsEnabledForAccount(const QString &userIdAtHost) const { return d->vfsEnabledForAccount(userIdAtHost); } +void FileProviderSettingsController::setVfsEnabledForAccount(const QString &userIdAtHost, const bool setEnabled) +{ + d->setVfsEnabledForAccount(userIdAtHost, setEnabled); +} + } // namespace Mac } // namespace OCC From ac608a661d3f8ae1adf442123426dc4f4f2d22d8 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Tue, 5 Sep 2023 10:46:45 +0800 Subject: [PATCH 026/144] Use default constructor for FileProviderSettingsController::MacImplementation Signed-off-by: Claudio Cambra --- src/gui/macOS/ui/fileprovidersettingscontroller_mac.mm | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/gui/macOS/ui/fileprovidersettingscontroller_mac.mm b/src/gui/macOS/ui/fileprovidersettingscontroller_mac.mm index 1b1ee9f8abded..e00c9cf9ba18d 100644 --- a/src/gui/macOS/ui/fileprovidersettingscontroller_mac.mm +++ b/src/gui/macOS/ui/fileprovidersettingscontroller_mac.mm @@ -47,10 +47,7 @@ _userDefaults = NSUserDefaults.standardUserDefaults; }; - ~MacImplementation() - { - [_userDefaults release]; - }; + ~MacImplementation() = default; QStringList enabledAccounts() const { From 3c26e25a3cc0709145fa0c639f8ebe3db6e1fe54 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Tue, 5 Sep 2023 10:52:29 +0800 Subject: [PATCH 027/144] Notify when enabled file provider vfs accounts change Signed-off-by: Claudio Cambra --- .../macOS/ui/fileprovidersettingscontroller.h | 3 +++ .../ui/fileprovidersettingscontroller_mac.mm | 16 +++++++++++++--- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/gui/macOS/ui/fileprovidersettingscontroller.h b/src/gui/macOS/ui/fileprovidersettingscontroller.h index 4bf463493371c..c093c50835d29 100644 --- a/src/gui/macOS/ui/fileprovidersettingscontroller.h +++ b/src/gui/macOS/ui/fileprovidersettingscontroller.h @@ -36,6 +36,9 @@ class FileProviderSettingsController : public QObject public slots: void setVfsEnabledForAccount(const QString &userIdAtHost, const bool setEnabled); +signals: + void vfsEnabledAccountsChanged(); + private: explicit FileProviderSettingsController(QObject *parent = nullptr); ~FileProviderSettingsController() override; diff --git a/src/gui/macOS/ui/fileprovidersettingscontroller_mac.mm b/src/gui/macOS/ui/fileprovidersettingscontroller_mac.mm index e00c9cf9ba18d..f0c99a62ff76d 100644 --- a/src/gui/macOS/ui/fileprovidersettingscontroller_mac.mm +++ b/src/gui/macOS/ui/fileprovidersettingscontroller_mac.mm @@ -41,6 +41,11 @@ class FileProviderSettingsController::MacImplementation { public: + enum class VfsAccountsAction { + VfsAccountsNoAction, + VfsAccountsEnabledChanged, + }; + MacImplementation(FileProviderSettingsController *const parent) { q = parent; @@ -65,14 +70,14 @@ bool vfsEnabledForAccount(const QString &userIdAtHost) const return [vfsEnabledAccounts containsObject:userIdAtHost.toNSString()]; } - void setVfsEnabledForAccount(const QString &userIdAtHost, const bool setEnabled) const + VfsAccountsAction setVfsEnabledForAccount(const QString &userIdAtHost, const bool setEnabled) const { NSArray *const vfsEnabledAccounts = nsEnabledAccounts(); NSString *const nsUserIdAtHost = userIdAtHost.toNSString(); const BOOL accountEnabled = [vfsEnabledAccounts containsObject:nsUserIdAtHost]; if (accountEnabled == setEnabled) { - return; + return VfsAccountsAction::VfsAccountsNoAction; } NSMutableArray *const mutableVfsAccounts = vfsEnabledAccounts.mutableCopy; @@ -86,6 +91,8 @@ void setVfsEnabledForAccount(const QString &userIdAtHost, const bool setEnabled) NSArray *const modifiedVfsAccounts = mutableVfsAccounts.copy; NSString *const accsKey = [NSString stringWithUTF8String:enabledAccountsSettingsKey]; [_userDefaults setObject:modifiedVfsAccounts forKey:accsKey]; + + return VfsAccountsAction::VfsAccountsEnabledChanged; } private: @@ -129,7 +136,10 @@ void setVfsEnabledForAccount(const QString &userIdAtHost, const bool setEnabled) void FileProviderSettingsController::setVfsEnabledForAccount(const QString &userIdAtHost, const bool setEnabled) { - d->setVfsEnabledForAccount(userIdAtHost, setEnabled); + const auto enabledAccountsAction = d->setVfsEnabledForAccount(userIdAtHost, setEnabled); + if (enabledAccountsAction == MacImplementation::VfsAccountsAction::VfsAccountsEnabledChanged) { + emit vfsEnabledAccountsChanged(); + } } } // namespace Mac From ba3baa406bbd2ce41f0df59a9a13fdb5fd647404 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Tue, 5 Sep 2023 14:55:18 +0800 Subject: [PATCH 028/144] Expose account user id with host to QML Signed-off-by: Claudio Cambra --- src/gui/accountsettings.cpp | 4 +++- src/gui/macOS/ui/FileProviderSettings.qml | 1 + src/gui/macOS/ui/fileprovidersettingscontroller.h | 3 ++- src/gui/macOS/ui/fileprovidersettingscontroller_mac.mm | 6 +++++- 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/gui/accountsettings.cpp b/src/gui/accountsettings.cpp index 7117cdf5a10d7..1565f272341b3 100644 --- a/src/gui/accountsettings.cpp +++ b/src/gui/accountsettings.cpp @@ -201,7 +201,9 @@ AccountSettings::AccountSettings(AccountState *accountState, QWidget *parent) if (Mac::FileProvider::fileProviderAvailable()) { const auto fileProviderTab = _ui->fileProviderTab; const auto fpSettingsLayout = new QVBoxLayout(fileProviderTab); - const auto fpSettingsWidget = Mac::FileProviderSettingsController::instance()->settingsViewWidget(fileProviderTab); + const auto fpAccountUserIdAtHost = _accountState->account()->userIdAtHostWithPort(); + const auto fpSettingsController = Mac::FileProviderSettingsController::instance(); + const auto fpSettingsWidget = fpSettingsController->settingsViewWidget(fpAccountUserIdAtHost, fileProviderTab); fpSettingsLayout->setMargin(0); fpSettingsLayout->addWidget(fpSettingsWidget); fileProviderTab->setLayout(fpSettingsLayout); diff --git a/src/gui/macOS/ui/FileProviderSettings.qml b/src/gui/macOS/ui/FileProviderSettings.qml index b4a220bead20d..c6336eba8bf00 100644 --- a/src/gui/macOS/ui/FileProviderSettings.qml +++ b/src/gui/macOS/ui/FileProviderSettings.qml @@ -25,6 +25,7 @@ Page { property bool showBorder: true property var controller: FileProviderSettingsController + property var accountUserIdAtHost: AccountUserIdAtHost title: qsTr("Virtual files settings") diff --git a/src/gui/macOS/ui/fileprovidersettingscontroller.h b/src/gui/macOS/ui/fileprovidersettingscontroller.h index c093c50835d29..7b9d4fc5885df 100644 --- a/src/gui/macOS/ui/fileprovidersettingscontroller.h +++ b/src/gui/macOS/ui/fileprovidersettingscontroller.h @@ -28,7 +28,8 @@ class FileProviderSettingsController : public QObject public: static FileProviderSettingsController *instance(); - [[nodiscard]] QQuickWidget *settingsViewWidget(QWidget *const parent = nullptr, + [[nodiscard]] QQuickWidget *settingsViewWidget(const QString &accountUserIdAtHost, + QWidget *const parent = nullptr, const QQuickWidget::ResizeMode resizeMode = QQuickWidget::SizeRootObjectToView); [[nodiscard]] Q_INVOKABLE bool vfsEnabledForAccount(const QString &userIdAtHost) const; diff --git a/src/gui/macOS/ui/fileprovidersettingscontroller_mac.mm b/src/gui/macOS/ui/fileprovidersettingscontroller_mac.mm index f0c99a62ff76d..3c8b0a06b4a3e 100644 --- a/src/gui/macOS/ui/fileprovidersettingscontroller_mac.mm +++ b/src/gui/macOS/ui/fileprovidersettingscontroller_mac.mm @@ -27,6 +27,7 @@ // FileProviderSettingsPage properties -- make sure they match up in QML file! constexpr auto fpSettingsControllerProp = "FileProviderSettingsController"; +constexpr auto fpSettingsAccountUserIdAtHostProp = "AccountUserIdAtHost"; // NSUserDefaults entries constexpr auto enabledAccountsSettingsKey = "enabledAccounts"; @@ -120,12 +121,15 @@ VfsAccountsAction setVfsEnabledForAccount(const QString &userIdAtHost, const boo d = std::make_unique(this); } -QQuickWidget *FileProviderSettingsController::settingsViewWidget(QWidget *const parent, const QQuickWidget::ResizeMode resizeMode) +QQuickWidget *FileProviderSettingsController::settingsViewWidget(const QString &accountUserIdAtHost, + QWidget *const parent, + const QQuickWidget::ResizeMode resizeMode) { const auto settingsViewWidget = new QQuickWidget(Systray::instance()->trayEngine(), parent); settingsViewWidget->setResizeMode(resizeMode); settingsViewWidget->setSource(QUrl(fpSettingsQmlPath)); settingsViewWidget->rootContext()->setContextProperty(fpSettingsControllerProp, this); + settingsViewWidget->rootContext()->setContextProperty(fpSettingsAccountUserIdAtHostProp, accountUserIdAtHost); return settingsViewWidget; } From a57cb3df9d0d7c40ecea92f06c3700c2468a64da Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Tue, 5 Sep 2023 17:15:36 +0800 Subject: [PATCH 029/144] Register file provider settings controller as singleton in qml engine Signed-off-by: Claudio Cambra --- src/gui/macOS/ui/FileProviderSettings.qml | 2 ++ src/gui/macOS/ui/fileprovidersettingscontroller_mac.mm | 4 +--- src/gui/owncloudgui.cpp | 8 ++++++++ 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/gui/macOS/ui/FileProviderSettings.qml b/src/gui/macOS/ui/FileProviderSettings.qml index c6336eba8bf00..0cdb890777598 100644 --- a/src/gui/macOS/ui/FileProviderSettings.qml +++ b/src/gui/macOS/ui/FileProviderSettings.qml @@ -20,6 +20,8 @@ import Style 1.0 import "../../filedetails" import "../../tray" +import com.nextcloud.desktopclient 1.0 + Page { id: root diff --git a/src/gui/macOS/ui/fileprovidersettingscontroller_mac.mm b/src/gui/macOS/ui/fileprovidersettingscontroller_mac.mm index 3c8b0a06b4a3e..503518e9b2023 100644 --- a/src/gui/macOS/ui/fileprovidersettingscontroller_mac.mm +++ b/src/gui/macOS/ui/fileprovidersettingscontroller_mac.mm @@ -26,8 +26,7 @@ constexpr auto fpSettingsQmlPath = "qrc:/qml/src/gui/macOS/ui/FileProviderSettings.qml"; // FileProviderSettingsPage properties -- make sure they match up in QML file! -constexpr auto fpSettingsControllerProp = "FileProviderSettingsController"; -constexpr auto fpSettingsAccountUserIdAtHostProp = "AccountUserIdAtHost"; +constexpr auto fpSettingsAccountUserIdAtHostProp = "accountUserIdAtHost"; // NSUserDefaults entries constexpr auto enabledAccountsSettingsKey = "enabledAccounts"; @@ -128,7 +127,6 @@ VfsAccountsAction setVfsEnabledForAccount(const QString &userIdAtHost, const boo const auto settingsViewWidget = new QQuickWidget(Systray::instance()->trayEngine(), parent); settingsViewWidget->setResizeMode(resizeMode); settingsViewWidget->setSource(QUrl(fpSettingsQmlPath)); - settingsViewWidget->rootContext()->setContextProperty(fpSettingsControllerProp, this); settingsViewWidget->rootContext()->setContextProperty(fpSettingsAccountUserIdAtHostProp, accountUserIdAtHost); return settingsViewWidget; } diff --git a/src/gui/owncloudgui.cpp b/src/gui/owncloudgui.cpp index 6749df8a6e91b..c14b5125a0861 100644 --- a/src/gui/owncloudgui.cpp +++ b/src/gui/owncloudgui.cpp @@ -62,6 +62,10 @@ #include #include +#ifdef BUILD_FILE_PROVIDER_MODULE +#include "macOS/fileprovidersettingscontroller.h" +#endif + namespace OCC { Q_LOGGING_CATEGORY(lcOwnCloudGui, "com.nextcloud.owncloudgui") @@ -146,6 +150,10 @@ ownCloudGui::ownCloudGui(Application *parent) qmlRegisterSingletonInstance("com.nextcloud.desktopclient", 1, 0, "UserAppsModel", UserAppsModel::instance()); qmlRegisterSingletonInstance("com.nextcloud.desktopclient", 1, 0, "Theme", Theme::instance()); qmlRegisterSingletonInstance("com.nextcloud.desktopclient", 1, 0, "Systray", Systray::instance()); + +#ifdef BUILD_FILE_PROVIDER_MODULE + qmlRegisterSingletonInstance("com.nextcloud.desktopclient", 1, 0, "FileProviderSettingsController", Mac::FileProviderSettingsController::instance()); +#endif } void ownCloudGui::createTray() From e9451e9281b6899151736cd3e9d17471cd05710b Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Tue, 5 Sep 2023 17:16:19 +0800 Subject: [PATCH 030/144] Set account as property of settings view root object rather than context property Signed-off-by: Claudio Cambra --- src/gui/macOS/ui/FileProviderSettings.qml | 2 +- src/gui/macOS/ui/fileprovidersettingscontroller_mac.mm | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/gui/macOS/ui/FileProviderSettings.qml b/src/gui/macOS/ui/FileProviderSettings.qml index 0cdb890777598..7840544102d16 100644 --- a/src/gui/macOS/ui/FileProviderSettings.qml +++ b/src/gui/macOS/ui/FileProviderSettings.qml @@ -27,7 +27,7 @@ Page { property bool showBorder: true property var controller: FileProviderSettingsController - property var accountUserIdAtHost: AccountUserIdAtHost + property string accountUserIdAtHost: "" title: qsTr("Virtual files settings") diff --git a/src/gui/macOS/ui/fileprovidersettingscontroller_mac.mm b/src/gui/macOS/ui/fileprovidersettingscontroller_mac.mm index 503518e9b2023..ee71e97f7e773 100644 --- a/src/gui/macOS/ui/fileprovidersettingscontroller_mac.mm +++ b/src/gui/macOS/ui/fileprovidersettingscontroller_mac.mm @@ -127,7 +127,7 @@ VfsAccountsAction setVfsEnabledForAccount(const QString &userIdAtHost, const boo const auto settingsViewWidget = new QQuickWidget(Systray::instance()->trayEngine(), parent); settingsViewWidget->setResizeMode(resizeMode); settingsViewWidget->setSource(QUrl(fpSettingsQmlPath)); - settingsViewWidget->rootContext()->setContextProperty(fpSettingsAccountUserIdAtHostProp, accountUserIdAtHost); + settingsViewWidget->rootObject()->setProperty(fpSettingsAccountUserIdAtHostProp, accountUserIdAtHost); return settingsViewWidget; } From 556bce26722fefc27771e733d4ed9a3230918d7a Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Tue, 5 Sep 2023 17:17:58 +0800 Subject: [PATCH 031/144] Move fp settings controller out of ui folder Signed-off-by: Claudio Cambra --- src/gui/CMakeLists.txt | 4 ++-- src/gui/accountsettings.h | 2 +- src/gui/macOS/{ui => }/fileprovidersettingscontroller.h | 0 src/gui/macOS/{ui => }/fileprovidersettingscontroller_mac.mm | 0 src/gui/macOS/ui/FileProviderSettings.qml | 2 ++ 5 files changed, 5 insertions(+), 3 deletions(-) rename src/gui/macOS/{ui => }/fileprovidersettingscontroller.h (100%) rename src/gui/macOS/{ui => }/fileprovidersettingscontroller_mac.mm (100%) diff --git a/src/gui/CMakeLists.txt b/src/gui/CMakeLists.txt index f79d0dfd8630e..1af5fdf3ba8d1 100644 --- a/src/gui/CMakeLists.txt +++ b/src/gui/CMakeLists.txt @@ -302,8 +302,8 @@ IF( APPLE ) macOS/fileproviderxpc_mac.mm macOS/fileproviderxpc_mac_utils.h macOS/fileproviderxpc_mac_utils.mm - macOS/ui/fileprovidersettingscontroller.h - macOS/ui/fileprovidersettingscontroller_mac.mm) + macOS/fileprovidersettingscontroller.h + macOS/fileprovidersettingscontroller_mac.mm) endif() if(SPARKLE_FOUND AND BUILD_UPDATER) diff --git a/src/gui/accountsettings.h b/src/gui/accountsettings.h index ddb7ff66a6b3d..117a3aa536a0a 100644 --- a/src/gui/accountsettings.h +++ b/src/gui/accountsettings.h @@ -28,7 +28,7 @@ #include "folderstatusmodel.h" #ifdef BUILD_FILE_PROVIDER_MODULE -#include "macOS/ui/fileprovidersettingscontroller.h" +#include "macOS/fileprovidersettingscontroller.h" #endif class QModelIndex; diff --git a/src/gui/macOS/ui/fileprovidersettingscontroller.h b/src/gui/macOS/fileprovidersettingscontroller.h similarity index 100% rename from src/gui/macOS/ui/fileprovidersettingscontroller.h rename to src/gui/macOS/fileprovidersettingscontroller.h diff --git a/src/gui/macOS/ui/fileprovidersettingscontroller_mac.mm b/src/gui/macOS/fileprovidersettingscontroller_mac.mm similarity index 100% rename from src/gui/macOS/ui/fileprovidersettingscontroller_mac.mm rename to src/gui/macOS/fileprovidersettingscontroller_mac.mm diff --git a/src/gui/macOS/ui/FileProviderSettings.qml b/src/gui/macOS/ui/FileProviderSettings.qml index 7840544102d16..50f282b93f970 100644 --- a/src/gui/macOS/ui/FileProviderSettings.qml +++ b/src/gui/macOS/ui/FileProviderSettings.qml @@ -68,6 +68,8 @@ Page { CheckBox { text: qsTr("Enable virtual files") + checked: root.controller.vfsEnabledForAccount(root.accountUserIdAtHost) + onClicked: root.controller.setVfsEnabledForAccount(root.accountUserIdAtHost, checked) } } } From 42b72f9d9a4eded92baa9b88f154dc8f09435644 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Wed, 6 Sep 2023 13:55:53 +0800 Subject: [PATCH 032/144] Use [[nodiscard]] for MacImplementation methods Signed-off-by: Claudio Cambra --- src/gui/macOS/fileprovidersettingscontroller_mac.mm | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/gui/macOS/fileprovidersettingscontroller_mac.mm b/src/gui/macOS/fileprovidersettingscontroller_mac.mm index ee71e97f7e773..bbfed238976a0 100644 --- a/src/gui/macOS/fileprovidersettingscontroller_mac.mm +++ b/src/gui/macOS/fileprovidersettingscontroller_mac.mm @@ -54,7 +54,7 @@ ~MacImplementation() = default; - QStringList enabledAccounts() const + [[nodiscard]] QStringList enabledAccounts() const { QStringList qEnabledAccounts; NSArray *const enabledAccounts = nsEnabledAccounts(); @@ -64,13 +64,13 @@ QStringList enabledAccounts() const return qEnabledAccounts; } - bool vfsEnabledForAccount(const QString &userIdAtHost) const + [[nodiscard]] bool vfsEnabledForAccount(const QString &userIdAtHost) const { NSArray *const vfsEnabledAccounts = nsEnabledAccounts(); return [vfsEnabledAccounts containsObject:userIdAtHost.toNSString()]; } - VfsAccountsAction setVfsEnabledForAccount(const QString &userIdAtHost, const bool setEnabled) const + [[nodiscard]] VfsAccountsAction setVfsEnabledForAccount(const QString &userIdAtHost, const bool setEnabled) const { NSArray *const vfsEnabledAccounts = nsEnabledAccounts(); NSString *const nsUserIdAtHost = userIdAtHost.toNSString(); @@ -96,7 +96,7 @@ VfsAccountsAction setVfsEnabledForAccount(const QString &userIdAtHost, const boo } private: - NSArray *nsEnabledAccounts() const + [[nodiscard]] NSArray *nsEnabledAccounts() const { NSString *const accsKey = [NSString stringWithUTF8String:enabledAccountsSettingsKey]; return (NSArray *)[_userDefaults objectForKey:accsKey]; From 5f059a23ce036086671c71240357eb4f54b2978e Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Wed, 6 Sep 2023 13:59:25 +0800 Subject: [PATCH 033/144] Add method to enable file provider vfs for all accounts Signed-off-by: Claudio Cambra --- .../fileprovidersettingscontroller_mac.mm | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/gui/macOS/fileprovidersettingscontroller_mac.mm b/src/gui/macOS/fileprovidersettingscontroller_mac.mm index bbfed238976a0..8ea8f7f79ab76 100644 --- a/src/gui/macOS/fileprovidersettingscontroller_mac.mm +++ b/src/gui/macOS/fileprovidersettingscontroller_mac.mm @@ -91,10 +91,37 @@ NSArray *const modifiedVfsAccounts = mutableVfsAccounts.copy; NSString *const accsKey = [NSString stringWithUTF8String:enabledAccountsSettingsKey]; [_userDefaults setObject:modifiedVfsAccounts forKey:accsKey]; + [_userDefaults synchronize]; + + qDebug() << userIdAtHost << setEnabled << enabledAccounts(); return VfsAccountsAction::VfsAccountsEnabledChanged; } + [[nodiscard]] VfsAccountsAction enableVfsForAllAccounts() const + { + const auto accManager = AccountManager::instance(); + const auto accountsList = accManager->accounts(); + + if (accountsList.count() == 0) { + return VfsAccountsAction::VfsAccountsNoAction; + } + + auto overallActResult = VfsAccountsAction::VfsAccountsNoAction; + + for (const auto &account : accountsList) { + const auto qAccountUserIdAtHost = account->account()->userIdAtHostWithPort(); + const auto accountActResult = setVfsEnabledForAccount(qAccountUserIdAtHost, true); + + if (accountActResult == VfsAccountsAction::VfsAccountsEnabledChanged) { + overallActResult = accountActResult; + } + } + + return overallActResult; + + } + private: [[nodiscard]] NSArray *nsEnabledAccounts() const { From f5b80e9ec1b23e314b40ff8af42ce72576034803 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Wed, 6 Sep 2023 14:20:29 +0800 Subject: [PATCH 034/144] Run initial check on creation of FileProviderSettingsController Signed-off-by: Claudio Cambra --- .../macOS/fileprovidersettingscontroller_mac.mm | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/gui/macOS/fileprovidersettingscontroller_mac.mm b/src/gui/macOS/fileprovidersettingscontroller_mac.mm index 8ea8f7f79ab76..b848203d2f936 100644 --- a/src/gui/macOS/fileprovidersettingscontroller_mac.mm +++ b/src/gui/macOS/fileprovidersettingscontroller_mac.mm @@ -50,6 +50,8 @@ { q = parent; _userDefaults = NSUserDefaults.standardUserDefaults; + + initialCheck(); }; ~MacImplementation() = default; @@ -129,6 +131,18 @@ return (NSArray *)[_userDefaults objectForKey:accsKey]; } + void initialCheck() + { + NSArray *const vfsEnabledAccounts = nsEnabledAccounts(); + if (vfsEnabledAccounts != nil) { + return; + } + + qCDebug(lcFileProviderSettingsController) << "Initial check for file provider settings found nil enabled vfs accounts array." + << "Enabling all accounts on initial setup."; + [[maybe_unused]] const auto result = enableVfsForAllAccounts(); + } + FileProviderSettingsController *q = nullptr; NSUserDefaults *_userDefaults = nil; }; From 58262a8d94028fd3a81988ce82e6c7eab07b5557 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Wed, 6 Sep 2023 15:07:10 +0800 Subject: [PATCH 035/144] Ensure account is file provider vfs enablement is correctly set in NSUserDefaults Signed-off-by: Claudio Cambra --- .../fileprovidersettingscontroller_mac.mm | 20 ++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/src/gui/macOS/fileprovidersettingscontroller_mac.mm b/src/gui/macOS/fileprovidersettingscontroller_mac.mm index b848203d2f936..9b571ef1731b9 100644 --- a/src/gui/macOS/fileprovidersettingscontroller_mac.mm +++ b/src/gui/macOS/fileprovidersettingscontroller_mac.mm @@ -74,11 +74,25 @@ [[nodiscard]] VfsAccountsAction setVfsEnabledForAccount(const QString &userIdAtHost, const bool setEnabled) const { - NSArray *const vfsEnabledAccounts = nsEnabledAccounts(); + NSArray *vfsEnabledAccounts = nsEnabledAccounts(); + + qCInfo(lcFileProviderSettingsController) << "Setting file provider-based vfs of account" + << userIdAtHost + << "to" + << setEnabled; + + if (vfsEnabledAccounts == nil) { + qCDebug(lcFileProviderSettingsController) << "Received nil array for accounts, creating new array"; + vfsEnabledAccounts = NSArray.array; + } + NSString *const nsUserIdAtHost = userIdAtHost.toNSString(); const BOOL accountEnabled = [vfsEnabledAccounts containsObject:nsUserIdAtHost]; if (accountEnabled == setEnabled) { + qCDebug(lcFileProviderSettingsController) << "VFS enablement status for" + << userIdAtHost + << "matches config."; return VfsAccountsAction::VfsAccountsNoAction; } @@ -93,9 +107,8 @@ NSArray *const modifiedVfsAccounts = mutableVfsAccounts.copy; NSString *const accsKey = [NSString stringWithUTF8String:enabledAccountsSettingsKey]; [_userDefaults setObject:modifiedVfsAccounts forKey:accsKey]; - [_userDefaults synchronize]; - qDebug() << userIdAtHost << setEnabled << enabledAccounts(); + Q_ASSERT(vfsEnabledForAccount(userIdAtHost) == userIdAtHost); return VfsAccountsAction::VfsAccountsEnabledChanged; } @@ -140,6 +153,7 @@ void initialCheck() qCDebug(lcFileProviderSettingsController) << "Initial check for file provider settings found nil enabled vfs accounts array." << "Enabling all accounts on initial setup."; + [[maybe_unused]] const auto result = enableVfsForAllAccounts(); } From 0c40ceff9c3cad75bb6785c0fce28fda0af28a19 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Wed, 6 Sep 2023 15:18:30 +0800 Subject: [PATCH 036/144] Init widely-used variables in MacImplementation at declaration, fix nullability warnings Signed-off-by: Claudio Cambra --- src/gui/macOS/fileprovidersettingscontroller_mac.mm | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/gui/macOS/fileprovidersettingscontroller_mac.mm b/src/gui/macOS/fileprovidersettingscontroller_mac.mm index 9b571ef1731b9..b9f3c5de71e0e 100644 --- a/src/gui/macOS/fileprovidersettingscontroller_mac.mm +++ b/src/gui/macOS/fileprovidersettingscontroller_mac.mm @@ -49,8 +49,6 @@ MacImplementation(FileProviderSettingsController *const parent) { q = parent; - _userDefaults = NSUserDefaults.standardUserDefaults; - initialCheck(); }; @@ -105,8 +103,7 @@ } NSArray *const modifiedVfsAccounts = mutableVfsAccounts.copy; - NSString *const accsKey = [NSString stringWithUTF8String:enabledAccountsSettingsKey]; - [_userDefaults setObject:modifiedVfsAccounts forKey:accsKey]; + [_userDefaults setObject:modifiedVfsAccounts forKey:_accountsKey]; Q_ASSERT(vfsEnabledForAccount(userIdAtHost) == userIdAtHost); @@ -140,8 +137,7 @@ private: [[nodiscard]] NSArray *nsEnabledAccounts() const { - NSString *const accsKey = [NSString stringWithUTF8String:enabledAccountsSettingsKey]; - return (NSArray *)[_userDefaults objectForKey:accsKey]; + return (NSArray *)[_userDefaults objectForKey:_accountsKey]; } void initialCheck() @@ -158,7 +154,8 @@ void initialCheck() } FileProviderSettingsController *q = nullptr; - NSUserDefaults *_userDefaults = nil; + NSUserDefaults *_userDefaults = NSUserDefaults.standardUserDefaults; + NSString *_accountsKey = [NSString stringWithUTF8String:enabledAccountsSettingsKey]; }; FileProviderSettingsController *FileProviderSettingsController::instance() From 1db59fecc149f89fb307681f37c682a9ff79a2fc Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Wed, 6 Sep 2023 15:40:19 +0800 Subject: [PATCH 037/144] Remove ConfigFile().macFileProviderModuleEnabled() config flag Since we are going to distribute the file provider client as separate from the normal client, this flag doesn't make any practical sense. The user using the FileProvider desktop client will not want to not use the file provider module Signed-off-by: Claudio Cambra --- src/gui/macOS/fileprovider_mac.mm | 7 ------- src/libsync/configfile.cpp | 14 -------------- src/libsync/configfile.h | 3 --- 3 files changed, 24 deletions(-) diff --git a/src/gui/macOS/fileprovider_mac.mm b/src/gui/macOS/fileprovider_mac.mm index f45b915569467..5303d9fa71a05 100644 --- a/src/gui/macOS/fileprovider_mac.mm +++ b/src/gui/macOS/fileprovider_mac.mm @@ -37,10 +37,6 @@ qCInfo(lcMacFileProvider) << "File provider system is not available on this version of macOS."; deleteLater(); return; - } else if (!ConfigFile().macFileProviderModuleEnabled()) { - qCInfo(lcMacFileProvider) << "File provider module is not enabled in application config."; - deleteLater(); - return; } qCInfo(lcMacFileProvider) << "Initialising file provider domain manager."; @@ -65,9 +61,6 @@ if (!fileProviderAvailable()) { qCInfo(lcMacFileProvider) << "File provider system is not available on this version of macOS."; return nullptr; - } else if (!ConfigFile().macFileProviderModuleEnabled()) { - qCInfo(lcMacFileProvider) << "File provider module is not enabled in application config."; - return nullptr; } if (!_instance) { diff --git a/src/libsync/configfile.cpp b/src/libsync/configfile.cpp index 7583956d8f5dc..d46ad50f0e87c 100644 --- a/src/libsync/configfile.cpp +++ b/src/libsync/configfile.cpp @@ -111,8 +111,6 @@ static constexpr char certPath[] = "http_certificatePath"; static constexpr char certPasswd[] = "http_certificatePasswd"; static const QSet validUpdateChannels { QStringLiteral("stable"), QStringLiteral("beta") }; - -static constexpr auto macFileProviderModuleEnabledC = "macFileProviderModuleEnabled"; } namespace OCC { @@ -1229,16 +1227,4 @@ void ConfigFile::setDiscoveredLegacyConfigPath(const QString &discoveredLegacyCo _discoveredLegacyConfigPath = discoveredLegacyConfigPath; } -bool ConfigFile::macFileProviderModuleEnabled() const -{ - QSettings settings(configFile(), QSettings::IniFormat); - return settings.value(macFileProviderModuleEnabledC, false).toBool(); -} - -void ConfigFile::setMacFileProviderModuleEnabled(const bool moduleEnabled) -{ - QSettings settings(configFile(), QSettings::IniFormat); - settings.setValue(QLatin1String(macFileProviderModuleEnabledC), moduleEnabled); -} - } diff --git a/src/libsync/configfile.h b/src/libsync/configfile.h index 7ae1f98df207b..97ec16e2f5ad7 100644 --- a/src/libsync/configfile.h +++ b/src/libsync/configfile.h @@ -236,9 +236,6 @@ class OWNCLOUDSYNC_EXPORT ConfigFile [[nodiscard]] static QString discoveredLegacyConfigPath(); static void setDiscoveredLegacyConfigPath(const QString &discoveredLegacyConfigPath); - [[nodiscard]] bool macFileProviderModuleEnabled() const; - void setMacFileProviderModuleEnabled(const bool moduleEnabled); - protected: [[nodiscard]] QVariant getPolicySetting(const QString &policy, const QVariant &defaultValue = QVariant()) const; void storeData(const QString &group, const QString &key, const QVariant &value); From ee6c0816035996150b204c58548bb8744e17ea7b Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Wed, 6 Sep 2023 15:42:12 +0800 Subject: [PATCH 038/144] Enable file provider domains per the settings in the file provider domain manager Signed-off-by: Claudio Cambra --- src/gui/macOS/fileproviderdomainmanager_mac.mm | 14 +++++++++++++- src/gui/macOS/fileprovidersettingscontroller.h | 1 + .../macOS/fileprovidersettingscontroller_mac.mm | 5 +++++ 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/src/gui/macOS/fileproviderdomainmanager_mac.mm b/src/gui/macOS/fileproviderdomainmanager_mac.mm index d6c9acda6dc4b..3f3f3f7000da1 100644 --- a/src/gui/macOS/fileproviderdomainmanager_mac.mm +++ b/src/gui/macOS/fileproviderdomainmanager_mac.mm @@ -19,6 +19,7 @@ #include "config.h" #include "fileproviderdomainmanager.h" +#include "fileprovidersettingscontroller.h" #include "pushnotifications.h" #include "gui/accountmanager.h" @@ -447,10 +448,21 @@ QStringList configuredDomainIds() const d->findExistingFileProviderDomains(); - for(auto &accountState : AccountManager::instance()->accounts()) { + const auto vfsEnabledAccounts = FileProviderSettingsController::instance()->vfsEnabledAccounts(); + auto domainsToRemove = d->configuredDomainIds(); + + for (const auto &accountUserIdAtHost : vfsEnabledAccounts) { + domainsToRemove.removeAll(accountUserIdAtHost); + + const auto accountState = AccountManager::instance()->accountFromUserId(accountUserIdAtHost); addFileProviderDomainForAccount(accountState.data()); } + for (const auto &remainingDomainUserId : domainsToRemove) { + const auto accountState = AccountManager::instance()->accountFromUserId(remainingDomainUserId); + removeFileProviderDomainForAccount(accountState.data()); + } + emit domainSetupComplete(); } diff --git a/src/gui/macOS/fileprovidersettingscontroller.h b/src/gui/macOS/fileprovidersettingscontroller.h index 7b9d4fc5885df..880f13c359944 100644 --- a/src/gui/macOS/fileprovidersettingscontroller.h +++ b/src/gui/macOS/fileprovidersettingscontroller.h @@ -32,6 +32,7 @@ class FileProviderSettingsController : public QObject QWidget *const parent = nullptr, const QQuickWidget::ResizeMode resizeMode = QQuickWidget::SizeRootObjectToView); + [[nodiscard]] QStringList vfsEnabledAccounts() const; [[nodiscard]] Q_INVOKABLE bool vfsEnabledForAccount(const QString &userIdAtHost) const; public slots: diff --git a/src/gui/macOS/fileprovidersettingscontroller_mac.mm b/src/gui/macOS/fileprovidersettingscontroller_mac.mm index b9f3c5de71e0e..18dd0c115a0b0 100644 --- a/src/gui/macOS/fileprovidersettingscontroller_mac.mm +++ b/src/gui/macOS/fileprovidersettingscontroller_mac.mm @@ -183,6 +183,11 @@ void initialCheck() return settingsViewWidget; } +QStringList FileProviderSettingsController::vfsEnabledAccounts() const +{ + return d->enabledAccounts(); +} + bool FileProviderSettingsController::vfsEnabledForAccount(const QString &userIdAtHost) const { return d->vfsEnabledForAccount(userIdAtHost); From 15525bca62069e9d8fe036929e74e6092bafcb89 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Wed, 6 Sep 2023 15:44:34 +0800 Subject: [PATCH 039/144] Separate file provider domain updating into separate slot Signed-off-by: Claudio Cambra --- src/gui/macOS/fileproviderdomainmanager.h | 1 + src/gui/macOS/fileproviderdomainmanager_mac.mm | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/src/gui/macOS/fileproviderdomainmanager.h b/src/gui/macOS/fileproviderdomainmanager.h index 33347dc5e1a30..e2a5e9db37f7c 100644 --- a/src/gui/macOS/fileproviderdomainmanager.h +++ b/src/gui/macOS/fileproviderdomainmanager.h @@ -40,6 +40,7 @@ class FileProviderDomainManager : public QObject private slots: void setupFileProviderDomains(); + void updateFileProviderDomains(); void addFileProviderDomainForAccount(const OCC::AccountState * const accountState); void removeFileProviderDomainForAccount(const OCC::AccountState * const accountState); diff --git a/src/gui/macOS/fileproviderdomainmanager_mac.mm b/src/gui/macOS/fileproviderdomainmanager_mac.mm index 3f3f3f7000da1..5c17d0f90531b 100644 --- a/src/gui/macOS/fileproviderdomainmanager_mac.mm +++ b/src/gui/macOS/fileproviderdomainmanager_mac.mm @@ -447,6 +447,14 @@ QStringList configuredDomainIds() const } d->findExistingFileProviderDomains(); + updateFileProviderDomains(); +} + +void FileProviderDomainManager::updateFileProviderDomains() +{ + if (!d) { + return; + } const auto vfsEnabledAccounts = FileProviderSettingsController::instance()->vfsEnabledAccounts(); auto domainsToRemove = d->configuredDomainIds(); From e4aeb5b481ba7cb9f23adc43edba5eb851841dcf Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Wed, 6 Sep 2023 15:45:56 +0800 Subject: [PATCH 040/144] Update file provider domain enablement status upon settings change Signed-off-by: Claudio Cambra --- src/gui/macOS/fileproviderdomainmanager_mac.mm | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/gui/macOS/fileproviderdomainmanager_mac.mm b/src/gui/macOS/fileproviderdomainmanager_mac.mm index 5c17d0f90531b..900760c3e7bae 100644 --- a/src/gui/macOS/fileproviderdomainmanager_mac.mm +++ b/src/gui/macOS/fileproviderdomainmanager_mac.mm @@ -438,6 +438,9 @@ QStringList configuredDomainIds() const const auto trReason = tr("%1 application has been closed. Reopen to reconnect.").arg(APPLICATION_NAME); disconnectFileProviderDomainForAccount(accountState, trReason); }); + + connect(FileProviderSettingsController::instance(), &FileProviderSettingsController::vfsEnabledAccountsChanged, + this, &FileProviderDomainManager::updateFileProviderDomains); } void FileProviderDomainManager::setupFileProviderDomains() From 5aa7138643b5b3656f9768b0c15056c5f7e47509 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Wed, 6 Sep 2023 15:59:53 +0800 Subject: [PATCH 041/144] Do not bother trying to add a fp domain if we know it is active Signed-off-by: Claudio Cambra --- src/gui/macOS/fileproviderdomainmanager_mac.mm | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/gui/macOS/fileproviderdomainmanager_mac.mm b/src/gui/macOS/fileproviderdomainmanager_mac.mm index 900760c3e7bae..3fc0cb5535794 100644 --- a/src/gui/macOS/fileproviderdomainmanager_mac.mm +++ b/src/gui/macOS/fileproviderdomainmanager_mac.mm @@ -460,16 +460,19 @@ QStringList configuredDomainIds() const } const auto vfsEnabledAccounts = FileProviderSettingsController::instance()->vfsEnabledAccounts(); - auto domainsToRemove = d->configuredDomainIds(); + auto configuredDomains = d->configuredDomainIds(); for (const auto &accountUserIdAtHost : vfsEnabledAccounts) { - domainsToRemove.removeAll(accountUserIdAtHost); + if (configuredDomains.contains(accountUserIdAtHost)) { + configuredDomains.removeAll(accountUserIdAtHost); + continue; + } const auto accountState = AccountManager::instance()->accountFromUserId(accountUserIdAtHost); addFileProviderDomainForAccount(accountState.data()); } - for (const auto &remainingDomainUserId : domainsToRemove) { + for (const auto &remainingDomainUserId : configuredDomains) { const auto accountState = AccountManager::instance()->accountFromUserId(remainingDomainUserId); removeFileProviderDomainForAccount(accountState.data()); } From 97c963dcab430929f64c222615452d0652dafd54 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Wed, 6 Sep 2023 16:00:11 +0800 Subject: [PATCH 042/144] Remove fp domain id from registered domains when removal is confirmed Signed-off-by: Claudio Cambra --- src/gui/macOS/fileproviderdomainmanager_mac.mm | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/gui/macOS/fileproviderdomainmanager_mac.mm b/src/gui/macOS/fileproviderdomainmanager_mac.mm index 3fc0cb5535794..c185c953b8df5 100644 --- a/src/gui/macOS/fileproviderdomainmanager_mac.mm +++ b/src/gui/macOS/fileproviderdomainmanager_mac.mm @@ -224,6 +224,8 @@ void removeFileProviderDomain(const AccountState * const accountState) NSFileProviderDomain * const domain = _registeredDomains.take(domainId); [domain release]; + + _registeredDomains.remove(domainId); }]; } } From b83f0a51a954c01cee58302e13fb2a7ac6215589 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Thu, 14 Sep 2023 14:05:16 +0800 Subject: [PATCH 043/144] Add starter fileproviderstorageuseenumerationobserver Signed-off-by: Claudio Cambra --- src/gui/CMakeLists.txt | 8 +++++--- ...ileproviderstorageuseenumerationobserver.h | 20 +++++++++++++++++++ ...ileproviderstorageuseenumerationobserver.m | 19 ++++++++++++++++++ 3 files changed, 44 insertions(+), 3 deletions(-) create mode 100644 src/gui/macOS/fileproviderstorageuseenumerationobserver.h create mode 100644 src/gui/macOS/fileproviderstorageuseenumerationobserver.m diff --git a/src/gui/CMakeLists.txt b/src/gui/CMakeLists.txt index 1af5fdf3ba8d1..54fd32e6f159a 100644 --- a/src/gui/CMakeLists.txt +++ b/src/gui/CMakeLists.txt @@ -293,17 +293,19 @@ IF( APPLE ) macOS/fileprovider_mac.mm macOS/fileproviderdomainmanager.h macOS/fileproviderdomainmanager_mac.mm + macOS/fileprovidersettingscontroller.h + macOS/fileprovidersettingscontroller_mac.mm macOS/fileprovidersocketcontroller.h macOS/fileprovidersocketcontroller.cpp macOS/fileprovidersocketserver.h macOS/fileprovidersocketserver.cpp macOS/fileprovidersocketserver_mac.mm + macOS/fileproviderstorageuseenumerationobserver.h + macOS/fileproviderstorageuseenumerationobserver.m macOS/fileproviderxpc.h macOS/fileproviderxpc_mac.mm macOS/fileproviderxpc_mac_utils.h - macOS/fileproviderxpc_mac_utils.mm - macOS/fileprovidersettingscontroller.h - macOS/fileprovidersettingscontroller_mac.mm) + macOS/fileproviderxpc_mac_utils.mm) endif() if(SPARKLE_FOUND AND BUILD_UPDATER) diff --git a/src/gui/macOS/fileproviderstorageuseenumerationobserver.h b/src/gui/macOS/fileproviderstorageuseenumerationobserver.h new file mode 100644 index 0000000000000..f8fa74e1f3846 --- /dev/null +++ b/src/gui/macOS/fileproviderstorageuseenumerationobserver.h @@ -0,0 +1,20 @@ +/* + * Copyright (C) 2023 by Claudio Cambra + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#import +#import + +@interface FileProviderStorageUseEnumerationObserver : NSObject + +@end diff --git a/src/gui/macOS/fileproviderstorageuseenumerationobserver.m b/src/gui/macOS/fileproviderstorageuseenumerationobserver.m new file mode 100644 index 0000000000000..0f96c4df58a68 --- /dev/null +++ b/src/gui/macOS/fileproviderstorageuseenumerationobserver.m @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2023 by Claudio Cambra + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#import "fileproviderstorageuseenumerationobserver.m" + +@implementation FileProviderStorageuseEnumerationObserver + +@end From 435e25d75cca7d5e74432a60ac8adcce74f9713a Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Thu, 14 Sep 2023 15:36:27 +0800 Subject: [PATCH 044/144] Define ompletion block for fileproviderstorageuseenumerationobserver Signed-off-by: Claudio Cambra --- src/gui/macOS/fileproviderstorageuseenumerationobserver.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/gui/macOS/fileproviderstorageuseenumerationobserver.h b/src/gui/macOS/fileproviderstorageuseenumerationobserver.h index f8fa74e1f3846..33044576bb10d 100644 --- a/src/gui/macOS/fileproviderstorageuseenumerationobserver.h +++ b/src/gui/macOS/fileproviderstorageuseenumerationobserver.h @@ -15,6 +15,10 @@ #import #import +typedef void(^UsageEnumerationFinishedHandler)(NSNumber *const usage, NSError *const error); + @interface FileProviderStorageUseEnumerationObserver : NSObject +@property (readwrite) UsageEnumerationFinishedHandler enumerationFinishedHandler; // In bytes + @end From 8fdc69b3ccd355bfb1a4a410734b50123ca04286 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Thu, 14 Sep 2023 15:37:04 +0800 Subject: [PATCH 045/144] Calculate total storage use from enumerator for materialised files in fileproviderstorageuseenumerationobserver Signed-off-by: Claudio Cambra --- ...ileproviderstorageuseenumerationobserver.m | 37 ++++++++++++++++++- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/src/gui/macOS/fileproviderstorageuseenumerationobserver.m b/src/gui/macOS/fileproviderstorageuseenumerationobserver.m index 0f96c4df58a68..d63a54e8372d1 100644 --- a/src/gui/macOS/fileproviderstorageuseenumerationobserver.m +++ b/src/gui/macOS/fileproviderstorageuseenumerationobserver.m @@ -12,8 +12,41 @@ * for more details. */ -#import "fileproviderstorageuseenumerationobserver.m" +#import "fileproviderstorageuseenumerationobserver.h" -@implementation FileProviderStorageuseEnumerationObserver +@interface FileProviderStorageUseEnumerationObserver () + +@property (readwrite) NSNumber *usage; + +@end + +@implementation FileProviderStorageUseEnumerationObserver + +- (instancetype)init +{ + self = [super init]; + if (self) { + self.usage = @(0); + } + return self; +} + +// NSFileProviderEnumerationObserver protocol methods +- (void)didEnumerateItems:(NSArray> *)updatedItems +{ + for (const id item in updatedItems) { + self.usage = @(self.usage.unsignedLongLongValue + item.documentSize.unsignedLongLongValue); + } +} + +- (void)finishEnumeratingWithError:(NSError *)error +{ + self.enumerationFinishedHandler(nil, error); +} + +- (void)finishEnumeratingUpToPage:(NSFileProviderPage)nextPage +{ + self.enumerationFinishedHandler(self.usage, nil); +} @end From 21055966439f6027ee99b6962bcd7af6d46cfef1 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Thu, 14 Sep 2023 15:38:26 +0800 Subject: [PATCH 046/144] Fetch materialised files storage usage per account on creation of FileProviderSettingsController Signed-off-by: Claudio Cambra --- .../macOS/fileprovidersettingscontroller.h | 1 + .../fileprovidersettingscontroller_mac.mm | 39 +++++++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/src/gui/macOS/fileprovidersettingscontroller.h b/src/gui/macOS/fileprovidersettingscontroller.h index 880f13c359944..a17fbdfa93c62 100644 --- a/src/gui/macOS/fileprovidersettingscontroller.h +++ b/src/gui/macOS/fileprovidersettingscontroller.h @@ -40,6 +40,7 @@ public slots: signals: void vfsEnabledAccountsChanged(); + void vfsStorageUseForAccountChanged(const QString &userIdAtHost); private: explicit FileProviderSettingsController(QObject *parent = nullptr); diff --git a/src/gui/macOS/fileprovidersettingscontroller_mac.mm b/src/gui/macOS/fileprovidersettingscontroller_mac.mm index 18dd0c115a0b0..f95d3e8cb612f 100644 --- a/src/gui/macOS/fileprovidersettingscontroller_mac.mm +++ b/src/gui/macOS/fileprovidersettingscontroller_mac.mm @@ -20,6 +20,8 @@ // Objective-C imports #import + +#import "fileproviderstorageuseenumerationobserver.h" // End of Objective-C imports namespace { @@ -140,6 +142,41 @@ return (NSArray *)[_userDefaults objectForKey:_accountsKey]; } + void fetchMaterialisedFilesStorageUsage() + { + [NSFileProviderManager getDomainsWithCompletionHandler: ^(NSArray *const domains, NSError *const error) { + if (error != nil) { + qCWarning(lcFileProviderSettingsController) << "Could not get file provider domains:" << error.localizedDescription; + return; + } + + for (NSFileProviderDomain *const domain in domains) { + NSFileProviderManager *const managerForDomain = [NSFileProviderManager managerForDomain:domain]; + id enumerator = [managerForDomain enumeratorForMaterializedItems]; + FileProviderStorageUseEnumerationObserver *const storageUseObserver = [[FileProviderStorageUseEnumerationObserver alloc] init]; + + storageUseObserver.enumerationFinishedHandler = ^(NSNumber *const usage, NSError *const error) { + if (error != nil) { + qCWarning(lcFileProviderSettingsController) << "Error while enumerating storage use" << error.localizedDescription; + return; + } + + Q_ASSERT(usage != nil); + + // Remember that OCC::Account::userIdAtHost == domain.identifier for us + NSMutableDictionary *const mutableStorageDictCopy = _storageUsage.mutableCopy; + [mutableStorageDictCopy setObject:usage forKey:domain.identifier]; + _storageUsage = mutableStorageDictCopy.copy; + + const auto qDomainIdentifier = QString::fromNSString(domain.identifier); + emit q->vfsStorageUseForAccountChanged(qDomainIdentifier); + }; + + [enumerator enumerateItemsForObserver:storageUseObserver startingAtPage:NSFileProviderInitialPageSortedByName]; + } + }]; + } + void initialCheck() { NSArray *const vfsEnabledAccounts = nsEnabledAccounts(); @@ -151,11 +188,13 @@ void initialCheck() << "Enabling all accounts on initial setup."; [[maybe_unused]] const auto result = enableVfsForAllAccounts(); + fetchMaterialisedFilesStorageUsage(); } FileProviderSettingsController *q = nullptr; NSUserDefaults *_userDefaults = NSUserDefaults.standardUserDefaults; NSString *_accountsKey = [NSString stringWithUTF8String:enabledAccountsSettingsKey]; + NSDictionary *_storageUsage = @{}; }; FileProviderSettingsController *FileProviderSettingsController::instance() From 18ed46ef770adb0e62c5e58863184bdcd5748db0 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Thu, 14 Sep 2023 15:52:04 +0800 Subject: [PATCH 047/144] Expose local storage usage for account in gigabytes to QML Signed-off-by: Claudio Cambra --- .../macOS/fileprovidersettingscontroller.h | 4 +++- .../fileprovidersettingscontroller_mac.mm | 23 ++++++++++++++++++- 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/src/gui/macOS/fileprovidersettingscontroller.h b/src/gui/macOS/fileprovidersettingscontroller.h index a17fbdfa93c62..701dfdc1c503c 100644 --- a/src/gui/macOS/fileprovidersettingscontroller.h +++ b/src/gui/macOS/fileprovidersettingscontroller.h @@ -34,13 +34,15 @@ class FileProviderSettingsController : public QObject [[nodiscard]] QStringList vfsEnabledAccounts() const; [[nodiscard]] Q_INVOKABLE bool vfsEnabledForAccount(const QString &userIdAtHost) const; + [[nodiscard]] unsigned long long localStorageUsageForAccount(const QString &userIdAtHost) const; + [[nodiscard]] Q_INVOKABLE float localStorageUsageGbForAccount(const QString &userIdAtHost) const; public slots: void setVfsEnabledForAccount(const QString &userIdAtHost, const bool setEnabled); signals: void vfsEnabledAccountsChanged(); - void vfsStorageUseForAccountChanged(const QString &userIdAtHost); + void localStorageUsageForAccountChanged(const QString &userIdAtHost); private: explicit FileProviderSettingsController(QObject *parent = nullptr); diff --git a/src/gui/macOS/fileprovidersettingscontroller_mac.mm b/src/gui/macOS/fileprovidersettingscontroller_mac.mm index f95d3e8cb612f..03fdd912a73ba 100644 --- a/src/gui/macOS/fileprovidersettingscontroller_mac.mm +++ b/src/gui/macOS/fileprovidersettingscontroller_mac.mm @@ -133,7 +133,17 @@ } return overallActResult; + } + [[nodiscard]] unsigned long long localStorageUsageForAccount(const QString &userIdAtHost) const + { + // Return cached value as we fetch asynchronously on initialisation of this class. + // We will then emit a signal when the new value is found. + NSNumber *const storageUsage = [_storageUsage objectForKey:userIdAtHost.toNSString()]; + if (storageUsage == nil) { + return 0; + } + return storageUsage.unsignedLongLongValue; } private: @@ -169,7 +179,7 @@ void fetchMaterialisedFilesStorageUsage() _storageUsage = mutableStorageDictCopy.copy; const auto qDomainIdentifier = QString::fromNSString(domain.identifier); - emit q->vfsStorageUseForAccountChanged(qDomainIdentifier); + emit q->localStorageUsageForAccountChanged(qDomainIdentifier); }; [enumerator enumerateItemsForObserver:storageUseObserver startingAtPage:NSFileProviderInitialPageSortedByName]; @@ -240,6 +250,17 @@ void initialCheck() } } +unsigned long long FileProviderSettingsController::localStorageUsageForAccount(const QString &userIdAtHost) const +{ + return d->localStorageUsageForAccount(userIdAtHost); +} + +float FileProviderSettingsController::localStorageUsageGbForAccount(const QString &userIdAtHost) const +{ + static constexpr auto bytesIn100Mb = 1ULL * 1000ULL * 1000ULL * 100ULL; + return (float)(localStorageUsageForAccount(userIdAtHost) / bytesIn100Mb) / 10.0; +} + } // namespace Mac } // namespace OCC From 9105a4584ec720b21e624abd8d0ad68cc9171ee8 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Mon, 25 Sep 2023 22:10:28 +0800 Subject: [PATCH 048/144] Use NSUInteger directly when calculationg usage in FileProviderStorageUseEnumerationObserver Signed-off-by: Claudio Cambra --- .../fileproviderstorageuseenumerationobserver.m | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/gui/macOS/fileproviderstorageuseenumerationobserver.m b/src/gui/macOS/fileproviderstorageuseenumerationobserver.m index d63a54e8372d1..94ba10d8f19c8 100644 --- a/src/gui/macOS/fileproviderstorageuseenumerationobserver.m +++ b/src/gui/macOS/fileproviderstorageuseenumerationobserver.m @@ -16,7 +16,7 @@ @interface FileProviderStorageUseEnumerationObserver () -@property (readwrite) NSNumber *usage; +@property (readwrite) NSUInteger usage; @end @@ -26,7 +26,7 @@ - (instancetype)init { self = [super init]; if (self) { - self.usage = @(0); + self.usage = 0ULL; } return self; } @@ -35,18 +35,23 @@ - (instancetype)init - (void)didEnumerateItems:(NSArray> *)updatedItems { for (const id item in updatedItems) { - self.usage = @(self.usage.unsignedLongLongValue + item.documentSize.unsignedLongLongValue); + NSLog(@"StorageUseEnumerationObserver: Enumerating %@ with size %llu", item.filename, item.documentSize.unsignedLongLongValue); + self.usage += item.documentSize.unsignedLongLongValue; } } - (void)finishEnumeratingWithError:(NSError *)error { - self.enumerationFinishedHandler(nil, error); + dispatch_async(dispatch_get_main_queue(), ^{ + self.enumerationFinishedHandler(nil, error); + }); } - (void)finishEnumeratingUpToPage:(NSFileProviderPage)nextPage { - self.enumerationFinishedHandler(self.usage, nil); + dispatch_async(dispatch_get_main_queue(), ^{ + self.enumerationFinishedHandler(@(self.usage), nil); + }); } @end From 22a521d2a2175349ae638fd5351e0290e8f9d640 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Mon, 25 Sep 2023 22:15:19 +0800 Subject: [PATCH 049/144] Hold a strong reference to UsageEnumerationFinishedHandler Signed-off-by: Claudio Cambra --- src/gui/macOS/fileproviderstorageuseenumerationobserver.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/macOS/fileproviderstorageuseenumerationobserver.h b/src/gui/macOS/fileproviderstorageuseenumerationobserver.h index 33044576bb10d..db71414306815 100644 --- a/src/gui/macOS/fileproviderstorageuseenumerationobserver.h +++ b/src/gui/macOS/fileproviderstorageuseenumerationobserver.h @@ -19,6 +19,6 @@ typedef void(^UsageEnumerationFinishedHandler)(NSNumber *const usage, NSError *c @interface FileProviderStorageUseEnumerationObserver : NSObject -@property (readwrite) UsageEnumerationFinishedHandler enumerationFinishedHandler; // In bytes +@property (readwrite, strong) UsageEnumerationFinishedHandler enumerationFinishedHandler; @end From 4e8eab6cd9aec420e2254ad3e483c40ae24fa596 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Mon, 25 Sep 2023 22:16:02 +0800 Subject: [PATCH 050/144] Handle edge cases with materialised files enumeration and improve logging Signed-off-by: Claudio Cambra --- .../fileprovidersettingscontroller_mac.mm | 47 +++++++++++++++++-- 1 file changed, 43 insertions(+), 4 deletions(-) diff --git a/src/gui/macOS/fileprovidersettingscontroller_mac.mm b/src/gui/macOS/fileprovidersettingscontroller_mac.mm index 03fdd912a73ba..16250d0b624ec 100644 --- a/src/gui/macOS/fileprovidersettingscontroller_mac.mm +++ b/src/gui/macOS/fileprovidersettingscontroller_mac.mm @@ -52,6 +52,7 @@ { q = parent; initialCheck(); + fetchMaterialisedFilesStorageUsage(); }; ~MacImplementation() = default; @@ -154,20 +155,46 @@ void fetchMaterialisedFilesStorageUsage() { + qCDebug(lcFileProviderSettingsController) << "Fetching materialised files storage usage"; + [NSFileProviderManager getDomainsWithCompletionHandler: ^(NSArray *const domains, NSError *const error) { if (error != nil) { - qCWarning(lcFileProviderSettingsController) << "Could not get file provider domains:" << error.localizedDescription; + qCWarning(lcFileProviderSettingsController) << "Could not get file provider domains:" + << error.localizedDescription + << "Will try again in 2 secs"; + + // HACK: Sometimes the system is not in a state where it wants to give us access to + // the file provider domains. We will try again in 2 seconds and hope it works + __block const auto thisQobject = (QObject*)this; + dispatch_async(dispatch_get_main_queue(), ^{ + [NSTimer scheduledTimerWithTimeInterval:2 repeats:NO block:^(NSTimer *const timer) { + QMetaObject::invokeMethod(thisQobject, [this] { fetchMaterialisedFilesStorageUsage(); }); + }]; + }); return; } for (NSFileProviderDomain *const domain in domains) { + qCDebug(lcFileProviderSettingsController) << "Checking storage use for domain:" << domain.identifier; + NSFileProviderManager *const managerForDomain = [NSFileProviderManager managerForDomain:domain]; - id enumerator = [managerForDomain enumeratorForMaterializedItems]; + if (managerForDomain == nil) { + qCWarning(lcFileProviderSettingsController) << "Got a nil file provider manager for domain" + << domain.identifier + << ", returning early."; + return; + } + + const id enumerator = [managerForDomain enumeratorForMaterializedItems]; + Q_ASSERT(enumerator != nil); + FileProviderStorageUseEnumerationObserver *const storageUseObserver = [[FileProviderStorageUseEnumerationObserver alloc] init]; storageUseObserver.enumerationFinishedHandler = ^(NSNumber *const usage, NSError *const error) { if (error != nil) { qCWarning(lcFileProviderSettingsController) << "Error while enumerating storage use" << error.localizedDescription; + [storageUseObserver release]; + [enumerator release]; return; } @@ -175,20 +202,33 @@ void fetchMaterialisedFilesStorageUsage() // Remember that OCC::Account::userIdAtHost == domain.identifier for us NSMutableDictionary *const mutableStorageDictCopy = _storageUsage.mutableCopy; + + qCDebug(lcFileProviderSettingsController) << "Local storage use for" + << domain.identifier + << usage.unsignedLongLongValue; + [mutableStorageDictCopy setObject:usage forKey:domain.identifier]; _storageUsage = mutableStorageDictCopy.copy; const auto qDomainIdentifier = QString::fromNSString(domain.identifier); emit q->localStorageUsageForAccountChanged(qDomainIdentifier); + + [storageUseObserver release]; + [enumerator release]; }; [enumerator enumerateItemsForObserver:storageUseObserver startingAtPage:NSFileProviderInitialPageSortedByName]; + + [storageUseObserver retain]; + [enumerator retain]; } }]; } void initialCheck() { + qCDebug(lcFileProviderSettingsController) << "Running initial checks for file provider settings controller."; + NSArray *const vfsEnabledAccounts = nsEnabledAccounts(); if (vfsEnabledAccounts != nil) { return; @@ -198,7 +238,6 @@ void initialCheck() << "Enabling all accounts on initial setup."; [[maybe_unused]] const auto result = enableVfsForAllAccounts(); - fetchMaterialisedFilesStorageUsage(); } FileProviderSettingsController *q = nullptr; @@ -258,7 +297,7 @@ void initialCheck() float FileProviderSettingsController::localStorageUsageGbForAccount(const QString &userIdAtHost) const { static constexpr auto bytesIn100Mb = 1ULL * 1000ULL * 1000ULL * 100ULL; - return (float)(localStorageUsageForAccount(userIdAtHost) / bytesIn100Mb) / 10.0; + return ((localStorageUsageForAccount(userIdAtHost) * 1.0) / bytesIn100Mb) / 10.0; } } // namespace Mac From 7d229b569feb746871a7de5fdc677b82af21a842 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Tue, 26 Sep 2023 15:09:44 +0800 Subject: [PATCH 051/144] Move GB with decimal number calculation to function Signed-off-by: Claudio Cambra --- src/gui/macOS/fileprovidersettingscontroller_mac.mm | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/gui/macOS/fileprovidersettingscontroller_mac.mm b/src/gui/macOS/fileprovidersettingscontroller_mac.mm index 16250d0b624ec..cab013a95f2cc 100644 --- a/src/gui/macOS/fileprovidersettingscontroller_mac.mm +++ b/src/gui/macOS/fileprovidersettingscontroller_mac.mm @@ -32,6 +32,12 @@ // NSUserDefaults entries constexpr auto enabledAccountsSettingsKey = "enabledAccounts"; + +float gbFromBytesWithOneDecimal(const unsigned long long bytes) +{ + constexpr auto bytesIn100Mb = 1ULL * 1000ULL * 1000ULL * 100ULL; + return ((bytes * 1.0) / bytesIn100Mb) / 10.0; +} } // namespace namespace OCC { @@ -296,8 +302,7 @@ void initialCheck() float FileProviderSettingsController::localStorageUsageGbForAccount(const QString &userIdAtHost) const { - static constexpr auto bytesIn100Mb = 1ULL * 1000ULL * 1000ULL * 100ULL; - return ((localStorageUsageForAccount(userIdAtHost) * 1.0) / bytesIn100Mb) / 10.0; + return gbFromBytesWithOneDecimal(localStorageUsageForAccount(userIdAtHost)); } } // namespace Mac From f68965a2410ba20d4105d470f3e88d9c9518db20 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Tue, 26 Sep 2023 17:29:34 +0800 Subject: [PATCH 052/144] Fetch and store user info for accounts in file provider settings controller Signed-off-by: Claudio Cambra --- src/gui/macOS/fileprovidersettingscontroller.h | 4 ++++ src/gui/macOS/fileprovidersettingscontroller_mac.mm | 12 ++++++++++++ 2 files changed, 16 insertions(+) diff --git a/src/gui/macOS/fileprovidersettingscontroller.h b/src/gui/macOS/fileprovidersettingscontroller.h index 701dfdc1c503c..7c5ac9adceae2 100644 --- a/src/gui/macOS/fileprovidersettingscontroller.h +++ b/src/gui/macOS/fileprovidersettingscontroller.h @@ -19,6 +19,8 @@ namespace OCC { +class UserInfo; + namespace Mac { class FileProviderSettingsController : public QObject @@ -50,6 +52,8 @@ public slots: class MacImplementation; std::unique_ptr d; + + QHash _userInfos; }; } // Mac diff --git a/src/gui/macOS/fileprovidersettingscontroller_mac.mm b/src/gui/macOS/fileprovidersettingscontroller_mac.mm index cab013a95f2cc..1eaa55ec9c968 100644 --- a/src/gui/macOS/fileprovidersettingscontroller_mac.mm +++ b/src/gui/macOS/fileprovidersettingscontroller_mac.mm @@ -264,6 +264,18 @@ void initialCheck() : QObject{parent} { d = std::make_unique(this); + + const auto accManager = AccountManager::instance(); + const auto accountsList = accManager->accounts(); + + for (const auto &accountState : accountsList) { + const auto userInfo = new UserInfo(accountState.data(), false, false, this); + const auto account = accountState->account(); + const auto accountUserIdAtHost = account->userIdAtHostWithPort(); + + _userInfos.insert(accountUserIdAtHost, userInfo); + userInfo->setActive(true); + } } QQuickWidget *FileProviderSettingsController::settingsViewWidget(const QString &accountUserIdAtHost, From 679177eae271f3862c539414956f520613f66470 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Wed, 27 Sep 2023 11:10:49 +0800 Subject: [PATCH 053/144] Add property to file provider settings controller displaying remote file storage usage Signed-off-by: Claudio Cambra --- .../macOS/fileprovidersettingscontroller.h | 3 +++ .../fileprovidersettingscontroller_mac.mm | 20 +++++++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/src/gui/macOS/fileprovidersettingscontroller.h b/src/gui/macOS/fileprovidersettingscontroller.h index 7c5ac9adceae2..e5d934604881e 100644 --- a/src/gui/macOS/fileprovidersettingscontroller.h +++ b/src/gui/macOS/fileprovidersettingscontroller.h @@ -38,6 +38,8 @@ class FileProviderSettingsController : public QObject [[nodiscard]] Q_INVOKABLE bool vfsEnabledForAccount(const QString &userIdAtHost) const; [[nodiscard]] unsigned long long localStorageUsageForAccount(const QString &userIdAtHost) const; [[nodiscard]] Q_INVOKABLE float localStorageUsageGbForAccount(const QString &userIdAtHost) const; + [[nodiscard]] unsigned long long remoteStorageUsageForAccount(const QString &userIdAtHost) const; + [[nodiscard]] Q_INVOKABLE float remoteStorageUsageGbForAccount(const QString &userIdAtHost) const; public slots: void setVfsEnabledForAccount(const QString &userIdAtHost, const bool setEnabled); @@ -45,6 +47,7 @@ public slots: signals: void vfsEnabledAccountsChanged(); void localStorageUsageForAccountChanged(const QString &userIdAtHost); + void remoteStorageUsageForAccountChanged(const QString &userIdAtHost); private: explicit FileProviderSettingsController(QObject *parent = nullptr); diff --git a/src/gui/macOS/fileprovidersettingscontroller_mac.mm b/src/gui/macOS/fileprovidersettingscontroller_mac.mm index 1eaa55ec9c968..98e245414ba2d 100644 --- a/src/gui/macOS/fileprovidersettingscontroller_mac.mm +++ b/src/gui/macOS/fileprovidersettingscontroller_mac.mm @@ -17,6 +17,7 @@ #include #include "gui/systray.h" +#include "gui/userinfo.h" // Objective-C imports #import @@ -174,6 +175,7 @@ void fetchMaterialisedFilesStorageUsage() __block const auto thisQobject = (QObject*)this; dispatch_async(dispatch_get_main_queue(), ^{ [NSTimer scheduledTimerWithTimeInterval:2 repeats:NO block:^(NSTimer *const timer) { + Q_UNUSED(timer) QMetaObject::invokeMethod(thisQobject, [this] { fetchMaterialisedFilesStorageUsage(); }); }]; }); @@ -274,6 +276,9 @@ void initialCheck() const auto accountUserIdAtHost = account->userIdAtHostWithPort(); _userInfos.insert(accountUserIdAtHost, userInfo); + connect(userInfo, &UserInfo::fetchedLastInfo, this, [this, accountUserIdAtHost] { + emit remoteStorageUsageForAccountChanged(accountUserIdAtHost); + }); userInfo->setActive(true); } } @@ -317,6 +322,21 @@ void initialCheck() return gbFromBytesWithOneDecimal(localStorageUsageForAccount(userIdAtHost)); } +unsigned long long FileProviderSettingsController::remoteStorageUsageForAccount(const QString &userIdAtHost) const +{ + const auto userInfoForAccount = _userInfos.value(userIdAtHost); + if (!userInfoForAccount) { + return 0; + } + + return userInfoForAccount->lastQuotaUsedBytes(); +} + +float FileProviderSettingsController::remoteStorageUsageGbForAccount(const QString &userIdAtHost) const +{ + return gbFromBytesWithOneDecimal(remoteStorageUsageForAccount(userIdAtHost)); +} + } // namespace Mac } // namespace OCC From 02b47b47f800883c88c3284d4fd21c6d3a20de15 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Wed, 27 Sep 2023 11:14:14 +0800 Subject: [PATCH 054/144] Fix positioning fo elements in FileProviderSettings UI Signed-off-by: Claudio Cambra --- src/gui/macOS/ui/FileProviderSettings.qml | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/gui/macOS/ui/FileProviderSettings.qml b/src/gui/macOS/ui/FileProviderSettings.qml index 50f282b93f970..ff030deceefcd 100644 --- a/src/gui/macOS/ui/FileProviderSettings.qml +++ b/src/gui/macOS/ui/FileProviderSettings.qml @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022 by Claudio Cambra + * Copyright (C) 2023 by Claudio Cambra * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -60,13 +60,23 @@ Page { padding: Style.standardSpacing ColumnLayout { + anchors { + top: parent.top + left: parent.left + right: parent.right + } + EnforcedPlainTextLabel { + Layout.fillWidth: true text: qsTr("General settings") font.bold: true font.pointSize: root.font.pointSize + 2 + elide: Text.ElideRight } CheckBox { + id: vfsEnabledCheckBox + Layout.fillWidth: true text: qsTr("Enable virtual files") checked: root.controller.vfsEnabledForAccount(root.accountUserIdAtHost) onClicked: root.controller.setVfsEnabledForAccount(root.accountUserIdAtHost, checked) From 0b8a2315a02932e6a96334258d5358c1622b8da5 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Thu, 28 Sep 2023 17:48:47 +0800 Subject: [PATCH 055/144] Leave usage as a property of materialised files enumerator Do this instead of passing as variable in completion handler Signed-off-by: Claudio Cambra --- .../macOS/fileprovidersettingscontroller_mac.mm | 10 +++++----- .../fileproviderstorageuseenumerationobserver.h | 3 ++- .../fileproviderstorageuseenumerationobserver.m | 17 +++++++---------- 3 files changed, 14 insertions(+), 16 deletions(-) diff --git a/src/gui/macOS/fileprovidersettingscontroller_mac.mm b/src/gui/macOS/fileprovidersettingscontroller_mac.mm index 98e245414ba2d..0459085e1db87 100644 --- a/src/gui/macOS/fileprovidersettingscontroller_mac.mm +++ b/src/gui/macOS/fileprovidersettingscontroller_mac.mm @@ -196,9 +196,9 @@ void fetchMaterialisedFilesStorageUsage() const id enumerator = [managerForDomain enumeratorForMaterializedItems]; Q_ASSERT(enumerator != nil); - FileProviderStorageUseEnumerationObserver *const storageUseObserver = [[FileProviderStorageUseEnumerationObserver alloc] init]; + __block FileProviderStorageUseEnumerationObserver *const storageUseObserver = [[FileProviderStorageUseEnumerationObserver alloc] init]; - storageUseObserver.enumerationFinishedHandler = ^(NSNumber *const usage, NSError *const error) { + storageUseObserver.enumerationFinishedHandler = ^(NSError *const error) { if (error != nil) { qCWarning(lcFileProviderSettingsController) << "Error while enumerating storage use" << error.localizedDescription; [storageUseObserver release]; @@ -206,16 +206,16 @@ void fetchMaterialisedFilesStorageUsage() return; } - Q_ASSERT(usage != nil); + const NSUInteger usage = storageUseObserver.usage; // Remember that OCC::Account::userIdAtHost == domain.identifier for us NSMutableDictionary *const mutableStorageDictCopy = _storageUsage.mutableCopy; qCDebug(lcFileProviderSettingsController) << "Local storage use for" << domain.identifier - << usage.unsignedLongLongValue; + << usage; - [mutableStorageDictCopy setObject:usage forKey:domain.identifier]; + [mutableStorageDictCopy setObject:@(usage) forKey:domain.identifier]; _storageUsage = mutableStorageDictCopy.copy; const auto qDomainIdentifier = QString::fromNSString(domain.identifier); diff --git a/src/gui/macOS/fileproviderstorageuseenumerationobserver.h b/src/gui/macOS/fileproviderstorageuseenumerationobserver.h index db71414306815..285b159c3ae7b 100644 --- a/src/gui/macOS/fileproviderstorageuseenumerationobserver.h +++ b/src/gui/macOS/fileproviderstorageuseenumerationobserver.h @@ -15,10 +15,11 @@ #import #import -typedef void(^UsageEnumerationFinishedHandler)(NSNumber *const usage, NSError *const error); +typedef void(^UsageEnumerationFinishedHandler)(NSError *const error); @interface FileProviderStorageUseEnumerationObserver : NSObject @property (readwrite, strong) UsageEnumerationFinishedHandler enumerationFinishedHandler; +@property (readonly) NSUInteger usage; @end diff --git a/src/gui/macOS/fileproviderstorageuseenumerationobserver.m b/src/gui/macOS/fileproviderstorageuseenumerationobserver.m index 94ba10d8f19c8..c88fa8228e379 100644 --- a/src/gui/macOS/fileproviderstorageuseenumerationobserver.m +++ b/src/gui/macOS/fileproviderstorageuseenumerationobserver.m @@ -14,11 +14,6 @@ #import "fileproviderstorageuseenumerationobserver.h" -@interface FileProviderStorageUseEnumerationObserver () - -@property (readwrite) NSUInteger usage; - -@end @implementation FileProviderStorageUseEnumerationObserver @@ -26,7 +21,7 @@ - (instancetype)init { self = [super init]; if (self) { - self.usage = 0ULL; + _usage = 0ULL; } return self; } @@ -35,22 +30,24 @@ - (instancetype)init - (void)didEnumerateItems:(NSArray> *)updatedItems { for (const id item in updatedItems) { - NSLog(@"StorageUseEnumerationObserver: Enumerating %@ with size %llu", item.filename, item.documentSize.unsignedLongLongValue); - self.usage += item.documentSize.unsignedLongLongValue; + NSLog(@"StorageUseEnumerationObserver: Enumerating %@ with size %llu", + item.filename, item.documentSize.unsignedLongLongValue); + + _usage += item.documentSize.unsignedLongLongValue; } } - (void)finishEnumeratingWithError:(NSError *)error { dispatch_async(dispatch_get_main_queue(), ^{ - self.enumerationFinishedHandler(nil, error); + self.enumerationFinishedHandler(error); }); } - (void)finishEnumeratingUpToPage:(NSFileProviderPage)nextPage { dispatch_async(dispatch_get_main_queue(), ^{ - self.enumerationFinishedHandler(@(self.usage), nil); + self.enumerationFinishedHandler(nil); }); } From c3490db27196dd1f57170efb0809104faf3e77d4 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Thu, 28 Sep 2023 19:48:54 +0800 Subject: [PATCH 056/144] Keep track of materialised files in storageuseenumerationobserver Signed-off-by: Claudio Cambra --- src/gui/macOS/fileproviderstorageuseenumerationobserver.h | 1 + src/gui/macOS/fileproviderstorageuseenumerationobserver.m | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/src/gui/macOS/fileproviderstorageuseenumerationobserver.h b/src/gui/macOS/fileproviderstorageuseenumerationobserver.h index 285b159c3ae7b..897c865c9b235 100644 --- a/src/gui/macOS/fileproviderstorageuseenumerationobserver.h +++ b/src/gui/macOS/fileproviderstorageuseenumerationobserver.h @@ -21,5 +21,6 @@ typedef void(^UsageEnumerationFinishedHandler)(NSError *const error); @property (readwrite, strong) UsageEnumerationFinishedHandler enumerationFinishedHandler; @property (readonly) NSUInteger usage; +@property (readonly) NSSet> *materialisedItems; @end diff --git a/src/gui/macOS/fileproviderstorageuseenumerationobserver.m b/src/gui/macOS/fileproviderstorageuseenumerationobserver.m index c88fa8228e379..7ffc1a0b2bc6d 100644 --- a/src/gui/macOS/fileproviderstorageuseenumerationobserver.m +++ b/src/gui/macOS/fileproviderstorageuseenumerationobserver.m @@ -29,12 +29,17 @@ - (instancetype)init // NSFileProviderEnumerationObserver protocol methods - (void)didEnumerateItems:(NSArray> *)updatedItems { + NSMutableSet> * const existingItems = self.materialisedItems.mutableCopy; + for (const id item in updatedItems) { NSLog(@"StorageUseEnumerationObserver: Enumerating %@ with size %llu", item.filename, item.documentSize.unsignedLongLongValue); _usage += item.documentSize.unsignedLongLongValue; + [existingItems addObject:item]; } + + _materialisedItems = existingItems.copy; } - (void)finishEnumeratingWithError:(NSError *)error From fec9902a25336e50ef3f3371e7a58568f6bfa7d4 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Thu, 28 Sep 2023 19:59:45 +0800 Subject: [PATCH 057/144] Store materialised file metadata in file provider settings controller Signed-off-by: Claudio Cambra --- src/gui/macOS/fileprovidersettingscontroller_mac.mm | 7 +++++++ src/gui/macOS/fileproviderstorageuseenumerationobserver.m | 1 + 2 files changed, 8 insertions(+) diff --git a/src/gui/macOS/fileprovidersettingscontroller_mac.mm b/src/gui/macOS/fileprovidersettingscontroller_mac.mm index 0459085e1db87..15a3329ed51e4 100644 --- a/src/gui/macOS/fileprovidersettingscontroller_mac.mm +++ b/src/gui/macOS/fileprovidersettingscontroller_mac.mm @@ -207,16 +207,22 @@ void fetchMaterialisedFilesStorageUsage() } const NSUInteger usage = storageUseObserver.usage; + NSSet> *const items = storageUseObserver.materialisedItems; + Q_ASSERT(items != nil); // Remember that OCC::Account::userIdAtHost == domain.identifier for us NSMutableDictionary *const mutableStorageDictCopy = _storageUsage.mutableCopy; + NSMutableDictionary> *> *const mutableFilesDictCopy = _materialisedFiles.mutableCopy; qCDebug(lcFileProviderSettingsController) << "Local storage use for" << domain.identifier << usage; [mutableStorageDictCopy setObject:@(usage) forKey:domain.identifier]; + [mutableFilesDictCopy setObject:items forKey:domain.identifier]; + _storageUsage = mutableStorageDictCopy.copy; + _materialisedFiles = mutableFilesDictCopy.copy; const auto qDomainIdentifier = QString::fromNSString(domain.identifier); emit q->localStorageUsageForAccountChanged(qDomainIdentifier); @@ -252,6 +258,7 @@ void initialCheck() NSUserDefaults *_userDefaults = NSUserDefaults.standardUserDefaults; NSString *_accountsKey = [NSString stringWithUTF8String:enabledAccountsSettingsKey]; NSDictionary *_storageUsage = @{}; + NSDictionary > *> *_materialisedFiles = @{}; }; FileProviderSettingsController *FileProviderSettingsController::instance() diff --git a/src/gui/macOS/fileproviderstorageuseenumerationobserver.m b/src/gui/macOS/fileproviderstorageuseenumerationobserver.m index 7ffc1a0b2bc6d..37981fe22b2d4 100644 --- a/src/gui/macOS/fileproviderstorageuseenumerationobserver.m +++ b/src/gui/macOS/fileproviderstorageuseenumerationobserver.m @@ -22,6 +22,7 @@ - (instancetype)init self = [super init]; if (self) { _usage = 0ULL; + _materialisedItems = [NSSet set]; } return self; } From 57d1dc84aa9fd0bbe89967b8bf280571ff17ef34 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Thu, 28 Sep 2023 20:45:19 +0800 Subject: [PATCH 058/144] Add a Qt-based data class for file provider items Signed-off-by: Claudio Cambra --- src/gui/CMakeLists.txt | 2 + src/gui/macOS/fileprovideritemmetadata.cpp | 168 +++++++++++++++++++++ src/gui/macOS/fileprovideritemmetadata.h | 125 +++++++++++++++ 3 files changed, 295 insertions(+) create mode 100644 src/gui/macOS/fileprovideritemmetadata.cpp create mode 100644 src/gui/macOS/fileprovideritemmetadata.h diff --git a/src/gui/CMakeLists.txt b/src/gui/CMakeLists.txt index 54fd32e6f159a..faa3a6761ac44 100644 --- a/src/gui/CMakeLists.txt +++ b/src/gui/CMakeLists.txt @@ -293,6 +293,8 @@ IF( APPLE ) macOS/fileprovider_mac.mm macOS/fileproviderdomainmanager.h macOS/fileproviderdomainmanager_mac.mm + macOS/fileprovideritemmetadata.h + macOS/fileprovideritemmetadata.cpp macOS/fileprovidersettingscontroller.h macOS/fileprovidersettingscontroller_mac.mm macOS/fileprovidersocketcontroller.h diff --git a/src/gui/macOS/fileprovideritemmetadata.cpp b/src/gui/macOS/fileprovideritemmetadata.cpp new file mode 100644 index 0000000000000..cec1dfa79e8fd --- /dev/null +++ b/src/gui/macOS/fileprovideritemmetadata.cpp @@ -0,0 +1,168 @@ +/* + * Copyright (C) 2023 by Claudio Cambra + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "fileprovideritemmetadata.h" + +namespace OCC { + +namespace Mac { + +QString FileProviderItemMetadata::identifier() const +{ + return _identifier; +} + +QString FileProviderItemMetadata::parentItemIdentifier() const +{ + return _parentItemIdentifier; +} + +QString FileProviderItemMetadata::filename() const +{ + return _filename; +} + +QString FileProviderItemMetadata::typeIdentifier() const +{ + return _typeIdentifier; +} + +QString FileProviderItemMetadata::symlinkTargetPath() const +{ + return _symlinkTargetPath; +} + +QString FileProviderItemMetadata::uploadingError() const +{ + return _uploadingError; +} + +QString FileProviderItemMetadata::downloadingError() const +{ + return _downloadingError; +} + +QString FileProviderItemMetadata::mostRecentEditorName() const +{ + return _mostRecentEditorName; +} + +QString FileProviderItemMetadata::ownerName() const +{ + return _ownerName; +} + +QDateTime FileProviderItemMetadata::contentModificationDate() const +{ + return _contentModificationDate; +} + +QDateTime FileProviderItemMetadata::creationDate() const +{ + return _creationDate; +} + +QDateTime FileProviderItemMetadata::lastUsedDate() const +{ + return _lastUsedDate; +} + +QByteArray FileProviderItemMetadata::contentVersion() const +{ + return _contentVersion; +} + +QByteArray FileProviderItemMetadata::metadataVersion() const +{ + return _metadataVersion; +} + +QByteArray FileProviderItemMetadata::tagData() const +{ + return _tagData; +} + +QHash FileProviderItemMetadata::extendedAttributes() const +{ + return _extendedAttributes; +} + +int FileProviderItemMetadata::capabilities() const +{ + return _capabilities; +} + +int FileProviderItemMetadata::fileSystemFlags() const +{ + return _fileSystemFlags; +} + +unsigned int FileProviderItemMetadata::childItemCount() const +{ + return _childItemCount; +} + +unsigned int FileProviderItemMetadata::typeOsCode() const +{ + return _typeOsCode; +} + +unsigned int FileProviderItemMetadata::creatorOsCode() const +{ + return _creatorOsCode; +} + +unsigned long long FileProviderItemMetadata::documentSize() const +{ + return _documentSize; +} + +bool FileProviderItemMetadata::mostRecentVersionDownloaded() const +{ + return _mostRecentVersionDownloaded; +} + +bool FileProviderItemMetadata::uploading() const +{ + return _uploading; +} + +bool FileProviderItemMetadata::uploaded() const +{ + return _uploaded; +} + +bool FileProviderItemMetadata::downloading() const +{ + return _downloading; +} + +bool FileProviderItemMetadata::downloaded() const +{ + return _downloaded; +} + +bool FileProviderItemMetadata::shared() const +{ + return _shared; +} + +bool FileProviderItemMetadata::sharedByCurrentUser() const +{ + return _sharedByCurrentUser; +} + +} + +} diff --git a/src/gui/macOS/fileprovideritemmetadata.h b/src/gui/macOS/fileprovideritemmetadata.h new file mode 100644 index 0000000000000..82b91bf5f580e --- /dev/null +++ b/src/gui/macOS/fileprovideritemmetadata.h @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2023 by Claudio Cambra + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#pragma once + +#include +#include + +namespace OCC { + +namespace Mac { + +class FileProviderItemMetadata +{ + Q_GADGET + + Q_PROPERTY(QString identifier READ identifier CONSTANT) + Q_PROPERTY(QString parentItemIdentifier READ parentItemIdentifier CONSTANT) + Q_PROPERTY(QString filename READ filename CONSTANT) + Q_PROPERTY(QString typeIdentifier READ typeIdentifier CONSTANT) + Q_PROPERTY(QString symlinkTargetPath READ symlinkTargetPath CONSTANT) + Q_PROPERTY(QString uploadingError READ uploadingError CONSTANT) + Q_PROPERTY(QString downloadingError READ downloadingError CONSTANT) + Q_PROPERTY(QString mostRecentEditorName READ mostRecentEditorName CONSTANT) + Q_PROPERTY(QString ownerName READ ownerName CONSTANT) + Q_PROPERTY(QDateTime contentModificationDate READ contentModificationDate CONSTANT) + Q_PROPERTY(QDateTime creationDate READ creationDate CONSTANT) + Q_PROPERTY(QDateTime lastUsedDate READ lastUsedDate CONSTANT) + Q_PROPERTY(QByteArray contentVersion READ contentVersion CONSTANT) + Q_PROPERTY(QByteArray metadataVersion READ metadataVersion CONSTANT) + Q_PROPERTY(QByteArray tagData READ tagData CONSTANT) + Q_PROPERTY(QHash extendedAttributes READ extendedAttributes CONSTANT) + Q_PROPERTY(int capabilities READ capabilities CONSTANT) + Q_PROPERTY(int fileSystemFlags READ fileSystemFlags CONSTANT) + Q_PROPERTY(unsigned int childItemCount READ childItemCount CONSTANT) + Q_PROPERTY(unsigned int typeOsCode READ typeOsCode CONSTANT) + Q_PROPERTY(unsigned int creatorOsCode READ creatorOsCode CONSTANT) + Q_PROPERTY(unsigned long long documentSize READ documentSize CONSTANT) + Q_PROPERTY(bool mostRecentVersionDownloaded READ mostRecentVersionDownloaded CONSTANT) + Q_PROPERTY(bool uploading READ uploading CONSTANT) + Q_PROPERTY(bool uploaded READ uploaded CONSTANT) + Q_PROPERTY(bool downloading READ downloading CONSTANT) + Q_PROPERTY(bool downloaded READ downloaded CONSTANT) + Q_PROPERTY(bool shared READ shared CONSTANT) + Q_PROPERTY(bool sharedByCurrentUser READ sharedByCurrentUser CONSTANT) + +public: + QString identifier() const; + QString parentItemIdentifier() const; + QString filename() const; + QString typeIdentifier() const; + QString symlinkTargetPath() const; + QString uploadingError() const; + QString downloadingError() const; + QString mostRecentEditorName() const; + QString ownerName() const; + QDateTime contentModificationDate() const; + QDateTime creationDate() const; + QDateTime lastUsedDate() const; + QByteArray contentVersion() const; + QByteArray metadataVersion() const; + QByteArray tagData() const; + QHash extendedAttributes() const; + int capabilities() const; + int fileSystemFlags() const; + unsigned int childItemCount() const; + unsigned int typeOsCode() const; + unsigned int creatorOsCode() const; + unsigned long long documentSize() const; + bool mostRecentVersionDownloaded() const; + bool uploading() const; + bool uploaded() const; + bool downloading() const; + bool downloaded() const; + bool shared() const; + bool sharedByCurrentUser() const; + +private: + QString _identifier; + QString _parentItemIdentifier; + QString _filename; + QString _typeIdentifier; + QString _symlinkTargetPath; + QString _uploadingError; + QString _downloadingError; + QString _mostRecentEditorName; + QString _ownerName; + QDateTime _contentModificationDate; + QDateTime _creationDate; + QDateTime _lastUsedDate; + QByteArray _contentVersion; + QByteArray _metadataVersion; + QByteArray _tagData; + QHash _extendedAttributes; + quint64 _favoriteRank = 0; + int _capabilities = 0; + int _fileSystemFlags = 0; + unsigned int _childItemCount = 0; + unsigned int _typeOsCode = 0; + unsigned int _creatorOsCode = 0; + unsigned long long _documentSize = 0; + bool _mostRecentVersionDownloaded = false; + bool _uploading = false; + bool _uploaded = false; + bool _downloading = false; + bool _downloaded = false; + bool _shared = false; + bool _sharedByCurrentUser = false; + bool _trashed = false; +}; + +} + +} From a34a390790dca30e34a00e8c4a809abfb1c95179 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Fri, 29 Sep 2023 00:38:12 +0800 Subject: [PATCH 059/144] Add a convenience function to convert from nsnamecomponents to qstring Signed-off-by: Claudio Cambra --- src/gui/CMakeLists.txt | 1 + src/gui/macOS/fileprovideritemmetadata_mac.mm | 33 +++++++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 src/gui/macOS/fileprovideritemmetadata_mac.mm diff --git a/src/gui/CMakeLists.txt b/src/gui/CMakeLists.txt index faa3a6761ac44..957b582722e86 100644 --- a/src/gui/CMakeLists.txt +++ b/src/gui/CMakeLists.txt @@ -295,6 +295,7 @@ IF( APPLE ) macOS/fileproviderdomainmanager_mac.mm macOS/fileprovideritemmetadata.h macOS/fileprovideritemmetadata.cpp + macOS/fileprovideritemmetadata_mac.mm macOS/fileprovidersettingscontroller.h macOS/fileprovidersettingscontroller_mac.mm macOS/fileprovidersocketcontroller.h diff --git a/src/gui/macOS/fileprovideritemmetadata_mac.mm b/src/gui/macOS/fileprovideritemmetadata_mac.mm new file mode 100644 index 0000000000000..2123f2008c5ed --- /dev/null +++ b/src/gui/macOS/fileprovideritemmetadata_mac.mm @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2023 by Claudio Cambra + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "fileprovideritemmetadata.h" + +#import +#import +#import + +namespace { + +QString nsNameComponentsToLocalisedQString(NSPersonNameComponents *const nameComponents) +{ + if (nameComponents == nil) { + return {}; + } + + NSString *const name = [NSPersonNameComponentsFormatter localizedStringFromPersonNameComponents:nameComponents style:NSPersonNameComponentsFormatterStyleDefault options:0]; + return QString::fromNSString(name); +} + +} From e3a0dabb07b4947d6e0b0a6a0b9301b7c95b68a6 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Fri, 29 Sep 2023 01:23:06 +0800 Subject: [PATCH 060/144] Add convenience function to convert extendedAttributes to QHash Signed-off-by: Claudio Cambra --- src/gui/macOS/fileprovideritemmetadata_mac.mm | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/gui/macOS/fileprovideritemmetadata_mac.mm b/src/gui/macOS/fileprovideritemmetadata_mac.mm index 2123f2008c5ed..5521baa463d16 100644 --- a/src/gui/macOS/fileprovideritemmetadata_mac.mm +++ b/src/gui/macOS/fileprovideritemmetadata_mac.mm @@ -30,4 +30,14 @@ QString nsNameComponentsToLocalisedQString(NSPersonNameComponents *const nameCom return QString::fromNSString(name); } +QHash extendedAttributesToHash(NSDictionary *const extendedAttributes) +{ + QHash hash; + for (NSString *const key in extendedAttributes) { + NSData *const value = [extendedAttributes objectForKey:key]; + hash.insert(QString::fromNSString(key), QByteArray::fromNSData(value)); + } + return hash; +} + } From 134eae63dd7246ba0bb1e1ff73e7d031ce7bba6d Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Fri, 29 Sep 2023 01:24:01 +0800 Subject: [PATCH 061/144] Add static convenience method to FileProviderItemMetadata to convert from NSFileProviderItem Signed-off-by: Claudio Cambra --- src/gui/macOS/fileprovideritemmetadata.h | 2 + src/gui/macOS/fileprovideritemmetadata_mac.mm | 49 +++++++++++++++++++ 2 files changed, 51 insertions(+) diff --git a/src/gui/macOS/fileprovideritemmetadata.h b/src/gui/macOS/fileprovideritemmetadata.h index 82b91bf5f580e..6ec4c0aca7f74 100644 --- a/src/gui/macOS/fileprovideritemmetadata.h +++ b/src/gui/macOS/fileprovideritemmetadata.h @@ -56,6 +56,8 @@ class FileProviderItemMetadata Q_PROPERTY(bool sharedByCurrentUser READ sharedByCurrentUser CONSTANT) public: + static FileProviderItemMetadata fromNSFileProviderItem(const void *const nsFileProviderItem); + QString identifier() const; QString parentItemIdentifier() const; QString filename() const; diff --git a/src/gui/macOS/fileprovideritemmetadata_mac.mm b/src/gui/macOS/fileprovideritemmetadata_mac.mm index 5521baa463d16..9248873ffbc96 100644 --- a/src/gui/macOS/fileprovideritemmetadata_mac.mm +++ b/src/gui/macOS/fileprovideritemmetadata_mac.mm @@ -41,3 +41,52 @@ QString nsNameComponentsToLocalisedQString(NSPersonNameComponents *const nameCom } } + +namespace OCC { + +namespace Mac { + +FileProviderItemMetadata FileProviderItemMetadata::fromNSFileProviderItem(const void *const nsFileProviderItem) +{ + FileProviderItemMetadata metadata; + const id bridgedNsFileProviderItem = (__bridge id)nsFileProviderItem; + if (bridgedNsFileProviderItem == nil) { + return {}; + } + + metadata._identifier = QString::fromNSString(bridgedNsFileProviderItem.itemIdentifier); + metadata._parentItemIdentifier = QString::fromNSString(bridgedNsFileProviderItem.parentItemIdentifier); + metadata._filename = QString::fromNSString(bridgedNsFileProviderItem.filename); + metadata._typeIdentifier = QString::fromNSString(bridgedNsFileProviderItem.contentType.identifier); + metadata._symlinkTargetPath = QString::fromNSString(bridgedNsFileProviderItem.symlinkTargetPath); + metadata._uploadingError = QString::fromNSString(bridgedNsFileProviderItem.uploadingError.localizedDescription); + metadata._downloadingError = QString::fromNSString(bridgedNsFileProviderItem.downloadingError.localizedDescription); + metadata._mostRecentEditorName = nsNameComponentsToLocalisedQString(bridgedNsFileProviderItem.mostRecentEditorNameComponents); + metadata._ownerName = nsNameComponentsToLocalisedQString(bridgedNsFileProviderItem.ownerNameComponents); + metadata._contentModificationDate = QDateTime::fromNSDate(bridgedNsFileProviderItem.contentModificationDate); + metadata._creationDate = QDateTime::fromNSDate(bridgedNsFileProviderItem.creationDate); + metadata._lastUsedDate = QDateTime::fromNSDate(bridgedNsFileProviderItem.lastUsedDate); + metadata._contentVersion = QByteArray::fromNSData(bridgedNsFileProviderItem.itemVersion.contentVersion); + metadata._metadataVersion = QByteArray::fromNSData(bridgedNsFileProviderItem.itemVersion.metadataVersion); + metadata._tagData = QByteArray::fromNSData(bridgedNsFileProviderItem.tagData); + metadata._extendedAttributes = extendedAttributesToHash(bridgedNsFileProviderItem.extendedAttributes); + metadata._capabilities = bridgedNsFileProviderItem.capabilities; + metadata._fileSystemFlags = bridgedNsFileProviderItem.fileSystemFlags; + metadata._childItemCount = bridgedNsFileProviderItem.childItemCount.unsignedIntegerValue; + metadata._typeOsCode = bridgedNsFileProviderItem.typeAndCreator.type; + metadata._creatorOsCode = bridgedNsFileProviderItem.typeAndCreator.creator; + metadata._documentSize = bridgedNsFileProviderItem.documentSize.unsignedLongLongValue; + metadata._mostRecentVersionDownloaded = bridgedNsFileProviderItem.mostRecentVersionDownloaded; + metadata._uploading = bridgedNsFileProviderItem.uploading; + metadata._uploaded = bridgedNsFileProviderItem.uploaded; + metadata._downloading = bridgedNsFileProviderItem.downloading; + metadata._downloaded = bridgedNsFileProviderItem.downloaded; + metadata._shared = bridgedNsFileProviderItem.shared; + metadata._sharedByCurrentUser = bridgedNsFileProviderItem.sharedByCurrentUser; + + return metadata; +} + +} + +} From 389e663219dbbcc84bc7de3d7c03ea6eaae210a2 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Fri, 29 Sep 2023 01:25:10 +0800 Subject: [PATCH 062/144] Add method to get qtified file provider item metadata for account in FileProviderSettingsController Signed-off-by: Claudio Cambra --- .../fileprovidersettingscontroller_mac.mm | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/gui/macOS/fileprovidersettingscontroller_mac.mm b/src/gui/macOS/fileprovidersettingscontroller_mac.mm index 15a3329ed51e4..61189b4d51632 100644 --- a/src/gui/macOS/fileprovidersettingscontroller_mac.mm +++ b/src/gui/macOS/fileprovidersettingscontroller_mac.mm @@ -18,6 +18,7 @@ #include "gui/systray.h" #include "gui/userinfo.h" +#include "gui/macOS/fileprovideritemmetadata.h" // Objective-C imports #import @@ -154,6 +155,24 @@ float gbFromBytesWithOneDecimal(const unsigned long long bytes) return storageUsage.unsignedLongLongValue; } + [[nodiscard]] QVector materialisedItemsForAccount(const QString &userIdAtHost) const + { + const auto materialisedItems = [_materialisedFiles objectForKey:userIdAtHost.toNSString()]; + if (materialisedItems == nil) { + return {}; + } + + QVector qMaterialisedItems; + qMaterialisedItems.reserve(materialisedItems.count); + + for (const id item in materialisedItems) { + const auto itemMetadata = FileProviderItemMetadata::fromNSFileProviderItem(item); + qMaterialisedItems.append(itemMetadata); + } + + return qMaterialisedItems; + } + private: [[nodiscard]] NSArray *nsEnabledAccounts() const { From 269fb03351d37d18ac2b82879d2bcf1e4f12fa0a Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Tue, 10 Oct 2023 11:30:29 +0800 Subject: [PATCH 063/144] Add starter FileProviderMaterialisedItemsModel Signed-off-by: Claudio Cambra --- src/gui/CMakeLists.txt | 2 + .../fileprovidermaterialiseditemsmodel.cpp | 38 +++++++++++++++++++ .../fileprovidermaterialiseditemsmodel.h | 35 +++++++++++++++++ 3 files changed, 75 insertions(+) create mode 100644 src/gui/macOS/fileprovidermaterialiseditemsmodel.cpp create mode 100644 src/gui/macOS/fileprovidermaterialiseditemsmodel.h diff --git a/src/gui/CMakeLists.txt b/src/gui/CMakeLists.txt index 957b582722e86..fb48ee902e163 100644 --- a/src/gui/CMakeLists.txt +++ b/src/gui/CMakeLists.txt @@ -296,6 +296,8 @@ IF( APPLE ) macOS/fileprovideritemmetadata.h macOS/fileprovideritemmetadata.cpp macOS/fileprovideritemmetadata_mac.mm + macOS/fileprovidermaterialiseditemsmodel.h + macOS/fileprovidermaterialiseditemsmodel.cpp macOS/fileprovidersettingscontroller.h macOS/fileprovidersettingscontroller_mac.mm macOS/fileprovidersocketcontroller.h diff --git a/src/gui/macOS/fileprovidermaterialiseditemsmodel.cpp b/src/gui/macOS/fileprovidermaterialiseditemsmodel.cpp new file mode 100644 index 0000000000000..f375b637ca570 --- /dev/null +++ b/src/gui/macOS/fileprovidermaterialiseditemsmodel.cpp @@ -0,0 +1,38 @@ +/* + * Copyright 2023 (c) Claudio Cambra + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "fileprovidermaterialiseditemsmodel.h" + +namespace OCC { + +namespace Mac { + +FileProviderMaterialisedItemsModel::FileProviderMaterialisedItemsModel(QObject * const parent) + : QAbstractListModel(parent) +{ +} + +int FileProviderMaterialisedItemsModel::rowCount(const QModelIndex &parent) const +{ + return 0; +} + +QVariant FileProviderMaterialisedItemsModel::data(const QModelIndex &index, int role) const +{ + return {}; +} + +} // namespace Mac + +} // namespace OCC diff --git a/src/gui/macOS/fileprovidermaterialiseditemsmodel.h b/src/gui/macOS/fileprovidermaterialiseditemsmodel.h new file mode 100644 index 0000000000000..339dc114e1fb2 --- /dev/null +++ b/src/gui/macOS/fileprovidermaterialiseditemsmodel.h @@ -0,0 +1,35 @@ +/* + * Copyright 2023 (c) Claudio Cambra + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#pragma once + +#include + +namespace OCC { + +namespace Mac { + +class FileProviderMaterialisedItemsModel : public QAbstractListModel +{ + Q_OBJECT + +public: + explicit FileProviderMaterialisedItemsModel(QObject *parent = nullptr); + int rowCount(const QModelIndex &parent = {}) const override; + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; +}; + +} // namespace Mac + +} // namespace OCC From 726503f3c779415da1993ac60d2180a0b6447d42 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Tue, 10 Oct 2023 13:43:06 +0800 Subject: [PATCH 064/144] Add custom equality check to FileProviderItemMetadata Signed-off-by: Claudio Cambra --- src/gui/macOS/fileprovideritemmetadata.cpp | 9 ++++++++- src/gui/macOS/fileprovideritemmetadata.h | 5 ++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/gui/macOS/fileprovideritemmetadata.cpp b/src/gui/macOS/fileprovideritemmetadata.cpp index cec1dfa79e8fd..0ef97d0c02f7d 100644 --- a/src/gui/macOS/fileprovideritemmetadata.cpp +++ b/src/gui/macOS/fileprovideritemmetadata.cpp @@ -163,6 +163,13 @@ bool FileProviderItemMetadata::sharedByCurrentUser() const return _sharedByCurrentUser; } +bool operator==(const FileProviderItemMetadata &lhs, const FileProviderItemMetadata &rhs) +{ + return lhs.identifier() == rhs.identifier() && + lhs.contentVersion() == rhs.contentVersion() && + lhs.metadataVersion() == rhs.metadataVersion(); } -} +} // namespace Mac + +} // namespace OCC diff --git a/src/gui/macOS/fileprovideritemmetadata.h b/src/gui/macOS/fileprovideritemmetadata.h index 6ec4c0aca7f74..9986e737f45db 100644 --- a/src/gui/macOS/fileprovideritemmetadata.h +++ b/src/gui/macOS/fileprovideritemmetadata.h @@ -86,7 +86,10 @@ class FileProviderItemMetadata bool downloading() const; bool downloaded() const; bool shared() const; - bool sharedByCurrentUser() const; + bool sharedByCurrentUser() const; + + // Check equality via identifier, contentVersion, and metadataVersion + friend bool operator==(const FileProviderItemMetadata &lhs, const FileProviderItemMetadata &rhs); private: QString _identifier; From f90f86d696d35264f9a95e4199333b6e7efdb360 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Tue, 10 Oct 2023 15:16:25 +0800 Subject: [PATCH 065/144] Set FileProviderItemMetadata vector in materialised items model Signed-off-by: Claudio Cambra --- .../fileprovidermaterialiseditemsmodel.cpp | 30 ++++++++++++++++++- .../fileprovidermaterialiseditemsmodel.h | 15 ++++++++++ 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/src/gui/macOS/fileprovidermaterialiseditemsmodel.cpp b/src/gui/macOS/fileprovidermaterialiseditemsmodel.cpp index f375b637ca570..fb4682cd93031 100644 --- a/src/gui/macOS/fileprovidermaterialiseditemsmodel.cpp +++ b/src/gui/macOS/fileprovidermaterialiseditemsmodel.cpp @@ -25,14 +25,42 @@ FileProviderMaterialisedItemsModel::FileProviderMaterialisedItemsModel(QObject * int FileProviderMaterialisedItemsModel::rowCount(const QModelIndex &parent) const { - return 0; + if (parent.isValid()) { + return 0; + } + + return _items.count(); } QVariant FileProviderMaterialisedItemsModel::data(const QModelIndex &index, int role) const { + const auto item = _items.at(index.row()); + + switch (role) { + case Qt::DisplayRole: + return item.filename(); + } return {}; } +QVector FileProviderMaterialisedItemsModel::items() const +{ + return _items; +} + +void FileProviderMaterialisedItemsModel::setItems(const QVector &items) +{ + if (items == _items) { + return; + } + + beginResetModel(); + _items = items; + endResetModel(); + + Q_EMIT itemsChanged(); +} + } // namespace Mac } // namespace OCC diff --git a/src/gui/macOS/fileprovidermaterialiseditemsmodel.h b/src/gui/macOS/fileprovidermaterialiseditemsmodel.h index 339dc114e1fb2..fc2a92cf2e93f 100644 --- a/src/gui/macOS/fileprovidermaterialiseditemsmodel.h +++ b/src/gui/macOS/fileprovidermaterialiseditemsmodel.h @@ -16,6 +16,8 @@ #include +#include "gui/macOS/fileprovideritemmetadata.h" + namespace OCC { namespace Mac { @@ -24,10 +26,23 @@ class FileProviderMaterialisedItemsModel : public QAbstractListModel { Q_OBJECT + Q_PROPERTY(QVector items READ items WRITE setItems NOTIFY itemsChanged) + public: explicit FileProviderMaterialisedItemsModel(QObject *parent = nullptr); int rowCount(const QModelIndex &parent = {}) const override; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; + + QVector items() const; + +signals: + void itemsChanged(); + +public slots: + void setItems(const QVector &items); + +private: + QVector _items; }; } // namespace Mac From 85b3a135b6348152191a943194d94df29108cb85 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Tue, 10 Oct 2023 15:20:55 +0800 Subject: [PATCH 066/144] Emit signal when materialised items for an account change Signed-off-by: Claudio Cambra --- src/gui/macOS/fileprovidersettingscontroller.h | 1 + src/gui/macOS/fileprovidersettingscontroller_mac.mm | 1 + 2 files changed, 2 insertions(+) diff --git a/src/gui/macOS/fileprovidersettingscontroller.h b/src/gui/macOS/fileprovidersettingscontroller.h index e5d934604881e..93a024cad3092 100644 --- a/src/gui/macOS/fileprovidersettingscontroller.h +++ b/src/gui/macOS/fileprovidersettingscontroller.h @@ -48,6 +48,7 @@ public slots: void vfsEnabledAccountsChanged(); void localStorageUsageForAccountChanged(const QString &userIdAtHost); void remoteStorageUsageForAccountChanged(const QString &userIdAtHost); + void materialisedItemsForAccountChanged(const QString &userIdAtHost); private: explicit FileProviderSettingsController(QObject *parent = nullptr); diff --git a/src/gui/macOS/fileprovidersettingscontroller_mac.mm b/src/gui/macOS/fileprovidersettingscontroller_mac.mm index 61189b4d51632..9ede05b585bf5 100644 --- a/src/gui/macOS/fileprovidersettingscontroller_mac.mm +++ b/src/gui/macOS/fileprovidersettingscontroller_mac.mm @@ -245,6 +245,7 @@ void fetchMaterialisedFilesStorageUsage() const auto qDomainIdentifier = QString::fromNSString(domain.identifier); emit q->localStorageUsageForAccountChanged(qDomainIdentifier); + emit q->materialisedItemsForAccountChanged(qDomainIdentifier); [storageUseObserver release]; [enumerator release]; From c1a5e788f862d48bfd6eba9fbed7a0734bfa262d Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Wed, 11 Oct 2023 10:40:22 +0800 Subject: [PATCH 067/144] Add method to generate materialised item models in settings controller Signed-off-by: Claudio Cambra --- .../macOS/fileprovidersettingscontroller.h | 4 ++++ .../fileprovidersettingscontroller_mac.mm | 22 +++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/src/gui/macOS/fileprovidersettingscontroller.h b/src/gui/macOS/fileprovidersettingscontroller.h index 93a024cad3092..b7c1cfe0f6843 100644 --- a/src/gui/macOS/fileprovidersettingscontroller.h +++ b/src/gui/macOS/fileprovidersettingscontroller.h @@ -17,6 +17,8 @@ #include #include +class QAbstractListModel; + namespace OCC { class UserInfo; @@ -41,6 +43,8 @@ class FileProviderSettingsController : public QObject [[nodiscard]] unsigned long long remoteStorageUsageForAccount(const QString &userIdAtHost) const; [[nodiscard]] Q_INVOKABLE float remoteStorageUsageGbForAccount(const QString &userIdAtHost) const; + [[nodiscard]] Q_INVOKABLE QAbstractListModel *materialisedItemsModelForAccount(const QString &userIdAtHost); + public slots: void setVfsEnabledForAccount(const QString &userIdAtHost, const bool setEnabled); diff --git a/src/gui/macOS/fileprovidersettingscontroller_mac.mm b/src/gui/macOS/fileprovidersettingscontroller_mac.mm index 9ede05b585bf5..f39e492af7814 100644 --- a/src/gui/macOS/fileprovidersettingscontroller_mac.mm +++ b/src/gui/macOS/fileprovidersettingscontroller_mac.mm @@ -364,6 +364,28 @@ void initialCheck() return gbFromBytesWithOneDecimal(remoteStorageUsageForAccount(userIdAtHost)); } +QAbstractListModel *FileProviderSettingsController::materialisedItemsModelForAccount(const QString &userIdAtHost) +{ + const auto items = d->materialisedItemsForAccount(userIdAtHost); + if (items.isEmpty()) { + return nullptr; + } + + const auto model = new FileProviderMaterialisedItemsModel(this); + model->setItems(items); + + connect(this, &FileProviderSettingsController::materialisedItemsForAccountChanged, model, [this, model, userIdAtHost](const QString &accountUserIdAtHost) { + if (accountUserIdAtHost != userIdAtHost) { + return; + } + + const auto items = d->materialisedItemsForAccount(userIdAtHost); + model->setItems(items); + }); + + return model; +} + } // namespace Mac } // namespace OCC From 2ce4e91383e583d44409a4144eb75fecc21e9547 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Wed, 11 Oct 2023 10:41:02 +0800 Subject: [PATCH 068/144] Add method to generate eviction of materialised item windows in settings controller Signed-off-by: Claudio Cambra --- .../macOS/fileprovidersettingscontroller.h | 2 ++ .../fileprovidersettingscontroller_mac.mm | 23 ++++++++++++++++--- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/src/gui/macOS/fileprovidersettingscontroller.h b/src/gui/macOS/fileprovidersettingscontroller.h index b7c1cfe0f6843..699c95b230979 100644 --- a/src/gui/macOS/fileprovidersettingscontroller.h +++ b/src/gui/macOS/fileprovidersettingscontroller.h @@ -48,6 +48,8 @@ class FileProviderSettingsController : public QObject public slots: void setVfsEnabledForAccount(const QString &userIdAtHost, const bool setEnabled); + void createEvictionWindowForAccount(const QString &userIdAtHost); + signals: void vfsEnabledAccountsChanged(); void localStorageUsageForAccountChanged(const QString &userIdAtHost); diff --git a/src/gui/macOS/fileprovidersettingscontroller_mac.mm b/src/gui/macOS/fileprovidersettingscontroller_mac.mm index f39e492af7814..02c4707779963 100644 --- a/src/gui/macOS/fileprovidersettingscontroller_mac.mm +++ b/src/gui/macOS/fileprovidersettingscontroller_mac.mm @@ -19,6 +19,7 @@ #include "gui/systray.h" #include "gui/userinfo.h" #include "gui/macOS/fileprovideritemmetadata.h" +#include "gui/macOS/fileprovidermaterialiseditemsmodel.h" // Objective-C imports #import @@ -28,9 +29,11 @@ namespace { constexpr auto fpSettingsQmlPath = "qrc:/qml/src/gui/macOS/ui/FileProviderSettings.qml"; +constexpr auto fpEvictionDialogQmlPath = "qrc:/qml/src/gui/macOS/ui/FileProviderEvictionDialog.qml"; -// FileProviderSettingsPage properties -- make sure they match up in QML file! -constexpr auto fpSettingsAccountUserIdAtHostProp = "accountUserIdAtHost"; +// QML properties -- make sure they match up in QML file! +constexpr auto fpAccountUserIdAtHostProp = "accountUserIdAtHost"; +constexpr auto fpMaterialisedItemsModelProp = "materialisedItemsModel"; // NSUserDefaults entries constexpr auto enabledAccountsSettingsKey = "enabledAccounts"; @@ -317,7 +320,7 @@ void initialCheck() const auto settingsViewWidget = new QQuickWidget(Systray::instance()->trayEngine(), parent); settingsViewWidget->setResizeMode(resizeMode); settingsViewWidget->setSource(QUrl(fpSettingsQmlPath)); - settingsViewWidget->rootObject()->setProperty(fpSettingsAccountUserIdAtHostProp, accountUserIdAtHost); + settingsViewWidget->rootObject()->setProperty(fpAccountUserIdAtHostProp, accountUserIdAtHost); return settingsViewWidget; } @@ -386,6 +389,20 @@ void initialCheck() return model; } +void FileProviderSettingsController::createEvictionWindowForAccount(const QString &userIdAtHost) +{ + const auto engine = Systray::instance()->trayEngine(); + QQmlComponent component(engine, QUrl(fpEvictionDialogQmlPath)); + const auto model = materialisedItemsModelForAccount(userIdAtHost); + const auto genericDialog = component.createWithInitialProperties({ + {fpAccountUserIdAtHostProp, userIdAtHost}, + {fpMaterialisedItemsModelProp, QVariant::fromValue(model)}, + }); + const auto dialog = qobject_cast(genericDialog); + Q_ASSERT(dialog); + dialog->show(); +} + } // namespace Mac } // namespace OCC From af98e4880536fbd721fd8e1d30aa9e5acf6b8775 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Wed, 11 Oct 2023 10:41:41 +0800 Subject: [PATCH 069/144] Add starter FileProviderEvictionDialog component Signed-off-by: Claudio Cambra --- resources.qrc | 1 + .../macOS/ui/FileProviderEvictionDialog.qml | 43 +++++++++++++++++++ 2 files changed, 44 insertions(+) create mode 100644 src/gui/macOS/ui/FileProviderEvictionDialog.qml diff --git a/resources.qrc b/resources.qrc index 34de449ff823e..0057443b8f680 100644 --- a/resources.qrc +++ b/resources.qrc @@ -63,5 +63,6 @@ src/gui/ConflictDelegate.qml src/gui/ConflictItemFileInfo.qml src/gui/macOS/ui/FileProviderSettings.qml + src/gui/macOS/ui/FileProviderEvictionDialog.qml diff --git a/src/gui/macOS/ui/FileProviderEvictionDialog.qml b/src/gui/macOS/ui/FileProviderEvictionDialog.qml new file mode 100644 index 0000000000000..d9b717324a449 --- /dev/null +++ b/src/gui/macOS/ui/FileProviderEvictionDialog.qml @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2023 by Claudio Cambra + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +import QtQuick 2.15 +import QtQuick.Controls 2.15 +import QtQuick.Layouts 1.15 + +import Style 1.0 +import "../../filedetails" +import "../../tray" + +import com.nextcloud.desktopclient 1.0 + +ApplicationWindow { + id: root + + property var materialisedItemsModel: null + property string accountUserIdAtHost: "" + + title: qsTr("Evict materialised files") + flags: Qt.Dialog | Qt.WindowStaysOnTopHint + width: 640 + height: 480 + + ListView { + anchors.fill: parent + model: root.materialisedItemsModel + delegate: Text { + text: model.display + } + } +} From d51c2a486b8d398e755e8669515776ac7f297387 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Wed, 11 Oct 2023 10:42:55 +0800 Subject: [PATCH 070/144] Add a general actions grid to the settings qml component to enable users to manage storage usage Signed-off-by: Claudio Cambra --- src/gui/macOS/ui/FileProviderSettings.qml | 63 +++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/src/gui/macOS/ui/FileProviderSettings.qml b/src/gui/macOS/ui/FileProviderSettings.qml index ff030deceefcd..1b62731b1c90f 100644 --- a/src/gui/macOS/ui/FileProviderSettings.qml +++ b/src/gui/macOS/ui/FileProviderSettings.qml @@ -81,5 +81,68 @@ Page { checked: root.controller.vfsEnabledForAccount(root.accountUserIdAtHost) onClicked: root.controller.setVfsEnabledForAccount(root.accountUserIdAtHost, checked) } + + GridLayout { + id: generalActionsGrid + + property real localUsedStorage: root.controller.localStorageUsageGbForAccount(root.accountUserIdAtHost) + property real remoteUsedStorage: root.controller.remoteStorageUsageGbForAccount(root.accountUserIdAtHost) + + Layout.fillWidth: true + columns: 3 + visible: vfsEnabledCheckBox.checked + + Connections { + target: root.controller + function onLocalStorageUsageForAccountChanged(accountUserIdAtHost) { + if (root.accountUserIdAtHost !== accountUserIdAtHost) { + return; + } + + generalActionsGrid.localUsedStorage = root.controller.localStorageUsageGbForAccount(root.accountUserIdAtHost); + } + + function onRemoteStorageUsageForAccountChanged(accountUserIdAtHost) { + if (root.accountUserIdAtHost !== accountUserIdAtHost) { + return; + } + + generalActionsGrid.remoteUsedStorage = root.controller.remoteStorageUsageGbForAccount(root.accountUserIdAtHost); + } + } + + EnforcedPlainTextLabel { + Layout.row: 0 + Layout.column: 0 + Layout.alignment: Layout.AlignLeft | Layout.AlignVCenter + Layout.fillWidth: true + text: qsTr("Local storage use") + font.bold: true + } + + EnforcedPlainTextLabel { + Layout.row: 0 + Layout.column: 1 + Layout.alignment: Layout.AlignRight | Layout.AlignVCenter + text: qsTr("%1 GB of %2 GB remote files synced").arg(generalActionsGrid.localUsedStorage).arg(generalActionsGrid.remoteUsedStorage); + color: Style.ncSecondaryTextColor + horizontalAlignment: Text.AlignRight + } + + CustomButton { + Layout.row: 0 + Layout.column: 2 + Layout.alignment: Layout.AlignRight | Layout.AlignVCenter + text: qsTr("Evict local copies...") + onPressed: root.controller.createEvictionWindowForAccount(root.accountUserIdAtHost) + } + + ProgressBar { + Layout.row: 1 + Layout.columnSpan: generalActionsGrid.columns + Layout.fillWidth: true + value: generalActionsGrid.localUsedStorage / generalActionsGrid.remoteUsedStorage + } + } } } From 89bb008bd7b3e2ffd16c9359b7dde40248f0c728 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Wed, 11 Oct 2023 17:22:27 +0800 Subject: [PATCH 071/144] Add additional roles to FileProviderMaterialisedItemsModel Signed-off-by: Claudio Cambra --- .../fileprovidermaterialiseditemsmodel.cpp | 55 +++++++++++++++++++ .../fileprovidermaterialiseditemsmodel.h | 32 +++++++++++ 2 files changed, 87 insertions(+) diff --git a/src/gui/macOS/fileprovidermaterialiseditemsmodel.cpp b/src/gui/macOS/fileprovidermaterialiseditemsmodel.cpp index fb4682cd93031..e9c8c481eaa1c 100644 --- a/src/gui/macOS/fileprovidermaterialiseditemsmodel.cpp +++ b/src/gui/macOS/fileprovidermaterialiseditemsmodel.cpp @@ -38,7 +38,62 @@ QVariant FileProviderMaterialisedItemsModel::data(const QModelIndex &index, int switch (role) { case Qt::DisplayRole: + case FilenameRole: return item.filename(); + case IdentifierRole: + return item.identifier(); + case ParentItemIdentifierRole: + return item.parentItemIdentifier(); + case TypeIdentifierRole: + return item.typeIdentifier(); + case SymlinkTargetPathRole: + return item.symlinkTargetPath(); + case UploadingErrorRole: + return item.uploadingError(); + case DownloadingErrorRole: + return item.downloadingError(); + case MostRecentEditorNameRole: + return item.mostRecentEditorName(); + case OwnerNameRole: + return item.ownerName(); + case ContentModificationDateRole: + return item.contentModificationDate(); + case CreationDateRole: + return item.creationDate(); + case LastUsedDateRole: + return item.lastUsedDate(); + case ContentVersionRole: + return item.contentVersion(); + case MetadataVersionRole: + return item.metadataVersion(); + case TagDataRole: + return item.tagData(); + case CapabilitiesRole: + return item.capabilities(); + case FileSystemFlagsRole: + return item.fileSystemFlags(); + case ChildItemCountRole: + return item.childItemCount(); + case TypeOsCodeRole: + return item.typeOsCode(); + case CreatorOsCodeRole: + return item.creatorOsCode(); + case DocumentSizeRole: + return item.documentSize(); + case MostRecentVersionDownloadedRole: + return item.mostRecentVersionDownloaded(); + case UploadingRole: + return item.uploading(); + case UploadedRole: + return item.uploaded(); + case DownloadingRole: + return item.downloading(); + case DownloadedRole: + return item.downloaded(); + case SharedRole: + return item.shared(); + case SharedByCurrentUserRole: + return item.sharedByCurrentUser(); } return {}; } diff --git a/src/gui/macOS/fileprovidermaterialiseditemsmodel.h b/src/gui/macOS/fileprovidermaterialiseditemsmodel.h index fc2a92cf2e93f..81d1624469b13 100644 --- a/src/gui/macOS/fileprovidermaterialiseditemsmodel.h +++ b/src/gui/macOS/fileprovidermaterialiseditemsmodel.h @@ -29,6 +29,38 @@ class FileProviderMaterialisedItemsModel : public QAbstractListModel Q_PROPERTY(QVector items READ items WRITE setItems NOTIFY itemsChanged) public: + enum Roles { + IdentifierRole = Qt::UserRole + 1, + ParentItemIdentifierRole, + FilenameRole, + TypeIdentifierRole, + SymlinkTargetPathRole, + UploadingErrorRole, + DownloadingErrorRole, + MostRecentEditorNameRole, + OwnerNameRole, + ContentModificationDateRole, + CreationDateRole, + LastUsedDateRole, + ContentVersionRole, + MetadataVersionRole, + TagDataRole, + CapabilitiesRole, + FileSystemFlagsRole, + ChildItemCountRole, + TypeOsCodeRole, + CreatorOsCodeRole, + DocumentSizeRole, + MostRecentVersionDownloadedRole, + UploadingRole, + UploadedRole, + DownloadingRole, + DownloadedRole, + SharedRole, + SharedByCurrentUserRole, + }; + Q_ENUM(Roles) + explicit FileProviderMaterialisedItemsModel(QObject *parent = nullptr); int rowCount(const QModelIndex &parent = {}) const override; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; From bfaba671f39695e9bc40c7f12f2b049762110b69 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Tue, 17 Oct 2023 14:31:40 +0800 Subject: [PATCH 072/144] Add rolenames for FileProviderMaterialisedItemsModel Signed-off-by: Claudio Cambra --- .../fileprovidermaterialiseditemsmodel.cpp | 36 +++++++++++++++++++ .../fileprovidermaterialiseditemsmodel.h | 1 + 2 files changed, 37 insertions(+) diff --git a/src/gui/macOS/fileprovidermaterialiseditemsmodel.cpp b/src/gui/macOS/fileprovidermaterialiseditemsmodel.cpp index e9c8c481eaa1c..c2b33c80576d4 100644 --- a/src/gui/macOS/fileprovidermaterialiseditemsmodel.cpp +++ b/src/gui/macOS/fileprovidermaterialiseditemsmodel.cpp @@ -98,6 +98,42 @@ QVariant FileProviderMaterialisedItemsModel::data(const QModelIndex &index, int return {}; } +QHash FileProviderMaterialisedItemsModel::roleNames() const +{ + auto roleNames = QAbstractListModel::roleNames(); + roleNames.insert({ + { IdentifierRole, "identifier" }, + { ParentItemIdentifierRole, "parentItemIdentifier" }, + { FilenameRole, "fileName" }, + { TypeIdentifierRole, "typeIdentifier" }, + { SymlinkTargetPathRole, "symlinkTargetPath" }, + { UploadingErrorRole, "uploadingError" }, + { DownloadingErrorRole, "downloadingError" }, + { MostRecentEditorNameRole, "mostRecentEditorName" }, + { OwnerNameRole, "ownerName" }, + { ContentModificationDateRole, "contentModificationDate" }, + { CreationDateRole, "creationDate" }, + { LastUsedDateRole, "lastUsedDate" }, + { ContentVersionRole, "contentVersion" }, + { MetadataVersionRole, "metadataVersion" }, + { TagDataRole, "tagData" }, + { CapabilitiesRole, "capabilities" }, + { FileSystemFlagsRole, "fileSystemFlags" }, + { ChildItemCountRole, "childItemCount" }, + { TypeOsCodeRole, "typeOsCode" }, + { CreatorOsCodeRole, "creatorOsCode" }, + { DocumentSizeRole, "documentSize" }, + { MostRecentVersionDownloadedRole, "mostRecentVersionDownloaded" }, + { UploadingRole, "uploading" }, + { UploadedRole, "uploaded" }, + { DownloadingRole, "downloading" }, + { DownloadedRole, "downloaded" }, + { SharedRole, "shared" }, + { SharedByCurrentUserRole, "sharedByCurrentUser" }, + }); + return roleNames; +} + QVector FileProviderMaterialisedItemsModel::items() const { return _items; diff --git a/src/gui/macOS/fileprovidermaterialiseditemsmodel.h b/src/gui/macOS/fileprovidermaterialiseditemsmodel.h index 81d1624469b13..70d2bcd6ba169 100644 --- a/src/gui/macOS/fileprovidermaterialiseditemsmodel.h +++ b/src/gui/macOS/fileprovidermaterialiseditemsmodel.h @@ -64,6 +64,7 @@ class FileProviderMaterialisedItemsModel : public QAbstractListModel explicit FileProviderMaterialisedItemsModel(QObject *parent = nullptr); int rowCount(const QModelIndex &parent = {}) const override; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; + QHash roleNames() const override; QVector items() const; From f2547140c4135811977067d84e145bbbe20e2d37 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Mon, 30 Oct 2023 19:19:31 +0800 Subject: [PATCH 073/144] Ensure correct index is set on hidden tab widget Signed-off-by: Claudio Cambra --- src/gui/accountsettings.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/gui/accountsettings.cpp b/src/gui/accountsettings.cpp index 1565f272341b3..e61043feda1e9 100644 --- a/src/gui/accountsettings.cpp +++ b/src/gui/accountsettings.cpp @@ -212,6 +212,7 @@ AccountSettings::AccountSettings(AccountState *accountState, QWidget *parent) } #else disguiseTabWidget(); + _ui->tabWidget->setCurrentIndex(0); #endif const auto mouseCursorChanger = new MouseCursorChanger(this); From ad2baeaba0fd03a6640a7d94a4666d4e3e53c982 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Tue, 31 Oct 2023 15:38:23 +0800 Subject: [PATCH 074/144] Keep track of item metadata's parent domain identifier Signed-off-by: Claudio Cambra --- src/gui/macOS/fileprovideritemmetadata.cpp | 5 +++++ src/gui/macOS/fileprovideritemmetadata.h | 5 ++++- src/gui/macOS/fileprovideritemmetadata_mac.mm | 3 ++- src/gui/macOS/fileprovidersettingscontroller_mac.mm | 2 +- 4 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/gui/macOS/fileprovideritemmetadata.cpp b/src/gui/macOS/fileprovideritemmetadata.cpp index 0ef97d0c02f7d..9a9d38047385c 100644 --- a/src/gui/macOS/fileprovideritemmetadata.cpp +++ b/src/gui/macOS/fileprovideritemmetadata.cpp @@ -28,6 +28,11 @@ QString FileProviderItemMetadata::parentItemIdentifier() const return _parentItemIdentifier; } +QString FileProviderItemMetadata::domainIdentifier() const +{ + return _domainIdentifier; +} + QString FileProviderItemMetadata::filename() const { return _filename; diff --git a/src/gui/macOS/fileprovideritemmetadata.h b/src/gui/macOS/fileprovideritemmetadata.h index 9986e737f45db..1decada982d41 100644 --- a/src/gui/macOS/fileprovideritemmetadata.h +++ b/src/gui/macOS/fileprovideritemmetadata.h @@ -27,6 +27,7 @@ class FileProviderItemMetadata Q_PROPERTY(QString identifier READ identifier CONSTANT) Q_PROPERTY(QString parentItemIdentifier READ parentItemIdentifier CONSTANT) + Q_PROPERTY(QString domainIdentifier READ domainIdentifier CONSTANT) Q_PROPERTY(QString filename READ filename CONSTANT) Q_PROPERTY(QString typeIdentifier READ typeIdentifier CONSTANT) Q_PROPERTY(QString symlinkTargetPath READ symlinkTargetPath CONSTANT) @@ -56,10 +57,11 @@ class FileProviderItemMetadata Q_PROPERTY(bool sharedByCurrentUser READ sharedByCurrentUser CONSTANT) public: - static FileProviderItemMetadata fromNSFileProviderItem(const void *const nsFileProviderItem); + static FileProviderItemMetadata fromNSFileProviderItem(const void *const nsFileProviderItem, const QString &domainIdentifier); QString identifier() const; QString parentItemIdentifier() const; + QString domainIdentifier() const; QString filename() const; QString typeIdentifier() const; QString symlinkTargetPath() const; @@ -94,6 +96,7 @@ class FileProviderItemMetadata private: QString _identifier; QString _parentItemIdentifier; + QString _domainIdentifier; QString _filename; QString _typeIdentifier; QString _symlinkTargetPath; diff --git a/src/gui/macOS/fileprovideritemmetadata_mac.mm b/src/gui/macOS/fileprovideritemmetadata_mac.mm index 9248873ffbc96..e5168a4517f22 100644 --- a/src/gui/macOS/fileprovideritemmetadata_mac.mm +++ b/src/gui/macOS/fileprovideritemmetadata_mac.mm @@ -46,7 +46,7 @@ QString nsNameComponentsToLocalisedQString(NSPersonNameComponents *const nameCom namespace Mac { -FileProviderItemMetadata FileProviderItemMetadata::fromNSFileProviderItem(const void *const nsFileProviderItem) +FileProviderItemMetadata FileProviderItemMetadata::fromNSFileProviderItem(const void *const nsFileProviderItem, const QString &domainIdentifier) { FileProviderItemMetadata metadata; const id bridgedNsFileProviderItem = (__bridge id)nsFileProviderItem; @@ -56,6 +56,7 @@ QString nsNameComponentsToLocalisedQString(NSPersonNameComponents *const nameCom metadata._identifier = QString::fromNSString(bridgedNsFileProviderItem.itemIdentifier); metadata._parentItemIdentifier = QString::fromNSString(bridgedNsFileProviderItem.parentItemIdentifier); + metadata._domainIdentifier = domainIdentifier; metadata._filename = QString::fromNSString(bridgedNsFileProviderItem.filename); metadata._typeIdentifier = QString::fromNSString(bridgedNsFileProviderItem.contentType.identifier); metadata._symlinkTargetPath = QString::fromNSString(bridgedNsFileProviderItem.symlinkTargetPath); diff --git a/src/gui/macOS/fileprovidersettingscontroller_mac.mm b/src/gui/macOS/fileprovidersettingscontroller_mac.mm index 02c4707779963..330af35cd3668 100644 --- a/src/gui/macOS/fileprovidersettingscontroller_mac.mm +++ b/src/gui/macOS/fileprovidersettingscontroller_mac.mm @@ -169,7 +169,7 @@ float gbFromBytesWithOneDecimal(const unsigned long long bytes) qMaterialisedItems.reserve(materialisedItems.count); for (const id item in materialisedItems) { - const auto itemMetadata = FileProviderItemMetadata::fromNSFileProviderItem(item); + const auto itemMetadata = FileProviderItemMetadata::fromNSFileProviderItem(item, userIdAtHost); qMaterialisedItems.append(itemMetadata); } From e03edc131d3b3fd9956d01418a1287020f5fe688 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Tue, 31 Oct 2023 15:43:32 +0800 Subject: [PATCH 075/144] Add method to get user visible path for an item metadata Signed-off-by: Claudio Cambra --- src/gui/macOS/fileprovideritemmetadata.h | 4 + src/gui/macOS/fileprovideritemmetadata_mac.mm | 81 ++++++++++++++++++- 2 files changed, 84 insertions(+), 1 deletion(-) diff --git a/src/gui/macOS/fileprovideritemmetadata.h b/src/gui/macOS/fileprovideritemmetadata.h index 1decada982d41..cde6508de5b63 100644 --- a/src/gui/macOS/fileprovideritemmetadata.h +++ b/src/gui/macOS/fileprovideritemmetadata.h @@ -56,6 +56,8 @@ class FileProviderItemMetadata Q_PROPERTY(bool shared READ shared CONSTANT) Q_PROPERTY(bool sharedByCurrentUser READ sharedByCurrentUser CONSTANT) + Q_PROPERTY(QString userVisiblePath READ userVisiblePath CONSTANT) + public: static FileProviderItemMetadata fromNSFileProviderItem(const void *const nsFileProviderItem, const QString &domainIdentifier); @@ -90,6 +92,8 @@ class FileProviderItemMetadata bool shared() const; bool sharedByCurrentUser() const; + QString userVisiblePath() const; + // Check equality via identifier, contentVersion, and metadataVersion friend bool operator==(const FileProviderItemMetadata &lhs, const FileProviderItemMetadata &rhs); diff --git a/src/gui/macOS/fileprovideritemmetadata_mac.mm b/src/gui/macOS/fileprovideritemmetadata_mac.mm index e5168a4517f22..daefc57219536 100644 --- a/src/gui/macOS/fileprovideritemmetadata_mac.mm +++ b/src/gui/macOS/fileprovideritemmetadata_mac.mm @@ -14,8 +14,10 @@ #include "fileprovideritemmetadata.h" +#include + #import -#import +#import #import namespace { @@ -46,6 +48,8 @@ QString nsNameComponentsToLocalisedQString(NSPersonNameComponents *const nameCom namespace Mac { +Q_LOGGING_CATEGORY(lcMacImplFileProviderItemMetadata, "nextcloud.gui.macfileprovideritemmetadatamacimpl", QtInfoMsg) + FileProviderItemMetadata FileProviderItemMetadata::fromNSFileProviderItem(const void *const nsFileProviderItem, const QString &domainIdentifier) { FileProviderItemMetadata metadata; @@ -88,6 +92,81 @@ QString nsNameComponentsToLocalisedQString(NSPersonNameComponents *const nameCom return metadata; } +QString FileProviderItemMetadata::userVisiblePath() const +{ + qCDebug(lcMacImplFileProviderItemMetadata) << "Getting user visible path"; + + const auto id = identifier(); + const auto domainId = domainIdentifier(); + + if (id.isEmpty() || domainId.isEmpty()) { + qCWarning(lcMacImplFileProviderItemMetadata) << "Could not fetch user visible path for item, no identifier or domainIdentifier"; + return QStringLiteral("Unknown"); + } + + NSString *const nsItemIdentifier = id.toNSString(); + NSString *const nsDomainIdentifier = domainId.toNSString(); + + __block QString returnPath = QObject::tr("Unknown"); + __block NSFileProviderManager *manager = nil; + dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); + + // getDomainsWithCompletionHandler is asynchronous -- we create a dispatch semaphore in order + // to wait until it is done. This should tell you that we should not call this method very + // often! + + [NSFileProviderManager getDomainsWithCompletionHandler:^(NSArray *const domains, NSError *const error) { + if (error != nil) { + qCWarning(lcMacImplFileProviderItemMetadata) << "Error fetching domains:" << error.localizedDescription; + dispatch_semaphore_signal(semaphore); + return; + } + + BOOL foundDomain = NO; + + for (NSFileProviderDomain *const domain in domains) { + if ([domain.identifier isEqualToString:nsDomainIdentifier]) { + foundDomain = YES; + manager = [NSFileProviderManager managerForDomain:domain]; + } + } + + if (!foundDomain) { + qCWarning(lcMacImplFileProviderItemMetadata) << "No matching item domain, cannot get item path"; + } + + dispatch_semaphore_signal(semaphore); + }]; + + dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); + + if (manager == nil) { + qCWarning(lcMacImplFileProviderItemMetadata) << "Null manager, cannot get item path"; + dispatch_release(semaphore); + return returnPath; + } + + // getUserVisibleUrl is also async, so wait here too + + [manager getUserVisibleURLForItemIdentifier:nsItemIdentifier + completionHandler:^(NSURL *const userVisibleFile, NSError *const error) { + qCDebug(lcMacImplFileProviderItemMetadata) << "Got user visible url for item identifier." << "url:" << userVisibleFile << "error:" << error.localizedDescription; + + if (error != nil) { + qCWarning(lcMacImplFileProviderItemMetadata) << "Error fetching user visible url for item identifier." << error.localizedDescription; + } else { + returnPath = QString::fromNSString(userVisibleFile.path); + } + + dispatch_semaphore_signal(semaphore); + }]; + + dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); + dispatch_release(semaphore); + + return returnPath; +} + } } From beb889c2f62049c46ca8fb99314ace3fd5f5b366 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Tue, 31 Oct 2023 15:51:53 +0800 Subject: [PATCH 076/144] Get and set userVisiblePath at item metadata construction time Signed-off-by: Claudio Cambra --- src/gui/macOS/fileprovideritemmetadata.cpp | 5 +++++ src/gui/macOS/fileprovideritemmetadata.h | 4 ++++ src/gui/macOS/fileprovideritemmetadata_mac.mm | 4 +++- 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/gui/macOS/fileprovideritemmetadata.cpp b/src/gui/macOS/fileprovideritemmetadata.cpp index 9a9d38047385c..0d7421abc3e9d 100644 --- a/src/gui/macOS/fileprovideritemmetadata.cpp +++ b/src/gui/macOS/fileprovideritemmetadata.cpp @@ -168,6 +168,11 @@ bool FileProviderItemMetadata::sharedByCurrentUser() const return _sharedByCurrentUser; } +QString FileProviderItemMetadata::userVisiblePath() const +{ + return _userVisiblePath; +} + bool operator==(const FileProviderItemMetadata &lhs, const FileProviderItemMetadata &rhs) { return lhs.identifier() == rhs.identifier() && diff --git a/src/gui/macOS/fileprovideritemmetadata.h b/src/gui/macOS/fileprovideritemmetadata.h index cde6508de5b63..59b45733ad070 100644 --- a/src/gui/macOS/fileprovideritemmetadata.h +++ b/src/gui/macOS/fileprovideritemmetadata.h @@ -98,6 +98,8 @@ class FileProviderItemMetadata friend bool operator==(const FileProviderItemMetadata &lhs, const FileProviderItemMetadata &rhs); private: + QString getUserVisiblePath() const; + QString _identifier; QString _parentItemIdentifier; QString _domainIdentifier; @@ -130,6 +132,8 @@ class FileProviderItemMetadata bool _shared = false; bool _sharedByCurrentUser = false; bool _trashed = false; + + QString _userVisiblePath; }; } diff --git a/src/gui/macOS/fileprovideritemmetadata_mac.mm b/src/gui/macOS/fileprovideritemmetadata_mac.mm index daefc57219536..822872b281cf1 100644 --- a/src/gui/macOS/fileprovideritemmetadata_mac.mm +++ b/src/gui/macOS/fileprovideritemmetadata_mac.mm @@ -89,10 +89,12 @@ QString nsNameComponentsToLocalisedQString(NSPersonNameComponents *const nameCom metadata._shared = bridgedNsFileProviderItem.shared; metadata._sharedByCurrentUser = bridgedNsFileProviderItem.sharedByCurrentUser; + metadata._userVisiblePath = metadata.getUserVisiblePath(); + return metadata; } -QString FileProviderItemMetadata::userVisiblePath() const +QString FileProviderItemMetadata::getUserVisiblePath() const { qCDebug(lcMacImplFileProviderItemMetadata) << "Getting user visible path"; From f060f0c271fb7c76830dad19b275012b0ceeec92 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Tue, 31 Oct 2023 15:53:42 +0800 Subject: [PATCH 077/144] Add UserVisiblePathRole to FileProviderMaterialisedItemsModel Signed-off-by: Claudio Cambra --- src/gui/macOS/fileprovidermaterialiseditemsmodel.cpp | 3 +++ src/gui/macOS/fileprovidermaterialiseditemsmodel.h | 1 + 2 files changed, 4 insertions(+) diff --git a/src/gui/macOS/fileprovidermaterialiseditemsmodel.cpp b/src/gui/macOS/fileprovidermaterialiseditemsmodel.cpp index c2b33c80576d4..7a06f42e81f08 100644 --- a/src/gui/macOS/fileprovidermaterialiseditemsmodel.cpp +++ b/src/gui/macOS/fileprovidermaterialiseditemsmodel.cpp @@ -94,6 +94,8 @@ QVariant FileProviderMaterialisedItemsModel::data(const QModelIndex &index, int return item.shared(); case SharedByCurrentUserRole: return item.sharedByCurrentUser(); + case UserVisiblePathRole: + return item.userVisiblePath(); } return {}; } @@ -130,6 +132,7 @@ QHash FileProviderMaterialisedItemsModel::roleNames() const { DownloadedRole, "downloaded" }, { SharedRole, "shared" }, { SharedByCurrentUserRole, "sharedByCurrentUser" }, + { UserVisiblePathRole, "userVisiblePath" }, }); return roleNames; } diff --git a/src/gui/macOS/fileprovidermaterialiseditemsmodel.h b/src/gui/macOS/fileprovidermaterialiseditemsmodel.h index 70d2bcd6ba169..b2870535c9d4f 100644 --- a/src/gui/macOS/fileprovidermaterialiseditemsmodel.h +++ b/src/gui/macOS/fileprovidermaterialiseditemsmodel.h @@ -58,6 +58,7 @@ class FileProviderMaterialisedItemsModel : public QAbstractListModel DownloadedRole, SharedRole, SharedByCurrentUserRole, + UserVisiblePathRole, }; Q_ENUM(Roles) From 371257a6de169fb1e8485c695d8ccd6be5a85220 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Tue, 31 Oct 2023 16:19:54 +0800 Subject: [PATCH 078/144] Add a user-understandable file type string to itemmetadata Signed-off-by: Claudio Cambra --- src/gui/macOS/fileprovideritemmetadata.cpp | 5 +++++ src/gui/macOS/fileprovideritemmetadata.h | 2 ++ src/gui/macOS/fileprovideritemmetadata_mac.mm | 1 + 3 files changed, 8 insertions(+) diff --git a/src/gui/macOS/fileprovideritemmetadata.cpp b/src/gui/macOS/fileprovideritemmetadata.cpp index 0d7421abc3e9d..2219a22262d7b 100644 --- a/src/gui/macOS/fileprovideritemmetadata.cpp +++ b/src/gui/macOS/fileprovideritemmetadata.cpp @@ -173,6 +173,11 @@ QString FileProviderItemMetadata::userVisiblePath() const return _userVisiblePath; } +QString FileProviderItemMetadata::fileTypeString() const +{ + return _fileTypeString; +} + bool operator==(const FileProviderItemMetadata &lhs, const FileProviderItemMetadata &rhs) { return lhs.identifier() == rhs.identifier() && diff --git a/src/gui/macOS/fileprovideritemmetadata.h b/src/gui/macOS/fileprovideritemmetadata.h index 59b45733ad070..cad6170b446b4 100644 --- a/src/gui/macOS/fileprovideritemmetadata.h +++ b/src/gui/macOS/fileprovideritemmetadata.h @@ -93,6 +93,7 @@ class FileProviderItemMetadata bool sharedByCurrentUser() const; QString userVisiblePath() const; + QString fileTypeString() const; // Check equality via identifier, contentVersion, and metadataVersion friend bool operator==(const FileProviderItemMetadata &lhs, const FileProviderItemMetadata &rhs); @@ -134,6 +135,7 @@ class FileProviderItemMetadata bool _trashed = false; QString _userVisiblePath; + QString _fileTypeString; }; } diff --git a/src/gui/macOS/fileprovideritemmetadata_mac.mm b/src/gui/macOS/fileprovideritemmetadata_mac.mm index 822872b281cf1..5aced7128b853 100644 --- a/src/gui/macOS/fileprovideritemmetadata_mac.mm +++ b/src/gui/macOS/fileprovideritemmetadata_mac.mm @@ -90,6 +90,7 @@ QString nsNameComponentsToLocalisedQString(NSPersonNameComponents *const nameCom metadata._sharedByCurrentUser = bridgedNsFileProviderItem.sharedByCurrentUser; metadata._userVisiblePath = metadata.getUserVisiblePath(); + metadata._fileTypeString = QString::fromNSString(bridgedNsFileProviderItem.contentType.localizedDescription); return metadata; } From b3c75750ab9c969b45610f0c1b0083aca02c9cf7 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Tue, 31 Oct 2023 16:20:25 +0800 Subject: [PATCH 079/144] Add file type role to FileProviderMaterialisedItemsModel Signed-off-by: Claudio Cambra --- src/gui/macOS/fileprovidermaterialiseditemsmodel.cpp | 3 +++ src/gui/macOS/fileprovidermaterialiseditemsmodel.h | 1 + 2 files changed, 4 insertions(+) diff --git a/src/gui/macOS/fileprovidermaterialiseditemsmodel.cpp b/src/gui/macOS/fileprovidermaterialiseditemsmodel.cpp index 7a06f42e81f08..35bce50dc50f6 100644 --- a/src/gui/macOS/fileprovidermaterialiseditemsmodel.cpp +++ b/src/gui/macOS/fileprovidermaterialiseditemsmodel.cpp @@ -96,6 +96,8 @@ QVariant FileProviderMaterialisedItemsModel::data(const QModelIndex &index, int return item.sharedByCurrentUser(); case UserVisiblePathRole: return item.userVisiblePath(); + case FileTypeRole: + return item.fileTypeString(); } return {}; } @@ -133,6 +135,7 @@ QHash FileProviderMaterialisedItemsModel::roleNames() const { SharedRole, "shared" }, { SharedByCurrentUserRole, "sharedByCurrentUser" }, { UserVisiblePathRole, "userVisiblePath" }, + { FileTypeRole, "fileType" }, }); return roleNames; } diff --git a/src/gui/macOS/fileprovidermaterialiseditemsmodel.h b/src/gui/macOS/fileprovidermaterialiseditemsmodel.h index b2870535c9d4f..faae4b9598cca 100644 --- a/src/gui/macOS/fileprovidermaterialiseditemsmodel.h +++ b/src/gui/macOS/fileprovidermaterialiseditemsmodel.h @@ -59,6 +59,7 @@ class FileProviderMaterialisedItemsModel : public QAbstractListModel SharedRole, SharedByCurrentUserRole, UserVisiblePathRole, + FileTypeRole, }; Q_ENUM(Roles) From da20e7e1797339d67176f830cec5c9f792335261 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Tue, 31 Oct 2023 16:29:52 +0800 Subject: [PATCH 080/144] Add basic FileProviderFileDelegate UI component Signed-off-by: Claudio Cambra --- resources.qrc | 1 + .../macOS/ui/FileProviderEvictionDialog.qml | 5 +- src/gui/macOS/ui/FileProviderFileDelegate.qml | 113 ++++++++++++++++++ 3 files changed, 117 insertions(+), 2 deletions(-) create mode 100644 src/gui/macOS/ui/FileProviderFileDelegate.qml diff --git a/resources.qrc b/resources.qrc index 0057443b8f680..70747c1b93687 100644 --- a/resources.qrc +++ b/resources.qrc @@ -63,6 +63,7 @@ src/gui/ConflictDelegate.qml src/gui/ConflictItemFileInfo.qml src/gui/macOS/ui/FileProviderSettings.qml + src/gui/macOS/ui/FileProviderFileDelegate.qml src/gui/macOS/ui/FileProviderEvictionDialog.qml diff --git a/src/gui/macOS/ui/FileProviderEvictionDialog.qml b/src/gui/macOS/ui/FileProviderEvictionDialog.qml index d9b717324a449..15e4a2da82f4b 100644 --- a/src/gui/macOS/ui/FileProviderEvictionDialog.qml +++ b/src/gui/macOS/ui/FileProviderEvictionDialog.qml @@ -36,8 +36,9 @@ ApplicationWindow { ListView { anchors.fill: parent model: root.materialisedItemsModel - delegate: Text { - text: model.display + delegate: FileProviderFileDelegate { + width: parent.width + height: 60 } } } diff --git a/src/gui/macOS/ui/FileProviderFileDelegate.qml b/src/gui/macOS/ui/FileProviderFileDelegate.qml new file mode 100644 index 0000000000000..48b6acf4987be --- /dev/null +++ b/src/gui/macOS/ui/FileProviderFileDelegate.qml @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2023 by Claudio Cambra + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +import QtQuick 2.15 +import QtQuick.Controls 2.15 +import QtQuick.Layouts 1.15 + +import Style 1.0 +import "../../filedetails" +import "../../tray" + +import com.nextcloud.desktopclient 1.0 + +Item { + id: root + + // Match with model rolenames for automagic setting of properties + required property string fileName + required property string userVisiblePath + required property string fileType + + required property size documentSize + + GridLayout { + id: internalLayout + + anchors.fill: parent + rows: 3 + columns: 4 + + Image { + id: fileIconImage + + Layout.fillHeight: true + Layout.row: 0 + Layout.rowSpan: internalLayout.rows + Layout.column: 0 + + verticalAlignment: Image.AlignVCenter + horizontalAlignment: Image.AlignHCenter + source: "image://tray-image-provider/:/fileicon/" + root.userVisiblePath + sourceSize.width: Style.trayListItemIconSize + sourceSize.height: Style.trayListItemIconSize + fillMode: Image.PreserveAspectFit + } + + EnforcedPlainTextLabel { + id: fileNameLabel + + Layout.fillWidth: true + Layout.row: 0 + Layout.column: 1 + Layout.columnSpan: 2 + + text: root.fileName + } + + CustomButton { + id: deleteButton + + Layout.preferredWidth: width + Layout.minimumWidth: implicitWidth + Layout.fillHeight: true + Layout.row: 0 + Layout.rowSpan: internalLayout.rows + Layout.column: 2 + + text: qsTr("Delete") + bgColor: Style.errorBoxBackgroundColor + } + + EnforcedPlainTextLabel { + id: pathLabel + + Layout.fillWidth: true + Layout.row: 1 + Layout.column: 1 + Layout.columnSpan: 2 + + text: root.userVisiblePath + } + + EnforcedPlainTextLabel { + id: fileSizeLabel + + Layout.row: 2 + Layout.column: 1 + + text: root.documentSize + } + + EnforcedPlainTextLabel { + id: fileTypeLabel + + Layout.row: 2 + Layout.column: 2 + + text: root.fileType + color: Style.ncSecondaryTextColor + } + } +} From 0b961e9e1791b02f36be45a3a227f401c2f160cb Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Tue, 31 Oct 2023 17:27:49 +0800 Subject: [PATCH 081/144] Add method to evict an item in FileProviderMaterialisedItemsModel Signed-off-by: Claudio Cambra --- src/gui/CMakeLists.txt | 1 + .../fileprovidermaterialiseditemsmodel.h | 1 + .../fileprovidermaterialiseditemsmodel_mac.mm | 82 +++++++++++++++++++ 3 files changed, 84 insertions(+) create mode 100644 src/gui/macOS/fileprovidermaterialiseditemsmodel_mac.mm diff --git a/src/gui/CMakeLists.txt b/src/gui/CMakeLists.txt index fb48ee902e163..db37c388b65da 100644 --- a/src/gui/CMakeLists.txt +++ b/src/gui/CMakeLists.txt @@ -298,6 +298,7 @@ IF( APPLE ) macOS/fileprovideritemmetadata_mac.mm macOS/fileprovidermaterialiseditemsmodel.h macOS/fileprovidermaterialiseditemsmodel.cpp + macOS/fileprovidermaterialiseditemsmodel_mac.mm macOS/fileprovidersettingscontroller.h macOS/fileprovidersettingscontroller_mac.mm macOS/fileprovidersocketcontroller.h diff --git a/src/gui/macOS/fileprovidermaterialiseditemsmodel.h b/src/gui/macOS/fileprovidermaterialiseditemsmodel.h index faae4b9598cca..e459e07606dd1 100644 --- a/src/gui/macOS/fileprovidermaterialiseditemsmodel.h +++ b/src/gui/macOS/fileprovidermaterialiseditemsmodel.h @@ -75,6 +75,7 @@ class FileProviderMaterialisedItemsModel : public QAbstractListModel public slots: void setItems(const QVector &items); + void evictItem(const QString &identifier, const QString &domainIdentifier); private: QVector _items; diff --git a/src/gui/macOS/fileprovidermaterialiseditemsmodel_mac.mm b/src/gui/macOS/fileprovidermaterialiseditemsmodel_mac.mm new file mode 100644 index 0000000000000..482e7e7ee67ac --- /dev/null +++ b/src/gui/macOS/fileprovidermaterialiseditemsmodel_mac.mm @@ -0,0 +1,82 @@ +/* + * Copyright 2023 (c) Claudio Cambra + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "fileprovidermaterialiseditemsmodel.h" + +#include + +#import + +namespace OCC { + +namespace Mac { + +Q_LOGGING_CATEGORY(lcMacImplFileProviderMaterialisedItemsModelMac, "nextcloud.gui.macfileprovidermaterialiseditemsmodelmac", QtInfoMsg) + +void FileProviderMaterialisedItemsModel::evictItem(const QString &identifier, const QString &domainIdentifier) +{ + __block NSFileProviderManager *manager = nil; + NSString *const nsDomainIdentifier = domainIdentifier.toNSString(); + dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); + + // getDomainsWithCompletionHandler is asynchronous -- we create a dispatch semaphore in order + // to wait until it is done. This should tell you that we should not call this method very + // often! + + [NSFileProviderManager getDomainsWithCompletionHandler:^(NSArray *const domains, NSError *const error) { + if (error != nil) { + qCWarning(lcMacImplFileProviderMaterialisedItemsModelMac) << "Error fetching domains:" + << error.localizedDescription; + dispatch_semaphore_signal(semaphore); + return; + } + + BOOL foundDomain = NO; + + for (NSFileProviderDomain *const domain in domains) { + if ([domain.identifier isEqualToString:nsDomainIdentifier]) { + foundDomain = YES; + manager = [NSFileProviderManager managerForDomain:domain]; + } + } + + if (!foundDomain) { + qCWarning(lcMacImplFileProviderMaterialisedItemsModelMac) << "No matching item domain, cannot get manager"; + } + + dispatch_semaphore_signal(semaphore); + }]; + + dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); + + if (manager == nil) { + qCWarning(lcMacImplFileProviderMaterialisedItemsModelMac) << "Received null manager for domain" << domainIdentifier + << "cannot evict item" << identifier; + return; + } + + [manager evictItemWithIdentifier:identifier.toNSString() completionHandler:^(NSError *error) { + if (error != nil) { + qCWarning(lcMacImplFileProviderMaterialisedItemsModelMac) << "Error evicting item due to error:" + << error.localizedDescription; + } + }]; + + // TODO: Update the model +} + + +} // namespace OCC + +} // namespace Mac From c763a9a227760803b7230de420542e01317b012f Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Tue, 31 Oct 2023 17:28:23 +0800 Subject: [PATCH 082/144] Expose items' domain identifier in FileProviderMaterialisedItemsModel Signed-off-by: Claudio Cambra --- src/gui/macOS/fileprovidermaterialiseditemsmodel.cpp | 3 +++ src/gui/macOS/fileprovidermaterialiseditemsmodel.h | 1 + 2 files changed, 4 insertions(+) diff --git a/src/gui/macOS/fileprovidermaterialiseditemsmodel.cpp b/src/gui/macOS/fileprovidermaterialiseditemsmodel.cpp index 35bce50dc50f6..8b21581bb305b 100644 --- a/src/gui/macOS/fileprovidermaterialiseditemsmodel.cpp +++ b/src/gui/macOS/fileprovidermaterialiseditemsmodel.cpp @@ -44,6 +44,8 @@ QVariant FileProviderMaterialisedItemsModel::data(const QModelIndex &index, int return item.identifier(); case ParentItemIdentifierRole: return item.parentItemIdentifier(); + case DomainIdentifierRole: + return item.domainIdentifier(); case TypeIdentifierRole: return item.typeIdentifier(); case SymlinkTargetPathRole: @@ -108,6 +110,7 @@ QHash FileProviderMaterialisedItemsModel::roleNames() const roleNames.insert({ { IdentifierRole, "identifier" }, { ParentItemIdentifierRole, "parentItemIdentifier" }, + { DomainIdentifierRole, "domainIdentifier" }, { FilenameRole, "fileName" }, { TypeIdentifierRole, "typeIdentifier" }, { SymlinkTargetPathRole, "symlinkTargetPath" }, diff --git a/src/gui/macOS/fileprovidermaterialiseditemsmodel.h b/src/gui/macOS/fileprovidermaterialiseditemsmodel.h index e459e07606dd1..4df4c34c6604b 100644 --- a/src/gui/macOS/fileprovidermaterialiseditemsmodel.h +++ b/src/gui/macOS/fileprovidermaterialiseditemsmodel.h @@ -32,6 +32,7 @@ class FileProviderMaterialisedItemsModel : public QAbstractListModel enum Roles { IdentifierRole = Qt::UserRole + 1, ParentItemIdentifierRole, + DomainIdentifierRole, FilenameRole, TypeIdentifierRole, SymlinkTargetPathRole, From d905f13d83b4a4a543a30783eaa91f42658eeca6 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Tue, 31 Oct 2023 17:28:58 +0800 Subject: [PATCH 083/144] Enable use of "Delete" button in FileProviderFileDelegate to evict item Signed-off-by: Claudio Cambra --- src/gui/macOS/ui/FileProviderEvictionDialog.qml | 1 + src/gui/macOS/ui/FileProviderFileDelegate.qml | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/src/gui/macOS/ui/FileProviderEvictionDialog.qml b/src/gui/macOS/ui/FileProviderEvictionDialog.qml index 15e4a2da82f4b..5884b63770a9b 100644 --- a/src/gui/macOS/ui/FileProviderEvictionDialog.qml +++ b/src/gui/macOS/ui/FileProviderEvictionDialog.qml @@ -39,6 +39,7 @@ ApplicationWindow { delegate: FileProviderFileDelegate { width: parent.width height: 60 + onEvictItem: root.materialisedItemsModel.evictItem(identifier, domainIdentifier) } } } diff --git a/src/gui/macOS/ui/FileProviderFileDelegate.qml b/src/gui/macOS/ui/FileProviderFileDelegate.qml index 48b6acf4987be..533bb70469feb 100644 --- a/src/gui/macOS/ui/FileProviderFileDelegate.qml +++ b/src/gui/macOS/ui/FileProviderFileDelegate.qml @@ -25,7 +25,11 @@ import com.nextcloud.desktopclient 1.0 Item { id: root + signal evictItem(string identifier, string domainIdentifier) + // Match with model rolenames for automagic setting of properties + required property string identifier + required property string domainIdentifier required property string fileName required property string userVisiblePath required property string fileType @@ -78,6 +82,7 @@ Item { text: qsTr("Delete") bgColor: Style.errorBoxBackgroundColor + onClicked: root.evictItem(root.identifier, root.domainIdentifier) } EnforcedPlainTextLabel { From 64e1166066f661e699f987448ff728b1c28899ba Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Tue, 31 Oct 2023 21:54:56 +0800 Subject: [PATCH 084/144] Fix layout for FileProviderFileDelegate Signed-off-by: Claudio Cambra --- src/gui/macOS/ui/FileProviderFileDelegate.qml | 79 +++++++------------ 1 file changed, 30 insertions(+), 49 deletions(-) diff --git a/src/gui/macOS/ui/FileProviderFileDelegate.qml b/src/gui/macOS/ui/FileProviderFileDelegate.qml index 533bb70469feb..df87fdae0394a 100644 --- a/src/gui/macOS/ui/FileProviderFileDelegate.qml +++ b/src/gui/macOS/ui/FileProviderFileDelegate.qml @@ -36,21 +36,14 @@ Item { required property size documentSize - GridLayout { + RowLayout { id: internalLayout anchors.fill: parent - rows: 3 - columns: 4 Image { id: fileIconImage - Layout.fillHeight: true - Layout.row: 0 - Layout.rowSpan: internalLayout.rows - Layout.column: 0 - verticalAlignment: Image.AlignVCenter horizontalAlignment: Image.AlignHCenter source: "image://tray-image-provider/:/fileicon/" + root.userVisiblePath @@ -59,60 +52,48 @@ Item { fillMode: Image.PreserveAspectFit } - EnforcedPlainTextLabel { - id: fileNameLabel - + Column { Layout.fillWidth: true - Layout.row: 0 - Layout.column: 1 - Layout.columnSpan: 2 - text: root.fileName + EnforcedPlainTextLabel { + id: fileNameLabel + width: parent.width + text: root.fileName + } + + EnforcedPlainTextLabel { + id: pathLabel + width: parent.width + text: root.userVisiblePath + elide: Text.ElideLeft + } + + Row { + width: parent.width + + EnforcedPlainTextLabel { + id: fileSizeLabel + text: root.documentSize + } + + EnforcedPlainTextLabel { + id: fileTypeLabel + text: root.fileType + color: Style.ncSecondaryTextColor + } + } } CustomButton { id: deleteButton - Layout.preferredWidth: width Layout.minimumWidth: implicitWidth Layout.fillHeight: true - Layout.row: 0 - Layout.rowSpan: internalLayout.rows - Layout.column: 2 + Layout.alignment: Qt.AlignRight | Qt.AlignVCenter text: qsTr("Delete") bgColor: Style.errorBoxBackgroundColor onClicked: root.evictItem(root.identifier, root.domainIdentifier) } - - EnforcedPlainTextLabel { - id: pathLabel - - Layout.fillWidth: true - Layout.row: 1 - Layout.column: 1 - Layout.columnSpan: 2 - - text: root.userVisiblePath - } - - EnforcedPlainTextLabel { - id: fileSizeLabel - - Layout.row: 2 - Layout.column: 1 - - text: root.documentSize - } - - EnforcedPlainTextLabel { - id: fileTypeLabel - - Layout.row: 2 - Layout.column: 2 - - text: root.fileType - color: Style.ncSecondaryTextColor - } } } From ba2bef2495f6702127bd1440467f61bd64d42bd2 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Wed, 1 Nov 2023 13:20:51 +0800 Subject: [PATCH 085/144] Add fileproviderutils namespace Signed-off-by: Claudio Cambra --- src/gui/CMakeLists.txt | 2 ++ src/gui/macOS/fileproviderutils.h | 43 ++++++++++++++++++++++++++ src/gui/macOS/fileproviderutils_mac.mm | 27 ++++++++++++++++ 3 files changed, 72 insertions(+) create mode 100644 src/gui/macOS/fileproviderutils.h create mode 100644 src/gui/macOS/fileproviderutils_mac.mm diff --git a/src/gui/CMakeLists.txt b/src/gui/CMakeLists.txt index db37c388b65da..99dcde464653b 100644 --- a/src/gui/CMakeLists.txt +++ b/src/gui/CMakeLists.txt @@ -308,6 +308,8 @@ IF( APPLE ) macOS/fileprovidersocketserver_mac.mm macOS/fileproviderstorageuseenumerationobserver.h macOS/fileproviderstorageuseenumerationobserver.m + macOS/fileproviderutils.h + macOS/fileproviderutils_mac.mm macOS/fileproviderxpc.h macOS/fileproviderxpc_mac.mm macOS/fileproviderxpc_mac_utils.h diff --git a/src/gui/macOS/fileproviderutils.h b/src/gui/macOS/fileproviderutils.h new file mode 100644 index 0000000000000..af9cfbc43b8d0 --- /dev/null +++ b/src/gui/macOS/fileproviderutils.h @@ -0,0 +1,43 @@ +/* + * Copyright 2023 (c) Claudio Cambra + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#pragma once + +#import + +/** + * This file contains the FileProviderUtils namespace, which contains + * utility functions for the FileProvider extension. + * + * Unlike other classes or namespaces in this module, this does not have + * a clear file separation between C++ and Objective C++ code. + * This is intended as a completely Objective-C++ namespace! + * + * You should threfore try to avoid using this in C++ code wherever possible + * and only use this in *_mac.mm implementation files. + */ + +namespace OCC { + +namespace Mac { + +namespace FileProviderUtils { + + + +} // namespace FileProviderUtils + +} // namespace Mac + +} // namespace OCC diff --git a/src/gui/macOS/fileproviderutils_mac.mm b/src/gui/macOS/fileproviderutils_mac.mm new file mode 100644 index 0000000000000..059ce34d0acd1 --- /dev/null +++ b/src/gui/macOS/fileproviderutils_mac.mm @@ -0,0 +1,27 @@ +/* + * Copyright 2023 (c) Claudio Cambra + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "fileproviderutils.h" + +namespace OCC { + +namespace Mac { + +namespace FileProviderUtils { + +} // namespace FileProviderUtils + +} // namespace Mac + +} // namespace OCC From b47665efbadf32b9e552e50001a3a635f3ad7b2a Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Wed, 1 Nov 2023 13:34:59 +0800 Subject: [PATCH 086/144] Add convenience function to FileProviderUtils to get manager for a given domain identifier Signed-off-by: Claudio Cambra --- src/gui/macOS/fileproviderutils.h | 7 +++- src/gui/macOS/fileproviderutils_mac.mm | 51 ++++++++++++++++++++++++++ 2 files changed, 56 insertions(+), 2 deletions(-) diff --git a/src/gui/macOS/fileproviderutils.h b/src/gui/macOS/fileproviderutils.h index af9cfbc43b8d0..a4dec29ef2e69 100644 --- a/src/gui/macOS/fileproviderutils.h +++ b/src/gui/macOS/fileproviderutils.h @@ -14,7 +14,9 @@ #pragma once -#import +class QString; + +@class NSFileProviderManager; /** * This file contains the FileProviderUtils namespace, which contains @@ -34,7 +36,8 @@ namespace Mac { namespace FileProviderUtils { - +// Synchronous function to get manager for a domain identifier +NSFileProviderManager *managerForDomainIdentifier(const QString &domainIdentifier); } // namespace FileProviderUtils diff --git a/src/gui/macOS/fileproviderutils_mac.mm b/src/gui/macOS/fileproviderutils_mac.mm index 059ce34d0acd1..7522b93ddf806 100644 --- a/src/gui/macOS/fileproviderutils_mac.mm +++ b/src/gui/macOS/fileproviderutils_mac.mm @@ -14,12 +14,63 @@ #include "fileproviderutils.h" +#include +#include + +#import + namespace OCC { namespace Mac { namespace FileProviderUtils { +Q_LOGGING_CATEGORY(lcMacFileProviderUtils, "nextcloud.gui.macfileproviderutils", QtInfoMsg) + +NSFileProviderManager *managerForDomainIdentifier(const QString &domainIdentifier) +{ + __block NSFileProviderManager *manager = nil; + NSString *const nsDomainIdentifier = domainIdentifier.toNSString(); + dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); + + // getDomainsWithCompletionHandler is asynchronous -- we create a dispatch semaphore in order + // to wait until it is done. This should tell you that we should not call this method very + // often! + + [NSFileProviderManager getDomainsWithCompletionHandler:^(NSArray *const domains, NSError *const error) { + if (error != nil) { + qCWarning(lcMacFileProviderUtils) << "Error fetching domains:" + << error.localizedDescription; + dispatch_semaphore_signal(semaphore); + return; + } + + BOOL foundDomain = NO; + + for (NSFileProviderDomain *const domain in domains) { + if ([domain.identifier isEqualToString:nsDomainIdentifier]) { + foundDomain = YES; + manager = [NSFileProviderManager managerForDomain:domain]; + } + } + + if (!foundDomain) { + qCWarning(lcMacFileProviderUtils) << "No matching item domain, cannot get manager"; + } + + dispatch_semaphore_signal(semaphore); + }]; + + dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); + + if (manager == nil) { + qCWarning(lcMacFileProviderUtils) << "Received null manager for domain" + << domainIdentifier; + } + + return manager; +} + } // namespace FileProviderUtils } // namespace Mac From 44a6f4673e0520b55256e8e39f104f8ab2b170ca Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Wed, 1 Nov 2023 13:44:37 +0800 Subject: [PATCH 087/144] Separate domain finding into separate function in FileProviderUtils Signed-off-by: Claudio Cambra --- src/gui/macOS/fileproviderutils.h | 4 ++++ src/gui/macOS/fileproviderutils_mac.mm | 27 ++++++++++++++++---------- 2 files changed, 21 insertions(+), 10 deletions(-) diff --git a/src/gui/macOS/fileproviderutils.h b/src/gui/macOS/fileproviderutils.h index a4dec29ef2e69..063be6d6d4d72 100644 --- a/src/gui/macOS/fileproviderutils.h +++ b/src/gui/macOS/fileproviderutils.h @@ -16,6 +16,7 @@ class QString; +@class NSFileProviderDomain; @class NSFileProviderManager; /** @@ -36,6 +37,9 @@ namespace Mac { namespace FileProviderUtils { +// Synchronous function to get the domain for a domain identifier +NSFileProviderDomain *domainForIdentifier(const QString &domainIdentifier); + // Synchronous function to get manager for a domain identifier NSFileProviderManager *managerForDomainIdentifier(const QString &domainIdentifier); diff --git a/src/gui/macOS/fileproviderutils_mac.mm b/src/gui/macOS/fileproviderutils_mac.mm index 7522b93ddf806..fbb40f42fb153 100644 --- a/src/gui/macOS/fileproviderutils_mac.mm +++ b/src/gui/macOS/fileproviderutils_mac.mm @@ -27,9 +27,9 @@ Q_LOGGING_CATEGORY(lcMacFileProviderUtils, "nextcloud.gui.macfileproviderutils", QtInfoMsg) -NSFileProviderManager *managerForDomainIdentifier(const QString &domainIdentifier) +NSFileProviderDomain *domainForIdentifier(const QString &domainIdentifier) { - __block NSFileProviderManager *manager = nil; + __block NSFileProviderDomain *foundDomain = nil; NSString *const nsDomainIdentifier = domainIdentifier.toNSString(); dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); @@ -45,24 +45,31 @@ return; } - BOOL foundDomain = NO; - for (NSFileProviderDomain *const domain in domains) { if ([domain.identifier isEqualToString:nsDomainIdentifier]) { - foundDomain = YES; - manager = [NSFileProviderManager managerForDomain:domain]; + foundDomain = domain; + break; } } - if (!foundDomain) { - qCWarning(lcMacFileProviderUtils) << "No matching item domain, cannot get manager"; - } - dispatch_semaphore_signal(semaphore); }]; dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); + if (foundDomain == nil) { + qCWarning(lcMacFileProviderUtils) << "No matching item domain for identifier" + << domainIdentifier; + } + + return foundDomain; +} + +NSFileProviderManager *managerForDomainIdentifier(const QString &domainIdentifier) +{ + NSFileProviderDomain * const domain = domainForIdentifier(domainIdentifier); + NSFileProviderManager * const manager = [NSFileProviderManager managerForDomain:domain]; + if (manager == nil) { qCWarning(lcMacFileProviderUtils) << "Received null manager for domain" << domainIdentifier; From b23e6bc4eeeea8d48904cdd4eeb6ebf6741e1372 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Wed, 1 Nov 2023 13:57:09 +0800 Subject: [PATCH 088/144] Use FileProviderUtils function to get manager for domain id in FileProviderItemMetadata Signed-off-by: Claudio Cambra --- src/gui/macOS/fileprovideritemmetadata_mac.mm | 46 ++++--------------- 1 file changed, 8 insertions(+), 38 deletions(-) diff --git a/src/gui/macOS/fileprovideritemmetadata_mac.mm b/src/gui/macOS/fileprovideritemmetadata_mac.mm index 5aced7128b853..e356a0245895c 100644 --- a/src/gui/macOS/fileprovideritemmetadata_mac.mm +++ b/src/gui/macOS/fileprovideritemmetadata_mac.mm @@ -20,6 +20,8 @@ #import #import +#include "fileproviderutils.h" + namespace { QString nsNameComponentsToLocalisedQString(NSPersonNameComponents *const nameComponents) @@ -107,53 +109,21 @@ QString nsNameComponentsToLocalisedQString(NSPersonNameComponents *const nameCom return QStringLiteral("Unknown"); } - NSString *const nsItemIdentifier = id.toNSString(); - NSString *const nsDomainIdentifier = domainId.toNSString(); - __block QString returnPath = QObject::tr("Unknown"); - __block NSFileProviderManager *manager = nil; - dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); - - // getDomainsWithCompletionHandler is asynchronous -- we create a dispatch semaphore in order - // to wait until it is done. This should tell you that we should not call this method very - // often! - - [NSFileProviderManager getDomainsWithCompletionHandler:^(NSArray *const domains, NSError *const error) { - if (error != nil) { - qCWarning(lcMacImplFileProviderItemMetadata) << "Error fetching domains:" << error.localizedDescription; - dispatch_semaphore_signal(semaphore); - return; - } - - BOOL foundDomain = NO; - - for (NSFileProviderDomain *const domain in domains) { - if ([domain.identifier isEqualToString:nsDomainIdentifier]) { - foundDomain = YES; - manager = [NSFileProviderManager managerForDomain:domain]; - } - } + NSFileProviderManager *manager = FileProviderUtils::managerForDomainIdentifier(domainId); - if (!foundDomain) { - qCWarning(lcMacImplFileProviderItemMetadata) << "No matching item domain, cannot get item path"; - } - - dispatch_semaphore_signal(semaphore); - }]; - - dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); - - if (manager == nil) { + if (manager == nil) { qCWarning(lcMacImplFileProviderItemMetadata) << "Null manager, cannot get item path"; - dispatch_release(semaphore); return returnPath; } - // getUserVisibleUrl is also async, so wait here too + NSString *const nsItemIdentifier = id.toNSString(); + dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); + + // getUserVisibleUrl is async, so wait here [manager getUserVisibleURLForItemIdentifier:nsItemIdentifier completionHandler:^(NSURL *const userVisibleFile, NSError *const error) { - qCDebug(lcMacImplFileProviderItemMetadata) << "Got user visible url for item identifier." << "url:" << userVisibleFile << "error:" << error.localizedDescription; if (error != nil) { qCWarning(lcMacImplFileProviderItemMetadata) << "Error fetching user visible url for item identifier." << error.localizedDescription; From 84d8561a8efabdaad868f1f764461538721847a8 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Wed, 1 Nov 2023 13:57:33 +0800 Subject: [PATCH 089/144] Use FileProviderUtils function to get manager from domain id in FileProviderMaterialisedItemsModel Signed-off-by: Claudio Cambra --- .../fileprovidermaterialiseditemsmodel_mac.mm | 37 ++----------------- 1 file changed, 3 insertions(+), 34 deletions(-) diff --git a/src/gui/macOS/fileprovidermaterialiseditemsmodel_mac.mm b/src/gui/macOS/fileprovidermaterialiseditemsmodel_mac.mm index 482e7e7ee67ac..6d2201b85bfaa 100644 --- a/src/gui/macOS/fileprovidermaterialiseditemsmodel_mac.mm +++ b/src/gui/macOS/fileprovidermaterialiseditemsmodel_mac.mm @@ -18,6 +18,8 @@ #import +#include "fileproviderutils.h" + namespace OCC { namespace Mac { @@ -26,40 +28,7 @@ void FileProviderMaterialisedItemsModel::evictItem(const QString &identifier, const QString &domainIdentifier) { - __block NSFileProviderManager *manager = nil; - NSString *const nsDomainIdentifier = domainIdentifier.toNSString(); - dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); - - // getDomainsWithCompletionHandler is asynchronous -- we create a dispatch semaphore in order - // to wait until it is done. This should tell you that we should not call this method very - // often! - - [NSFileProviderManager getDomainsWithCompletionHandler:^(NSArray *const domains, NSError *const error) { - if (error != nil) { - qCWarning(lcMacImplFileProviderMaterialisedItemsModelMac) << "Error fetching domains:" - << error.localizedDescription; - dispatch_semaphore_signal(semaphore); - return; - } - - BOOL foundDomain = NO; - - for (NSFileProviderDomain *const domain in domains) { - if ([domain.identifier isEqualToString:nsDomainIdentifier]) { - foundDomain = YES; - manager = [NSFileProviderManager managerForDomain:domain]; - } - } - - if (!foundDomain) { - qCWarning(lcMacImplFileProviderMaterialisedItemsModelMac) << "No matching item domain, cannot get manager"; - } - - dispatch_semaphore_signal(semaphore); - }]; - - dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); - + NSFileProviderManager * const manager = FileProviderUtils::managerForDomainIdentifier(domainIdentifier); if (manager == nil) { qCWarning(lcMacImplFileProviderMaterialisedItemsModelMac) << "Received null manager for domain" << domainIdentifier << "cannot evict item" << identifier; From 643d30a3d565e7b7690c0a1c1b7f596abae10d20 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Wed, 1 Nov 2023 14:33:05 +0800 Subject: [PATCH 090/144] Fix retain crash when calling managerForDomain Signed-off-by: Claudio Cambra --- src/gui/macOS/fileproviderutils_mac.mm | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/gui/macOS/fileproviderutils_mac.mm b/src/gui/macOS/fileproviderutils_mac.mm index fbb40f42fb153..1f3d046d9fcf4 100644 --- a/src/gui/macOS/fileproviderutils_mac.mm +++ b/src/gui/macOS/fileproviderutils_mac.mm @@ -47,8 +47,9 @@ for (NSFileProviderDomain *const domain in domains) { if ([domain.identifier isEqualToString:nsDomainIdentifier]) { - foundDomain = domain; - break; + [domain retain]; + foundDomain = domain; + break; } } @@ -56,6 +57,7 @@ }]; dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); + dispatch_release(semaphore); if (foundDomain == nil) { qCWarning(lcMacFileProviderUtils) << "No matching item domain for identifier" @@ -68,13 +70,20 @@ NSFileProviderManager *managerForDomainIdentifier(const QString &domainIdentifier) { NSFileProviderDomain * const domain = domainForIdentifier(domainIdentifier); - NSFileProviderManager * const manager = [NSFileProviderManager managerForDomain:domain]; + if (domain == nil) { + qCWarning(lcMacFileProviderUtils) << "Received null domain for identifier" + << domainIdentifier + << "cannot acquire manager"; + return nil; + } + NSFileProviderManager * const manager = [NSFileProviderManager managerForDomain:domain]; if (manager == nil) { qCWarning(lcMacFileProviderUtils) << "Received null manager for domain" << domainIdentifier; } + [domain release]; return manager; } From f22bf9e52769375ae995acf745e8d4be03221c9a Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Wed, 1 Nov 2023 16:48:32 +0800 Subject: [PATCH 091/144] Display file sizes as nicely formatted string in file provider file delegate Signed-off-by: Claudio Cambra --- src/gui/macOS/fileprovidermaterialiseditemsmodel.cpp | 7 +++++-- src/gui/macOS/fileprovidermaterialiseditemsmodel.h | 5 ++++- src/gui/macOS/ui/FileProviderFileDelegate.qml | 8 ++++---- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/src/gui/macOS/fileprovidermaterialiseditemsmodel.cpp b/src/gui/macOS/fileprovidermaterialiseditemsmodel.cpp index 8b21581bb305b..a4c0729910be4 100644 --- a/src/gui/macOS/fileprovidermaterialiseditemsmodel.cpp +++ b/src/gui/macOS/fileprovidermaterialiseditemsmodel.cpp @@ -98,8 +98,10 @@ QVariant FileProviderMaterialisedItemsModel::data(const QModelIndex &index, int return item.sharedByCurrentUser(); case UserVisiblePathRole: return item.userVisiblePath(); - case FileTypeRole: + case FileTypeStringRole: return item.fileTypeString(); + case FileSizeStringRole: + return _locale.formattedDataSize(item.documentSize()); } return {}; } @@ -138,7 +140,8 @@ QHash FileProviderMaterialisedItemsModel::roleNames() const { SharedRole, "shared" }, { SharedByCurrentUserRole, "sharedByCurrentUser" }, { UserVisiblePathRole, "userVisiblePath" }, - { FileTypeRole, "fileType" }, + { FileTypeStringRole, "fileTypeString" }, + { FileSizeStringRole, "fileSizeString" }, }); return roleNames; } diff --git a/src/gui/macOS/fileprovidermaterialiseditemsmodel.h b/src/gui/macOS/fileprovidermaterialiseditemsmodel.h index 4df4c34c6604b..9b7ff8035b57d 100644 --- a/src/gui/macOS/fileprovidermaterialiseditemsmodel.h +++ b/src/gui/macOS/fileprovidermaterialiseditemsmodel.h @@ -15,6 +15,7 @@ #pragma once #include +#include #include "gui/macOS/fileprovideritemmetadata.h" @@ -60,7 +61,8 @@ class FileProviderMaterialisedItemsModel : public QAbstractListModel SharedRole, SharedByCurrentUserRole, UserVisiblePathRole, - FileTypeRole, + FileTypeStringRole, + FileSizeStringRole, }; Q_ENUM(Roles) @@ -80,6 +82,7 @@ public slots: private: QVector _items; + QLocale _locale; }; } // namespace Mac diff --git a/src/gui/macOS/ui/FileProviderFileDelegate.qml b/src/gui/macOS/ui/FileProviderFileDelegate.qml index df87fdae0394a..b16e7361ea48c 100644 --- a/src/gui/macOS/ui/FileProviderFileDelegate.qml +++ b/src/gui/macOS/ui/FileProviderFileDelegate.qml @@ -32,9 +32,9 @@ Item { required property string domainIdentifier required property string fileName required property string userVisiblePath - required property string fileType + required property string fileTypeString - required property size documentSize + required property string fileSizeString RowLayout { id: internalLayout @@ -73,12 +73,12 @@ Item { EnforcedPlainTextLabel { id: fileSizeLabel - text: root.documentSize + text: root.fileSizeString } EnforcedPlainTextLabel { id: fileTypeLabel - text: root.fileType + text: root.fileTypeString color: Style.ncSecondaryTextColor } } From 5c3cd6925296a166c23f3d3cd894927c10e3232b Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Wed, 1 Nov 2023 16:48:58 +0800 Subject: [PATCH 092/144] Improve visuals of file delegate details UI Signed-off-by: Claudio Cambra --- src/gui/macOS/ui/FileProviderFileDelegate.qml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/gui/macOS/ui/FileProviderFileDelegate.qml b/src/gui/macOS/ui/FileProviderFileDelegate.qml index b16e7361ea48c..25d812f6623e0 100644 --- a/src/gui/macOS/ui/FileProviderFileDelegate.qml +++ b/src/gui/macOS/ui/FileProviderFileDelegate.qml @@ -70,10 +70,12 @@ Item { Row { width: parent.width + spacing: Style.smallSpacing EnforcedPlainTextLabel { id: fileSizeLabel text: root.fileSizeString + font.bold: true } EnforcedPlainTextLabel { From a204f114d2b1cbf7e676d792db07a95e4aedd4f8 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Wed, 1 Nov 2023 16:53:19 +0800 Subject: [PATCH 093/144] Have backup for 0 value in itemmetadata documentsize in materialised items model Signed-off-by: Claudio Cambra --- .../macOS/fileprovidermaterialiseditemsmodel.cpp | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/gui/macOS/fileprovidermaterialiseditemsmodel.cpp b/src/gui/macOS/fileprovidermaterialiseditemsmodel.cpp index a4c0729910be4..b8b4fa8f602c6 100644 --- a/src/gui/macOS/fileprovidermaterialiseditemsmodel.cpp +++ b/src/gui/macOS/fileprovidermaterialiseditemsmodel.cpp @@ -14,6 +14,8 @@ #include "fileprovidermaterialiseditemsmodel.h" +#include + namespace OCC { namespace Mac { @@ -101,7 +103,19 @@ QVariant FileProviderMaterialisedItemsModel::data(const QModelIndex &index, int case FileTypeStringRole: return item.fileTypeString(); case FileSizeStringRole: - return _locale.formattedDataSize(item.documentSize()); + { + const auto docSize = item.documentSize(); + if (docSize > 0) { + return _locale.formattedDataSize(item.documentSize()); + } + + // If the document size is 0, we can try to get the size of the file + // directly from its path. These are all materialised files anyway + // so the size will be properly represented + const auto path = item.userVisiblePath(); + const auto fileInfo = QFileInfo(path); + return _locale.formattedDataSize(fileInfo.size()); + } } return {}; } From cfbdf3a77376c4d79fcad5b59f6fe4ff8cfb41c2 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Wed, 1 Nov 2023 17:30:43 +0800 Subject: [PATCH 094/144] Provide feedback when materialised item eviction fails Signed-off-by: Claudio Cambra --- .../fileprovidermaterialiseditemsmodel_mac.mm | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/gui/macOS/fileprovidermaterialiseditemsmodel_mac.mm b/src/gui/macOS/fileprovidermaterialiseditemsmodel_mac.mm index 6d2201b85bfaa..b24f3833ffafd 100644 --- a/src/gui/macOS/fileprovidermaterialiseditemsmodel_mac.mm +++ b/src/gui/macOS/fileprovidermaterialiseditemsmodel_mac.mm @@ -20,6 +20,8 @@ #include "fileproviderutils.h" +#include "gui/systray.h" + namespace OCC { namespace Mac { @@ -30,15 +32,23 @@ { NSFileProviderManager * const manager = FileProviderUtils::managerForDomainIdentifier(domainIdentifier); if (manager == nil) { - qCWarning(lcMacImplFileProviderMaterialisedItemsModelMac) << "Received null manager for domain" << domainIdentifier - << "cannot evict item" << identifier; + qCWarning(lcMacImplFileProviderMaterialisedItemsModelMac) << "Received null manager for domain" + << domainIdentifier + << "cannot evict item" + << identifier; + Systray::instance()->showMessage(tr("Error"), + tr("An internal error occurred. Please try again later."), + QSystemTrayIcon::Warning); return; } [manager evictItemWithIdentifier:identifier.toNSString() completionHandler:^(NSError *error) { if (error != nil) { - qCWarning(lcMacImplFileProviderMaterialisedItemsModelMac) << "Error evicting item due to error:" - << error.localizedDescription; + const auto errorDesc = QString::fromNSString(error.localizedDescription); + qCWarning(lcMacImplFileProviderMaterialisedItemsModelMac) << "Error evicting item:" << errorDesc; + Systray::instance()->showMessage(tr("Error"), + tr("An error occurred while trying to delete the local copy of this item: %1").arg(errorDesc), + QSystemTrayIcon::Warning); } }]; From b9cf1350803122971fb44eb641bacbf9281d4802 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Wed, 1 Nov 2023 17:42:55 +0800 Subject: [PATCH 095/144] Update the materialised items model post-file eviction Signed-off-by: Claudio Cambra --- .../fileprovidermaterialiseditemsmodel_mac.mm | 25 ++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/src/gui/macOS/fileprovidermaterialiseditemsmodel_mac.mm b/src/gui/macOS/fileprovidermaterialiseditemsmodel_mac.mm index b24f3833ffafd..ec1dd2ce0c98b 100644 --- a/src/gui/macOS/fileprovidermaterialiseditemsmodel_mac.mm +++ b/src/gui/macOS/fileprovidermaterialiseditemsmodel_mac.mm @@ -42,6 +42,8 @@ return; } + __block BOOL successfullyDeleted = YES; + [manager evictItemWithIdentifier:identifier.toNSString() completionHandler:^(NSError *error) { if (error != nil) { const auto errorDesc = QString::fromNSString(error.localizedDescription); @@ -49,10 +51,31 @@ Systray::instance()->showMessage(tr("Error"), tr("An error occurred while trying to delete the local copy of this item: %1").arg(errorDesc), QSystemTrayIcon::Warning); + successfullyDeleted = NO; } }]; - // TODO: Update the model + if (successfullyDeleted == NO) { + return; + } + + const auto deletedItemIt = std::find_if(_items.cbegin(), + _items.cend(), + [identifier, domainIdentifier](const FileProviderItemMetadata &item) { + return item.identifier() == identifier && item.domainIdentifier() == domainIdentifier; + }); + + if (deletedItemIt == _items.cend()) { + qCWarning(lcMacImplFileProviderMaterialisedItemsModelMac) << "Could not find item" + << identifier + << "in model items."; + return; + } + + const auto deletedItemRow = std::distance(_items.cbegin(), deletedItemIt); + beginRemoveRows({}, deletedItemRow, deletedItemRow); + _items.remove(deletedItemRow); + endRemoveRows(); } From 0ddd22ddbb72ee1b56b084c66e61f682a671ed44 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Wed, 1 Nov 2023 18:51:51 +0800 Subject: [PATCH 096/144] Add function to retrieve log entries in File provider Logger extension Signed-off-by: Claudio Cambra --- .../Extensions/Logger+Extensions.swift | 23 ++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Extensions/Logger+Extensions.swift b/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Extensions/Logger+Extensions.swift index f58ff0e908878..f84ea068e59cd 100644 --- a/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Extensions/Logger+Extensions.swift +++ b/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Extensions/Logger+Extensions.swift @@ -26,5 +26,26 @@ extension Logger { static let localFileOps = Logger(subsystem: subsystem, category: "localfileoperations") static let ncFilesDatabase = Logger(subsystem: subsystem, category: "nextcloudfilesdatabase") static let materialisedFileHandling = Logger( - subsystem: subsystem, category: "materialisedfilehandling") + subsystem: subsystem, category: "materialisedfilehandling" + ) + static let logger = Logger(subsystem: subsystem, category: "logger") + + @available(macOSApplicationExtension 12.0, *) + static func logEntries(interval: TimeInterval = -3600) -> Array? { + do { + let logStore = try OSLogStore(scope: .currentProcessIdentifier) + let timeDate = Date().addingTimeInterval(interval) + let logPosition = logStore.position(date: timeDate) + let entries = try logStore.getEntries(at: logPosition) + + return entries + .compactMap { $0 as? OSLogEntryLog } + .filter { $0.subsystem == Logger.subsystem } + .map { $0.composedMessage } + + } catch let error { + Logger.logger.error("Could not acquire os log store: \(error)"); + return nil + } + } } From 1dcfee4087a8adea962ffcbf0873704ef7c5ff83 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Wed, 1 Nov 2023 18:52:27 +0800 Subject: [PATCH 097/144] Add function to File Provider Logger extension to create debug logs file Signed-off-by: Claudio Cambra --- .../Extensions/Logger+Extensions.swift | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Extensions/Logger+Extensions.swift b/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Extensions/Logger+Extensions.swift index f84ea068e59cd..cffeb366f74c3 100644 --- a/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Extensions/Logger+Extensions.swift +++ b/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Extensions/Logger+Extensions.swift @@ -48,4 +48,24 @@ extension Logger { return nil } } + + @available(macOSApplicationExtension 12.0, *) + static func createDebugArchive(saveFolderUrl: URL) { + let saveFileUrl = saveFolderUrl.appendingPathComponent("nc-fileprovider-debug.txt") + let saveFilePath = saveFolderUrl.path + + guard FileManager.default.createFile(atPath: saveFilePath, contents: nil) else { + Logger.logger.error("Could not create log file") + return + } + + guard let logs = Logger.logEntries() else { + Logger.logger.error("Cannot create debug archive without any logs.") + return + } + + for logString in logs { + try? logString.write(to: saveFileUrl, atomically: true, encoding: .utf8) + } + } } From 0a5df3ba66db286feafb985d9f294d88a10b1684 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Tue, 14 Nov 2023 16:35:08 +0800 Subject: [PATCH 098/144] Add public convenience static method to get domainIdentifier from a given accountState Signed-off-by: Claudio Cambra --- src/gui/macOS/fileproviderdomainmanager.h | 2 ++ src/gui/macOS/fileproviderdomainmanager_mac.mm | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/src/gui/macOS/fileproviderdomainmanager.h b/src/gui/macOS/fileproviderdomainmanager.h index e2a5e9db37f7c..8de3fc1f24939 100644 --- a/src/gui/macOS/fileproviderdomainmanager.h +++ b/src/gui/macOS/fileproviderdomainmanager.h @@ -33,6 +33,8 @@ class FileProviderDomainManager : public QObject ~FileProviderDomainManager() override; static AccountStatePtr accountStateFromFileProviderDomainIdentifier(const QString &domainIdentifier); + static QString fileProviderDomainIdentifierFromAccountState(const AccountStatePtr &accountState); + void start(); signals: diff --git a/src/gui/macOS/fileproviderdomainmanager_mac.mm b/src/gui/macOS/fileproviderdomainmanager_mac.mm index c185c953b8df5..331c44df54dbf 100644 --- a/src/gui/macOS/fileproviderdomainmanager_mac.mm +++ b/src/gui/macOS/fileproviderdomainmanager_mac.mm @@ -677,6 +677,11 @@ QStringList configuredDomainIds() const return accountForReceivedDomainIdentifier; } +QString FileProviderDomainManager::fileProviderDomainIdentifierFromAccountState(const AccountStatePtr &accountState) +{ + return domainIdentifierForAccount(accountState->account()); +} + } // namespace Mac } // namespace OCC From 292ff9b3bc82da96313bc1bafc63a487d96a0ca3 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Tue, 14 Nov 2023 16:52:34 +0800 Subject: [PATCH 099/144] Add convenience method in FileProvider to send a message to a given file provider domain Signed-off-by: Claudio Cambra --- src/gui/macOS/fileprovider.h | 3 +++ src/gui/macOS/fileprovider_mac.mm | 19 ++++++++++++++++--- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/src/gui/macOS/fileprovider.h b/src/gui/macOS/fileprovider.h index e9d89b7a5ba8a..30bfaf791c146 100644 --- a/src/gui/macOS/fileprovider.h +++ b/src/gui/macOS/fileprovider.h @@ -39,6 +39,9 @@ class FileProvider : public QObject static bool fileProviderAvailable(); +public slots: + void sendMessageToDomain(const QString &domainIdentifier, const QString &message); + private slots: void configureXPC(); diff --git a/src/gui/macOS/fileprovider_mac.mm b/src/gui/macOS/fileprovider_mac.mm index 5303d9fa71a05..5ba8f93892176 100644 --- a/src/gui/macOS/fileprovider_mac.mm +++ b/src/gui/macOS/fileprovider_mac.mm @@ -12,13 +12,15 @@ * for more details. */ -#import + +#include "fileprovider.h" #include -#include "configfile.h" +#include "libsync/configfile.h" +#include "gui/macOS/fileprovidersocketcontroller.h" -#include "fileprovider.h" +#import namespace OCC { @@ -95,5 +97,16 @@ } } +void FileProvider::sendMessageToDomain(const QString &domainIdentifier, const QString &message) +{ + const auto domainSocketController = _socketServer->socketControllerForDomain(domainIdentifier); + if (!domainSocketController) { + qCWarning(lcMacFileProvider) << "Could not find socket controller for domain identifier" << domainIdentifier; + return; + } + + domainSocketController->sendMessage(message); +} + } // namespace Mac } // namespace OCC From 24dda9b43701f1cc7f05445cc463e4971b47ad4d Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Tue, 14 Nov 2023 17:12:30 +0800 Subject: [PATCH 100/144] Add createFileProvider slot to FileProviderSettingsController Signed-off-by: Claudio Cambra --- src/gui/macOS/fileprovidersettingscontroller.h | 1 + .../macOS/fileprovidersettingscontroller_mac.mm | 16 ++++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/src/gui/macOS/fileprovidersettingscontroller.h b/src/gui/macOS/fileprovidersettingscontroller.h index 699c95b230979..72d983144ce9d 100644 --- a/src/gui/macOS/fileprovidersettingscontroller.h +++ b/src/gui/macOS/fileprovidersettingscontroller.h @@ -49,6 +49,7 @@ public slots: void setVfsEnabledForAccount(const QString &userIdAtHost, const bool setEnabled); void createEvictionWindowForAccount(const QString &userIdAtHost); + void createDebugArchive(const QString &userIdAtHost); signals: void vfsEnabledAccountsChanged(); diff --git a/src/gui/macOS/fileprovidersettingscontroller_mac.mm b/src/gui/macOS/fileprovidersettingscontroller_mac.mm index 330af35cd3668..a1beaca8630fd 100644 --- a/src/gui/macOS/fileprovidersettingscontroller_mac.mm +++ b/src/gui/macOS/fileprovidersettingscontroller_mac.mm @@ -14,10 +14,12 @@ #include "fileprovidersettingscontroller.h" +#include #include #include "gui/systray.h" #include "gui/userinfo.h" +#include "gui/macOS/fileprovider.h" #include "gui/macOS/fileprovideritemmetadata.h" #include "gui/macOS/fileprovidermaterialiseditemsmodel.h" @@ -403,6 +405,20 @@ void initialCheck() dialog->show(); } +void FileProviderSettingsController::createDebugArchive(const QString &userIdAtHost) +{ + const auto filename = QFileDialog::getSaveFileName(nullptr, + tr("Create Debug Archive"), + {}, + tr("Zip Archives") + " (*.zip)"); + if (filename.isEmpty()) { + return; + } + + const auto message = QString(QStringLiteral("CREATE_DEBUG_ARCHIVE") + "~" + filename); + FileProvider::instance()->sendMessageToDomain(userIdAtHost, message); +} + } // namespace Mac } // namespace OCC From 9733c11f7f8a387cccd82215eb1dd3071e22bc35 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Tue, 14 Nov 2023 18:10:14 +0800 Subject: [PATCH 101/144] Add button to create debug archive Signed-off-by: Claudio Cambra --- src/gui/macOS/ui/FileProviderSettings.qml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/gui/macOS/ui/FileProviderSettings.qml b/src/gui/macOS/ui/FileProviderSettings.qml index 1b62731b1c90f..095251dfc4113 100644 --- a/src/gui/macOS/ui/FileProviderSettings.qml +++ b/src/gui/macOS/ui/FileProviderSettings.qml @@ -144,5 +144,10 @@ Page { value: generalActionsGrid.localUsedStorage / generalActionsGrid.remoteUsedStorage } } + + CustomButton { + text: qsTr("Create debug archive") + onClicked: root.controller.createDebugArchive(root.accountUserIdAtHost) + } } } From 70521e95bc71798aa8de72c1917775ca0569e15f Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Tue, 2 Jan 2024 20:11:05 +0800 Subject: [PATCH 102/144] Implement creating debug archive in client communication service Signed-off-by: Claudio Cambra --- .../FileProviderExt/Services/ClientCommunicationProtocol.h | 1 + .../Services/ClientCommunicationService.swift | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Services/ClientCommunicationProtocol.h b/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Services/ClientCommunicationProtocol.h index 766eab1f6778d..bcf439c149e21 100644 --- a/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Services/ClientCommunicationProtocol.h +++ b/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Services/ClientCommunicationProtocol.h @@ -24,6 +24,7 @@ serverUrl:(NSString *)serverUrl password:(NSString *)password; - (void)removeAccountConfig; +- (void)createDebugArchiveAtURL:(NSURL *)url; @end diff --git a/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Services/ClientCommunicationService.swift b/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Services/ClientCommunicationService.swift index 83d26ae3a84ce..06c0afcc2b770 100644 --- a/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Services/ClientCommunicationService.swift +++ b/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Services/ClientCommunicationService.swift @@ -60,4 +60,10 @@ class ClientCommunicationService: NSObject, NSFileProviderServiceSource, NSXPCLi func removeAccountConfig() { self.fpExtension.removeAccountConfig() } + + func createDebugArchive(at url: URL!) { + if #available(macOSApplicationExtension 12.0, *) { + Logger.createDebugArchive(saveFolderUrl: url) + } + } } From b2e5659c43ffc52d88c937443a48b89cd1434d7d Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Tue, 2 Jan 2024 20:11:33 +0800 Subject: [PATCH 103/144] Replace old and now broken socket based debug archive command with command over XPC Signed-off-by: Claudio Cambra --- src/gui/macOS/fileprovider.h | 2 +- src/gui/macOS/fileprovider_mac.mm | 12 +++--------- src/gui/macOS/fileprovidersettingscontroller_mac.mm | 4 +--- src/gui/macOS/fileproviderxpc.h | 1 + src/gui/macOS/fileproviderxpc_mac.mm | 6 ++++++ 5 files changed, 12 insertions(+), 13 deletions(-) diff --git a/src/gui/macOS/fileprovider.h b/src/gui/macOS/fileprovider.h index 30bfaf791c146..215a62dfb2530 100644 --- a/src/gui/macOS/fileprovider.h +++ b/src/gui/macOS/fileprovider.h @@ -40,7 +40,7 @@ class FileProvider : public QObject static bool fileProviderAvailable(); public slots: - void sendMessageToDomain(const QString &domainIdentifier, const QString &message); + void createDebugArchiveForDomain(const QString &domainIdentifier, const QString &filename) const; private slots: void configureXPC(); diff --git a/src/gui/macOS/fileprovider_mac.mm b/src/gui/macOS/fileprovider_mac.mm index 5ba8f93892176..94b1d9f0190e6 100644 --- a/src/gui/macOS/fileprovider_mac.mm +++ b/src/gui/macOS/fileprovider_mac.mm @@ -18,7 +18,7 @@ #include #include "libsync/configfile.h" -#include "gui/macOS/fileprovidersocketcontroller.h" +#include "gui/macOS/fileproviderxpc.h" #import @@ -97,15 +97,9 @@ } } -void FileProvider::sendMessageToDomain(const QString &domainIdentifier, const QString &message) +void FileProvider::createDebugArchiveForDomain(const QString &domainIdentifier, const QString &filename) const { - const auto domainSocketController = _socketServer->socketControllerForDomain(domainIdentifier); - if (!domainSocketController) { - qCWarning(lcMacFileProvider) << "Could not find socket controller for domain identifier" << domainIdentifier; - return; - } - - domainSocketController->sendMessage(message); + _xpc->createDebugArchiveForExtension(domainIdentifier, filename); } } // namespace Mac diff --git a/src/gui/macOS/fileprovidersettingscontroller_mac.mm b/src/gui/macOS/fileprovidersettingscontroller_mac.mm index a1beaca8630fd..682a91632a5a8 100644 --- a/src/gui/macOS/fileprovidersettingscontroller_mac.mm +++ b/src/gui/macOS/fileprovidersettingscontroller_mac.mm @@ -414,9 +414,7 @@ void initialCheck() if (filename.isEmpty()) { return; } - - const auto message = QString(QStringLiteral("CREATE_DEBUG_ARCHIVE") + "~" + filename); - FileProvider::instance()->sendMessageToDomain(userIdAtHost, message); + FileProvider::instance()->createDebugArchiveForDomain(userIdAtHost, filename); } } // namespace Mac diff --git a/src/gui/macOS/fileproviderxpc.h b/src/gui/macOS/fileproviderxpc.h index 25efb05ad2894..9e234ae2ee3dc 100644 --- a/src/gui/macOS/fileproviderxpc.h +++ b/src/gui/macOS/fileproviderxpc.h @@ -39,6 +39,7 @@ public slots: void configureExtensions(); void authenticateExtension(const QString &extensionAccountId) const; void unauthenticateExtension(const QString &extensionAccountId) const; + void createDebugArchiveForExtension(const QString &extensionAccountId, const QString &filename) const; private slots: void slotAccountStateChanged(AccountState::State state) const; diff --git a/src/gui/macOS/fileproviderxpc_mac.mm b/src/gui/macOS/fileproviderxpc_mac.mm index 399c1af6d4bf9..22cd6ab60acbb 100644 --- a/src/gui/macOS/fileproviderxpc_mac.mm +++ b/src/gui/macOS/fileproviderxpc_mac.mm @@ -102,5 +102,11 @@ break; } } +void FileProviderXPC::createDebugArchiveForExtension(const QString &extensionAccountId, const QString &filename) const +{ + const auto clientCommService = (NSObject *)_clientCommServices.value(extensionAccountId); + NSURL *const fileURL = [NSURL fileURLWithPath:filename.toNSString()]; + [clientCommService createDebugArchiveAtURL:fileURL]; +} } // namespace OCC::Mac From 571b1ca2386012cf5d18f4ec5ecb6f89425a2a6c Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Tue, 2 Jan 2024 20:45:29 +0800 Subject: [PATCH 104/144] Directly provide text file path to logger for debug archive creation Signed-off-by: Claudio Cambra --- .../FileProviderExt/Extensions/Logger+Extensions.swift | 9 +++++---- .../Services/ClientCommunicationService.swift | 2 +- src/gui/macOS/fileprovidersettingscontroller_mac.mm | 4 ++-- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Extensions/Logger+Extensions.swift b/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Extensions/Logger+Extensions.swift index cffeb366f74c3..cc6285deaa03d 100644 --- a/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Extensions/Logger+Extensions.swift +++ b/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Extensions/Logger+Extensions.swift @@ -50,9 +50,10 @@ extension Logger { } @available(macOSApplicationExtension 12.0, *) - static func createDebugArchive(saveFolderUrl: URL) { - let saveFileUrl = saveFolderUrl.appendingPathComponent("nc-fileprovider-debug.txt") - let saveFilePath = saveFolderUrl.path + static func createDebugArchive(saveFileURL: URL) { + let saveFilePath = saveFileURL.path + + Logger.logger.info("Creating debug file at path \(saveFilePath, privacy: .public)") guard FileManager.default.createFile(atPath: saveFilePath, contents: nil) else { Logger.logger.error("Could not create log file") @@ -65,7 +66,7 @@ extension Logger { } for logString in logs { - try? logString.write(to: saveFileUrl, atomically: true, encoding: .utf8) + try? logString.write(to: saveFileURL, atomically: true, encoding: .utf8) } } } diff --git a/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Services/ClientCommunicationService.swift b/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Services/ClientCommunicationService.swift index 06c0afcc2b770..31d2b3400e8c4 100644 --- a/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Services/ClientCommunicationService.swift +++ b/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Services/ClientCommunicationService.swift @@ -63,7 +63,7 @@ class ClientCommunicationService: NSObject, NSFileProviderServiceSource, NSXPCLi func createDebugArchive(at url: URL!) { if #available(macOSApplicationExtension 12.0, *) { - Logger.createDebugArchive(saveFolderUrl: url) + Logger.createDebugArchive(saveFileURL: url) } } } diff --git a/src/gui/macOS/fileprovidersettingscontroller_mac.mm b/src/gui/macOS/fileprovidersettingscontroller_mac.mm index 682a91632a5a8..4aca60f25cd50 100644 --- a/src/gui/macOS/fileprovidersettingscontroller_mac.mm +++ b/src/gui/macOS/fileprovidersettingscontroller_mac.mm @@ -409,8 +409,8 @@ void initialCheck() { const auto filename = QFileDialog::getSaveFileName(nullptr, tr("Create Debug Archive"), - {}, - tr("Zip Archives") + " (*.zip)"); + QStandardPaths::writableLocation(QStandardPaths::StandardLocation::DocumentsLocation), + tr("Text files") + " (*.txt)"); if (filename.isEmpty()) { return; } From 9946495edb614a878539cdf45ee98d271abe449c Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Wed, 3 Jan 2024 17:16:00 +0800 Subject: [PATCH 105/144] Replace handling of debug archive creation in clientcommunicationservice with simple retrieval of debug string Signed-off-by: Claudio Cambra --- .../Extensions/Logger+Extensions.swift | 30 ++++--------------- .../Services/ClientCommunicationProtocol.h | 2 +- .../Services/ClientCommunicationService.swift | 15 ++++++++-- 3 files changed, 19 insertions(+), 28 deletions(-) diff --git a/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Extensions/Logger+Extensions.swift b/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Extensions/Logger+Extensions.swift index cc6285deaa03d..6edb6ab4be9f5 100644 --- a/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Extensions/Logger+Extensions.swift +++ b/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Extensions/Logger+Extensions.swift @@ -31,42 +31,22 @@ extension Logger { static let logger = Logger(subsystem: subsystem, category: "logger") @available(macOSApplicationExtension 12.0, *) - static func logEntries(interval: TimeInterval = -3600) -> Array? { + static func logEntries(interval: TimeInterval = -3600) -> (Array?, Error?) { do { let logStore = try OSLogStore(scope: .currentProcessIdentifier) let timeDate = Date().addingTimeInterval(interval) let logPosition = logStore.position(date: timeDate) let entries = try logStore.getEntries(at: logPosition) - return entries + return (entries .compactMap { $0 as? OSLogEntryLog } .filter { $0.subsystem == Logger.subsystem } - .map { $0.composedMessage } + .map { $0.composedMessage }, nil) } catch let error { Logger.logger.error("Could not acquire os log store: \(error)"); - return nil - } - } - - @available(macOSApplicationExtension 12.0, *) - static func createDebugArchive(saveFileURL: URL) { - let saveFilePath = saveFileURL.path - - Logger.logger.info("Creating debug file at path \(saveFilePath, privacy: .public)") - - guard FileManager.default.createFile(atPath: saveFilePath, contents: nil) else { - Logger.logger.error("Could not create log file") - return - } - - guard let logs = Logger.logEntries() else { - Logger.logger.error("Cannot create debug archive without any logs.") - return - } - - for logString in logs { - try? logString.write(to: saveFileURL, atomically: true, encoding: .utf8) + return (nil, error) } } } + diff --git a/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Services/ClientCommunicationProtocol.h b/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Services/ClientCommunicationProtocol.h index bcf439c149e21..47eb6c95bfec6 100644 --- a/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Services/ClientCommunicationProtocol.h +++ b/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Services/ClientCommunicationProtocol.h @@ -24,7 +24,7 @@ serverUrl:(NSString *)serverUrl password:(NSString *)password; - (void)removeAccountConfig; -- (void)createDebugArchiveAtURL:(NSURL *)url; +- (void)createDebugLogStringWithCompletionHandler:(void(^)(NSString *debugLogString, NSError *error))completionHandler; @end diff --git a/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Services/ClientCommunicationService.swift b/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Services/ClientCommunicationService.swift index 31d2b3400e8c4..ccdc1dc902099 100644 --- a/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Services/ClientCommunicationService.swift +++ b/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Services/ClientCommunicationService.swift @@ -61,9 +61,20 @@ class ClientCommunicationService: NSObject, NSFileProviderServiceSource, NSXPCLi self.fpExtension.removeAccountConfig() } - func createDebugArchive(at url: URL!) { + func createDebugLogString(completionHandler: ((String?, Error?) -> Void)!) { if #available(macOSApplicationExtension 12.0, *) { - Logger.createDebugArchive(saveFileURL: url) + let (logs, error) = Logger.logEntries() + guard error == nil else { + Logger.logger.error("Cannot create debug archive, received error: \(error, privacy: .public)") + completionHandler(nil, error) + return + } + guard let logs = logs else { + Logger.logger.error("Canot create debug archive with nil logs.") + completionHandler(nil, nil) + return + } + completionHandler(logs.joined(separator: "\n"), nil) } } } From 62bbf6a2ad5143f3b2d4274a3d084b6e49362fb3 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Wed, 3 Jan 2024 17:16:10 +0800 Subject: [PATCH 106/144] Create debug archive on client side Signed-off-by: Claudio Cambra --- src/gui/macOS/fileproviderxpc_mac.mm | 32 ++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/src/gui/macOS/fileproviderxpc_mac.mm b/src/gui/macOS/fileproviderxpc_mac.mm index 22cd6ab60acbb..260804b71bc31 100644 --- a/src/gui/macOS/fileproviderxpc_mac.mm +++ b/src/gui/macOS/fileproviderxpc_mac.mm @@ -104,9 +104,37 @@ } void FileProviderXPC::createDebugArchiveForExtension(const QString &extensionAccountId, const QString &filename) const { + qCInfo(lcFileProviderXPC) << "Creating debug archive for extension" << extensionAccountId << "at" << filename; + // You need to fetch the contents from the extension and then create the archive from the client side. + // The extension is not allowed to ask for permission to write into the file system as it is not a user facing process. const auto clientCommService = (NSObject *)_clientCommServices.value(extensionAccountId); - NSURL *const fileURL = [NSURL fileURLWithPath:filename.toNSString()]; - [clientCommService createDebugArchiveAtURL:fileURL]; + const auto group = dispatch_group_create(); + __block NSString *rcvdDebugLogString; + dispatch_group_enter(group); + [clientCommService createDebugLogStringWithCompletionHandler:^(NSString *const debugLogString, NSError *const error) { + if (error != nil) { + qCWarning(lcFileProviderXPC) << "Error getting debug log string" << error.localizedDescription; + dispatch_group_leave(group); + return; + } else if (debugLogString == nil) { + qCWarning(lcFileProviderXPC) << "Debug log string is nil"; + dispatch_group_leave(group); + return; + } + rcvdDebugLogString = [NSString stringWithString:debugLogString]; + [rcvdDebugLogString retain]; + dispatch_group_leave(group); + }]; + dispatch_group_wait(group, DISPATCH_TIME_FOREVER); + + QFile debugLogFile(filename); + if (debugLogFile.open(QIODevice::WriteOnly)) { + debugLogFile.write(rcvdDebugLogString.UTF8String); + debugLogFile.close(); + qCInfo(lcFileProviderXPC) << "Debug log file written to" << filename; + } else { + qCWarning(lcFileProviderXPC) << "Could not open debug log file" << filename; + } } } // namespace OCC::Mac From 6a0f76de7ec624b2309006982ba8140c588db8e5 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Wed, 3 Jan 2024 21:07:46 +0800 Subject: [PATCH 107/144] Mark MacImplementation constructor for FileProviderSettingsController as explicit Signed-off-by: Claudio Cambra --- src/gui/macOS/fileprovidersettingscontroller_mac.mm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/macOS/fileprovidersettingscontroller_mac.mm b/src/gui/macOS/fileprovidersettingscontroller_mac.mm index 4aca60f25cd50..164460c44b745 100644 --- a/src/gui/macOS/fileprovidersettingscontroller_mac.mm +++ b/src/gui/macOS/fileprovidersettingscontroller_mac.mm @@ -61,7 +61,7 @@ float gbFromBytesWithOneDecimal(const unsigned long long bytes) VfsAccountsEnabledChanged, }; - MacImplementation(FileProviderSettingsController *const parent) + explicit MacImplementation(FileProviderSettingsController *const parent) { q = parent; initialCheck(); From fd95ab71718825cd46795f300e719533a90c9948 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Wed, 3 Jan 2024 21:11:18 +0800 Subject: [PATCH 108/144] Directly generate file provider item metadatas and cache Signed-off-by: Claudio Cambra --- .../fileprovidersettingscontroller_mac.mm | 75 +++++++------------ 1 file changed, 28 insertions(+), 47 deletions(-) diff --git a/src/gui/macOS/fileprovidersettingscontroller_mac.mm b/src/gui/macOS/fileprovidersettingscontroller_mac.mm index 164460c44b745..f9be6ab1c414c 100644 --- a/src/gui/macOS/fileprovidersettingscontroller_mac.mm +++ b/src/gui/macOS/fileprovidersettingscontroller_mac.mm @@ -153,29 +153,12 @@ explicit MacImplementation(FileProviderSettingsController *const parent) { // Return cached value as we fetch asynchronously on initialisation of this class. // We will then emit a signal when the new value is found. - NSNumber *const storageUsage = [_storageUsage objectForKey:userIdAtHost.toNSString()]; - if (storageUsage == nil) { - return 0; - } - return storageUsage.unsignedLongLongValue; + return _storageUsage.value(userIdAtHost); } [[nodiscard]] QVector materialisedItemsForAccount(const QString &userIdAtHost) const { - const auto materialisedItems = [_materialisedFiles objectForKey:userIdAtHost.toNSString()]; - if (materialisedItems == nil) { - return {}; - } - - QVector qMaterialisedItems; - qMaterialisedItems.reserve(materialisedItems.count); - - for (const id item in materialisedItems) { - const auto itemMetadata = FileProviderItemMetadata::fromNSFileProviderItem(item, userIdAtHost); - qMaterialisedItems.append(itemMetadata); - } - - return qMaterialisedItems; + return _materialisedFiles.value(userIdAtHost); } private: @@ -186,7 +169,7 @@ explicit MacImplementation(FileProviderSettingsController *const parent) void fetchMaterialisedFilesStorageUsage() { - qCDebug(lcFileProviderSettingsController) << "Fetching materialised files storage usage"; + qCInfo(lcFileProviderSettingsController) << "Fetching materialised files storage usage"; [NSFileProviderManager getDomainsWithCompletionHandler: ^(NSArray *const domains, NSError *const error) { if (error != nil) { @@ -196,7 +179,7 @@ void fetchMaterialisedFilesStorageUsage() // HACK: Sometimes the system is not in a state where it wants to give us access to // the file provider domains. We will try again in 2 seconds and hope it works - __block const auto thisQobject = (QObject*)this; + const auto thisQobject = (QObject*)this; dispatch_async(dispatch_get_main_queue(), ^{ [NSTimer scheduledTimerWithTimeInterval:2 repeats:NO block:^(NSTimer *const timer) { Q_UNUSED(timer) @@ -207,7 +190,7 @@ void fetchMaterialisedFilesStorageUsage() } for (NSFileProviderDomain *const domain in domains) { - qCDebug(lcFileProviderSettingsController) << "Checking storage use for domain:" << domain.identifier; + qCInfo(lcFileProviderSettingsController) << "Checking storage use for domain:" << domain.identifier; NSFileProviderManager *const managerForDomain = [NSFileProviderManager managerForDomain:domain]; if (managerForDomain == nil) { @@ -219,10 +202,12 @@ void fetchMaterialisedFilesStorageUsage() const id enumerator = [managerForDomain enumeratorForMaterializedItems]; Q_ASSERT(enumerator != nil); + [enumerator retain]; - __block FileProviderStorageUseEnumerationObserver *const storageUseObserver = [[FileProviderStorageUseEnumerationObserver alloc] init]; - + FileProviderStorageUseEnumerationObserver *const storageUseObserver = [[FileProviderStorageUseEnumerationObserver alloc] init]; + [storageUseObserver retain]; storageUseObserver.enumerationFinishedHandler = ^(NSError *const error) { + qCInfo(lcFileProviderSettingsController) << "Enumeration finished for" << domain.identifier; if (error != nil) { qCWarning(lcFileProviderSettingsController) << "Error while enumerating storage use" << error.localizedDescription; [storageUseObserver release]; @@ -230,50 +215,46 @@ void fetchMaterialisedFilesStorageUsage() return; } - const NSUInteger usage = storageUseObserver.usage; - NSSet> *const items = storageUseObserver.materialisedItems; + const auto items = storageUseObserver.materialisedItems; Q_ASSERT(items != nil); // Remember that OCC::Account::userIdAtHost == domain.identifier for us - NSMutableDictionary *const mutableStorageDictCopy = _storageUsage.mutableCopy; - NSMutableDictionary> *> *const mutableFilesDictCopy = _materialisedFiles.mutableCopy; - - qCDebug(lcFileProviderSettingsController) << "Local storage use for" - << domain.identifier - << usage; - - [mutableStorageDictCopy setObject:@(usage) forKey:domain.identifier]; - [mutableFilesDictCopy setObject:items forKey:domain.identifier]; - - _storageUsage = mutableStorageDictCopy.copy; - _materialisedFiles = mutableFilesDictCopy.copy; - const auto qDomainIdentifier = QString::fromNSString(domain.identifier); + QVector qMaterialisedItems; + qMaterialisedItems.reserve(items.count); + for (const id item in items) { + const auto itemMetadata = FileProviderItemMetadata::fromNSFileProviderItem(item, qDomainIdentifier); + const auto storageUsage = _storageUsage.value(qDomainIdentifier) + itemMetadata.documentSize(); + qCDebug(lcFileProviderSettingsController) << "Adding item" << itemMetadata.identifier() + << "with size" << itemMetadata.documentSize() + << "to storage usage for account" << qDomainIdentifier + << "with total size" << storageUsage; + qMaterialisedItems.append(itemMetadata); + _storageUsage.insert(qDomainIdentifier, storageUsage); + } + _materialisedFiles.insert(qDomainIdentifier, qMaterialisedItems); + emit q->localStorageUsageForAccountChanged(qDomainIdentifier); emit q->materialisedItemsForAccountChanged(qDomainIdentifier); [storageUseObserver release]; [enumerator release]; }; - [enumerator enumerateItemsForObserver:storageUseObserver startingAtPage:NSFileProviderInitialPageSortedByName]; - - [storageUseObserver retain]; - [enumerator retain]; } }]; } void initialCheck() { - qCDebug(lcFileProviderSettingsController) << "Running initial checks for file provider settings controller."; + qCInfo(lcFileProviderSettingsController) << "Running initial checks for file provider settings controller."; NSArray *const vfsEnabledAccounts = nsEnabledAccounts(); if (vfsEnabledAccounts != nil) { return; } - qCDebug(lcFileProviderSettingsController) << "Initial check for file provider settings found nil enabled vfs accounts array." + qCInfo(lcFileProviderSettingsController) << "Initial check for file provider settings found nil enabled vfs accounts array." << "Enabling all accounts on initial setup."; [[maybe_unused]] const auto result = enableVfsForAllAccounts(); @@ -282,8 +263,8 @@ void initialCheck() FileProviderSettingsController *q = nullptr; NSUserDefaults *_userDefaults = NSUserDefaults.standardUserDefaults; NSString *_accountsKey = [NSString stringWithUTF8String:enabledAccountsSettingsKey]; - NSDictionary *_storageUsage = @{}; - NSDictionary > *> *_materialisedFiles = @{}; + QHash> _materialisedFiles; + QHash _storageUsage; }; FileProviderSettingsController *FileProviderSettingsController::instance() From 3b179cc1a1d931ec57233e539a9b849708619406 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Wed, 3 Jan 2024 21:11:33 +0800 Subject: [PATCH 109/144] Remove unused usage property from enumeration observer Signed-off-by: Claudio Cambra --- src/gui/macOS/fileproviderstorageuseenumerationobserver.h | 1 - src/gui/macOS/fileproviderstorageuseenumerationobserver.m | 4 ---- 2 files changed, 5 deletions(-) diff --git a/src/gui/macOS/fileproviderstorageuseenumerationobserver.h b/src/gui/macOS/fileproviderstorageuseenumerationobserver.h index 897c865c9b235..149d4249a6d46 100644 --- a/src/gui/macOS/fileproviderstorageuseenumerationobserver.h +++ b/src/gui/macOS/fileproviderstorageuseenumerationobserver.h @@ -20,7 +20,6 @@ typedef void(^UsageEnumerationFinishedHandler)(NSError *const error); @interface FileProviderStorageUseEnumerationObserver : NSObject @property (readwrite, strong) UsageEnumerationFinishedHandler enumerationFinishedHandler; -@property (readonly) NSUInteger usage; @property (readonly) NSSet> *materialisedItems; @end diff --git a/src/gui/macOS/fileproviderstorageuseenumerationobserver.m b/src/gui/macOS/fileproviderstorageuseenumerationobserver.m index 37981fe22b2d4..619f632cd015d 100644 --- a/src/gui/macOS/fileproviderstorageuseenumerationobserver.m +++ b/src/gui/macOS/fileproviderstorageuseenumerationobserver.m @@ -14,14 +14,12 @@ #import "fileproviderstorageuseenumerationobserver.h" - @implementation FileProviderStorageUseEnumerationObserver - (instancetype)init { self = [super init]; if (self) { - _usage = 0ULL; _materialisedItems = [NSSet set]; } return self; @@ -35,8 +33,6 @@ - (void)didEnumerateItems:(NSArray> *)updatedItems for (const id item in updatedItems) { NSLog(@"StorageUseEnumerationObserver: Enumerating %@ with size %llu", item.filename, item.documentSize.unsignedLongLongValue); - - _usage += item.documentSize.unsignedLongLongValue; [existingItems addObject:item]; } From 1d01f677902e1bdefe05adc9d0fc73183b8b643e Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Wed, 3 Jan 2024 21:21:10 +0800 Subject: [PATCH 110/144] Always perform fallback document size discovery in fileprovideritemmetadata Signed-off-by: Claudio Cambra --- src/gui/macOS/fileprovideritemmetadata_mac.mm | 10 ++++++++++ .../macOS/fileprovidermaterialiseditemsmodel.cpp | 14 +------------- 2 files changed, 11 insertions(+), 13 deletions(-) diff --git a/src/gui/macOS/fileprovideritemmetadata_mac.mm b/src/gui/macOS/fileprovideritemmetadata_mac.mm index e356a0245895c..d8e64abb68832 100644 --- a/src/gui/macOS/fileprovideritemmetadata_mac.mm +++ b/src/gui/macOS/fileprovideritemmetadata_mac.mm @@ -14,6 +14,7 @@ #include "fileprovideritemmetadata.h" +#include #include #import @@ -94,6 +95,15 @@ QString nsNameComponentsToLocalisedQString(NSPersonNameComponents *const nameCom metadata._userVisiblePath = metadata.getUserVisiblePath(); metadata._fileTypeString = QString::fromNSString(bridgedNsFileProviderItem.contentType.localizedDescription); + if (metadata._documentSize == 0) { + // If the document size is 0, we can try to get the size of the file + // directly from its path. These are all materialised files anyway + // so the size will be properly represented + const auto path = metadata.userVisiblePath(); + const auto fileInfo = QFileInfo(path); + metadata._documentSize = fileInfo.size(); + } + return metadata; } diff --git a/src/gui/macOS/fileprovidermaterialiseditemsmodel.cpp b/src/gui/macOS/fileprovidermaterialiseditemsmodel.cpp index b8b4fa8f602c6..2e18666c39b67 100644 --- a/src/gui/macOS/fileprovidermaterialiseditemsmodel.cpp +++ b/src/gui/macOS/fileprovidermaterialiseditemsmodel.cpp @@ -103,19 +103,7 @@ QVariant FileProviderMaterialisedItemsModel::data(const QModelIndex &index, int case FileTypeStringRole: return item.fileTypeString(); case FileSizeStringRole: - { - const auto docSize = item.documentSize(); - if (docSize > 0) { - return _locale.formattedDataSize(item.documentSize()); - } - - // If the document size is 0, we can try to get the size of the file - // directly from its path. These are all materialised files anyway - // so the size will be properly represented - const auto path = item.userVisiblePath(); - const auto fileInfo = QFileInfo(path); - return _locale.formattedDataSize(fileInfo.size()); - } + return _locale.formattedDataSize(item.documentSize()); } return {}; } From f1c7811962526c2e5f376e42fe43f133fa388509 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Tue, 9 Jan 2024 22:48:59 +0800 Subject: [PATCH 111/144] Add method to signal file provider domain via file provider settings controller Signed-off-by: Claudio Cambra --- .../macOS/fileprovidersettingscontroller.h | 1 + .../fileprovidersettingscontroller_mac.mm | 24 +++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/src/gui/macOS/fileprovidersettingscontroller.h b/src/gui/macOS/fileprovidersettingscontroller.h index 72d983144ce9d..2bfa68e357aa6 100644 --- a/src/gui/macOS/fileprovidersettingscontroller.h +++ b/src/gui/macOS/fileprovidersettingscontroller.h @@ -49,6 +49,7 @@ public slots: void setVfsEnabledForAccount(const QString &userIdAtHost, const bool setEnabled); void createEvictionWindowForAccount(const QString &userIdAtHost); + void signalFileProviderDomain(const QString &userIdAtHost); void createDebugArchive(const QString &userIdAtHost); signals: diff --git a/src/gui/macOS/fileprovidersettingscontroller_mac.mm b/src/gui/macOS/fileprovidersettingscontroller_mac.mm index f9be6ab1c414c..9629b07a5a242 100644 --- a/src/gui/macOS/fileprovidersettingscontroller_mac.mm +++ b/src/gui/macOS/fileprovidersettingscontroller_mac.mm @@ -22,6 +22,7 @@ #include "gui/macOS/fileprovider.h" #include "gui/macOS/fileprovideritemmetadata.h" #include "gui/macOS/fileprovidermaterialiseditemsmodel.h" +#include "gui/macOS/fileproviderutils.h" // Objective-C imports #import @@ -161,6 +162,24 @@ explicit MacImplementation(FileProviderSettingsController *const parent) return _materialisedFiles.value(userIdAtHost); } + void signalFileProviderDomain(const QString &userIdAtHost) const + { + qCInfo(lcFileProviderSettingsController) << "Signalling file provider domain" << userIdAtHost; + NSFileProviderDomain * const domain = FileProviderUtils::domainForIdentifier(userIdAtHost); + NSFileProviderManager * const manager = [NSFileProviderManager managerForDomain:domain]; + [manager signalEnumeratorForContainerItemIdentifier:NSFileProviderRootContainerItemIdentifier + completionHandler:^(NSError *const error) { + if (error != nil) { + qCWarning(lcFileProviderSettingsController) << "Could not signal file provider domain, error" + << error.localizedDescription; + return; + } + + qCInfo(lcFileProviderSettingsController) << "Successfully signalled file provider domain"; + // TODO: Provide some feedback in the UI + }]; + } + private: [[nodiscard]] NSArray *nsEnabledAccounts() const { @@ -386,6 +405,11 @@ void initialCheck() dialog->show(); } +void FileProviderSettingsController::signalFileProviderDomain(const QString &userIdAtHost) +{ + d->signalFileProviderDomain(userIdAtHost); +} + void FileProviderSettingsController::createDebugArchive(const QString &userIdAtHost) { const auto filename = QFileDialog::getSaveFileName(nullptr, From 369c1d737a8f39e61efd80efc6b39160ced54792 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Tue, 9 Jan 2024 22:49:22 +0800 Subject: [PATCH 112/144] Add UI button to signal file provider domain Signed-off-by: Claudio Cambra --- src/gui/macOS/ui/FileProviderSettings.qml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/gui/macOS/ui/FileProviderSettings.qml b/src/gui/macOS/ui/FileProviderSettings.qml index 095251dfc4113..7102324e9d263 100644 --- a/src/gui/macOS/ui/FileProviderSettings.qml +++ b/src/gui/macOS/ui/FileProviderSettings.qml @@ -145,6 +145,20 @@ Page { } } + EnforcedPlainTextLabel { + Layout.fillWidth: true + Layout.topMargin: Style.standardSpacing + text: qsTr("Advanced") + font.bold: true + font.pointSize: root.font.pointSize + 2 + elide: Text.ElideRight + } + + CustomButton { + text: qsTr("Signal file provider domain") + onClicked: root.controller.signalFileProviderDomain(root.accountUserIdAtHost) + } + CustomButton { text: qsTr("Create debug archive") onClicked: root.controller.createDebugArchive(root.accountUserIdAtHost) From 7a9a17a2f3c8cd29616047aaf4426d1b1e9abdba Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Tue, 9 Jan 2024 23:02:41 +0800 Subject: [PATCH 113/144] Add starter FileProviderDomainSyncStatus Signed-off-by: Claudio Cambra --- src/gui/CMakeLists.txt | 2 ++ .../macOS/fileproviderdomainsyncstatus.cpp | 20 ++++++++++++++++ src/gui/macOS/fileproviderdomainsyncstatus.h | 24 +++++++++++++++++++ 3 files changed, 46 insertions(+) create mode 100644 src/gui/macOS/fileproviderdomainsyncstatus.cpp create mode 100644 src/gui/macOS/fileproviderdomainsyncstatus.h diff --git a/src/gui/CMakeLists.txt b/src/gui/CMakeLists.txt index 99dcde464653b..5cced9edd18f0 100644 --- a/src/gui/CMakeLists.txt +++ b/src/gui/CMakeLists.txt @@ -293,6 +293,8 @@ IF( APPLE ) macOS/fileprovider_mac.mm macOS/fileproviderdomainmanager.h macOS/fileproviderdomainmanager_mac.mm + macOS/fileproviderdomainsyncstatus.h + macOS/fileproviderdomainsyncstatus.cpp macOS/fileprovideritemmetadata.h macOS/fileprovideritemmetadata.cpp macOS/fileprovideritemmetadata_mac.mm diff --git a/src/gui/macOS/fileproviderdomainsyncstatus.cpp b/src/gui/macOS/fileproviderdomainsyncstatus.cpp new file mode 100644 index 0000000000000..7e7508ab28dd5 --- /dev/null +++ b/src/gui/macOS/fileproviderdomainsyncstatus.cpp @@ -0,0 +1,20 @@ +/* +* Copyright (C) 2024 by Claudio Cambra +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +* for more details. +*/ + +#include "fileproviderdomainsyncstatus.h" + +namespace OCC::Mac +{ + +} // OCC::Mac \ No newline at end of file diff --git a/src/gui/macOS/fileproviderdomainsyncstatus.h b/src/gui/macOS/fileproviderdomainsyncstatus.h new file mode 100644 index 0000000000000..d95f28779bed4 --- /dev/null +++ b/src/gui/macOS/fileproviderdomainsyncstatus.h @@ -0,0 +1,24 @@ +/* +* Copyright (C) 2024 by Claudio Cambra +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +* for more details. +*/ + +#pragma once + +namespace OCC::Mac +{ + +class FileProviderDomainSyncStatus +{ +}; + +} // OCC::Mac From 62c85de35bc102c7f40a974d17c8ab97cba88c7a Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Tue, 9 Jan 2024 23:30:27 +0800 Subject: [PATCH 114/144] Define basic FileProviderDomainSyncStatus private implementation Signed-off-by: Claudio Cambra --- .../macOS/fileproviderdomainsyncstatus.cpp | 20 ------- src/gui/macOS/fileproviderdomainsyncstatus.h | 12 ++++- .../macOS/fileproviderdomainsyncstatus_mac.mm | 54 +++++++++++++++++++ 3 files changed, 65 insertions(+), 21 deletions(-) delete mode 100644 src/gui/macOS/fileproviderdomainsyncstatus.cpp create mode 100644 src/gui/macOS/fileproviderdomainsyncstatus_mac.mm diff --git a/src/gui/macOS/fileproviderdomainsyncstatus.cpp b/src/gui/macOS/fileproviderdomainsyncstatus.cpp deleted file mode 100644 index 7e7508ab28dd5..0000000000000 --- a/src/gui/macOS/fileproviderdomainsyncstatus.cpp +++ /dev/null @@ -1,20 +0,0 @@ -/* -* Copyright (C) 2024 by Claudio Cambra -* -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; either version 2 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, but -* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -* for more details. -*/ - -#include "fileproviderdomainsyncstatus.h" - -namespace OCC::Mac -{ - -} // OCC::Mac \ No newline at end of file diff --git a/src/gui/macOS/fileproviderdomainsyncstatus.h b/src/gui/macOS/fileproviderdomainsyncstatus.h index d95f28779bed4..fc299a10bdd7d 100644 --- a/src/gui/macOS/fileproviderdomainsyncstatus.h +++ b/src/gui/macOS/fileproviderdomainsyncstatus.h @@ -12,13 +12,23 @@ * for more details. */ +#include + #pragma once namespace OCC::Mac { -class FileProviderDomainSyncStatus +class FileProviderDomainSyncStatus : public QObject { + Q_OBJECT + +public: + explicit FileProviderDomainSyncStatus(const QString &domainIdentifier, QObject *parent = nullptr); + +private: + class MacImplementation; + std::unique_ptr d; }; } // OCC::Mac diff --git a/src/gui/macOS/fileproviderdomainsyncstatus_mac.mm b/src/gui/macOS/fileproviderdomainsyncstatus_mac.mm new file mode 100644 index 0000000000000..c8b822aa0d7e4 --- /dev/null +++ b/src/gui/macOS/fileproviderdomainsyncstatus_mac.mm @@ -0,0 +1,54 @@ +/* +* Copyright (C) 2024 by Claudio Cambra +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +* for more details. +*/ + +#include "fileproviderdomainsyncstatus.h" + +#include + +#include "gui/macOS/fileproviderutils.h" + +#import + +namespace OCC::Mac +{ + +Q_LOGGING_CATEGORY(lcMacFileProviderDomainSyncStatus, "nextcloud.gui.macfileproviderdomainsyncstatus", QtInfoMsg) + +class FileProviderDomainSyncStatus::MacImplementation +{ +public: + explicit MacImplementation(const QString &domainIdentifier) + { + _domain = FileProviderUtils::domainForIdentifier(domainIdentifier); + _manager = [NSFileProviderManager managerForDomain:_domain]; + + if (_manager == nil) { + qCWarning(lcMacFileProviderDomainSyncStatus) << "Could not get manager for domain" << domainIdentifier; + } + } + + ~MacImplementation() = default; + +private: + NSFileProviderDomain *_domain; + NSFileProviderManager *_manager; +}; + +FileProviderDomainSyncStatus::FileProviderDomainSyncStatus(const QString &domainIdentifier, QObject *parent) + : QObject(parent) + , d(std::make_unique(domainIdentifier)) +{ +} + +} // OCC::Mac From fe6d03a16b3dc9c33af93111ec4505eec2faab99 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Tue, 9 Jan 2024 23:32:53 +0800 Subject: [PATCH 115/144] Add q pointer to MacImplementation for FileProviderDomainSyncStatus Signed-off-by: Claudio Cambra --- src/gui/macOS/fileproviderdomainsyncstatus_mac.mm | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/gui/macOS/fileproviderdomainsyncstatus_mac.mm b/src/gui/macOS/fileproviderdomainsyncstatus_mac.mm index c8b822aa0d7e4..a89ccbc50cbd0 100644 --- a/src/gui/macOS/fileproviderdomainsyncstatus_mac.mm +++ b/src/gui/macOS/fileproviderdomainsyncstatus_mac.mm @@ -28,7 +28,8 @@ class FileProviderDomainSyncStatus::MacImplementation { public: - explicit MacImplementation(const QString &domainIdentifier) + explicit MacImplementation(const QString &domainIdentifier, FileProviderDomainSyncStatus *parent = nullptr) + : q(parent) { _domain = FileProviderUtils::domainForIdentifier(domainIdentifier); _manager = [NSFileProviderManager managerForDomain:_domain]; @@ -43,11 +44,12 @@ explicit MacImplementation(const QString &domainIdentifier) private: NSFileProviderDomain *_domain; NSFileProviderManager *_manager; + FileProviderDomainSyncStatus *q; }; FileProviderDomainSyncStatus::FileProviderDomainSyncStatus(const QString &domainIdentifier, QObject *parent) : QObject(parent) - , d(std::make_unique(domainIdentifier)) + , d(std::make_unique(domainIdentifier, this)) { } From 6fa969d8f2077b64e4efb2b74a9827ec514f0c75 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Wed, 10 Jan 2024 00:15:37 +0800 Subject: [PATCH 116/144] Add a starter ProgressObserver Objective-C class Signed-off-by: Claudio Cambra --- src/gui/CMakeLists.txt | 6 ++++-- src/gui/macOS/progressobserver.h | 27 +++++++++++++++++++++++++++ src/gui/macOS/progressobserver.m | 28 ++++++++++++++++++++++++++++ 3 files changed, 59 insertions(+), 2 deletions(-) create mode 100644 src/gui/macOS/progressobserver.h create mode 100644 src/gui/macOS/progressobserver.m diff --git a/src/gui/CMakeLists.txt b/src/gui/CMakeLists.txt index 5cced9edd18f0..097e4df7909e0 100644 --- a/src/gui/CMakeLists.txt +++ b/src/gui/CMakeLists.txt @@ -294,7 +294,7 @@ IF( APPLE ) macOS/fileproviderdomainmanager.h macOS/fileproviderdomainmanager_mac.mm macOS/fileproviderdomainsyncstatus.h - macOS/fileproviderdomainsyncstatus.cpp + macOS/fileproviderdomainsyncstatus_mac.mm macOS/fileprovideritemmetadata.h macOS/fileprovideritemmetadata.cpp macOS/fileprovideritemmetadata_mac.mm @@ -315,7 +315,9 @@ IF( APPLE ) macOS/fileproviderxpc.h macOS/fileproviderxpc_mac.mm macOS/fileproviderxpc_mac_utils.h - macOS/fileproviderxpc_mac_utils.mm) + macOS/fileproviderxpc_mac_utils.mm + macOS/progressobserver.h + macOS/progressobserver.m) endif() if(SPARKLE_FOUND AND BUILD_UPDATER) diff --git a/src/gui/macOS/progressobserver.h b/src/gui/macOS/progressobserver.h new file mode 100644 index 0000000000000..ad91c6394df0c --- /dev/null +++ b/src/gui/macOS/progressobserver.h @@ -0,0 +1,27 @@ +/* +* Copyright 2024 (c) Claudio Cambra +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +* for more details. +*/ + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface ProgressObserver : NSObject + +@property (readonly) NSProgress *progress; + +- (instancetype)initWithProgress:(NSProgress *)progress; + +@end + +NS_ASSUME_NONNULL_END diff --git a/src/gui/macOS/progressobserver.m b/src/gui/macOS/progressobserver.m new file mode 100644 index 0000000000000..274b3ee1054a9 --- /dev/null +++ b/src/gui/macOS/progressobserver.m @@ -0,0 +1,28 @@ +/* +* Copyright 2024 (c) Claudio Cambra +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +* for more details. +*/ + +#import "progressobserver.h" + +@implementation ProgressObserver + +- (instancetype)initWithProgress:(NSProgress *)progress +{ + self = [super init]; + if (self) { + _progress = progress; + } + return self; +} + +@end From e314fd05e748af3f4dcd194f1426b3ffb3bd18f5 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Wed, 10 Jan 2024 00:16:15 +0800 Subject: [PATCH 117/144] Acquire upload/download progress in domain sync status Signed-off-by: Claudio Cambra --- src/gui/macOS/fileproviderdomainsyncstatus_mac.mm | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/gui/macOS/fileproviderdomainsyncstatus_mac.mm b/src/gui/macOS/fileproviderdomainsyncstatus_mac.mm index a89ccbc50cbd0..065bc79e77908 100644 --- a/src/gui/macOS/fileproviderdomainsyncstatus_mac.mm +++ b/src/gui/macOS/fileproviderdomainsyncstatus_mac.mm @@ -36,7 +36,11 @@ explicit MacImplementation(const QString &domainIdentifier, FileProviderDomainSy if (_manager == nil) { qCWarning(lcMacFileProviderDomainSyncStatus) << "Could not get manager for domain" << domainIdentifier; + return; } + + _downloadProgress = [_manager globalProgressForKind:NSProgressFileOperationKindDownloading]; + _uploadProgress = [_manager globalProgressForKind:NSProgressFileOperationKindUploading]; } ~MacImplementation() = default; @@ -44,6 +48,9 @@ explicit MacImplementation(const QString &domainIdentifier, FileProviderDomainSy private: NSFileProviderDomain *_domain; NSFileProviderManager *_manager; + NSProgress *_downloadProgress; + NSProgress *_uploadProgress; + QTimer _timer; FileProviderDomainSyncStatus *q; }; From 13b0244ce6b229b9cf8058fab8c0625033d1c96f Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Wed, 10 Jan 2024 00:18:20 +0800 Subject: [PATCH 118/144] Add ProgressKVOChangeHandler property to ProgressObserver Signed-off-by: Claudio Cambra --- src/gui/macOS/progressobserver.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/gui/macOS/progressobserver.h b/src/gui/macOS/progressobserver.h index ad91c6394df0c..8e6f83b5be5e3 100644 --- a/src/gui/macOS/progressobserver.h +++ b/src/gui/macOS/progressobserver.h @@ -16,9 +16,12 @@ NS_ASSUME_NONNULL_BEGIN +typedef void(^ProgressKVOChangeHandler)(NSProgress *const progress); + @interface ProgressObserver : NSObject @property (readonly) NSProgress *progress; +@property (readwrite, atomic) ProgressKVOChangeHandler progressKVOChangeHandler; - (instancetype)initWithProgress:(NSProgress *)progress; From d387eb96ab986982f8fb86695d761f34d2d26466 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Wed, 10 Jan 2024 00:25:55 +0800 Subject: [PATCH 119/144] Add observing for important properties of nsprogress in progresshandler Signed-off-by: Claudio Cambra --- src/gui/macOS/progressobserver.m | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/gui/macOS/progressobserver.m b/src/gui/macOS/progressobserver.m index 274b3ee1054a9..b52e13b26161d 100644 --- a/src/gui/macOS/progressobserver.m +++ b/src/gui/macOS/progressobserver.m @@ -21,8 +21,22 @@ - (instancetype)initWithProgress:(NSProgress *)progress self = [super init]; if (self) { _progress = progress; + [_progress addObserver:self forKeyPath:@"totalUnitCount" options:NSKeyValueObservingOptionNew context:nil]; + [_progress addObserver:self forKeyPath:@"completedUnitCount" options:NSKeyValueObservingOptionNew context:nil]; + [_progress addObserver:self forKeyPath:@"cancelled" options:NSKeyValueObservingOptionNew context:nil]; + [_progress addObserver:self forKeyPath:@"paused" options:NSKeyValueObservingOptionNew context:nil]; + [_progress addObserver:self forKeyPath:@"fileTotalCount" options:NSKeyValueObservingOptionNew context:nil]; + [_progress addObserver:self forKeyPath:@"fileCompletedCount" options:NSKeyValueObservingOptionNew context:nil]; } return self; } +- (void)observeValueForKeyPath:(NSString *)keyPath + ofObject:(id)object + change:(NSDictionary *)change + context:(void *)context +{ + self.progressKVOChangeHandler(self.progress); +} + @end From f881c1d483f65bbe74a7b51c650fb8a172428552 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Wed, 10 Jan 2024 01:04:52 +0800 Subject: [PATCH 120/144] Add main properties to FileProviderDomainSyncStatus Signed-off-by: Claudio Cambra --- src/gui/macOS/fileproviderdomainsyncstatus.h | 52 +++++++ .../macOS/fileproviderdomainsyncstatus_mac.mm | 136 ++++++++++++++++++ 2 files changed, 188 insertions(+) diff --git a/src/gui/macOS/fileproviderdomainsyncstatus.h b/src/gui/macOS/fileproviderdomainsyncstatus.h index fc299a10bdd7d..11573e013e7a0 100644 --- a/src/gui/macOS/fileproviderdomainsyncstatus.h +++ b/src/gui/macOS/fileproviderdomainsyncstatus.h @@ -22,11 +22,63 @@ namespace OCC::Mac class FileProviderDomainSyncStatus : public QObject { Q_OBJECT + Q_PROPERTY(bool syncing READ syncing NOTIFY syncingChanged) + Q_PROPERTY(bool downloading READ downloading NOTIFY downloadingChanged) + Q_PROPERTY(bool uploading READ uploading NOTIFY uploadingChanged) + Q_PROPERTY(double fractionCompleted READ fractionCompleted NOTIFY fractionCompletedChanged) + Q_PROPERTY(double downloadFractionCompleted READ downloadFractionCompleted NOTIFY downloadFractionCompletedChanged) + Q_PROPERTY(double uploadFractionCompleted READ uploadFractionCompleted NOTIFY uploadFractionCompletedChanged) + Q_PROPERTY(int downloadFileTotalCount READ downloadFileTotalCount NOTIFY downloadFileTotalCountChanged) + Q_PROPERTY(int downloadFileCompletedCount READ downloadFileCompletedCount NOTIFY downloadFileCompletedCountChanged) + Q_PROPERTY(int uploadFileTotalCount READ uploadFileTotalCount NOTIFY uploadFileTotalCountChanged) + Q_PROPERTY(int uploadFileCompletedCount READ uploadFileCompletedCount NOTIFY uploadFileCompletedCountChanged) + // TODO: more detailed reporting (time remaining, megabytes, etc.) public: explicit FileProviderDomainSyncStatus(const QString &domainIdentifier, QObject *parent = nullptr); + bool syncing() const; + bool downloading() const; + bool uploading() const; + double fractionCompleted() const; + double downloadFractionCompleted() const; + double uploadFractionCompleted() const; + int downloadFileTotalCount() const; + int downloadFileCompletedCount() const; + int uploadFileTotalCount() const; + int uploadFileCompletedCount() const; + +signals: + void syncingChanged(bool syncing); + void downloadingChanged(bool downloading); + void uploadingChanged(bool uploading); + void fractionCompletedChanged(double fractionCompleted); + void downloadFractionCompletedChanged(double downloadFractionCompleted); + void uploadFractionCompletedChanged(double uploadFractionCompleted); + void downloadFileTotalCountChanged(int downloadFileTotalCount); + void downloadFileCompletedCountChanged(int downloadFileCompletedCount); + void uploadFileTotalCountChanged(int uploadFileTotalCount); + void uploadFileCompletedCountChanged(int uploadFileCompletedCount); + private: + void setDownloading(const bool syncing); + void setUploading(const bool syncing); + void setDownloadFractionCompleted(const double fractionCompleted); + void setUploadFractionCompleted(const double fractionCompleted); + void setDownloadFileTotalCount(const int fileTotalCount); + void setDownloadFileCompletedCount(const int fileCompletedCount); + void setUploadFileTotalCount(const int fileTotalCount); + void setUploadFileCompletedCount(const int fileCompletedCount); + + bool _downloading = false; + bool _uploading = false; + double _downloadFractionCompleted = 0.0; + double _uploadFractionCompleted = 0.0; + int _downloadFileTotalCount = 0; + int _downloadFileCompletedCount = 0; + int _uploadFileTotalCount = 0; + int _uploadFileCompletedCount = 0; + class MacImplementation; std::unique_ptr d; }; diff --git a/src/gui/macOS/fileproviderdomainsyncstatus_mac.mm b/src/gui/macOS/fileproviderdomainsyncstatus_mac.mm index 065bc79e77908..f81ebb01e0f1b 100644 --- a/src/gui/macOS/fileproviderdomainsyncstatus_mac.mm +++ b/src/gui/macOS/fileproviderdomainsyncstatus_mac.mm @@ -60,4 +60,140 @@ explicit MacImplementation(const QString &domainIdentifier, FileProviderDomainSy { } +FileProviderDomainSyncStatus::~FileProviderDomainSyncStatus() = default; + +bool FileProviderDomainSyncStatus::syncing() const +{ + return downloading() || uploading(); +} + +bool FileProviderDomainSyncStatus::downloading() const +{ + return _downloading; +} + +bool FileProviderDomainSyncStatus::uploading() const +{ + return _uploading; +} + +double FileProviderDomainSyncStatus::fractionCompleted() const +{ + return (downloadFractionCompleted() + uploadFractionCompleted()) / 2; +} + +double FileProviderDomainSyncStatus::downloadFractionCompleted() const +{ + return _downloadFractionCompleted; +} + +double FileProviderDomainSyncStatus::uploadFractionCompleted() const +{ + return _uploadFractionCompleted; +} + +int FileProviderDomainSyncStatus::downloadFileTotalCount() const +{ + return _downloadFileTotalCount; +} + +int FileProviderDomainSyncStatus::downloadFileCompletedCount() const +{ + return _downloadFileCompletedCount; +} + +int FileProviderDomainSyncStatus::uploadFileTotalCount() const +{ + return _uploadFileTotalCount; +} + +int FileProviderDomainSyncStatus::uploadFileCompletedCount() const +{ + return _uploadFileCompletedCount; +} + +void FileProviderDomainSyncStatus::setDownloading(const bool downloading) +{ + if (_downloading == downloading) { + return; + } + + _downloading = downloading; + emit downloadingChanged(_downloading); + emit syncingChanged(syncing()); +} + +void FileProviderDomainSyncStatus::setUploading(const bool uploading) +{ + if (_uploading == uploading) { + return; + } + + _uploading = uploading; + emit uploadingChanged(_uploading); + emit syncingChanged(syncing()); +} + +void FileProviderDomainSyncStatus::setDownloadFractionCompleted(const double fractionCompleted) +{ + if (_downloadFractionCompleted == fractionCompleted) { + return; + } + + _downloadFractionCompleted = fractionCompleted; + emit downloadFractionCompletedChanged(_downloadFractionCompleted); + emit fractionCompletedChanged(fractionCompleted()); +} + +void FileProviderDomainSyncStatus::setUploadFractionCompleted(const double fractionCompleted) +{ + if (_uploadFractionCompleted == fractionCompleted) { + return; + } + + _uploadFractionCompleted = fractionCompleted; + emit uploadFractionCompletedChanged(_uploadFractionCompleted); + emit fractionCompletedChanged(fractionCompleted()); +} + +void FileProviderDomainSyncStatus::setDownloadFileTotalCount(const int fileTotalCount) +{ + if (_downloadFileTotalCount == fileTotalCount) { + return; + } + + _downloadFileTotalCount = fileTotalCount; + emit downloadFileTotalCountChanged(_downloadFileTotalCount); +} + +void FileProviderDomainSyncStatus::setDownloadFileCompletedCount(const int fileCompletedCount) +{ + if (_downloadFileCompletedCount == fileCompletedCount) { + return; + } + + _downloadFileCompletedCount = fileCompletedCount; + emit downloadFileCompletedCountChanged(_downloadFileCompletedCount); +} + +void FileProviderDomainSyncStatus::setUploadFileTotalCount(const int fileTotalCount) +{ + if (_uploadFileTotalCount == fileTotalCount) { + return; + } + + _uploadFileTotalCount = fileTotalCount; + emit uploadFileTotalCountChanged(_uploadFileTotalCount); +} + +void FileProviderDomainSyncStatus::setUploadFileCompletedCount(const int fileCompletedCount) +{ + if (_uploadFileCompletedCount == fileCompletedCount) { + return; + } + + _uploadFileCompletedCount = fileCompletedCount; + emit uploadFileCompletedCountChanged(_uploadFileCompletedCount); +} + } // OCC::Mac From 6d9c44526d863008a721ea6addb9418e8078a1a1 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Wed, 10 Jan 2024 01:07:49 +0800 Subject: [PATCH 121/144] Update properties via ProgressObserver on FileProviderDomainSyncStatus Signed-off-by: Claudio Cambra --- .../macOS/fileproviderdomainsyncstatus_mac.mm | 34 ++++++++++++++----- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/src/gui/macOS/fileproviderdomainsyncstatus_mac.mm b/src/gui/macOS/fileproviderdomainsyncstatus_mac.mm index f81ebb01e0f1b..373f19868a565 100644 --- a/src/gui/macOS/fileproviderdomainsyncstatus_mac.mm +++ b/src/gui/macOS/fileproviderdomainsyncstatus_mac.mm @@ -20,6 +20,8 @@ #import +#import "gui/macOS/progressobserver.h" + namespace OCC::Mac { @@ -39,19 +41,35 @@ explicit MacImplementation(const QString &domainIdentifier, FileProviderDomainSy return; } - _downloadProgress = [_manager globalProgressForKind:NSProgressFileOperationKindDownloading]; - _uploadProgress = [_manager globalProgressForKind:NSProgressFileOperationKindUploading]; + NSProgress *const downloadProgress = [_manager globalProgressForKind:NSProgressFileOperationKindDownloading]; + NSProgress *const uploadProgress = [_manager globalProgressForKind:NSProgressFileOperationKindUploading]; + _downloadProgressObserver = [[ProgressObserver alloc] initWithProgress:downloadProgress]; + _uploadProgressObserver = [[ProgressObserver alloc] initWithProgress:uploadProgress]; + + _downloadProgressObserver.progressKVOChangeHandler = ^(NSProgress *const progress){ + qCDebug(lcMacFileProviderDomainSyncStatus) << "Download progress changed" << progress.localizedDescription; + q->setDownloading(!progress.paused && !progress.cancelled && !progress.finished); + q->setDownloadFractionCompleted(progress.fractionCompleted); + q->setDownloadFileTotalCount(progress.fileTotalCount.intValue); + q->setDownloadFileCompletedCount(progress.fileCompletedCount.intValue); + }; + _uploadProgressObserver.progressKVOChangeHandler = ^(NSProgress *const progress){ + qCDebug(lcMacFileProviderDomainSyncStatus) << "Upload progress changed" << progress.localizedDescription; + q->setUploading(!progress.paused && !progress.cancelled && !progress.finished); + q->setUploadFractionCompleted(progress.fractionCompleted); + q->setUploadFileTotalCount(progress.fileTotalCount.intValue); + q->setUploadFileCompletedCount(progress.fileCompletedCount.intValue); + }; } ~MacImplementation() = default; private: - NSFileProviderDomain *_domain; - NSFileProviderManager *_manager; - NSProgress *_downloadProgress; - NSProgress *_uploadProgress; - QTimer _timer; - FileProviderDomainSyncStatus *q; + NSFileProviderDomain *_domain = nil; + NSFileProviderManager *_manager = nil; + ProgressObserver *_downloadProgressObserver = nullptr; + ProgressObserver *_uploadProgressObserver = nullptr; + FileProviderDomainSyncStatus *q = nullptr; }; FileProviderDomainSyncStatus::FileProviderDomainSyncStatus(const QString &domainIdentifier, QObject *parent) From 78732bfeb00d8841a1352b355ad2e4fce2dbb0b1 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Wed, 10 Jan 2024 02:15:17 +0800 Subject: [PATCH 122/144] Fix parameter name shadowing in fraction completed methods of domain sync status Signed-off-by: Claudio Cambra --- src/gui/macOS/fileproviderdomainsyncstatus_mac.mm | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/gui/macOS/fileproviderdomainsyncstatus_mac.mm b/src/gui/macOS/fileproviderdomainsyncstatus_mac.mm index 373f19868a565..c954a76497631 100644 --- a/src/gui/macOS/fileproviderdomainsyncstatus_mac.mm +++ b/src/gui/macOS/fileproviderdomainsyncstatus_mac.mm @@ -152,24 +152,24 @@ explicit MacImplementation(const QString &domainIdentifier, FileProviderDomainSy emit syncingChanged(syncing()); } -void FileProviderDomainSyncStatus::setDownloadFractionCompleted(const double fractionCompleted) +void FileProviderDomainSyncStatus::setDownloadFractionCompleted(const double downloadFractionCompleted) { - if (_downloadFractionCompleted == fractionCompleted) { + if (_downloadFractionCompleted == downloadFractionCompleted) { return; } - _downloadFractionCompleted = fractionCompleted; + _downloadFractionCompleted = downloadFractionCompleted; emit downloadFractionCompletedChanged(_downloadFractionCompleted); emit fractionCompletedChanged(fractionCompleted()); } -void FileProviderDomainSyncStatus::setUploadFractionCompleted(const double fractionCompleted) +void FileProviderDomainSyncStatus::setUploadFractionCompleted(const double uploadFractionCompleted) { - if (_uploadFractionCompleted == fractionCompleted) { + if (_uploadFractionCompleted == uploadFractionCompleted) { return; } - _uploadFractionCompleted = fractionCompleted; + _uploadFractionCompleted = uploadFractionCompleted; emit uploadFractionCompletedChanged(_uploadFractionCompleted); emit fractionCompletedChanged(fractionCompleted()); } From 21a317cff3bc4b057c780601a27569b9c115138d Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Wed, 10 Jan 2024 02:15:32 +0800 Subject: [PATCH 123/144] Fix unique ptr compile issue in domain sync status Signed-off-by: Claudio Cambra --- src/gui/macOS/fileproviderdomainsyncstatus.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/gui/macOS/fileproviderdomainsyncstatus.h b/src/gui/macOS/fileproviderdomainsyncstatus.h index 11573e013e7a0..c0321698bce37 100644 --- a/src/gui/macOS/fileproviderdomainsyncstatus.h +++ b/src/gui/macOS/fileproviderdomainsyncstatus.h @@ -36,6 +36,7 @@ class FileProviderDomainSyncStatus : public QObject public: explicit FileProviderDomainSyncStatus(const QString &domainIdentifier, QObject *parent = nullptr); + ~FileProviderDomainSyncStatus() override; bool syncing() const; bool downloading() const; From 9774ac6dde380a97404cf148405ee4fc40bd6360 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Wed, 10 Jan 2024 02:16:28 +0800 Subject: [PATCH 124/144] Make mac implementation of file provider settings controller a QObject Signed-off-by: Claudio Cambra --- src/gui/macOS/fileprovidersettingscontroller.h | 3 +-- src/gui/macOS/fileprovidersettingscontroller_mac.mm | 7 ++----- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/src/gui/macOS/fileprovidersettingscontroller.h b/src/gui/macOS/fileprovidersettingscontroller.h index 2bfa68e357aa6..2d5ef10b10bd2 100644 --- a/src/gui/macOS/fileprovidersettingscontroller.h +++ b/src/gui/macOS/fileprovidersettingscontroller.h @@ -60,10 +60,9 @@ public slots: private: explicit FileProviderSettingsController(QObject *parent = nullptr); - ~FileProviderSettingsController() override; class MacImplementation; - std::unique_ptr d; + MacImplementation *d; QHash _userInfos; }; diff --git a/src/gui/macOS/fileprovidersettingscontroller_mac.mm b/src/gui/macOS/fileprovidersettingscontroller_mac.mm index 9629b07a5a242..9905ccd5ede57 100644 --- a/src/gui/macOS/fileprovidersettingscontroller_mac.mm +++ b/src/gui/macOS/fileprovidersettingscontroller_mac.mm @@ -54,7 +54,7 @@ float gbFromBytesWithOneDecimal(const unsigned long long bytes) Q_LOGGING_CATEGORY(lcFileProviderSettingsController, "nextcloud.gui.mac.fileprovider.settingscontroller") -class FileProviderSettingsController::MacImplementation +class FileProviderSettingsController::MacImplementation : public QObject { public: enum class VfsAccountsAction { @@ -292,13 +292,10 @@ void initialCheck() return &controller; } -FileProviderSettingsController::~FileProviderSettingsController() = default; - FileProviderSettingsController::FileProviderSettingsController(QObject *parent) : QObject{parent} + , d(new FileProviderSettingsController::MacImplementation(this)) { - d = std::make_unique(this); - const auto accManager = AccountManager::instance(); const auto accountsList = accManager->accounts(); From 9ca418c92262895cf0ee13e6926a6cc30b5942a3 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Wed, 10 Jan 2024 02:18:32 +0800 Subject: [PATCH 125/144] Setup domain sync statuses in settings controller Signed-off-by: Claudio Cambra --- src/gui/macOS/fileprovidersettingscontroller.h | 2 ++ .../macOS/fileprovidersettingscontroller_mac.mm | 16 ++++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/src/gui/macOS/fileprovidersettingscontroller.h b/src/gui/macOS/fileprovidersettingscontroller.h index 2d5ef10b10bd2..3e0e04659c67e 100644 --- a/src/gui/macOS/fileprovidersettingscontroller.h +++ b/src/gui/macOS/fileprovidersettingscontroller.h @@ -17,6 +17,8 @@ #include #include +#include "gui/macOS/fileproviderdomainsyncstatus.h" + class QAbstractListModel; namespace OCC { diff --git a/src/gui/macOS/fileprovidersettingscontroller_mac.mm b/src/gui/macOS/fileprovidersettingscontroller_mac.mm index 9905ccd5ede57..8a1483ae21d62 100644 --- a/src/gui/macOS/fileprovidersettingscontroller_mac.mm +++ b/src/gui/macOS/fileprovidersettingscontroller_mac.mm @@ -180,6 +180,19 @@ void signalFileProviderDomain(const QString &userIdAtHost) const }]; } +private slots: + void updateDomainSyncStatuses() + { + qCInfo(lcFileProviderSettingsController) << "Updating domain sync statuses"; + _fileProviderDomainSyncStatuses.clear(); + const auto enabledAccounts = nsEnabledAccounts(); + for (NSString *const domainIdentifier in enabledAccounts) { + const auto qDomainIdentifier = QString::fromNSString(domainIdentifier); + const auto syncStatus = new FileProviderDomainSyncStatus(qDomainIdentifier, q); + _fileProviderDomainSyncStatuses.insert(qDomainIdentifier, syncStatus); + } + } + private: [[nodiscard]] NSArray *nsEnabledAccounts() const { @@ -270,6 +283,8 @@ void initialCheck() NSArray *const vfsEnabledAccounts = nsEnabledAccounts(); if (vfsEnabledAccounts != nil) { + updateDomainSyncStatuses(); + connect(q, &FileProviderSettingsController::vfsEnabledAccountsChanged, this, &MacImplementation::updateDomainSyncStatuses); return; } @@ -284,6 +299,7 @@ void initialCheck() NSString *_accountsKey = [NSString stringWithUTF8String:enabledAccountsSettingsKey]; QHash> _materialisedFiles; QHash _storageUsage; + QHash _fileProviderDomainSyncStatuses; }; FileProviderSettingsController *FileProviderSettingsController::instance() From 36001aeff75008af9fc7fdf51a72046ab07bd629 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Wed, 10 Jan 2024 02:19:02 +0800 Subject: [PATCH 126/144] Add method to acquire domain sync status in settings controller Signed-off-by: Claudio Cambra --- src/gui/macOS/fileprovidersettingscontroller.h | 1 + src/gui/macOS/fileprovidersettingscontroller_mac.mm | 10 ++++++++++ 2 files changed, 11 insertions(+) diff --git a/src/gui/macOS/fileprovidersettingscontroller.h b/src/gui/macOS/fileprovidersettingscontroller.h index 3e0e04659c67e..bf980fdf770c7 100644 --- a/src/gui/macOS/fileprovidersettingscontroller.h +++ b/src/gui/macOS/fileprovidersettingscontroller.h @@ -46,6 +46,7 @@ class FileProviderSettingsController : public QObject [[nodiscard]] Q_INVOKABLE float remoteStorageUsageGbForAccount(const QString &userIdAtHost) const; [[nodiscard]] Q_INVOKABLE QAbstractListModel *materialisedItemsModelForAccount(const QString &userIdAtHost); + [[nodiscard]] Q_INVOKABLE FileProviderDomainSyncStatus *domainSyncStatusForAccount(const QString &userIdAtHost) const; public slots: void setVfsEnabledForAccount(const QString &userIdAtHost, const bool setEnabled); diff --git a/src/gui/macOS/fileprovidersettingscontroller_mac.mm b/src/gui/macOS/fileprovidersettingscontroller_mac.mm index 8a1483ae21d62..2a2fd0663d704 100644 --- a/src/gui/macOS/fileprovidersettingscontroller_mac.mm +++ b/src/gui/macOS/fileprovidersettingscontroller_mac.mm @@ -180,6 +180,11 @@ void signalFileProviderDomain(const QString &userIdAtHost) const }]; } + [[nodiscard]] FileProviderDomainSyncStatus *domainSyncStatusForAccount(const QString &userIdAtHost) const + { + return _fileProviderDomainSyncStatuses.value(userIdAtHost); + } + private slots: void updateDomainSyncStatuses() { @@ -435,6 +440,11 @@ void initialCheck() FileProvider::instance()->createDebugArchiveForDomain(userIdAtHost, filename); } +FileProviderDomainSyncStatus *FileProviderSettingsController::domainSyncStatusForAccount(const QString &userIdAtHost) const +{ + return d->domainSyncStatusForAccount(userIdAtHost); +} + } // namespace Mac } // namespace OCC From f8ebbe8c7111dd29930091089a2677f4231dbfba Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Wed, 10 Jan 2024 15:42:33 +0800 Subject: [PATCH 127/144] Fix crash on state change in file provider domain sync status Signed-off-by: Claudio Cambra --- .../macOS/fileproviderdomainsyncstatus_mac.mm | 40 ++++++++++++++----- src/gui/macOS/progressobserver.h | 2 +- 2 files changed, 30 insertions(+), 12 deletions(-) diff --git a/src/gui/macOS/fileproviderdomainsyncstatus_mac.mm b/src/gui/macOS/fileproviderdomainsyncstatus_mac.mm index c954a76497631..7df9bb7a8665e 100644 --- a/src/gui/macOS/fileproviderdomainsyncstatus_mac.mm +++ b/src/gui/macOS/fileproviderdomainsyncstatus_mac.mm @@ -30,7 +30,7 @@ class FileProviderDomainSyncStatus::MacImplementation { public: - explicit MacImplementation(const QString &domainIdentifier, FileProviderDomainSyncStatus *parent = nullptr) + explicit MacImplementation(const QString &domainIdentifier, FileProviderDomainSyncStatus *parent) : q(parent) { _domain = FileProviderUtils::domainForIdentifier(domainIdentifier); @@ -47,23 +47,41 @@ explicit MacImplementation(const QString &domainIdentifier, FileProviderDomainSy _uploadProgressObserver = [[ProgressObserver alloc] initWithProgress:uploadProgress]; _downloadProgressObserver.progressKVOChangeHandler = ^(NSProgress *const progress){ - qCDebug(lcMacFileProviderDomainSyncStatus) << "Download progress changed" << progress.localizedDescription; - q->setDownloading(!progress.paused && !progress.cancelled && !progress.finished); - q->setDownloadFractionCompleted(progress.fractionCompleted); - q->setDownloadFileTotalCount(progress.fileTotalCount.intValue); - q->setDownloadFileCompletedCount(progress.fileCompletedCount.intValue); + updateDownload(progress); }; _uploadProgressObserver.progressKVOChangeHandler = ^(NSProgress *const progress){ - qCDebug(lcMacFileProviderDomainSyncStatus) << "Upload progress changed" << progress.localizedDescription; - q->setUploading(!progress.paused && !progress.cancelled && !progress.finished); - q->setUploadFractionCompleted(progress.fractionCompleted); - q->setUploadFileTotalCount(progress.fileTotalCount.intValue); - q->setUploadFileCompletedCount(progress.fileCompletedCount.intValue); + updateUpload(progress); }; } ~MacImplementation() = default; + void updateDownload(NSProgress *const progress) const + { + qCInfo(lcMacFileProviderDomainSyncStatus) << "Download progress changed" << progress.localizedDescription; + if (progress == nil || q == nullptr) { + return; + } + + q->setDownloading(!progress.paused && !progress.cancelled && !progress.finished); + q->setDownloadFractionCompleted(progress.fractionCompleted); + q->setDownloadFileTotalCount(progress.fileTotalCount.intValue); + q->setDownloadFileCompletedCount(progress.fileCompletedCount.intValue); + } + + void updateUpload(NSProgress *const progress) const + { + qCInfo(lcMacFileProviderDomainSyncStatus) << "Upload progress changed" << progress.localizedDescription; + if (progress == nil || q == nullptr) { + return; + } + + q->setUploading(!progress.paused && !progress.cancelled && !progress.finished); + q->setUploadFractionCompleted(progress.fractionCompleted); + q->setUploadFileTotalCount(progress.fileTotalCount.intValue); + q->setUploadFileCompletedCount(progress.fileCompletedCount.intValue); + } + private: NSFileProviderDomain *_domain = nil; NSFileProviderManager *_manager = nil; diff --git a/src/gui/macOS/progressobserver.h b/src/gui/macOS/progressobserver.h index 8e6f83b5be5e3..51b23ed92fbcd 100644 --- a/src/gui/macOS/progressobserver.h +++ b/src/gui/macOS/progressobserver.h @@ -21,7 +21,7 @@ typedef void(^ProgressKVOChangeHandler)(NSProgress *const progress); @interface ProgressObserver : NSObject @property (readonly) NSProgress *progress; -@property (readwrite, atomic) ProgressKVOChangeHandler progressKVOChangeHandler; +@property (readwrite, copy) ProgressKVOChangeHandler progressKVOChangeHandler; - (instancetype)initWithProgress:(NSProgress *)progress; From 9e235f99fa5ce74c30272fa9101f42c76189c1b0 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Mon, 15 Jan 2024 01:28:11 +0800 Subject: [PATCH 128/144] Enable use of domain sync status class in QML Signed-off-by: Claudio Cambra --- src/gui/macOS/fileproviderdomainsyncstatus.h | 5 +++++ src/gui/macOS/fileproviderdomainsyncstatus_mac.mm | 1 + 2 files changed, 6 insertions(+) diff --git a/src/gui/macOS/fileproviderdomainsyncstatus.h b/src/gui/macOS/fileproviderdomainsyncstatus.h index c0321698bce37..db0f377161b4b 100644 --- a/src/gui/macOS/fileproviderdomainsyncstatus.h +++ b/src/gui/macOS/fileproviderdomainsyncstatus.h @@ -13,6 +13,7 @@ */ #include +#include #pragma once @@ -22,6 +23,8 @@ namespace OCC::Mac class FileProviderDomainSyncStatus : public QObject { Q_OBJECT + QML_ELEMENT + QML_UNCREATABLE("FileProviderDomainSyncStatus cannot be instantiated from QML") Q_PROPERTY(bool syncing READ syncing NOTIFY syncingChanged) Q_PROPERTY(bool downloading READ downloading NOTIFY downloadingChanged) Q_PROPERTY(bool uploading READ uploading NOTIFY uploadingChanged) @@ -85,3 +88,5 @@ class FileProviderDomainSyncStatus : public QObject }; } // OCC::Mac + +Q_DECLARE_METATYPE(OCC::Mac::FileProviderDomainSyncStatus*) diff --git a/src/gui/macOS/fileproviderdomainsyncstatus_mac.mm b/src/gui/macOS/fileproviderdomainsyncstatus_mac.mm index 7df9bb7a8665e..1455f93b1613a 100644 --- a/src/gui/macOS/fileproviderdomainsyncstatus_mac.mm +++ b/src/gui/macOS/fileproviderdomainsyncstatus_mac.mm @@ -94,6 +94,7 @@ void updateUpload(NSProgress *const progress) const : QObject(parent) , d(std::make_unique(domainIdentifier, this)) { + qRegisterMetaType("FileProviderDomainSyncStatus*"); } FileProviderDomainSyncStatus::~FileProviderDomainSyncStatus() = default; From 3060ff6a716c7a993eb6579bcbff428a0e986067 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Mon, 15 Jan 2024 01:38:31 +0800 Subject: [PATCH 129/144] Add current sync status UI to file provider settings view Signed-off-by: Claudio Cambra --- src/gui/macOS/ui/FileProviderSettings.qml | 38 +++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/src/gui/macOS/ui/FileProviderSettings.qml b/src/gui/macOS/ui/FileProviderSettings.qml index 7102324e9d263..9d55b0d637ad3 100644 --- a/src/gui/macOS/ui/FileProviderSettings.qml +++ b/src/gui/macOS/ui/FileProviderSettings.qml @@ -82,6 +82,44 @@ Page { onClicked: root.controller.setVfsEnabledForAccount(root.accountUserIdAtHost, checked) } + GridLayout { + id: currentSyncGrid + + readonly property var syncStatus: root.controller.domainSyncStatusForAccount(root.accountUserIdAtHost) + + EnforcedPlainTextLabel { + Layout.row: 0 + Layout.column: 1 + Layout.columnSpan: currentSyncGrid.syncStatus.syncing ? 2 : 1 + Layout.fillWidth: true + text: currentSyncGrid.syncStatus.syncing ? qsTr("Syncing") : qsTr("All synced!") + } + + NCBusyIndicator { + id: syncIcon + + property int size: Style.trayListItemIconSize * 0.6 + + Layout.row: 0 + Layout.rowSpan: 2 + Layout.column: 0 + Layout.preferredWidth: size + Layout.preferredHeight: size + Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter + + imageSource: currentSyncGrid.syncStatus.icon + running: currentSyncGrid.syncStatus.syncing + } + + ProgressBar { + Layout.row: 1 + Layout.column: 1 + Layout.fillWidth: true + value: currentSyncGrid.syncStatus.fractionCompleted + visible: currentSyncGrid.syncStatus.syncing + } + } + GridLayout { id: generalActionsGrid From 2f752a6c5c32527dddd72050c469adf272c7c28a Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Mon, 15 Jan 2024 01:51:28 +0800 Subject: [PATCH 130/144] Only load file provider settings items if domain is enabled Signed-off-by: Claudio Cambra --- src/gui/macOS/ui/FileProviderSettings.qml | 207 ++++++++++++---------- 1 file changed, 109 insertions(+), 98 deletions(-) diff --git a/src/gui/macOS/ui/FileProviderSettings.qml b/src/gui/macOS/ui/FileProviderSettings.qml index 9d55b0d637ad3..f87ce1e3a3f9c 100644 --- a/src/gui/macOS/ui/FileProviderSettings.qml +++ b/src/gui/macOS/ui/FileProviderSettings.qml @@ -82,124 +82,135 @@ Page { onClicked: root.controller.setVfsEnabledForAccount(root.accountUserIdAtHost, checked) } - GridLayout { - id: currentSyncGrid + Loader { + id: vfsSettingsLoader - readonly property var syncStatus: root.controller.domainSyncStatusForAccount(root.accountUserIdAtHost) + Layout.fillWidth: true + Layout.fillHeight: true - EnforcedPlainTextLabel { - Layout.row: 0 - Layout.column: 1 - Layout.columnSpan: currentSyncGrid.syncStatus.syncing ? 2 : 1 - Layout.fillWidth: true - text: currentSyncGrid.syncStatus.syncing ? qsTr("Syncing") : qsTr("All synced!") - } + active: vfsEnabledCheckBox.checked + sourceComponent: ColumnLayout { + GridLayout { + id: currentSyncGrid - NCBusyIndicator { - id: syncIcon + readonly property var syncStatus: root.controller.domainSyncStatusForAccount(root.accountUserIdAtHost) - property int size: Style.trayListItemIconSize * 0.6 + EnforcedPlainTextLabel { + Layout.row: 0 + Layout.column: 1 + Layout.columnSpan: currentSyncGrid.syncStatus.syncing ? 2 : 1 + Layout.fillWidth: true + text: currentSyncGrid.syncStatus.syncing ? qsTr("Syncing") : qsTr("All synced!") + } - Layout.row: 0 - Layout.rowSpan: 2 - Layout.column: 0 - Layout.preferredWidth: size - Layout.preferredHeight: size - Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter + NCBusyIndicator { + id: syncIcon - imageSource: currentSyncGrid.syncStatus.icon - running: currentSyncGrid.syncStatus.syncing - } + property int size: Style.trayListItemIconSize * 0.6 - ProgressBar { - Layout.row: 1 - Layout.column: 1 - Layout.fillWidth: true - value: currentSyncGrid.syncStatus.fractionCompleted - visible: currentSyncGrid.syncStatus.syncing - } - } + Layout.row: 0 + Layout.rowSpan: 2 + Layout.column: 0 + Layout.preferredWidth: size + Layout.preferredHeight: size + Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter - GridLayout { - id: generalActionsGrid - - property real localUsedStorage: root.controller.localStorageUsageGbForAccount(root.accountUserIdAtHost) - property real remoteUsedStorage: root.controller.remoteStorageUsageGbForAccount(root.accountUserIdAtHost) - - Layout.fillWidth: true - columns: 3 - visible: vfsEnabledCheckBox.checked - - Connections { - target: root.controller - function onLocalStorageUsageForAccountChanged(accountUserIdAtHost) { - if (root.accountUserIdAtHost !== accountUserIdAtHost) { - return; + imageSource: currentSyncGrid.syncStatus.icon + running: currentSyncGrid.syncStatus.syncing } - generalActionsGrid.localUsedStorage = root.controller.localStorageUsageGbForAccount(root.accountUserIdAtHost); + ProgressBar { + Layout.row: 1 + Layout.column: 1 + Layout.fillWidth: true + value: currentSyncGrid.syncStatus.fractionCompleted + visible: currentSyncGrid.syncStatus.syncing + } } - function onRemoteStorageUsageForAccountChanged(accountUserIdAtHost) { - if (root.accountUserIdAtHost !== accountUserIdAtHost) { - return; - } + GridLayout { + id: generalActionsGrid - generalActionsGrid.remoteUsedStorage = root.controller.remoteStorageUsageGbForAccount(root.accountUserIdAtHost); - } - } + property real localUsedStorage: root.controller.localStorageUsageGbForAccount(root.accountUserIdAtHost) + property real remoteUsedStorage: root.controller.remoteStorageUsageGbForAccount(root.accountUserIdAtHost) - EnforcedPlainTextLabel { - Layout.row: 0 - Layout.column: 0 - Layout.alignment: Layout.AlignLeft | Layout.AlignVCenter - Layout.fillWidth: true - text: qsTr("Local storage use") - font.bold: true - } + Layout.fillWidth: true + columns: 3 + visible: vfsEnabledCheckBox.checked - EnforcedPlainTextLabel { - Layout.row: 0 - Layout.column: 1 - Layout.alignment: Layout.AlignRight | Layout.AlignVCenter - text: qsTr("%1 GB of %2 GB remote files synced").arg(generalActionsGrid.localUsedStorage).arg(generalActionsGrid.remoteUsedStorage); - color: Style.ncSecondaryTextColor - horizontalAlignment: Text.AlignRight - } + Connections { + target: root.controller - CustomButton { - Layout.row: 0 - Layout.column: 2 - Layout.alignment: Layout.AlignRight | Layout.AlignVCenter - text: qsTr("Evict local copies...") - onPressed: root.controller.createEvictionWindowForAccount(root.accountUserIdAtHost) - } + function onLocalStorageUsageForAccountChanged(accountUserIdAtHost) { + if (root.accountUserIdAtHost !== accountUserIdAtHost) { + return; + } - ProgressBar { - Layout.row: 1 - Layout.columnSpan: generalActionsGrid.columns - Layout.fillWidth: true - value: generalActionsGrid.localUsedStorage / generalActionsGrid.remoteUsedStorage - } - } + generalActionsGrid.localUsedStorage = root.controller.localStorageUsageGbForAccount(root.accountUserIdAtHost); + } - EnforcedPlainTextLabel { - Layout.fillWidth: true - Layout.topMargin: Style.standardSpacing - text: qsTr("Advanced") - font.bold: true - font.pointSize: root.font.pointSize + 2 - elide: Text.ElideRight - } + function onRemoteStorageUsageForAccountChanged(accountUserIdAtHost) { + if (root.accountUserIdAtHost !== accountUserIdAtHost) { + return; + } - CustomButton { - text: qsTr("Signal file provider domain") - onClicked: root.controller.signalFileProviderDomain(root.accountUserIdAtHost) - } + generalActionsGrid.remoteUsedStorage = root.controller.remoteStorageUsageGbForAccount(root.accountUserIdAtHost); + } + } + + EnforcedPlainTextLabel { + Layout.row: 0 + Layout.column: 0 + Layout.alignment: Layout.AlignLeft | Layout.AlignVCenter + Layout.fillWidth: true + text: qsTr("Local storage use") + font.bold: true + } + + EnforcedPlainTextLabel { + Layout.row: 0 + Layout.column: 1 + Layout.alignment: Layout.AlignRight | Layout.AlignVCenter + text: qsTr("%1 GB of %2 GB remote files synced").arg(generalActionsGrid.localUsedStorage).arg(generalActionsGrid.remoteUsedStorage); + color: Style.ncSecondaryTextColor + horizontalAlignment: Text.AlignRight + } + + CustomButton { + Layout.row: 0 + Layout.column: 2 + Layout.alignment: Layout.AlignRight | Layout.AlignVCenter + text: qsTr("Evict local copies...") + onPressed: root.controller.createEvictionWindowForAccount(root.accountUserIdAtHost) + } + + ProgressBar { + Layout.row: 1 + Layout.columnSpan: generalActionsGrid.columns + Layout.fillWidth: true + value: generalActionsGrid.localUsedStorage / generalActionsGrid.remoteUsedStorage + } + } + + EnforcedPlainTextLabel { + Layout.fillWidth: true + Layout.topMargin: Style.standardSpacing + text: qsTr("Advanced") + font.bold: true + font.pointSize: root.font.pointSize + 2 + elide: Text.ElideRight + } + + CustomButton { + text: qsTr("Signal file provider domain") + onClicked: root.controller.signalFileProviderDomain(root.accountUserIdAtHost) + } - CustomButton { - text: qsTr("Create debug archive") - onClicked: root.controller.createDebugArchive(root.accountUserIdAtHost) + CustomButton { + text: qsTr("Create debug archive") + onClicked: root.controller.createDebugArchive(root.accountUserIdAtHost) + } + } } } } From b9ae82ce3e1d1cc3a2785dbbc153a69233f1babe Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Mon, 15 Jan 2024 02:06:21 +0800 Subject: [PATCH 131/144] Extract sync status layout to separate file Signed-off-by: Claudio Cambra --- resources.qrc | 1 + src/gui/macOS/ui/FileProviderSettings.qml | 38 +------------ src/gui/macOS/ui/FileProviderSyncStatus.qml | 61 +++++++++++++++++++++ 3 files changed, 64 insertions(+), 36 deletions(-) create mode 100644 src/gui/macOS/ui/FileProviderSyncStatus.qml diff --git a/resources.qrc b/resources.qrc index 70747c1b93687..217e9c312b392 100644 --- a/resources.qrc +++ b/resources.qrc @@ -65,5 +65,6 @@ src/gui/macOS/ui/FileProviderSettings.qml src/gui/macOS/ui/FileProviderFileDelegate.qml src/gui/macOS/ui/FileProviderEvictionDialog.qml + src/gui/macOS/ui/FileProviderSyncStatus.qml diff --git a/src/gui/macOS/ui/FileProviderSettings.qml b/src/gui/macOS/ui/FileProviderSettings.qml index f87ce1e3a3f9c..f85618d5214e7 100644 --- a/src/gui/macOS/ui/FileProviderSettings.qml +++ b/src/gui/macOS/ui/FileProviderSettings.qml @@ -90,42 +90,8 @@ Page { active: vfsEnabledCheckBox.checked sourceComponent: ColumnLayout { - GridLayout { - id: currentSyncGrid - - readonly property var syncStatus: root.controller.domainSyncStatusForAccount(root.accountUserIdAtHost) - - EnforcedPlainTextLabel { - Layout.row: 0 - Layout.column: 1 - Layout.columnSpan: currentSyncGrid.syncStatus.syncing ? 2 : 1 - Layout.fillWidth: true - text: currentSyncGrid.syncStatus.syncing ? qsTr("Syncing") : qsTr("All synced!") - } - - NCBusyIndicator { - id: syncIcon - - property int size: Style.trayListItemIconSize * 0.6 - - Layout.row: 0 - Layout.rowSpan: 2 - Layout.column: 0 - Layout.preferredWidth: size - Layout.preferredHeight: size - Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter - - imageSource: currentSyncGrid.syncStatus.icon - running: currentSyncGrid.syncStatus.syncing - } - - ProgressBar { - Layout.row: 1 - Layout.column: 1 - Layout.fillWidth: true - value: currentSyncGrid.syncStatus.fractionCompleted - visible: currentSyncGrid.syncStatus.syncing - } + FileProviderSyncStatus { + syncStatus: root.controller.domainSyncStatusForAccount(root.accountUserIdAtHost) } GridLayout { diff --git a/src/gui/macOS/ui/FileProviderSyncStatus.qml b/src/gui/macOS/ui/FileProviderSyncStatus.qml new file mode 100644 index 0000000000000..9a16358eb2d8d --- /dev/null +++ b/src/gui/macOS/ui/FileProviderSyncStatus.qml @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2024 by Claudio Cambra + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +import QtQuick 2.15 +import QtQuick.Controls 2.15 +import QtQuick.Layouts 1.15 + +import Style 1.0 +import "../../filedetails" +import "../../tray" + +import com.nextcloud.desktopclient 1.0 + +GridLayout { + id: root + + required property var syncStatus + + EnforcedPlainTextLabel { + Layout.row: 0 + Layout.column: 1 + Layout.columnSpan: root.syncStatus.syncing ? 2 : 1 + Layout.fillWidth: true + text: root.syncStatus.syncing ? qsTr("Syncing") : qsTr("All synced!") + } + + NCBusyIndicator { + id: syncIcon + + property int size: Style.trayListItemIconSize * 0.6 + + Layout.row: 0 + Layout.rowSpan: 2 + Layout.column: 0 + Layout.preferredWidth: size + Layout.preferredHeight: size + Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter + + imageSource: root.syncStatus.icon + running: root.syncStatus.syncing + } + + ProgressBar { + Layout.row: 1 + Layout.column: 1 + Layout.fillWidth: true + value: root.syncStatus.fractionCompleted + visible: root.syncStatus.syncing + } +} \ No newline at end of file From ed12541e15605b327fdaa30e6334a3dee51f005b Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Mon, 15 Jan 2024 02:20:22 +0800 Subject: [PATCH 132/144] Extract File Provider storage settings to separate file Signed-off-by: Claudio Cambra --- resources.qrc | 1 + src/gui/macOS/ui/FileProviderSettings.qml | 52 ++------------- src/gui/macOS/ui/FileProviderStorageInfo.qml | 68 ++++++++++++++++++++ 3 files changed, 76 insertions(+), 45 deletions(-) create mode 100644 src/gui/macOS/ui/FileProviderStorageInfo.qml diff --git a/resources.qrc b/resources.qrc index 217e9c312b392..79a38f1e61370 100644 --- a/resources.qrc +++ b/resources.qrc @@ -66,5 +66,6 @@ src/gui/macOS/ui/FileProviderFileDelegate.qml src/gui/macOS/ui/FileProviderEvictionDialog.qml src/gui/macOS/ui/FileProviderSyncStatus.qml + src/gui/macOS/ui/FileProviderStorageInfo.qml diff --git a/src/gui/macOS/ui/FileProviderSettings.qml b/src/gui/macOS/ui/FileProviderSettings.qml index f85618d5214e7..491a8a9f7f44d 100644 --- a/src/gui/macOS/ui/FileProviderSettings.qml +++ b/src/gui/macOS/ui/FileProviderSettings.qml @@ -94,15 +94,12 @@ Page { syncStatus: root.controller.domainSyncStatusForAccount(root.accountUserIdAtHost) } - GridLayout { - id: generalActionsGrid + FileProviderStorageInfo { + id: storageInfo + localUsedStorage: root.controller.localStorageUsageGbForAccount(root.accountUserIdAtHost) + remoteUsedStorage: root.controller.remoteStorageUsageGbForAccount(root.accountUserIdAtHost) - property real localUsedStorage: root.controller.localStorageUsageGbForAccount(root.accountUserIdAtHost) - property real remoteUsedStorage: root.controller.remoteStorageUsageGbForAccount(root.accountUserIdAtHost) - - Layout.fillWidth: true - columns: 3 - visible: vfsEnabledCheckBox.checked + onEvictDialogRequested: root.controller.createEvictionWindowForAccount(root.accountUserIdAtHost) Connections { target: root.controller @@ -111,51 +108,16 @@ Page { if (root.accountUserIdAtHost !== accountUserIdAtHost) { return; } - - generalActionsGrid.localUsedStorage = root.controller.localStorageUsageGbForAccount(root.accountUserIdAtHost); + storageInfo.localUsedStorage = root.controller.localStorageUsageGbForAccount(root.accountUserIdAtHost); } function onRemoteStorageUsageForAccountChanged(accountUserIdAtHost) { if (root.accountUserIdAtHost !== accountUserIdAtHost) { return; } - - generalActionsGrid.remoteUsedStorage = root.controller.remoteStorageUsageGbForAccount(root.accountUserIdAtHost); + storageInfo.remoteUsedStorage = root.controller.remoteStorageUsageGbForAccount(root.accountUserIdAtHost); } } - - EnforcedPlainTextLabel { - Layout.row: 0 - Layout.column: 0 - Layout.alignment: Layout.AlignLeft | Layout.AlignVCenter - Layout.fillWidth: true - text: qsTr("Local storage use") - font.bold: true - } - - EnforcedPlainTextLabel { - Layout.row: 0 - Layout.column: 1 - Layout.alignment: Layout.AlignRight | Layout.AlignVCenter - text: qsTr("%1 GB of %2 GB remote files synced").arg(generalActionsGrid.localUsedStorage).arg(generalActionsGrid.remoteUsedStorage); - color: Style.ncSecondaryTextColor - horizontalAlignment: Text.AlignRight - } - - CustomButton { - Layout.row: 0 - Layout.column: 2 - Layout.alignment: Layout.AlignRight | Layout.AlignVCenter - text: qsTr("Evict local copies...") - onPressed: root.controller.createEvictionWindowForAccount(root.accountUserIdAtHost) - } - - ProgressBar { - Layout.row: 1 - Layout.columnSpan: generalActionsGrid.columns - Layout.fillWidth: true - value: generalActionsGrid.localUsedStorage / generalActionsGrid.remoteUsedStorage - } } EnforcedPlainTextLabel { diff --git a/src/gui/macOS/ui/FileProviderStorageInfo.qml b/src/gui/macOS/ui/FileProviderStorageInfo.qml new file mode 100644 index 0000000000000..ff8b6f3b2b697 --- /dev/null +++ b/src/gui/macOS/ui/FileProviderStorageInfo.qml @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2024 by Claudio Cambra + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +import QtQuick 2.15 +import QtQuick.Controls 2.15 +import QtQuick.Layouts 1.15 + +import Style 1.0 +import "../../filedetails" +import "../../tray" + +import com.nextcloud.desktopclient 1.0 + +GridLayout { + id: root + + signal evictDialogRequested() + + required property real localUsedStorage + required property real remoteUsedStorage + + Layout.fillWidth: true + columns: 3 + + EnforcedPlainTextLabel { + Layout.row: 0 + Layout.column: 0 + Layout.alignment: Layout.AlignLeft | Layout.AlignVCenter + Layout.fillWidth: true + text: qsTr("Local storage use") + font.bold: true + } + + EnforcedPlainTextLabel { + Layout.row: 0 + Layout.column: 1 + Layout.alignment: Layout.AlignRight | Layout.AlignVCenter + text: qsTr("%1 GB of %2 GB remote files synced").arg(root.localUsedStorage).arg(root.remoteUsedStorage); + color: Style.ncSecondaryTextColor + horizontalAlignment: Text.AlignRight + } + + CustomButton { + Layout.row: 0 + Layout.column: 2 + Layout.alignment: Layout.AlignRight | Layout.AlignVCenter + text: qsTr("Evict local copies...") + onPressed: root.evictDialogRequested() + } + + ProgressBar { + Layout.row: 1 + Layout.columnSpan: root.columns + Layout.fillWidth: true + value: root.localUsedStorage / root.remoteUsedStorage + } +} \ No newline at end of file From 034822fcc69fa339f95e01e316ec3a3ec4b554eb Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Mon, 15 Jan 2024 02:28:09 +0800 Subject: [PATCH 133/144] Fix grid layout for sync status of file provider Signed-off-by: Claudio Cambra --- src/gui/macOS/ui/FileProviderSyncStatus.qml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/gui/macOS/ui/FileProviderSyncStatus.qml b/src/gui/macOS/ui/FileProviderSyncStatus.qml index 9a16358eb2d8d..82d5ecf0c861a 100644 --- a/src/gui/macOS/ui/FileProviderSyncStatus.qml +++ b/src/gui/macOS/ui/FileProviderSyncStatus.qml @@ -27,6 +27,8 @@ GridLayout { required property var syncStatus + rows: syncStatus.syncing ? 2 : 1 + EnforcedPlainTextLabel { Layout.row: 0 Layout.column: 1 @@ -41,7 +43,7 @@ GridLayout { property int size: Style.trayListItemIconSize * 0.6 Layout.row: 0 - Layout.rowSpan: 2 + Layout.rowSpan: root.syncStatus.syncing ? 2 : 1 Layout.column: 0 Layout.preferredWidth: size Layout.preferredHeight: size From 7b99a06eb98441b7abb0bb49953524e8afae156d Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Mon, 15 Jan 2024 02:45:27 +0800 Subject: [PATCH 134/144] Add separator to dynamically loaded fp settings Signed-off-by: Claudio Cambra --- src/gui/macOS/ui/FileProviderSettings.qml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/gui/macOS/ui/FileProviderSettings.qml b/src/gui/macOS/ui/FileProviderSettings.qml index 491a8a9f7f44d..5083b76162e3e 100644 --- a/src/gui/macOS/ui/FileProviderSettings.qml +++ b/src/gui/macOS/ui/FileProviderSettings.qml @@ -90,6 +90,12 @@ Page { active: vfsEnabledCheckBox.checked sourceComponent: ColumnLayout { + Rectangle { + Layout.fillWidth: true + height: Style.normalBorderWidth + color: Style.ncSecondaryTextColor + } + FileProviderSyncStatus { syncStatus: root.controller.domainSyncStatusForAccount(root.accountUserIdAtHost) } From 7d8778d12aa4b656bf2a074b0b582b8ac19ba8c5 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Mon, 15 Jan 2024 02:45:41 +0800 Subject: [PATCH 135/144] Bolden sync state text for fp Signed-off-by: Claudio Cambra --- src/gui/macOS/ui/FileProviderSyncStatus.qml | 1 + 1 file changed, 1 insertion(+) diff --git a/src/gui/macOS/ui/FileProviderSyncStatus.qml b/src/gui/macOS/ui/FileProviderSyncStatus.qml index 82d5ecf0c861a..f9b2024358566 100644 --- a/src/gui/macOS/ui/FileProviderSyncStatus.qml +++ b/src/gui/macOS/ui/FileProviderSyncStatus.qml @@ -34,6 +34,7 @@ GridLayout { Layout.column: 1 Layout.columnSpan: root.syncStatus.syncing ? 2 : 1 Layout.fillWidth: true + font.bold: true text: root.syncStatus.syncing ? qsTr("Syncing") : qsTr("All synced!") } From a469d44123499e12db8f3e0110cd999d101b6b08 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Mon, 15 Jan 2024 16:35:49 +0800 Subject: [PATCH 136/144] Provide correct sync state icon in file provider domain sync status Signed-off-by: Claudio Cambra --- src/gui/macOS/fileproviderdomainsyncstatus.h | 6 +++++ .../macOS/fileproviderdomainsyncstatus_mac.mm | 25 +++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/src/gui/macOS/fileproviderdomainsyncstatus.h b/src/gui/macOS/fileproviderdomainsyncstatus.h index db0f377161b4b..d92c2c5536c52 100644 --- a/src/gui/macOS/fileproviderdomainsyncstatus.h +++ b/src/gui/macOS/fileproviderdomainsyncstatus.h @@ -36,6 +36,7 @@ class FileProviderDomainSyncStatus : public QObject Q_PROPERTY(int uploadFileTotalCount READ uploadFileTotalCount NOTIFY uploadFileTotalCountChanged) Q_PROPERTY(int uploadFileCompletedCount READ uploadFileCompletedCount NOTIFY uploadFileCompletedCountChanged) // TODO: more detailed reporting (time remaining, megabytes, etc.) + Q_PROPERTY(QUrl icon READ icon NOTIFY iconChanged) public: explicit FileProviderDomainSyncStatus(const QString &domainIdentifier, QObject *parent = nullptr); @@ -51,6 +52,7 @@ class FileProviderDomainSyncStatus : public QObject int downloadFileCompletedCount() const; int uploadFileTotalCount() const; int uploadFileCompletedCount() const; + QUrl icon() const; signals: void syncingChanged(bool syncing); @@ -63,6 +65,7 @@ class FileProviderDomainSyncStatus : public QObject void downloadFileCompletedCountChanged(int downloadFileCompletedCount); void uploadFileTotalCountChanged(int uploadFileTotalCount); void uploadFileCompletedCountChanged(int uploadFileCompletedCount); + void iconChanged(const QUrl &icon); private: void setDownloading(const bool syncing); @@ -73,6 +76,8 @@ class FileProviderDomainSyncStatus : public QObject void setDownloadFileCompletedCount(const int fileCompletedCount); void setUploadFileTotalCount(const int fileTotalCount); void setUploadFileCompletedCount(const int fileCompletedCount); + void setIcon(const QUrl &icon); + void updateIcon(); bool _downloading = false; bool _uploading = false; @@ -82,6 +87,7 @@ class FileProviderDomainSyncStatus : public QObject int _downloadFileCompletedCount = 0; int _uploadFileTotalCount = 0; int _uploadFileCompletedCount = 0; + QUrl _icon; class MacImplementation; std::unique_ptr d; diff --git a/src/gui/macOS/fileproviderdomainsyncstatus_mac.mm b/src/gui/macOS/fileproviderdomainsyncstatus_mac.mm index 1455f93b1613a..6cc7efd42ae4c 100644 --- a/src/gui/macOS/fileproviderdomainsyncstatus_mac.mm +++ b/src/gui/macOS/fileproviderdomainsyncstatus_mac.mm @@ -17,6 +17,7 @@ #include #include "gui/macOS/fileproviderutils.h" +#include "libsync/theme.h" #import @@ -67,6 +68,7 @@ void updateDownload(NSProgress *const progress) const q->setDownloadFractionCompleted(progress.fractionCompleted); q->setDownloadFileTotalCount(progress.fileTotalCount.intValue); q->setDownloadFileCompletedCount(progress.fileCompletedCount.intValue); + q->updateIcon(); } void updateUpload(NSProgress *const progress) const @@ -80,6 +82,7 @@ void updateUpload(NSProgress *const progress) const q->setUploadFractionCompleted(progress.fractionCompleted); q->setUploadFileTotalCount(progress.fileTotalCount.intValue); q->setUploadFileCompletedCount(progress.fileCompletedCount.intValue); + q->updateIcon(); } private: @@ -95,6 +98,7 @@ void updateUpload(NSProgress *const progress) const , d(std::make_unique(domainIdentifier, this)) { qRegisterMetaType("FileProviderDomainSyncStatus*"); + updateIcon(); } FileProviderDomainSyncStatus::~FileProviderDomainSyncStatus() = default; @@ -149,6 +153,11 @@ void updateUpload(NSProgress *const progress) const return _uploadFileCompletedCount; } +QUrl FileProviderDomainSyncStatus::icon() const +{ + return _icon; +} + void FileProviderDomainSyncStatus::setDownloading(const bool downloading) { if (_downloading == downloading) { @@ -233,4 +242,20 @@ void updateUpload(NSProgress *const progress) const emit uploadFileCompletedCountChanged(_uploadFileCompletedCount); } +void FileProviderDomainSyncStatus::setIcon(const QUrl &icon) +{ + if (_icon == icon) { + return; + } + + _icon = icon; + emit iconChanged(_icon); +} + +void FileProviderDomainSyncStatus::updateIcon() +{ + const auto iconUrl = syncing() ? Theme::instance()->syncStatusRunning() : Theme::instance()->syncStatusOk(); + setIcon(iconUrl); +} + } // OCC::Mac From 472bba8149bd1a294e99cc8558b15b0148690194 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Mon, 15 Jan 2024 17:08:11 +0800 Subject: [PATCH 137/144] Add useful font sizes to Style.qml Signed-off-by: Claudio Cambra --- theme/Style/Style.qml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/theme/Style/Style.qml b/theme/Style/Style.qml index 4d1360c31e0a1..9dd321c4b3a84 100644 --- a/theme/Style/Style.qml +++ b/theme/Style/Style.qml @@ -33,6 +33,10 @@ QtObject { // We are using pixel size because this is cross platform comparable, point size isn't readonly property int topLinePixelSize: pixelSize readonly property int subLinePixelSize: topLinePixelSize - 2 + readonly property int defaultFontPtSize: fontMetrics.font.pointSize + readonly property int subheaderFontPtSize: defaultFontPtSize + 2 + readonly property int headerFontPtSize: defaultFontPtSize + 4 + readonly property int titleFontPtSize: defaultFontPtSize + 8 // Dimensions and sizes property int trayWindowWidth: variableSize(400) From 918e411b107f1c8b362c0718334140553efa0360 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Mon, 15 Jan 2024 17:14:52 +0800 Subject: [PATCH 138/144] Use font sizes in Style.qml in FileProviderSettings Signed-off-by: Claudio Cambra --- src/gui/macOS/ui/FileProviderSettings.qml | 4 ++-- src/gui/macOS/ui/FileProviderSyncStatus.qml | 19 ++++++++++--------- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/src/gui/macOS/ui/FileProviderSettings.qml b/src/gui/macOS/ui/FileProviderSettings.qml index 5083b76162e3e..f3844f2458c20 100644 --- a/src/gui/macOS/ui/FileProviderSettings.qml +++ b/src/gui/macOS/ui/FileProviderSettings.qml @@ -70,7 +70,7 @@ Page { Layout.fillWidth: true text: qsTr("General settings") font.bold: true - font.pointSize: root.font.pointSize + 2 + font.pointSize: Style.subheaderFontPtSize elide: Text.ElideRight } @@ -131,7 +131,7 @@ Page { Layout.topMargin: Style.standardSpacing text: qsTr("Advanced") font.bold: true - font.pointSize: root.font.pointSize + 2 + font.pointSize: Style.subheaderFontPtSize elide: Text.ElideRight } diff --git a/src/gui/macOS/ui/FileProviderSyncStatus.qml b/src/gui/macOS/ui/FileProviderSyncStatus.qml index f9b2024358566..8a898d30c556b 100644 --- a/src/gui/macOS/ui/FileProviderSyncStatus.qml +++ b/src/gui/macOS/ui/FileProviderSyncStatus.qml @@ -29,15 +29,6 @@ GridLayout { rows: syncStatus.syncing ? 2 : 1 - EnforcedPlainTextLabel { - Layout.row: 0 - Layout.column: 1 - Layout.columnSpan: root.syncStatus.syncing ? 2 : 1 - Layout.fillWidth: true - font.bold: true - text: root.syncStatus.syncing ? qsTr("Syncing") : qsTr("All synced!") - } - NCBusyIndicator { id: syncIcon @@ -54,6 +45,16 @@ GridLayout { running: root.syncStatus.syncing } + EnforcedPlainTextLabel { + Layout.row: 0 + Layout.column: 1 + Layout.columnSpan: root.syncStatus.syncing ? 2 : 1 + Layout.fillWidth: true + font.bold: true + font.pointSize: Style.headerFontPtSize + text: root.syncStatus.syncing ? qsTr("Syncing") : qsTr("All synced!") + } + ProgressBar { Layout.row: 1 Layout.column: 1 From 1f70c85e224d1eb27ad3a0724ac3a114bc6b123b Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Mon, 15 Jan 2024 17:15:11 +0800 Subject: [PATCH 139/144] Adjust alignment and sizing of file provider sync status icon Signed-off-by: Claudio Cambra --- src/gui/macOS/ui/FileProviderSyncStatus.qml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/gui/macOS/ui/FileProviderSyncStatus.qml b/src/gui/macOS/ui/FileProviderSyncStatus.qml index 8a898d30c556b..7f1c53249cbe6 100644 --- a/src/gui/macOS/ui/FileProviderSyncStatus.qml +++ b/src/gui/macOS/ui/FileProviderSyncStatus.qml @@ -32,7 +32,7 @@ GridLayout { NCBusyIndicator { id: syncIcon - property int size: Style.trayListItemIconSize * 0.6 + property int size: Style.trayListItemIconSize * 0.8 Layout.row: 0 Layout.rowSpan: root.syncStatus.syncing ? 2 : 1 @@ -41,6 +41,8 @@ GridLayout { Layout.preferredHeight: size Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter + padding: 0 + spacing: 0 imageSource: root.syncStatus.icon running: root.syncStatus.syncing } From 81d4aa74465543215a5a08ff8cb831b0ad614d50 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Mon, 15 Jan 2024 17:18:55 +0800 Subject: [PATCH 140/144] Use NCProgressBar for file provider sync status Signed-off-by: Claudio Cambra --- src/gui/macOS/ui/FileProviderSyncStatus.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/macOS/ui/FileProviderSyncStatus.qml b/src/gui/macOS/ui/FileProviderSyncStatus.qml index 7f1c53249cbe6..11f093bbcd88b 100644 --- a/src/gui/macOS/ui/FileProviderSyncStatus.qml +++ b/src/gui/macOS/ui/FileProviderSyncStatus.qml @@ -57,7 +57,7 @@ GridLayout { text: root.syncStatus.syncing ? qsTr("Syncing") : qsTr("All synced!") } - ProgressBar { + NCProgressBar { Layout.row: 1 Layout.column: 1 Layout.fillWidth: true From a428256e4f98f38514eb24da6cd0f0cc85b2951a Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Mon, 15 Jan 2024 17:27:19 +0800 Subject: [PATCH 141/144] Limit gigabyte sizing string to two decimal figures in file provider storage info Signed-off-by: Claudio Cambra --- src/gui/macOS/ui/FileProviderStorageInfo.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/macOS/ui/FileProviderStorageInfo.qml b/src/gui/macOS/ui/FileProviderStorageInfo.qml index ff8b6f3b2b697..2830309b30982 100644 --- a/src/gui/macOS/ui/FileProviderStorageInfo.qml +++ b/src/gui/macOS/ui/FileProviderStorageInfo.qml @@ -46,7 +46,7 @@ GridLayout { Layout.row: 0 Layout.column: 1 Layout.alignment: Layout.AlignRight | Layout.AlignVCenter - text: qsTr("%1 GB of %2 GB remote files synced").arg(root.localUsedStorage).arg(root.remoteUsedStorage); + text: qsTr("%1 GB of %2 GB remote files synced").arg(root.localUsedStorage.toFixed(2)).arg(root.remoteUsedStorage.toFixed(2)); color: Style.ncSecondaryTextColor horizontalAlignment: Text.AlignRight } From b4e1338bc8541a9852bc116b5eac22b8a0fe830f Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Tue, 16 Jan 2024 16:57:43 +0800 Subject: [PATCH 142/144] Ensure [[nodiscard]] in new file provider classes Signed-off-by: Claudio Cambra --- src/gui/macOS/fileproviderdomainsyncstatus.h | 22 +++--- src/gui/macOS/fileprovideritemmetadata.h | 68 +++++++++---------- .../fileprovidermaterialiseditemsmodel.h | 8 +-- 3 files changed, 49 insertions(+), 49 deletions(-) diff --git a/src/gui/macOS/fileproviderdomainsyncstatus.h b/src/gui/macOS/fileproviderdomainsyncstatus.h index d92c2c5536c52..b6b1256acf9ec 100644 --- a/src/gui/macOS/fileproviderdomainsyncstatus.h +++ b/src/gui/macOS/fileproviderdomainsyncstatus.h @@ -42,17 +42,17 @@ class FileProviderDomainSyncStatus : public QObject explicit FileProviderDomainSyncStatus(const QString &domainIdentifier, QObject *parent = nullptr); ~FileProviderDomainSyncStatus() override; - bool syncing() const; - bool downloading() const; - bool uploading() const; - double fractionCompleted() const; - double downloadFractionCompleted() const; - double uploadFractionCompleted() const; - int downloadFileTotalCount() const; - int downloadFileCompletedCount() const; - int uploadFileTotalCount() const; - int uploadFileCompletedCount() const; - QUrl icon() const; + [[nodiscard]] bool syncing() const; + [[nodiscard]] bool downloading() const; + [[nodiscard]] bool uploading() const; + [[nodiscard]] double fractionCompleted() const; + [[nodiscard]] double downloadFractionCompleted() const; + [[nodiscard]] double uploadFractionCompleted() const; + [[nodiscard]] int downloadFileTotalCount() const; + [[nodiscard]] int downloadFileCompletedCount() const; + [[nodiscard]] int uploadFileTotalCount() const; + [[nodiscard]] int uploadFileCompletedCount() const; + [[nodiscard]] QUrl icon() const; signals: void syncingChanged(bool syncing); diff --git a/src/gui/macOS/fileprovideritemmetadata.h b/src/gui/macOS/fileprovideritemmetadata.h index cad6170b446b4..e3e0b0a0cd232 100644 --- a/src/gui/macOS/fileprovideritemmetadata.h +++ b/src/gui/macOS/fileprovideritemmetadata.h @@ -61,45 +61,45 @@ class FileProviderItemMetadata public: static FileProviderItemMetadata fromNSFileProviderItem(const void *const nsFileProviderItem, const QString &domainIdentifier); - QString identifier() const; - QString parentItemIdentifier() const; - QString domainIdentifier() const; - QString filename() const; - QString typeIdentifier() const; - QString symlinkTargetPath() const; - QString uploadingError() const; - QString downloadingError() const; - QString mostRecentEditorName() const; - QString ownerName() const; - QDateTime contentModificationDate() const; - QDateTime creationDate() const; - QDateTime lastUsedDate() const; - QByteArray contentVersion() const; - QByteArray metadataVersion() const; - QByteArray tagData() const; - QHash extendedAttributes() const; - int capabilities() const; - int fileSystemFlags() const; - unsigned int childItemCount() const; - unsigned int typeOsCode() const; - unsigned int creatorOsCode() const; - unsigned long long documentSize() const; - bool mostRecentVersionDownloaded() const; - bool uploading() const; - bool uploaded() const; - bool downloading() const; - bool downloaded() const; - bool shared() const; - bool sharedByCurrentUser() const; - - QString userVisiblePath() const; - QString fileTypeString() const; + [[nodiscard]] QString identifier() const; + [[nodiscard]] QString parentItemIdentifier() const; + [[nodiscard]] QString domainIdentifier() const; + [[nodiscard]] QString filename() const; + [[nodiscard]] QString typeIdentifier() const; + [[nodiscard]] QString symlinkTargetPath() const; + [[nodiscard]] QString uploadingError() const; + [[nodiscard]] QString downloadingError() const; + [[nodiscard]] QString mostRecentEditorName() const; + [[nodiscard]] QString ownerName() const; + [[nodiscard]] QDateTime contentModificationDate() const; + [[nodiscard]] QDateTime creationDate() const; + [[nodiscard]] QDateTime lastUsedDate() const; + [[nodiscard]] QByteArray contentVersion() const; + [[nodiscard]] QByteArray metadataVersion() const; + [[nodiscard]] QByteArray tagData() const; + [[nodiscard]] QHash extendedAttributes() const; + [[nodiscard]] int capabilities() const; + [[nodiscard]] int fileSystemFlags() const; + [[nodiscard]] unsigned int childItemCount() const; + [[nodiscard]] unsigned int typeOsCode() const; + [[nodiscard]] unsigned int creatorOsCode() const; + [[nodiscard]] unsigned long long documentSize() const; + [[nodiscard]] bool mostRecentVersionDownloaded() const; + [[nodiscard]] bool uploading() const; + [[nodiscard]] bool uploaded() const; + [[nodiscard]] bool downloading() const; + [[nodiscard]] bool downloaded() const; + [[nodiscard]] bool shared() const; + [[nodiscard]] bool sharedByCurrentUser() const; + + [[nodiscard]] QString userVisiblePath() const; + [[nodiscard]] QString fileTypeString() const; // Check equality via identifier, contentVersion, and metadataVersion friend bool operator==(const FileProviderItemMetadata &lhs, const FileProviderItemMetadata &rhs); private: - QString getUserVisiblePath() const; + [[nodiscard]] QString getUserVisiblePath() const; QString _identifier; QString _parentItemIdentifier; diff --git a/src/gui/macOS/fileprovidermaterialiseditemsmodel.h b/src/gui/macOS/fileprovidermaterialiseditemsmodel.h index 9b7ff8035b57d..3d34dd9f2b7fe 100644 --- a/src/gui/macOS/fileprovidermaterialiseditemsmodel.h +++ b/src/gui/macOS/fileprovidermaterialiseditemsmodel.h @@ -67,11 +67,11 @@ class FileProviderMaterialisedItemsModel : public QAbstractListModel Q_ENUM(Roles) explicit FileProviderMaterialisedItemsModel(QObject *parent = nullptr); - int rowCount(const QModelIndex &parent = {}) const override; - QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; - QHash roleNames() const override; + [[nodiscard]] int rowCount(const QModelIndex &parent = {}) const override; + [[nodiscard]] QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; + [[nodiscard]] QHash roleNames() const override; - QVector items() const; + [[nodiscard]] QVector items() const; signals: void itemsChanged(); From 28cfd8fe7032bd35a067d001d8b199547ed3d36e Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Tue, 16 Jan 2024 17:17:26 +0800 Subject: [PATCH 143/144] Mark MacImplementation for FileProviderSettings destructor as override Signed-off-by: Claudio Cambra --- src/gui/macOS/fileprovidersettingscontroller_mac.mm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/macOS/fileprovidersettingscontroller_mac.mm b/src/gui/macOS/fileprovidersettingscontroller_mac.mm index 2a2fd0663d704..17d277e5ef1a6 100644 --- a/src/gui/macOS/fileprovidersettingscontroller_mac.mm +++ b/src/gui/macOS/fileprovidersettingscontroller_mac.mm @@ -69,7 +69,7 @@ explicit MacImplementation(FileProviderSettingsController *const parent) fetchMaterialisedFilesStorageUsage(); }; - ~MacImplementation() = default; + ~MacImplementation() override = default; [[nodiscard]] QStringList enabledAccounts() const { From 92a1d808ef34092a6ece304810f6d9a2f87b51b1 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Mon, 19 Feb 2024 14:12:34 +0800 Subject: [PATCH 144/144] Temporarily remove eviction dialog button until eviction works on extension side Signed-off-by: Claudio Cambra --- src/gui/macOS/ui/FileProviderStorageInfo.qml | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/src/gui/macOS/ui/FileProviderStorageInfo.qml b/src/gui/macOS/ui/FileProviderStorageInfo.qml index 2830309b30982..9189507239273 100644 --- a/src/gui/macOS/ui/FileProviderStorageInfo.qml +++ b/src/gui/macOS/ui/FileProviderStorageInfo.qml @@ -31,7 +31,7 @@ GridLayout { required property real remoteUsedStorage Layout.fillWidth: true - columns: 3 + columns: 2 EnforcedPlainTextLabel { Layout.row: 0 @@ -51,14 +51,6 @@ GridLayout { horizontalAlignment: Text.AlignRight } - CustomButton { - Layout.row: 0 - Layout.column: 2 - Layout.alignment: Layout.AlignRight | Layout.AlignVCenter - text: qsTr("Evict local copies...") - onPressed: root.evictDialogRequested() - } - ProgressBar { Layout.row: 1 Layout.columnSpan: root.columns