From 1d29abfb7c60998ae88eb5c6fbb763661b21362b Mon Sep 17 00:00:00 2001 From: Gabriel Bolbotina Date: Thu, 12 Mar 2026 16:05:01 +0200 Subject: [PATCH 1/4] Added modifications --- app/notificationmodel.cpp | 6 ++++++ app/notificationmodel.h | 4 +++- app/qml/main.qml | 21 ++++++++++++++++++ app/synchronizationmanager.cpp | 1 + core/merginapi.cpp | 39 ++++++++++++++++++++++++++++++++++ core/merginapi.h | 8 +++++++ 6 files changed, 78 insertions(+), 1 deletion(-) diff --git a/app/notificationmodel.cpp b/app/notificationmodel.cpp index d5fc1c74a..247ab6f57 100644 --- a/app/notificationmodel.cpp +++ b/app/notificationmodel.cpp @@ -156,6 +156,12 @@ void NotificationModel::onNotificationClicked( uint id ) emit showSyncFailedDialogClicked(); break; } + case NotificationType::ActionType::ShowProjectNewVersionAction: + { + remove( id ); + emit showProjectNewVersionClicked(); + break; + } default: break; } } diff --git a/app/notificationmodel.h b/app/notificationmodel.h index 91711029c..76420f323 100644 --- a/app/notificationmodel.h +++ b/app/notificationmodel.h @@ -43,7 +43,8 @@ class NotificationType NoAction, ShowProjectIssuesAction, ShowSwitchWorkspaceAction, - ShowSyncFailedDialog + ShowSyncFailedDialog, + ShowProjectNewVersionAction }; Q_ENUM( ActionType ) @@ -111,6 +112,7 @@ class NotificationModel : public QAbstractListModel void rowCountChanged(); void showProjectIssuesActionClicked(); void showSwitchWorkspaceActionClicked(); + void showProjectNewVersionClicked(); void showSyncFailedDialogClicked(); private: diff --git a/app/qml/main.qml b/app/qml/main.qml index d417de897..7b518cb77 100644 --- a/app/qml/main.qml +++ b/app/qml/main.qml @@ -84,6 +84,10 @@ ApplicationWindow { // Stop/Start sync animation when user goes to map syncButton.iconRotateAnimationRunning = ( __syncManager.hasPendingSync( __activeProject.projectFullName() ) ) + + if ( __activeProject.projectFullName() !== "" ) { + __merginApi.isProjectSyncNeeded( __activeProject.projectFullName(), true ) + } } else if ( stateManager.state === "projects" ) { projectController.openPanel() @@ -1090,6 +1094,17 @@ ApplicationWindow { { ssoExpiredTokenDialog.open() } + + function onProjectSyncRequired( projectFullName ) + { + if ( __activeProject.projectFullName() === projectFullName ) + { + __notificationModel.addInfo( + __inputUtils.htmlLink( qsTr( "There is a new version of the project available" ), __style.forestColor ), + MM.NotificationType.ShowProjectNewVersionAction + ) + } + } } Connections { @@ -1112,6 +1127,9 @@ ApplicationWindow { function onShowSyncFailedDialogClicked() { syncFailedDialog.open() } + function onShowProjectNewVersionClicked() { + __activeProject.requestSync() + } } Connections { @@ -1159,6 +1177,9 @@ ApplicationWindow { AppSettings.defaultProject = __activeProject.localProject.qgisProjectFilePath ?? "" AppSettings.activeProject = __activeProject.localProject.qgisProjectFilePath ?? "" + if ( __activeProject.projectFullName() !== "" ) { + __merginApi.isProjectSyncNeeded( __activeProject.projectFullName(), true ) + } } function onProjectWillBeReloaded() { diff --git a/app/synchronizationmanager.cpp b/app/synchronizationmanager.cpp index f5322de7c..a65a70eca 100644 --- a/app/synchronizationmanager.cpp +++ b/app/synchronizationmanager.cpp @@ -328,3 +328,4 @@ void SynchronizationManager::onProjectReloadNeededAfterSync( const QString &proj } } + diff --git a/core/merginapi.cpp b/core/merginapi.cpp index ab91e0611..20e2ebd45 100644 --- a/core/merginapi.cpp +++ b/core/merginapi.cpp @@ -4597,3 +4597,42 @@ bool MerginApi::serverVersionIsAtLeast( const int requiredMajor, const int requi // check patch return serverPatch >= requiredPatch; } + +void MerginApi::isProjectSyncNeededFinished() +{ + QNetworkReply *r = qobject_cast( sender() ); + Q_ASSERT( r ); + + QString projectFullName = r->request().attribute( static_cast( AttrProjectFullName ) ).toString(); + mPendingSyncChecks.remove( projectFullName ); + + if ( r->error() == QNetworkReply::NoError ) + { + QByteArray data = r->readAll(); + MerginProjectMetadata serverProject = MerginProjectMetadata::fromJson( data ); + + // Skip if a sync is already in progress for this project + if ( !mTransactionalStatus.contains( projectFullName ) ) + { + LocalProject projectInfo = mLocalProjects.projectFromMerginName( projectFullName ); + if ( projectInfo.isValid() && projectInfo.localVersion != -1 && projectInfo.localVersion < serverProject.version ) + { + emit projectSyncRequired( projectFullName ); + } + } + } + r->deleteLater(); +} + +void MerginApi::isProjectSyncNeeded( const QString &projectFullName, bool withAuth ) +{ + if ( mPendingSyncChecks.contains( projectFullName ) ) + return; + + QNetworkReply *reply = getProjectInfo( projectFullName, withAuth ); + if ( !reply ) + return; + + mPendingSyncChecks.insert( projectFullName ); + connect( reply, &QNetworkReply::finished, this, &MerginApi::isProjectSyncNeededFinished ); +} diff --git a/core/merginapi.h b/core/merginapi.h index 202e042c6..d94a1664e 100644 --- a/core/merginapi.h +++ b/core/merginapi.h @@ -645,6 +645,8 @@ class MerginApi: public QObject */ Q_INVOKABLE void reloadProjectRole( const QString &projectFullName ); + Q_INVOKABLE void isProjectSyncNeeded( const QString &projectFullName, bool withAuth ); + /** * Returns the network manager used for Mergin API requests */ @@ -689,6 +691,7 @@ class MerginApi: public QObject void listProjectsFinished( const MerginProjectsList &merginProjects, int projectCount, int page, QString requestId ); void listProjectsFailed(); + void projectSyncRequired( const QString &projectFullName ); void listProjectsByNameFinished( const MerginProjectsList &merginProjects, QString requestId ); void syncProjectFinished( const QString &projectFullName, bool successfully, int version ); void projectReloadNeededAfterSync( const QString &projectFullName ); @@ -777,12 +780,15 @@ class MerginApi: public QObject void userSelfRegistrationEnabledChanged(); + private slots: void listProjectsReplyFinished( QString requestId ); void listProjectsByNameReplyFinished( QString requestId ); // Pull slots void pullInfoReplyFinished(); + void isProjectSyncNeededFinished(); + void downloadItemReplyFinished( DownloadQueueItem item ); void cacheServerConfig(); @@ -979,6 +985,8 @@ class MerginApi: public QObject MerginServerType::ServerType mServerType = MerginServerType::ServerType::OLD; QString mServerDiagnosticLogsUrl = MerginApi::sDefaultReportLogUrl; + QSet mPendingSyncChecks; //!< projects with an in-flight isProjectSyncNeeded request + QOAuth2AuthorizationCodeFlow mOauth2Flow; #ifdef MOBILE_OS QOAuthUriSchemeReplyHandler *mOauth2ReplyHandler = nullptr; // parented by mOauth2Flow From 7edbb56facf6f6534a2d93d1613405c54008361f Mon Sep 17 00:00:00 2001 From: Gabriel Bolbotina Date: Thu, 12 Mar 2026 16:13:54 +0200 Subject: [PATCH 2/4] Small changes --- app/synchronizationmanager.cpp | 1 - core/merginapi.cpp | 2 +- core/merginapi.h | 3 +-- 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/app/synchronizationmanager.cpp b/app/synchronizationmanager.cpp index a65a70eca..f5322de7c 100644 --- a/app/synchronizationmanager.cpp +++ b/app/synchronizationmanager.cpp @@ -328,4 +328,3 @@ void SynchronizationManager::onProjectReloadNeededAfterSync( const QString &proj } } - diff --git a/core/merginapi.cpp b/core/merginapi.cpp index 20e2ebd45..dceec9b0a 100644 --- a/core/merginapi.cpp +++ b/core/merginapi.cpp @@ -4611,7 +4611,7 @@ void MerginApi::isProjectSyncNeededFinished() QByteArray data = r->readAll(); MerginProjectMetadata serverProject = MerginProjectMetadata::fromJson( data ); - // Skip if a sync is already in progress for this project + // skip if a sync is already in progress for this project if ( !mTransactionalStatus.contains( projectFullName ) ) { LocalProject projectInfo = mLocalProjects.projectFromMerginName( projectFullName ); diff --git a/core/merginapi.h b/core/merginapi.h index d94a1664e..8486a204e 100644 --- a/core/merginapi.h +++ b/core/merginapi.h @@ -780,7 +780,6 @@ class MerginApi: public QObject void userSelfRegistrationEnabledChanged(); - private slots: void listProjectsReplyFinished( QString requestId ); void listProjectsByNameReplyFinished( QString requestId ); @@ -985,7 +984,7 @@ class MerginApi: public QObject MerginServerType::ServerType mServerType = MerginServerType::ServerType::OLD; QString mServerDiagnosticLogsUrl = MerginApi::sDefaultReportLogUrl; - QSet mPendingSyncChecks; //!< projects with an in-flight isProjectSyncNeeded request + QSet mPendingSyncChecks; // not yet updated projects with isProjectSyncNeeded request QOAuth2AuthorizationCodeFlow mOauth2Flow; #ifdef MOBILE_OS From a26f78f13a4ce4c54ef92e91bb202117115d1af0 Mon Sep 17 00:00:00 2001 From: Gabriel Bolbotina Date: Thu, 26 Mar 2026 19:59:46 +0200 Subject: [PATCH 3/4] Implemented code findings --- app/activeproject.cpp | 16 ++++++++++++++++ app/activeproject.h | 7 +++++++ app/main.cpp | 2 +- app/notificationmodel.cpp | 6 ++++-- app/notificationmodel.h | 4 ++-- app/qml/components/MMNotification.qml | 10 ++++++++-- app/qml/main.qml | 11 +++-------- app/test/testactiveproject.cpp | 12 ++++++------ app/test/testmerginapi.cpp | 2 +- core/merginapi.cpp | 15 +++++---------- core/merginapi.h | 1 - 11 files changed, 53 insertions(+), 33 deletions(-) diff --git a/app/activeproject.cpp b/app/activeproject.cpp index 6f1859b0c..c5f9af835 100644 --- a/app/activeproject.cpp +++ b/app/activeproject.cpp @@ -21,6 +21,7 @@ #include "activeproject.h" #include "coreutils.h" +#include "merginapi.h" #ifdef ANDROID #include "position/tracking/androidtrackingbroadcast.h" @@ -32,6 +33,7 @@ const int ActiveProject::LOADING_FLAG_FILE_EXPIRATION_MS = 5000; ActiveProject::ActiveProject( AppSettings &appSettings , ActiveLayer &activeLayer , LocalProjectsManager &localProjectsManager + , MerginApi *merginApi , QObject *parent ) : QObject( parent ) @@ -39,6 +41,7 @@ ActiveProject::ActiveProject( AppSettings &appSettings , mActiveLayer( activeLayer ) , mAuthManager( QgsApplication::authManager() ) , mLocalProjectsManager( localProjectsManager ) + , mMerginApi( merginApi ) , mProjectLoadingLog( "" ) { // we used to have our own QgsProject instance, but unfortunately few pieces of qgis_core @@ -211,6 +214,11 @@ bool ActiveProject::forceLoad( const QString &filePath, bool force ) emit projectReloaded( mQgsProject ); emit positionTrackingSupportedChanged(); emit mapSketchesEnabledChanged(); + + if ( mLocalProject.isValid() && mMerginApi ) + { + mMerginApi->isProjectSyncNeeded( mLocalProject.fullName(), true ); + } } bool foundErrorsInLoadedProject = validateProject(); @@ -668,3 +676,11 @@ bool ActiveProject::photoSketchingEnabled() const return mQgsProject->readBoolEntry( QStringLiteral( "Mergin" ), QStringLiteral( "PhotoSketching/Enabled" ), false ); } + +void ActiveProject::checkForProjectUpdate() +{ + if ( isProjectLoaded() && mMerginApi ) + { + mMerginApi->isProjectSyncNeeded( projectFullName(), true ); + } +} diff --git a/app/activeproject.h b/app/activeproject.h index 92fee83b8..07aa9cb38 100644 --- a/app/activeproject.h +++ b/app/activeproject.h @@ -25,6 +25,8 @@ #include "merginprojectmetadata.h" #include "synchronizationoptions.h" +class MerginApi; + /** * \brief The ActiveProject class can load a QGIS project and holds its data. */ @@ -47,6 +49,7 @@ class ActiveProject: public QObject AppSettings &appSettings , ActiveLayer &activeLayer , LocalProjectsManager &localProjectsManager + , MerginApi *merginApi , QObject *parent = nullptr ); virtual ~ActiveProject(); @@ -192,6 +195,9 @@ class ActiveProject: public QObject void requestSync( SyncOptions::RequestOrigin requestOrigin = SyncOptions::RequestOrigin::ManualRequest ); + //! Checks whether the currently loaded project has a newer version available on the server + Q_INVOKABLE void checkForProjectUpdate(); + private: /** @@ -220,6 +226,7 @@ class ActiveProject: public QObject LocalProject mLocalProject; AppSettings &mAppSettings; + MerginApi *mMerginApi = nullptr; ActiveLayer &mActiveLayer; QgsAuthManager *mAuthManager = nullptr; LocalProjectsManager &mLocalProjectsManager; diff --git a/app/main.cpp b/app/main.cpp index e91cb18ec..53c51c795 100644 --- a/app/main.cpp +++ b/app/main.cpp @@ -532,7 +532,7 @@ int main( int argc, char *argv[] ) NotificationModel notificationModel; ActiveLayer al; - ActiveProject activeProject( *as, al, localProjectsManager ); + ActiveProject activeProject( *as, al, localProjectsManager, ma.get() ); std::unique_ptr vm( new VariablesManager( ma.get() ) ); vm->registerInputExpressionFunctions(); diff --git a/app/notificationmodel.cpp b/app/notificationmodel.cpp index 247ab6f57..7209124e3 100644 --- a/app/notificationmodel.cpp +++ b/app/notificationmodel.cpp @@ -40,7 +40,8 @@ QHash NotificationModel::roleNames() const { IdRole, "id" }, { MessageRole, "message" }, { TypeRole, "type" }, - { IconRole, "icon" } + { IconRole, "icon" }, + { ActionRole, "action" } }; } @@ -60,6 +61,7 @@ QVariant NotificationModel::data( const QModelIndex &index, int role ) const if ( role == MessageRole ) return notification.message(); if ( role == TypeRole ) return notification.type(); if ( role == IconRole ) return notification.icon(); + if ( role == ActionRole ) return notification.action(); return {}; } @@ -156,7 +158,7 @@ void NotificationModel::onNotificationClicked( uint id ) emit showSyncFailedDialogClicked(); break; } - case NotificationType::ActionType::ShowProjectNewVersionAction: + case NotificationType::ActionType::SyncProjectAction: { remove( id ); emit showProjectNewVersionClicked(); diff --git a/app/notificationmodel.h b/app/notificationmodel.h index 76420f323..a8cb3ec2e 100644 --- a/app/notificationmodel.h +++ b/app/notificationmodel.h @@ -44,7 +44,7 @@ class NotificationType ShowProjectIssuesAction, ShowSwitchWorkspaceAction, ShowSyncFailedDialog, - ShowProjectNewVersionAction + SyncProjectAction }; Q_ENUM( ActionType ) @@ -90,7 +90,7 @@ class NotificationModel : public QAbstractListModel public: enum NotificationModelRoles { - IdRole = Qt::UserRole + 1, MessageRole, TypeRole, IconRole + IdRole = Qt::UserRole + 1, MessageRole, TypeRole, IconRole, ActionRole }; Q_ENUM( NotificationModelRoles ) diff --git a/app/qml/components/MMNotification.qml b/app/qml/components/MMNotification.qml index 0e7677a32..64076ce27 100644 --- a/app/qml/components/MMNotification.qml +++ b/app/qml/components/MMNotification.qml @@ -109,12 +109,18 @@ Rectangle { verticalCenter: parent.verticalCenter rightMargin: 20 * __dp } - iconSource: __style.closeIcon + iconSource: model.action === MM.NotificationType.SyncProjectAction ? __style.syncIcon : __style.closeIcon iconColor: text.color bgndColor: __style.transparentColor bgndHoverColor: __style.transparentColor - onClicked: __notificationModel.remove(model.id) + onClicked: { + if ( model.action === MM.NotificationType.SyncProjectAction ) { + __notificationModel.onNotificationClicked( model.id ) + } else { + __notificationModel.remove( model.id ) + } + } } Behavior on scale { NumberAnimation { easing.type: Easing.OutCubic; from: 0; to: 1.0; duration: 200 } } diff --git a/app/qml/main.qml b/app/qml/main.qml index 7b518cb77..e876a7397 100644 --- a/app/qml/main.qml +++ b/app/qml/main.qml @@ -85,9 +85,7 @@ ApplicationWindow { // Stop/Start sync animation when user goes to map syncButton.iconRotateAnimationRunning = ( __syncManager.hasPendingSync( __activeProject.projectFullName() ) ) - if ( __activeProject.projectFullName() !== "" ) { - __merginApi.isProjectSyncNeeded( __activeProject.projectFullName(), true ) - } + __activeProject.checkForProjectUpdate() } else if ( stateManager.state === "projects" ) { projectController.openPanel() @@ -1100,8 +1098,8 @@ ApplicationWindow { if ( __activeProject.projectFullName() === projectFullName ) { __notificationModel.addInfo( - __inputUtils.htmlLink( qsTr( "There is a new version of the project available" ), __style.forestColor ), - MM.NotificationType.ShowProjectNewVersionAction + qsTr( "There is a new version of the project available" ), + MM.NotificationType.SyncProjectAction ) } } @@ -1177,9 +1175,6 @@ ApplicationWindow { AppSettings.defaultProject = __activeProject.localProject.qgisProjectFilePath ?? "" AppSettings.activeProject = __activeProject.localProject.qgisProjectFilePath ?? "" - if ( __activeProject.projectFullName() !== "" ) { - __merginApi.isProjectSyncNeeded( __activeProject.projectFullName(), true ) - } } function onProjectWillBeReloaded() { diff --git a/app/test/testactiveproject.cpp b/app/test/testactiveproject.cpp index a93ca1614..4c910c7e9 100644 --- a/app/test/testactiveproject.cpp +++ b/app/test/testactiveproject.cpp @@ -38,7 +38,7 @@ void TestActiveProject::testProjectValidations() AppSettings as; ActiveLayer activeLayer; - ActiveProject activeProject( as, activeLayer, mApi->localProjectsManager() ); + ActiveProject activeProject( as, activeLayer, mApi->localProjectsManager(), mApi ); QSignalSpy spyReportIssues( &activeProject, &ActiveProject::reportIssue ); QSignalSpy spyErrorsFound( &activeProject, &ActiveProject::loadingErrorFound ); @@ -63,7 +63,7 @@ void TestActiveProject::testProjectLoadFailure() AppSettings as; ActiveLayer activeLayer; - ActiveProject activeProject( as, activeLayer, mApi->localProjectsManager() ); + ActiveProject activeProject( as, activeLayer, mApi->localProjectsManager(), mApi ); mApi->localProjectsManager().addLocalProject( projectdir, projectname ); @@ -83,7 +83,7 @@ void TestActiveProject::testPositionTrackingFlag() AppSettings as; ActiveLayer activeLayer; - ActiveProject activeProject( as, activeLayer, mApi->localProjectsManager() ); + ActiveProject activeProject( as, activeLayer, mApi->localProjectsManager(), mApi ); // project "planes" - tracking not enabled QString projectDir = TestUtils::testDataDir() + "/planes/"; @@ -123,7 +123,7 @@ void TestActiveProject::testRecordingAllowed() AppSettings as; ActiveLayer activeLayer; - ActiveProject activeProject( as, activeLayer, mApi->localProjectsManager() ); + ActiveProject activeProject( as, activeLayer, mApi->localProjectsManager(), mApi ); mApi->localProjectsManager().addLocalProject( projectDir, projectFilename ); QVERIFY( activeProject.load( projectDir + "/" + projectFilename ) ); @@ -171,7 +171,7 @@ void TestActiveProject::testLoadingFlagFileExpiration() { AppSettings as; ActiveLayer activeLayer; - ActiveProject activeProject( as, activeLayer, mApi->localProjectsManager() ); + ActiveProject activeProject( as, activeLayer, mApi->localProjectsManager(), mApi ); // project "planes" - tracking not enabled QString projectDir = TestUtils::testDataDir() + "/planes/"; @@ -197,7 +197,7 @@ void TestActiveProject::testLoadingAuthFileFromConfiguration() { AppSettings appSettings; ActiveLayer activeLayer; - ActiveProject activeProject( appSettings, activeLayer, mApi->localProjectsManager() ); + ActiveProject activeProject( appSettings, activeLayer, mApi->localProjectsManager(), mApi ); QString projectDir = TestUtils::testDataDir() + QStringLiteral( "/project_auth_file/" ); QString projectName = QStringLiteral( "auth-test.qgz" ); QString authFile = QDir( projectDir ).filePath( CoreUtils::AUTH_CONFIG_FILENAME ); diff --git a/app/test/testmerginapi.cpp b/app/test/testmerginapi.cpp index 2b5e0c91d..b920d8d50 100644 --- a/app/test/testmerginapi.cpp +++ b/app/test/testmerginapi.cpp @@ -2377,7 +2377,7 @@ void TestMerginApi::testAutosync() MapThemesModel mtm; AppSettings as; ActiveLayer al; - ActiveProject activeProject( as, al, mApi->localProjectsManager() ); + ActiveProject activeProject( as, al, mApi->localProjectsManager(), mApi ); mApi->localProjectsManager().addLocalProject( projectDir, projectName ); diff --git a/core/merginapi.cpp b/core/merginapi.cpp index dceec9b0a..5549be1e7 100644 --- a/core/merginapi.cpp +++ b/core/merginapi.cpp @@ -4603,18 +4603,17 @@ void MerginApi::isProjectSyncNeededFinished() QNetworkReply *r = qobject_cast( sender() ); Q_ASSERT( r ); - QString projectFullName = r->request().attribute( static_cast( AttrProjectFullName ) ).toString(); - mPendingSyncChecks.remove( projectFullName ); + const QString projectFullName = r->request().attribute( static_cast( AttrProjectFullName ) ).toString(); if ( r->error() == QNetworkReply::NoError ) { - QByteArray data = r->readAll(); - MerginProjectMetadata serverProject = MerginProjectMetadata::fromJson( data ); + const QByteArray data = r->readAll(); + const MerginProjectMetadata serverProject = MerginProjectMetadata::fromJson( data ); // skip if a sync is already in progress for this project if ( !mTransactionalStatus.contains( projectFullName ) ) { - LocalProject projectInfo = mLocalProjects.projectFromMerginName( projectFullName ); + const LocalProject projectInfo = mLocalProjects.projectFromMerginName( projectFullName ); if ( projectInfo.isValid() && projectInfo.localVersion != -1 && projectInfo.localVersion < serverProject.version ) { emit projectSyncRequired( projectFullName ); @@ -4626,13 +4625,9 @@ void MerginApi::isProjectSyncNeededFinished() void MerginApi::isProjectSyncNeeded( const QString &projectFullName, bool withAuth ) { - if ( mPendingSyncChecks.contains( projectFullName ) ) - return; - - QNetworkReply *reply = getProjectInfo( projectFullName, withAuth ); + const QNetworkReply *reply = getProjectInfo( projectFullName, withAuth ); if ( !reply ) return; - mPendingSyncChecks.insert( projectFullName ); connect( reply, &QNetworkReply::finished, this, &MerginApi::isProjectSyncNeededFinished ); } diff --git a/core/merginapi.h b/core/merginapi.h index 8486a204e..2fd95e58e 100644 --- a/core/merginapi.h +++ b/core/merginapi.h @@ -984,7 +984,6 @@ class MerginApi: public QObject MerginServerType::ServerType mServerType = MerginServerType::ServerType::OLD; QString mServerDiagnosticLogsUrl = MerginApi::sDefaultReportLogUrl; - QSet mPendingSyncChecks; // not yet updated projects with isProjectSyncNeeded request QOAuth2AuthorizationCodeFlow mOauth2Flow; #ifdef MOBILE_OS From 51d1f82dd8c0c251e23d06347b20260b4ebdb025 Mon Sep 17 00:00:00 2001 From: Gabriel Bolbotina Date: Tue, 31 Mar 2026 10:38:03 +0300 Subject: [PATCH 4/4] Removed mergin api passing in active project Implemented code findings --- app/activeproject.cpp | 11 ++++------- app/activeproject.h | 6 ++---- app/main.cpp | 4 +++- app/test/testactiveproject.cpp | 12 ++++++------ app/test/testmerginapi.cpp | 3 ++- core/merginapi.h | 1 - 6 files changed, 17 insertions(+), 20 deletions(-) diff --git a/app/activeproject.cpp b/app/activeproject.cpp index c5f9af835..792957e4d 100644 --- a/app/activeproject.cpp +++ b/app/activeproject.cpp @@ -21,7 +21,6 @@ #include "activeproject.h" #include "coreutils.h" -#include "merginapi.h" #ifdef ANDROID #include "position/tracking/androidtrackingbroadcast.h" @@ -33,7 +32,6 @@ const int ActiveProject::LOADING_FLAG_FILE_EXPIRATION_MS = 5000; ActiveProject::ActiveProject( AppSettings &appSettings , ActiveLayer &activeLayer , LocalProjectsManager &localProjectsManager - , MerginApi *merginApi , QObject *parent ) : QObject( parent ) @@ -41,7 +39,6 @@ ActiveProject::ActiveProject( AppSettings &appSettings , mActiveLayer( activeLayer ) , mAuthManager( QgsApplication::authManager() ) , mLocalProjectsManager( localProjectsManager ) - , mMerginApi( merginApi ) , mProjectLoadingLog( "" ) { // we used to have our own QgsProject instance, but unfortunately few pieces of qgis_core @@ -215,9 +212,9 @@ bool ActiveProject::forceLoad( const QString &filePath, bool force ) emit positionTrackingSupportedChanged(); emit mapSketchesEnabledChanged(); - if ( mLocalProject.isValid() && mMerginApi ) + if ( mLocalProject.isValid() ) { - mMerginApi->isProjectSyncNeeded( mLocalProject.fullName(), true ); + emit projectSyncCheckRequested( mLocalProject.fullName(), true ); } } @@ -679,8 +676,8 @@ bool ActiveProject::photoSketchingEnabled() const void ActiveProject::checkForProjectUpdate() { - if ( isProjectLoaded() && mMerginApi ) + if ( isProjectLoaded() ) { - mMerginApi->isProjectSyncNeeded( projectFullName(), true ); + emit projectSyncCheckRequested( projectFullName(), true ); } } diff --git a/app/activeproject.h b/app/activeproject.h index 07aa9cb38..bc885ad53 100644 --- a/app/activeproject.h +++ b/app/activeproject.h @@ -25,8 +25,6 @@ #include "merginprojectmetadata.h" #include "synchronizationoptions.h" -class MerginApi; - /** * \brief The ActiveProject class can load a QGIS project and holds its data. */ @@ -49,7 +47,6 @@ class ActiveProject: public QObject AppSettings &appSettings , ActiveLayer &activeLayer , LocalProjectsManager &localProjectsManager - , MerginApi *merginApi , QObject *parent = nullptr ); virtual ~ActiveProject(); @@ -172,6 +169,8 @@ class ActiveProject: public QObject void syncActiveProject( const LocalProject &project, SyncOptions::RequestOrigin requestOrigin ); + void projectSyncCheckRequested( const QString &projectFullName, bool withAuth ); + void mapThemeChanged( const QString &mapTheme ); void positionTrackingSupportedChanged(); @@ -226,7 +225,6 @@ class ActiveProject: public QObject LocalProject mLocalProject; AppSettings &mAppSettings; - MerginApi *mMerginApi = nullptr; ActiveLayer &mActiveLayer; QgsAuthManager *mAuthManager = nullptr; LocalProjectsManager &mLocalProjectsManager; diff --git a/app/main.cpp b/app/main.cpp index 53c51c795..03c2082c0 100644 --- a/app/main.cpp +++ b/app/main.cpp @@ -532,7 +532,7 @@ int main( int argc, char *argv[] ) NotificationModel notificationModel; ActiveLayer al; - ActiveProject activeProject( *as, al, localProjectsManager, ma.get() ); + ActiveProject activeProject( *as, al, localProjectsManager ); std::unique_ptr vm( new VariablesManager( ma.get() ) ); vm->registerInputExpressionFunctions(); @@ -646,6 +646,8 @@ int main( int argc, char *argv[] ) merginApi->reloadProjectRole( activeProject.projectFullName() ); } ); + QObject::connect( &activeProject, &ActiveProject::projectSyncCheckRequested, ma.get(), &MerginApi::isProjectSyncNeeded ); + QObject::connect( ma.get(), &MerginApi::authChanged, &lambdaContext, [merginApi = ma.get(), &activeProject]() { if ( activeProject.isProjectLoaded() ) diff --git a/app/test/testactiveproject.cpp b/app/test/testactiveproject.cpp index 4c910c7e9..a93ca1614 100644 --- a/app/test/testactiveproject.cpp +++ b/app/test/testactiveproject.cpp @@ -38,7 +38,7 @@ void TestActiveProject::testProjectValidations() AppSettings as; ActiveLayer activeLayer; - ActiveProject activeProject( as, activeLayer, mApi->localProjectsManager(), mApi ); + ActiveProject activeProject( as, activeLayer, mApi->localProjectsManager() ); QSignalSpy spyReportIssues( &activeProject, &ActiveProject::reportIssue ); QSignalSpy spyErrorsFound( &activeProject, &ActiveProject::loadingErrorFound ); @@ -63,7 +63,7 @@ void TestActiveProject::testProjectLoadFailure() AppSettings as; ActiveLayer activeLayer; - ActiveProject activeProject( as, activeLayer, mApi->localProjectsManager(), mApi ); + ActiveProject activeProject( as, activeLayer, mApi->localProjectsManager() ); mApi->localProjectsManager().addLocalProject( projectdir, projectname ); @@ -83,7 +83,7 @@ void TestActiveProject::testPositionTrackingFlag() AppSettings as; ActiveLayer activeLayer; - ActiveProject activeProject( as, activeLayer, mApi->localProjectsManager(), mApi ); + ActiveProject activeProject( as, activeLayer, mApi->localProjectsManager() ); // project "planes" - tracking not enabled QString projectDir = TestUtils::testDataDir() + "/planes/"; @@ -123,7 +123,7 @@ void TestActiveProject::testRecordingAllowed() AppSettings as; ActiveLayer activeLayer; - ActiveProject activeProject( as, activeLayer, mApi->localProjectsManager(), mApi ); + ActiveProject activeProject( as, activeLayer, mApi->localProjectsManager() ); mApi->localProjectsManager().addLocalProject( projectDir, projectFilename ); QVERIFY( activeProject.load( projectDir + "/" + projectFilename ) ); @@ -171,7 +171,7 @@ void TestActiveProject::testLoadingFlagFileExpiration() { AppSettings as; ActiveLayer activeLayer; - ActiveProject activeProject( as, activeLayer, mApi->localProjectsManager(), mApi ); + ActiveProject activeProject( as, activeLayer, mApi->localProjectsManager() ); // project "planes" - tracking not enabled QString projectDir = TestUtils::testDataDir() + "/planes/"; @@ -197,7 +197,7 @@ void TestActiveProject::testLoadingAuthFileFromConfiguration() { AppSettings appSettings; ActiveLayer activeLayer; - ActiveProject activeProject( appSettings, activeLayer, mApi->localProjectsManager(), mApi ); + ActiveProject activeProject( appSettings, activeLayer, mApi->localProjectsManager() ); QString projectDir = TestUtils::testDataDir() + QStringLiteral( "/project_auth_file/" ); QString projectName = QStringLiteral( "auth-test.qgz" ); QString authFile = QDir( projectDir ).filePath( CoreUtils::AUTH_CONFIG_FILENAME ); diff --git a/app/test/testmerginapi.cpp b/app/test/testmerginapi.cpp index b920d8d50..34b29f2f6 100644 --- a/app/test/testmerginapi.cpp +++ b/app/test/testmerginapi.cpp @@ -2377,7 +2377,8 @@ void TestMerginApi::testAutosync() MapThemesModel mtm; AppSettings as; ActiveLayer al; - ActiveProject activeProject( as, al, mApi->localProjectsManager(), mApi ); + ActiveProject activeProject( as, al, mApi->localProjectsManager() ); + QObject::connect( &activeProject, &ActiveProject::projectSyncCheckRequested, mApi, &MerginApi::isProjectSyncNeeded ); mApi->localProjectsManager().addLocalProject( projectDir, projectName ); diff --git a/core/merginapi.h b/core/merginapi.h index 2fd95e58e..1ce95e407 100644 --- a/core/merginapi.h +++ b/core/merginapi.h @@ -984,7 +984,6 @@ class MerginApi: public QObject MerginServerType::ServerType mServerType = MerginServerType::ServerType::OLD; QString mServerDiagnosticLogsUrl = MerginApi::sDefaultReportLogUrl; - QOAuth2AuthorizationCodeFlow mOauth2Flow; #ifdef MOBILE_OS QOAuthUriSchemeReplyHandler *mOauth2ReplyHandler = nullptr; // parented by mOauth2Flow