From aaf262dbcaccf39672a0419a61a3e3dd3872f2fe Mon Sep 17 00:00:00 2001 From: Carl Schwan Date: Mon, 3 Nov 2025 10:19:31 +0100 Subject: [PATCH] refactor: Port to QML modules Signed-off-by: Carl Schwan --- CMakeLists.txt | 1 + resources.qrc | 57 ----------- src/3rdparty/kirigami/wheelhandler.h | 2 + src/gui/CMakeLists.txt | 99 +++++++++---------- src/gui/accountstate.cpp | 3 + src/gui/accountstate.h | 3 - src/gui/callstatechecker.h | 2 + src/gui/emojimodel.h | 1 + src/gui/filedetails/CMakeLists.txt | 37 +++++++ src/gui/filedetails/datefieldbackend.h | 2 + src/gui/filedetails/filedetails.h | 2 + src/gui/filedetails/shareemodel.h | 2 + src/gui/filedetails/sharemodel.h | 2 + src/gui/filedetails/sortedsharemodel.h | 2 + src/gui/macOS/CMakeLists.txt | 12 +++ .../macOS/fileprovidersettingscontroller.h | 9 ++ src/gui/main.cpp | 5 +- src/gui/owncloudgui.cpp | 52 ---------- src/gui/syncconflictsmodel.h | 2 + src/gui/systray.cpp | 4 +- src/gui/systray.h | 11 ++- src/gui/tray/CMakeLists.txt | 69 +++++++++++++ src/gui/tray/activitydata.h | 3 + src/gui/tray/activitylistmodel.h | 4 +- src/gui/{ => tray}/fileactivitylistmodel.cpp | 0 src/gui/{ => tray}/fileactivitylistmodel.h | 1 + src/gui/tray/sortedactivitylistmodel.h | 2 + src/gui/tray/syncstatussummary.h | 2 + src/gui/tray/unifiedsearchresultslistmodel.h | 3 + src/gui/tray/usermodel.h | 20 ++++ src/gui/types.cpp | 3 + src/gui/types.h | 53 ++++++++++ src/gui/userstatusselectormodel.h | 2 + 33 files changed, 303 insertions(+), 169 deletions(-) create mode 100644 src/gui/filedetails/CMakeLists.txt create mode 100644 src/gui/macOS/CMakeLists.txt create mode 100644 src/gui/tray/CMakeLists.txt rename src/gui/{ => tray}/fileactivitylistmodel.cpp (100%) rename src/gui/{ => tray}/fileactivitylistmodel.h (97%) create mode 100644 src/gui/types.cpp create mode 100644 src/gui/types.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 3a9c91deae16b..4a6de570db4fc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,6 +10,7 @@ if(APPLE) set(CMAKE_OSX_DEPLOYMENT_TARGET "12.0" CACHE STRING "Minimum OSX deployment version") endif() +set(CMAKE_POSITION_INDEPENDENT_CODE ON) set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD_REQUIRED 20) diff --git a/resources.qrc b/resources.qrc index 2681104929615..2d2e9595b2a9f 100644 --- a/resources.qrc +++ b/resources.qrc @@ -1,64 +1,7 @@ - src/gui/UserStatusMessageView.qml - src/gui/UserStatusSelectorPage.qml - src/gui/EmojiPicker.qml - src/gui/UserStatusSelectorButton.qml - src/gui/UserStatusSetStatusView.qml - src/gui/PredefinedStatusButton.qml - src/gui/ErrorBox.qml - src/gui/filedetails/FileActivityView.qml - src/gui/filedetails/FileDetailsPage.qml - src/gui/filedetails/FileDetailsView.qml - src/gui/filedetails/FileDetailsWindow.qml - src/gui/filedetails/FileTag.qml - src/gui/filedetails/NCInputDateField.qml - src/gui/filedetails/NCInputTextArea.qml - src/gui/filedetails/NCInputTextField.qml - src/gui/filedetails/NCTabButton.qml - src/gui/filedetails/ShareeDelegate.qml - src/gui/filedetails/ShareDelegate.qml - src/gui/filedetails/ShareDetailsPage.qml - src/gui/filedetails/ShareeSearchField.qml - src/gui/filedetails/ShareView.qml - src/gui/tray/MainWindow.qml - src/gui/tray/UserLine.qml - src/gui/tray/HeaderButton.qml - src/gui/tray/SyncStatus.qml - src/gui/tray/ActivityItem.qml - src/gui/tray/AutoSizingMenu.qml - src/gui/tray/ActivityList.qml - src/gui/tray/CurrentAccountHeaderButton.qml - src/gui/tray/TrayWindowHeader.qml - src/gui/tray/UnifiedSearchInputContainer.qml - src/gui/tray/UnifiedSearchResultFetchMoreTrigger.qml - src/gui/tray/UnifiedSearchResultItem.qml - src/gui/tray/UnifiedSearchResultItemSkeleton.qml - src/gui/tray/UnifiedSearchResultItemSkeletonContainer.qml - src/gui/tray/UnifiedSearchResultItemSkeletonGradientRectangle.qml - src/gui/tray/UnifiedSearchResultListItem.qml - src/gui/tray/UnifiedSearchResultNothingFound.qml - src/gui/tray/UnifiedSearchPlaceholderView.qml - src/gui/tray/UnifiedSearchResultSectionItem.qml - src/gui/tray/ActivityItemContextMenu.qml - src/gui/tray/ActivityItemActions.qml - src/gui/tray/ActivityItemContent.qml - src/gui/tray/TalkReplyTextField.qml - src/gui/tray/CallNotificationDialog.qml - src/gui/tray/EditFileLocallyLoadingDialog.qml - src/gui/tray/EncryptionTokenDiscoveryDialog.qml - src/gui/tray/NCBusyIndicator.qml - src/gui/tray/NCIconWithBackgroundImage.qml - src/gui/tray/NCProgressBar.qml - src/gui/tray/EnforcedPlainTextLabel.qml theme/Style/Style.qml theme/Style/qmldir - src/gui/tray/ListItemLineAndSubline.qml - src/gui/tray/TrayFoldersMenuButton.qml - src/gui/tray/TrayFolderListItem.qml - src/gui/ResolveConflictsDialog.qml - src/gui/ConflictDelegate.qml - src/gui/ConflictItemFileInfo.qml src/gui/macOS/ui/FileProviderSettings.qml src/gui/macOS/ui/FileProviderFileDelegate.qml diff --git a/src/3rdparty/kirigami/wheelhandler.h b/src/3rdparty/kirigami/wheelhandler.h index d921a6c9d7c24..4944d076eb9ce 100644 --- a/src/3rdparty/kirigami/wheelhandler.h +++ b/src/3rdparty/kirigami/wheelhandler.h @@ -11,6 +11,7 @@ #include #include #include +#include class QWheelEvent; class WheelHandler; @@ -21,6 +22,7 @@ class WheelHandler; class KirigamiWheelEvent : public QObject { Q_OBJECT + QML_NAMED_ELEMENT(WheelEvent) /** * x: real diff --git a/src/gui/CMakeLists.txt b/src/gui/CMakeLists.txt index c3a77451aee2d..ec354eefe1669 100644 --- a/src/gui/CMakeLists.txt +++ b/src/gui/CMakeLists.txt @@ -183,40 +183,7 @@ set(client_SRCS emojimodel.cpp syncconflictsmodel.h syncconflictsmodel.cpp - fileactivitylistmodel.h - fileactivitylistmodel.cpp - filedetails/datefieldbackend.h - filedetails/datefieldbackend.cpp - filedetails/filedetails.h - filedetails/filedetails.cpp - filedetails/sharemodel.h - filedetails/sharemodel.cpp - filedetails/shareemodel.h - filedetails/shareemodel.cpp - filedetails/sortedsharemodel.h - filedetails/sortedsharemodel.cpp - tray/svgimageprovider.h - tray/svgimageprovider.cpp - tray/syncstatussummary.h - tray/syncstatussummary.cpp - tray/activitydata.h - tray/activitydata.cpp - tray/activitylistmodel.h - tray/activitylistmodel.cpp - tray/unifiedsearchresult.h - tray/asyncimageresponse.cpp - tray/unifiedsearchresult.cpp - tray/unifiedsearchresultslistmodel.h - tray/trayimageprovider.cpp - tray/unifiedsearchresultslistmodel.cpp - tray/usermodel.h - tray/usermodel.cpp - tray/notificationhandler.h - tray/notificationhandler.cpp - tray/sortedactivitylistmodel.h - tray/sortedactivitylistmodel.cpp creds/credentialsfactory.h - tray/talkreply.cpp creds/credentialsfactory.cpp creds/httpcredentialsgui.h creds/httpcredentialsgui.cpp @@ -534,26 +501,41 @@ endif() add_library(nextcloudCore STATIC ${final_src}) -target_link_libraries(nextcloudCore - PUBLIC - Nextcloud::sync - Qt::Widgets - Qt::Svg - Qt::Network - Qt::Xml - Qt::Qml - Qt::Quick - Qt::QuickControls2 - Qt::QuickWidgets - KF6::Archive - ) +qt_add_qml_module(nextcloudCore + URI com.nextcloud.desktopclient + IMPORTS + com.nextcloud.desktopclient.tray + com.nextcloud.desktopclient.filedetails + QML_FILES + UserStatusMessageView.qml + UserStatusSelectorPage.qml + EmojiPicker.qml + UserStatusSelectorButton.qml + UserStatusSetStatusView.qml + PredefinedStatusButton.qml + ErrorBox.qml +) -if(KF6GuiAddons_FOUND) - target_link_libraries(nextcloudCore - PUBLIC - KF6::GuiAddons - ) - add_definitions(-DHAVE_KGUIADDONS) +target_link_libraries(nextcloudCore PUBLIC + Nextcloud::sync + Qt::Widgets + Qt::Svg + Qt::Network + Qt::Xml + Qt::Qml + Qt::Quick + Qt::QuickControls2 + Qt::QuickWidgets + KF6::Archive +) + +target_include_directories(nextcloudCore PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) + +if(TARGET KF6::GuiAddons) + target_link_libraries(nextcloudCore PUBLIC + KF6::GuiAddons + ) + add_definitions(-DHAVE_KGUIADDONS) endif() add_subdirectory(socketapi) @@ -589,6 +571,9 @@ target_include_directories(nextcloudCore ${CMAKE_CURRENT_SOURCE_DIR} ) +add_subdirectory(tray) +add_subdirectory(filedetails) + if(NOT BUILD_OWNCLOUD_OSX_BUNDLE) if(NOT WIN32) file(GLOB _icons "${theme_dir}/colored/*-${APPLICATION_ICON_NAME}-icon.png") @@ -652,7 +637,15 @@ set_target_properties(nextcloud PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${BIN_OUTPUT_DIRECTORY} ) -target_link_libraries(nextcloud PRIVATE nextcloudCore) +set_target_properties(nextcloud PROPERTIES POSITION_INDEPENDENT_CODE ON) +target_link_libraries(nextcloud PRIVATE + nextcloudTray + nextcloudTrayplugin + nextcloudFileDetails + nextcloudFileDetailsplugin + nextcloudCore + nextcloudCoreplugin +) if(TARGET PkgConfig::CLOUDPROVIDERS) message("Building with libcloudproviderssupport") diff --git a/src/gui/accountstate.cpp b/src/gui/accountstate.cpp index 458f68cf84374..bc5ce495e748c 100644 --- a/src/gui/accountstate.cpp +++ b/src/gui/accountstate.cpp @@ -698,3 +698,6 @@ QUrl AccountApp::iconUrl() const /*-------------------------------------------------------------------------------------*/ } // namespace OCC + +Q_DECLARE_METATYPE(OCC::AccountState *) +Q_DECLARE_METATYPE(OCC::AccountStatePtr) diff --git a/src/gui/accountstate.h b/src/gui/accountstate.h index f658f855e80e1..84dbf3682ab3f 100644 --- a/src/gui/accountstate.h +++ b/src/gui/accountstate.h @@ -284,7 +284,4 @@ class AccountApp : public QObject } -Q_DECLARE_METATYPE(OCC::AccountState *) -Q_DECLARE_METATYPE(OCC::AccountStatePtr) - #endif //ACCOUNTINFO_H diff --git a/src/gui/callstatechecker.h b/src/gui/callstatechecker.h index ac77e2c678da8..a3c1f11e47b76 100644 --- a/src/gui/callstatechecker.h +++ b/src/gui/callstatechecker.h @@ -7,6 +7,7 @@ #include #include +#include #include "networkjobs.h" #include "accountstate.h" @@ -16,6 +17,7 @@ namespace OCC { class CallStateChecker : public QObject { Q_OBJECT + QML_ELEMENT Q_PROPERTY(QString token READ token WRITE setToken NOTIFY tokenChanged) Q_PROPERTY(AccountState* accountState READ accountState WRITE setAccountState NOTIFY accountStateChanged) Q_PROPERTY(bool checking READ checking WRITE setChecking NOTIFY checkingChanged) diff --git a/src/gui/emojimodel.h b/src/gui/emojimodel.h index dd55abad8804d..cf220050f411b 100644 --- a/src/gui/emojimodel.h +++ b/src/gui/emojimodel.h @@ -75,6 +75,7 @@ class EmojiCategoriesModel : public QAbstractListModel class EmojiModel : public QObject { Q_OBJECT + QML_ELEMENT Q_PROPERTY(QVariantList model READ model NOTIFY modelChanged) Q_PROPERTY(QAbstractListModel *emojiCategoriesModel READ emojiCategoriesModel CONSTANT) diff --git a/src/gui/filedetails/CMakeLists.txt b/src/gui/filedetails/CMakeLists.txt new file mode 100644 index 0000000000000..6b384f524e2eb --- /dev/null +++ b/src/gui/filedetails/CMakeLists.txt @@ -0,0 +1,37 @@ +# SPDX-FileCopyrightText: 2025 Nextcloud GmbH +# SPDX-FileContributor: Carl Schwan +# SPDX-License-Identifier: BSD-3-Clause + +add_library(nextcloudFileDetails STATIC) + +qt_add_qml_module(nextcloudFileDetails + URI com.nextcloud.desktopclient.filedetails + QML_FILES + FileActivityView.qml + FileDetailsPage.qml + FileDetailsView.qml + FileDetailsWindow.qml + FileTag.qml + NCInputDateField.qml + NCInputTextArea.qml + NCInputTextField.qml + NCTabButton.qml + ShareeDelegate.qml + ShareDelegate.qml + ShareDetailsPage.qml + ShareeSearchField.qml + ShareView.qml + SOURCES + datefieldbackend.h + datefieldbackend.cpp + filedetails.h + filedetails.cpp + sharemodel.h + sharemodel.cpp + shareemodel.h + shareemodel.cpp + sortedsharemodel.h + sortedsharemodel.cpp +) + +target_link_libraries(nextcloudFileDetails PRIVATE nextcloudCore) diff --git a/src/gui/filedetails/datefieldbackend.h b/src/gui/filedetails/datefieldbackend.h index 2a5fe57a4440c..e72a30bf23524 100644 --- a/src/gui/filedetails/datefieldbackend.h +++ b/src/gui/filedetails/datefieldbackend.h @@ -7,6 +7,7 @@ #include #include +#include class TestDateFieldBackend; @@ -18,6 +19,7 @@ namespace Quick class DateFieldBackend : public QObject { Q_OBJECT + QML_ELEMENT Q_PROPERTY(QDate date READ date WRITE setDate NOTIFY dateChanged) Q_PROPERTY(qint64 dateMsecs READ dateMsecs WRITE setDateMsecs NOTIFY dateMsecsChanged) diff --git a/src/gui/filedetails/filedetails.h b/src/gui/filedetails/filedetails.h index af115735ce19b..061c9ed267736 100644 --- a/src/gui/filedetails/filedetails.h +++ b/src/gui/filedetails/filedetails.h @@ -9,6 +9,7 @@ #include #include #include +#include #include "common/syncjournalfilerecord.h" @@ -21,6 +22,7 @@ class Folder; class FileDetails : public QObject { Q_OBJECT + QML_ELEMENT Q_PROPERTY(QString localPath READ localPath WRITE setLocalPath NOTIFY localPathChanged) Q_PROPERTY(QString name READ name NOTIFY fileChanged) Q_PROPERTY(QString sizeString READ sizeString NOTIFY fileChanged) diff --git a/src/gui/filedetails/shareemodel.h b/src/gui/filedetails/shareemodel.h index d57681355434d..6657be645d9f7 100644 --- a/src/gui/filedetails/shareemodel.h +++ b/src/gui/filedetails/shareemodel.h @@ -7,6 +7,7 @@ #include #include +#include #include "accountstate.h" #include "sharee.h" @@ -19,6 +20,7 @@ namespace OCC { class ShareeModel : public QAbstractListModel { Q_OBJECT + QML_ELEMENT Q_PROPERTY(AccountState* accountState READ accountState WRITE setAccountState NOTIFY accountStateChanged) Q_PROPERTY(bool shareItemIsFolder READ shareItemIsFolder WRITE setShareItemIsFolder NOTIFY shareItemIsFolderChanged) Q_PROPERTY(QString searchString READ searchString WRITE setSearchString NOTIFY searchStringChanged) diff --git a/src/gui/filedetails/sharemodel.h b/src/gui/filedetails/sharemodel.h index 0209e3a5a736c..378d7cb1d4ebc 100644 --- a/src/gui/filedetails/sharemodel.h +++ b/src/gui/filedetails/sharemodel.h @@ -6,6 +6,7 @@ #pragma once #include +#include #include "accountstate.h" #include "folder.h" @@ -17,6 +18,7 @@ namespace OCC { class ShareModel : public QAbstractListModel { Q_OBJECT + QML_ELEMENT Q_PROPERTY(AccountState* accountState READ accountState WRITE setAccountState NOTIFY accountStateChanged) Q_PROPERTY(QString localPath READ localPath WRITE setLocalPath NOTIFY localPathChanged) Q_PROPERTY(bool accountConnected READ accountConnected NOTIFY accountConnectedChanged) diff --git a/src/gui/filedetails/sortedsharemodel.h b/src/gui/filedetails/sortedsharemodel.h index f8e6eff1efa5c..1b1d7eb27d87d 100644 --- a/src/gui/filedetails/sortedsharemodel.h +++ b/src/gui/filedetails/sortedsharemodel.h @@ -6,6 +6,7 @@ #pragma once #include +#include #include "sharemodel.h" namespace OCC { @@ -13,6 +14,7 @@ namespace OCC { class SortedShareModel : public QSortFilterProxyModel { Q_OBJECT + QML_ELEMENT public: explicit SortedShareModel(QObject *parent = nullptr); diff --git a/src/gui/macOS/CMakeLists.txt b/src/gui/macOS/CMakeLists.txt new file mode 100644 index 0000000000000..5ac8b4c9785ea --- /dev/null +++ b/src/gui/macOS/CMakeLists.txt @@ -0,0 +1,12 @@ +# SPDX-FileCopyrightText: 2025 Nextcloud GmbH +# SPDX-FileContributor: Carl Schwan +# SPDX-License-Identifier: BSD-3-Clause + +add_library(nextcloudMacOS STATIC) + +qt_add_qml_module(nextcloudMacOS + URI com.nextcloud.desktopclient.nextcloud.macos + QML_FILES + ui/FileProviderSettings.qml + ui/FileProviderFileDelegate.qml +) diff --git a/src/gui/macOS/fileprovidersettingscontroller.h b/src/gui/macOS/fileprovidersettingscontroller.h index 081a28c784646..398da25cb7273 100644 --- a/src/gui/macOS/fileprovidersettingscontroller.h +++ b/src/gui/macOS/fileprovidersettingscontroller.h @@ -19,6 +19,8 @@ namespace Mac { class FileProviderSettingsController : public QObject { Q_OBJECT + QML_ELEMENT + QML_SINGLETON public: static FileProviderSettingsController *instance(); @@ -32,6 +34,13 @@ class FileProviderSettingsController : public QObject [[nodiscard]] Q_INVOKABLE bool trashDeletionEnabledForAccount(const QString &userIdAtHost) const; [[nodiscard]] Q_INVOKABLE bool trashDeletionSetForAccount(const QString &userIdAtHost) const; + static FileProviderSettingsController *create(QQmlEngine *, QJSEngine *engine) + { + auto _instance = Theme::instance(); + QQmlEngine::setObjectOwnership(_instance, QJSEngine::CppOwnership); + return _instance; + } + public slots: void setVfsEnabledForAccount(const QString &userIdAtHost, const bool setEnabled, const bool showInformationDialog = true); void setTrashDeletionEnabledForAccount(const QString &userIdAtHost, const bool setEnabled); diff --git a/src/gui/main.cpp b/src/gui/main.cpp index 073630d9dc9bf..c669b9ae7c659 100644 --- a/src/gui/main.cpp +++ b/src/gui/main.cpp @@ -32,6 +32,9 @@ #include #include #include +#include + +Q_IMPORT_QML_PLUGIN(com_nextcloud_desktopclient_trayPlugin) using namespace OCC; @@ -103,7 +106,7 @@ int main(int argc, char **argv) } #ifndef Q_OS_WIN - signal(SIGPIPE, SIG_IGN); +// signal(SIGPIPE, SIG_IGN); #endif if (app.giveHelp()) { app.showHelp(); diff --git a/src/gui/owncloudgui.cpp b/src/gui/owncloudgui.cpp index eb12c92d8fd4c..9919e787af503 100644 --- a/src/gui/owncloudgui.cpp +++ b/src/gui/owncloudgui.cpp @@ -11,8 +11,6 @@ #include "accountstate.h" #include "application.h" #include "callstatechecker.h" -#include "emojimodel.h" -#include "fileactivitylistmodel.h" #include "folderman.h" #include "guiutility.h" #include "logbrowser.h" @@ -21,18 +19,8 @@ #include "owncloudsetupwizard.h" #include "progressdispatcher.h" #include "settingsdialog.h" -#include "theme.h" -#include "wheelhandler.h" #include "syncconflictsmodel.h" #include "syncengine.h" -#include "filedetails/datefieldbackend.h" -#include "filedetails/filedetails.h" -#include "filedetails/shareemodel.h" -#include "filedetails/sharemodel.h" -#include "filedetails/sortedsharemodel.h" -#include "tray/sortedactivitylistmodel.h" -#include "tray/syncstatussummary.h" -#include "tray/unifiedsearchresultslistmodel.h" #include "filesystem.h" #ifdef WITH_LIBCLOUDPROVIDERS @@ -119,46 +107,6 @@ ownCloudGui::ownCloudGui(Application *parent) connect(Logger::instance(), &Logger::guiLog, this, &ownCloudGui::slotShowTrayMessage); connect(Logger::instance(), &Logger::guiMessage, this, &ownCloudGui::slotShowGuiMessage); - - qmlRegisterType("com.nextcloud.desktopclient", 1, 0, "SyncStatusSummary"); - qmlRegisterType("com.nextcloud.desktopclient", 1, 0, "EmojiModel"); - qmlRegisterType("com.nextcloud.desktopclient", 1, 0, "UserStatusSelectorModel"); - qmlRegisterType("com.nextcloud.desktopclient", 1, 0, "ActivityListModel"); - qmlRegisterType("com.nextcloud.desktopclient", 1, 0, "FileActivityListModel"); - qmlRegisterType("com.nextcloud.desktopclient", 1, 0, "SortedActivityListModel"); - qmlRegisterType("com.nextcloud.desktopclient", 1, 0, "WheelHandler"); - qmlRegisterType("com.nextcloud.desktopclient", 1, 0, "CallStateChecker"); - qmlRegisterType("com.nextcloud.desktopclient", 1, 0, "DateFieldBackend"); - qmlRegisterType("com.nextcloud.desktopclient", 1, 0, "FileDetails"); - qmlRegisterType("com.nextcloud.desktopclient", 1, 0, "ShareModel"); - qmlRegisterType("com.nextcloud.desktopclient", 1, 0, "ShareeModel"); - qmlRegisterType("com.nextcloud.desktopclient", 1, 0, "SortedShareModel"); - qmlRegisterType("com.nextcloud.desktopclient", 1, 0, "SyncConflictsModel"); - - qmlRegisterUncreatableType("com.nextcloud.desktopclient", 1, 0, "QAbstractItemModel", "QAbstractItemModel"); - qmlRegisterUncreatableType("com.nextcloud.desktopclient", 1, 0, "Activity", "Activity"); - qmlRegisterUncreatableType("com.nextcloud.desktopclient", 1, 0, "TalkNotificationData", "TalkNotificationData"); - qmlRegisterUncreatableType("com.nextcloud.desktopclient", 1, 0, "UnifiedSearchResultsListModel", "UnifiedSearchResultsListModel"); - qmlRegisterUncreatableType("com.nextcloud.desktopclient", 1, 0, "UserStatus", "Access to Status enum"); - qmlRegisterUncreatableType("com.nextcloud.desktopclient", 1, 0, "Sharee", "Access to Type enum"); - qmlRegisterUncreatableType("com.nextcloud.desktopclient", 1, 0, "ClientSideEncryptionTokenSelector", "Access to the certificate selector"); - - qRegisterMetaType("ActivityListModel*"); - qRegisterMetaType("UnifiedSearchResultsListModel*"); - qRegisterMetaType("UserStatus"); - qRegisterMetaType("SharePtr"); - qRegisterMetaType("ShareePtr"); - qRegisterMetaType("Sharee"); - qRegisterMetaType("ActivityList"); - - qmlRegisterSingletonInstance("com.nextcloud.desktopclient", 1, 0, "UserModel", UserModel::instance()); - 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() diff --git a/src/gui/syncconflictsmodel.h b/src/gui/syncconflictsmodel.h index d3e2f44495435..7402206208975 100644 --- a/src/gui/syncconflictsmodel.h +++ b/src/gui/syncconflictsmodel.h @@ -12,12 +12,14 @@ #include #include #include +#include namespace OCC { class SyncConflictsModel : public QAbstractListModel { Q_OBJECT + QML_ELEMENT Q_PROPERTY(OCC::ActivityList conflictActivities READ conflictActivities WRITE setConflictActivities NOTIFY conflictActivitiesChanged) diff --git a/src/gui/systray.cpp b/src/gui/systray.cpp index e9fc7564b75b4..cd61e146726e7 100644 --- a/src/gui/systray.cpp +++ b/src/gui/systray.cpp @@ -115,7 +115,9 @@ void Systray::create() _trayEngine->rootContext()->setContextProperty("activityModel", &_fakeActivityModel); } - QQmlComponent trayWindowComponent(trayEngine(), QStringLiteral("qrc:/qml/src/gui/tray/MainWindow.qml")); + QQmlComponent trayWindowComponent(trayEngine(), "com.nextcloud.desktopclient.tray", "MainWindow"); + + qWarning() << "has error" << trayWindowComponent.isError(); if(trayWindowComponent.isError()) { qCWarning(lcSystray) << trayWindowComponent.errorString(); diff --git a/src/gui/systray.h b/src/gui/systray.h index 87f4a6b196ccd..70cb75f5e5a6b 100644 --- a/src/gui/systray.h +++ b/src/gui/systray.h @@ -11,6 +11,7 @@ #include "tray/usermodel.h" #include +#include #include #include @@ -18,7 +19,6 @@ class QScreen; class QQmlApplicationEngine; class QQuickWindow; class QWindow; -class QQuickWindow; class QGuiApplication; namespace OCC { @@ -57,6 +57,8 @@ double menuBarThickness(); class Systray : public QSystemTrayIcon { Q_OBJECT + QML_ELEMENT + QML_SINGLETON Q_PROPERTY(QString windowTitle READ windowTitle CONSTANT) Q_PROPERTY(bool useNormalWindow READ useNormalWindow CONSTANT) @@ -69,6 +71,13 @@ class Systray : public QSystemTrayIcon static Systray *instance(); ~Systray() override = default; + static Systray *create(QQmlEngine *, QJSEngine *) + { + auto _instance = instance(); + QQmlEngine::setObjectOwnership(_instance, QJSEngine::CppOwnership); + return _instance; + } + enum class TaskBarPosition { Bottom, Left, Top, Right }; Q_ENUM(TaskBarPosition); diff --git a/src/gui/tray/CMakeLists.txt b/src/gui/tray/CMakeLists.txt new file mode 100644 index 0000000000000..edcdc2a3c019e --- /dev/null +++ b/src/gui/tray/CMakeLists.txt @@ -0,0 +1,69 @@ +# SPDX-FileCopyrightText: 2025 Nextcloud GmbH +# SPDX-FileContributor: Carl Schwan +# SPDX-License-Identifier: BSD-3-Clause + +add_library(nextcloudTray STATIC + activitydata.cpp + activitydata.h + activitylistmodel.cpp + activitylistmodel.h + asyncimageresponse.cpp + fileactivitylistmodel.cpp + fileactivitylistmodel.h + notificationhandler.cpp + notificationhandler.h + sortedactivitylistmodel.cpp + sortedactivitylistmodel.h + svgimageprovider.cpp + svgimageprovider.h + syncstatussummary.cpp + syncstatussummary.h + talkreply.cpp + trayimageprovider.cpp + unifiedsearchresult.cpp + unifiedsearchresult.h + unifiedsearchresultslistmodel.cpp + unifiedsearchresultslistmodel.h + usermodel.cpp + usermodel.h +) + +target_link_libraries(nextcloudTray PRIVATE nextcloudCore) + +qt_add_qml_module(nextcloudTray + URI com.nextcloud.desktopclient.tray + QML_FILES + MainWindow.qml + UserLine.qml + HeaderButton.qml + SyncStatus.qml + ActivityItem.qml + AutoSizingMenu.qml + ActivityList.qml + CurrentAccountHeaderButton.qml + TrayWindowHeader.qml + UnifiedSearchInputContainer.qml + UnifiedSearchResultFetchMoreTrigger.qml + UnifiedSearchResultItem.qml + UnifiedSearchResultItemSkeleton.qml + UnifiedSearchResultItemSkeletonContainer.qml + UnifiedSearchResultItemSkeletonGradientRectangle.qml + UnifiedSearchResultListItem.qml + UnifiedSearchResultNothingFound.qml + UnifiedSearchPlaceholderView.qml + UnifiedSearchResultSectionItem.qml + ActivityItemContextMenu.qml + ActivityItemActions.qml + ActivityItemContent.qml + TalkReplyTextField.qml + CallNotificationDialog.qml + EditFileLocallyLoadingDialog.qml + EncryptionTokenDiscoveryDialog.qml + NCBusyIndicator.qml + NCIconWithBackgroundImage.qml + NCProgressBar.qml + EnforcedPlainTextLabel.qml + ListItemLineAndSubline.qml + TrayFoldersMenuButton.qml + TrayFolderListItem.qml +) diff --git a/src/gui/tray/activitydata.h b/src/gui/tray/activitydata.h index 00cae91de5c10..f67118283d5a4 100644 --- a/src/gui/tray/activitydata.h +++ b/src/gui/tray/activitydata.h @@ -15,6 +15,7 @@ #include #include #include +#include namespace OCC { /** @@ -93,6 +94,7 @@ struct RichSubjectParameter { struct TalkNotificationData { Q_GADGET + QML_ELEMENT Q_PROPERTY(QString conversationToken MEMBER conversationToken) Q_PROPERTY(QString messageId MEMBER messageId) Q_PROPERTY(QString messageSent MEMBER messageSent) @@ -131,6 +133,7 @@ struct TalkNotificationData { class Activity { Q_GADGET + QML_ELEMENT Q_PROPERTY(OCC::Activity::Type type MEMBER _type) Q_PROPERTY(OCC::TalkNotificationData talkNotificationData MEMBER _talkNotificationData) Q_PROPERTY(QVariantMap subjectRichParameters MEMBER _subjectRichParameters) diff --git a/src/gui/tray/activitylistmodel.h b/src/gui/tray/activitylistmodel.h index d200baa6ed669..5c66f6f359fbb 100644 --- a/src/gui/tray/activitylistmodel.h +++ b/src/gui/tray/activitylistmodel.h @@ -8,8 +8,10 @@ #define ACTIVITYLISTMODEL_H #include +#include #include "activitydata.h" +#include "accountstate.h" class QJsonDocument; @@ -21,7 +23,6 @@ namespace OCC { Q_DECLARE_LOGGING_CATEGORY(lcActivity) -class AccountState; class ConflictDialog; class InvalidFilenameDialog; class CaseClashFilenameDialog; @@ -36,6 +37,7 @@ class CaseClashFilenameDialog; class ActivityListModel : public QAbstractListModel { Q_OBJECT + QML_ELEMENT Q_PROPERTY(quint32 maxActionButtons READ maxActionButtons CONSTANT) Q_PROPERTY(AccountState *accountState READ accountState WRITE setAccountState NOTIFY accountStateChanged) Q_PROPERTY(bool hasSyncConflicts READ hasSyncConflicts NOTIFY hasSyncConflictsChanged) diff --git a/src/gui/fileactivitylistmodel.cpp b/src/gui/tray/fileactivitylistmodel.cpp similarity index 100% rename from src/gui/fileactivitylistmodel.cpp rename to src/gui/tray/fileactivitylistmodel.cpp diff --git a/src/gui/fileactivitylistmodel.h b/src/gui/tray/fileactivitylistmodel.h similarity index 97% rename from src/gui/fileactivitylistmodel.h rename to src/gui/tray/fileactivitylistmodel.h index c2d6a9c96e135..312cfadc78dab 100644 --- a/src/gui/fileactivitylistmodel.h +++ b/src/gui/tray/fileactivitylistmodel.h @@ -13,6 +13,7 @@ namespace OCC { class FileActivityListModel : public ActivityListModel { Q_OBJECT + QML_ELEMENT Q_PROPERTY(QString localPath READ localPath WRITE setLocalPath NOTIFY localPathChanged) public: diff --git a/src/gui/tray/sortedactivitylistmodel.h b/src/gui/tray/sortedactivitylistmodel.h index 36dd4603c4db4..226e4f7016b94 100644 --- a/src/gui/tray/sortedactivitylistmodel.h +++ b/src/gui/tray/sortedactivitylistmodel.h @@ -6,6 +6,7 @@ #pragma once #include +#include namespace OCC { @@ -14,6 +15,7 @@ class ActivityListModel; class SortedActivityListModel : public QSortFilterProxyModel { Q_OBJECT + QML_ELEMENT public: explicit SortedActivityListModel(QObject *parent = nullptr); diff --git a/src/gui/tray/syncstatussummary.h b/src/gui/tray/syncstatussummary.h index ad95d1ba65cde..f72f6229e06a8 100644 --- a/src/gui/tray/syncstatussummary.h +++ b/src/gui/tray/syncstatussummary.h @@ -14,12 +14,14 @@ #include #include +#include namespace OCC { class SyncStatusSummary : public QObject { Q_OBJECT + QML_ELEMENT Q_PROPERTY(double syncProgress READ syncProgress NOTIFY syncProgressChanged) Q_PROPERTY(QUrl syncIcon READ syncIcon NOTIFY syncIconChanged) diff --git a/src/gui/tray/unifiedsearchresultslistmodel.h b/src/gui/tray/unifiedsearchresultslistmodel.h index a2c07eb651fab..56292e4d5e0d5 100644 --- a/src/gui/tray/unifiedsearchresultslistmodel.h +++ b/src/gui/tray/unifiedsearchresultslistmodel.h @@ -10,6 +10,7 @@ #include #include +#include namespace OCC { class AccountState; @@ -23,6 +24,8 @@ class AccountState; class UnifiedSearchResultsListModel : public QAbstractListModel { Q_OBJECT + QML_ELEMENT + QML_UNCREATABLE("") Q_PROPERTY(bool isSearchInProgress READ isSearchInProgress NOTIFY isSearchInProgressChanged) Q_PROPERTY(QString currentFetchMoreInProgressProviderId READ currentFetchMoreInProgressProviderId NOTIFY diff --git a/src/gui/tray/usermodel.h b/src/gui/tray/usermodel.h index ec416007b2f68..8e524783d7303 100644 --- a/src/gui/tray/usermodel.h +++ b/src/gui/tray/usermodel.h @@ -12,6 +12,7 @@ #include #include #include +#include #include "accountfwd.h" #include "accountmanager.h" @@ -218,6 +219,8 @@ private slots: class UserModel : public QAbstractListModel { Q_OBJECT + QML_ELEMENT + QML_SINGLETON Q_PROPERTY(User* currentUser READ currentUser NOTIFY currentUserChanged) Q_PROPERTY(int currentUserId READ currentUserId WRITE setCurrentUserId NOTIFY currentUserChanged) public: @@ -225,6 +228,13 @@ class UserModel : public QAbstractListModel static UserModel *instance(); ~UserModel() override = default; + static UserModel *create(QQmlEngine *, QJSEngine *) + { + auto i = instance(); + QQmlEngine::setObjectOwnership(i, QJSEngine::CppOwnership); + return i; + } + void addUser(AccountStatePtr &user, const bool &isCurrent = false); int currentUserIndex(); @@ -309,10 +319,20 @@ class ImageProvider : public QQuickAsyncImageProvider class UserAppsModel : public QAbstractListModel { Q_OBJECT + QML_ELEMENT + QML_SINGLETON + public: static UserAppsModel *instance(); ~UserAppsModel() override = default; + static UserAppsModel *create(QQmlEngine *, QJSEngine *) + { + auto _instance = instance(); + QQmlEngine::setObjectOwnership(_instance, QJSEngine::CppOwnership); + return _instance; + } + [[nodiscard]] int rowCount(const QModelIndex &parent = QModelIndex()) const override; [[nodiscard]] QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; diff --git a/src/gui/types.cpp b/src/gui/types.cpp new file mode 100644 index 0000000000000..28353d4e276d0 --- /dev/null +++ b/src/gui/types.cpp @@ -0,0 +1,3 @@ +// SPDX-FIl + +#include "types.h" diff --git a/src/gui/types.h b/src/gui/types.h new file mode 100644 index 0000000000000..adfa8ce29bd2f --- /dev/null +++ b/src/gui/types.h @@ -0,0 +1,53 @@ +// SPDX-FileCopyrightText: 2025 Nextcloud GmbH +// SPDX-FileContributor: Carl Schwan +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "userstatusconnector.h" +#include "clientsideencryptiontokenselector.h" +#include "theme.h" +#include "sharee.h" + +#include +#include + +class UserStatusForeign +{ + Q_GADGET + QML_NAMED_ELEMENT(UserStatus) + QML_FOREIGN(UserStatus) + QML_UNCREATABLE() +}; + +class ShareeForeign +{ + Q_GADGET + QML_NAMED_ELEMENT(Sharee) + QML_FOREIGN(Sharee) + QML_UNCREATABLE() +}; + +class ClientSideEncryptionTokenSelectorForeign : public QObject +{ + Q_OBJECT + QML_NAMED_ELEMENT(ClientSideEncryptionTokenSelector) + QML_FOREIGN(ClientSideEncryptionTokenSelector) + QML_UNCREATABLE() +}; + +class ThemeForeign : public QObject +{ + Q_OBJECT + QML_NAMED_ELEMENT(Theme) + QML_FOREIGN(Theme) + QML_SINGLETON + QML_UNCREATABLE() + + static Theme *create(QQmlEngine *, QJSEngine *engine) + { + auto _instance = Theme::instance(); + QQmlEngine::setObjectOwnership(_instance, QJSEngine::CppOwnership); + return _instance; + } +}; diff --git a/src/gui/userstatusselectormodel.h b/src/gui/userstatusselectormodel.h index 424925f555b12..113ca88509eee 100644 --- a/src/gui/userstatusselectormodel.h +++ b/src/gui/userstatusselectormodel.h @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -24,6 +25,7 @@ namespace OCC { class UserStatusSelectorModel : public QObject { Q_OBJECT + QML_ELEMENT Q_PROPERTY(int userIndex READ userIndex WRITE setUserIndex NOTIFY userIndexChanged) Q_PROPERTY(QString userStatusMessage READ userStatusMessage WRITE setUserStatusMessage NOTIFY userStatusChanged)