diff --git a/app/images/ReachedMonthlyContributorLimit.svg b/app/images/ReachedMonthlyContributorLimit.svg new file mode 100644 index 000000000..c6f1c4a51 --- /dev/null +++ b/app/images/ReachedMonthlyContributorLimit.svg @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/images/images.qrc b/app/images/images.qrc index b0b772a30..ef3cf2f4f 100644 --- a/app/images/images.qrc +++ b/app/images/images.qrc @@ -35,5 +35,6 @@ SignIn.svg NoWorkspace.svg BlueInfo.svg + ReachedMonthlyContributorLimit.svg diff --git a/app/mmstyle.h b/app/mmstyle.h index 16587bb81..b51d4f8ea 100644 --- a/app/mmstyle.h +++ b/app/mmstyle.h @@ -198,6 +198,7 @@ class MMStyle: public QObject Q_PROPERTY( QUrl acceptInvitationImage READ acceptInvitationImage CONSTANT ) Q_PROPERTY( QUrl acceptInvitationLogoImage READ acceptInvitationLogoImage CONSTANT ) Q_PROPERTY( QUrl reachedDataLimitImage READ reachedDataLimitImage CONSTANT ) + Q_PROPERTY( QUrl reachedMonthlyContributorLimitImage READ reachedMonthlyContributorLimitImage CONSTANT ) Q_PROPERTY( QUrl uploadImage READ uploadImage CONSTANT ) Q_PROPERTY( QUrl noMapThemesImage READ noMapThemesImage CONSTANT ) Q_PROPERTY( QUrl syncFailedImage READ syncFailedImage CONSTANT ) @@ -496,6 +497,7 @@ class MMStyle: public QObject QUrl noPermissionsImage() {return QUrl( "qrc:/images/NoPermissions.svg" );} QUrl signInImage() {return QUrl( "qrc:/images/SignIn.svg" );} QUrl reachedDataLimitImage() {return QUrl( "qrc:/images/ReachedDataLimit.svg" );} + QUrl reachedMonthlyContributorLimitImage() {return QUrl( "qrc:/images/ReachedMonthlyContributorLimit.svg" );} QUrl warnLogoImage() {return QUrl( "qrc:/images/WarnLogoImage.svg" );} QUrl mapPinImage() {return QUrl( "qrc:/images/MapPin.svg" );} QUrl positionTrackingRunningImage() {return QUrl( "qrc:/images/PositionTrackingRunning.svg" );} diff --git a/app/qml/CMakeLists.txt b/app/qml/CMakeLists.txt index ccf99a8d5..9caf23291 100644 --- a/app/qml/CMakeLists.txt +++ b/app/qml/CMakeLists.txt @@ -59,6 +59,7 @@ set(MM_QML dialogs/MMDownloadProjectDialog.qml dialogs/MMMigrateToMerginDialog.qml dialogs/MMMissingAuthDialog.qml + dialogs/MMMonthlyContributorsLimitDialog.qml dialogs/MMNoPermissionsDialog.qml dialogs/MMPositionTrackingDialog.qml dialogs/MMProjectLimitDialog.qml diff --git a/app/qml/dialogs/MMMonthlyContributorsLimitDialog.qml b/app/qml/dialogs/MMMonthlyContributorsLimitDialog.qml new file mode 100644 index 000000000..1c3f923f0 --- /dev/null +++ b/app/qml/dialogs/MMMonthlyContributorsLimitDialog.qml @@ -0,0 +1,38 @@ +/*************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +import QtQuick + +import "../components" as MMComponents + + +MMComponents.MMDrawerDialog { + id: root + + property int contributorsQuota + + signal manageAccountClicked() + + title: qsTr( "You've reached the maximum number of active monthly contributors (%1) for your current subscription." ).arg( contributorsQuota ) + imageSource: __style.reachedMonthlyContributorLimitImage + + description: qsTr( "Upgrade your subscription or wait until next month for the limit to reset." ) + + primaryButton.text: qsTr( "Upgrade" ) + secondaryButton.text: qsTr( "Cancel" ) + + onPrimaryButtonClicked: { + root.manageAccountClicked() + close() + } + + onSecondaryButtonClicked: { + close() + } +} diff --git a/app/qml/main.qml b/app/qml/main.qml index d6b7ea116..4769ffa73 100644 --- a/app/qml/main.qml +++ b/app/qml/main.qml @@ -715,6 +715,12 @@ ApplicationWindow { onManageAccountClicked: Qt.openUrlExternally(__inputHelp.merginSubscriptionLink) } + MMMonthlyContributorsLimitDialog { + id: monthlyContributorsLimitDialog + + onManageAccountClicked: Qt.openUrlExternally(__inputHelp.merginSubscriptionLink) + } + MMProjectLimitDialog { id: projectLimitDialog @@ -895,6 +901,11 @@ ApplicationWindow { storageLimitDialog.open() } + function onMonthlyContributorLimitReached( quota, serverMsg ) { + monthlyContributorsLimitDialog.contributorsQuota = quota + monthlyContributorsLimitDialog.open() + } + function onProjectLimitReached( maxProjects, errorMsg ) { __merginApi.getUserInfo() if (__merginApi.apiSupportsSubscriptions) { @@ -914,7 +925,7 @@ ApplicationWindow { } function onMigrationRequested( version ) { - if( __appSettings.ignoreMigrateVersion !== version ) { + if ( __appSettings.ignoreMigrateVersion !== version ) { migrationDialog.version = version migrationDialog.open() } diff --git a/core/merginapi.cpp b/core/merginapi.cpp index ab5e4a618..b385c6e9f 100644 --- a/core/merginapi.cpp +++ b/core/merginapi.cpp @@ -2117,14 +2117,13 @@ void MerginApi::pushStartReplyFinished() serverMsg = sSyncCanceledMessage; QString code = extractServerErrorCode( data ); - bool showLimitReachedDialog = EnumHelper::isEqual( code, ErrorCode::StorageLimitHit ); CoreUtils::log( "push " + projectFullName, QStringLiteral( "FAILED - %1. %2" ).arg( r->errorString(), serverMsg ) ); transaction.replyPushStart->deleteLater(); transaction.replyPushStart = nullptr; - if ( showLimitReachedDialog ) + if ( EnumHelper::isEqual( code, ErrorCode::StorageLimitHit ) ) { const QList files = transaction.pushQueue; qreal uploadSize = 0; @@ -2144,6 +2143,14 @@ void MerginApi::pushStartReplyFinished() deleteProject( projectNamespace, projectName, false ); } } + else if ( EnumHelper::isEqual( code, ErrorCode::MonthlyContributorsLimitHit ) ) + { + int quota = 0; + QVariant maximunMonthlyContributor = extractServerErrorValue( data, "projects_quota" ); + if ( maximunMonthlyContributor.isValid() ) + quota = maximunMonthlyContributor.toInt(); + emit monthlyContributorLimitReached( quota, serverMsg ); + } else { int httpCode = r->attribute( QNetworkRequest::HttpStatusCodeAttribute ).toInt(); diff --git a/core/merginapi.h b/core/merginapi.h index 0e5380bb2..8e7ef31d7 100644 --- a/core/merginapi.h +++ b/core/merginapi.h @@ -195,7 +195,8 @@ class ErrorCode { Unknown = 0, ProjectsLimitHit, - StorageLimitHit + StorageLimitHit, + MonthlyContributorsLimitHit, }; Q_ENUM( Value ); }; @@ -597,6 +598,7 @@ class MerginApi: public QObject ); void storageLimitReached( qreal uploadSize ); + void monthlyContributorLimitReached( int contributorsQuota, const QString &message ); void projectLimitReached( int maxProjects, const QString &message ); void migrationRequested( const QString &version ); void notifySuccess( const QString &message ); diff --git a/gallery/qml.qrc b/gallery/qml.qrc index b54c2ff92..d19fa58e4 100644 --- a/gallery/qml.qrc +++ b/gallery/qml.qrc @@ -30,6 +30,7 @@ ../app/qml/dialogs/MMStreamingModeDialog.qml ../app/qml/dialogs/MMPositionTrackingDialog.qml ../app/qml/dialogs/MMStorageLimitDialog.qml + ../app/qml/dialogs/MMMonthlyContributorsLimitDialog.qml ../app/qml/dialogs/MMCloseAccountDialog.qml ../app/qml/dialogs/MMRemoveProjectDialog.qml ../app/qml/dialogs/MMDownloadProjectDialog.qml diff --git a/gallery/qml/pages/DrawerPage.qml b/gallery/qml/pages/DrawerPage.qml index e3400a423..8304e7ecc 100644 --- a/gallery/qml/pages/DrawerPage.qml +++ b/gallery/qml/pages/DrawerPage.qml @@ -38,6 +38,11 @@ Page { onClicked: storageLimitDialog.open() } + Button { + text: "MMMonthlyContributorsLimitDialog" + onClicked: monthlyContributorsLimitDialog.open() + } + Button { text: "MMCloseAccountDialog" onClicked: closeAccountDialog.open() @@ -289,6 +294,16 @@ Page { } } + MMMonthlyContributorsLimitDialog { + id: monthlyContributorsLimitDialog + + contributorsQuota: 15 + + onPrimaryButtonClicked: { + console.log("Manage workspace clicked") + } + } + MMSyncFailedDialog { id: syncFailedDialog } diff --git a/gallery/qml/pages/ImagesPage.qml b/gallery/qml/pages/ImagesPage.qml index ed931d11b..bc4532417 100644 --- a/gallery/qml/pages/ImagesPage.qml +++ b/gallery/qml/pages/ImagesPage.qml @@ -41,6 +41,7 @@ ScrollView { Column { Image { source: __style.externalGpsGreenImage } Text { text: "externalGpsGreenImage" } } Column { Image { source: __style.externalGpsRedImage } Text { text: "externalGpsRedImage" } } Column { Image { source: __style.reachedDataLimitImage } Text { text: "reachedDataLimitImage" } } + Column { Image { source: __style.reachedMonthlyContributorLimitImage } Text { text: "reachedMonthlyContributorLimitImage" } } Column { Image { source: __style.positiveMMSymbolImage } Text { text: "positiveMMSymbolImage" } } Column { Image { source: __style.negativeMMSymbolImage } Text { text: "negativeMMSymbolImage" } } Column { Image { source: __style.closeAccountImage } Text { text: "closeAccountImage" } }