From c83546925307c635344c86ef0a3ab4f3f98ff9ca Mon Sep 17 00:00:00 2001 From: Tomas Mizera Date: Thu, 5 Oct 2023 18:51:46 +0200 Subject: [PATCH] Remove subscription pages for iOS and call-to-actions (#2835) * remove subscription pages for ios and call-to-actions * bring back button to account page to get to the dashboard * merge url params --- app/inputhelp.cpp | 32 ++++- app/purchasing.cpp | 13 -- app/purchasing.h | 1 - app/qml/CMakeLists.txt | 4 - app/qml/ProjectLimitDialog.qml | 2 +- app/qml/ProjectPanel.qml | 38 +----- app/qml/StorageLimitDialog.qml | 2 +- app/qml/SubscribePage.qml | 168 ------------------------- app/qml/SubscribePlanItem.qml | 105 ---------------- app/qml/WorkspaceAccountPage.qml | 32 ++++- app/qml/WorkspaceSubscribePage.qml | 155 ----------------------- app/qml/WorkspaceSubscribePlanItem.qml | 85 ------------- 12 files changed, 61 insertions(+), 576 deletions(-) delete mode 100644 app/qml/SubscribePage.qml delete mode 100644 app/qml/SubscribePlanItem.qml delete mode 100644 app/qml/WorkspaceSubscribePage.qml delete mode 100644 app/qml/WorkspaceSubscribePlanItem.qml diff --git a/app/inputhelp.cpp b/app/inputhelp.cpp index 2f065b065..dff880a2d 100644 --- a/app/inputhelp.cpp +++ b/app/inputhelp.cpp @@ -63,12 +63,40 @@ QString InputHelp::merginWebLink() const QString InputHelp::merginDashboardLink() const { + QString activeWorkspacePathPart; + + if ( mMerginApi && mMerginApi->apiSupportsWorkspaces() ) + { + int activeWS = mMerginApi->userInfo()->activeWorkspaceId(); + if ( activeWS >= 0 ) + { + activeWorkspacePathPart = QStringLiteral( "?workspace=%1" ).arg( activeWS ); + } + } + if ( mMerginApi && mMerginApi->apiRoot() != MerginApi::defaultApiRoot() ) { - return mMerginApi->apiRoot() + "dashboard"; // UTM tags are included only for production server + return mMerginApi->apiRoot() + "dashboard" + activeWorkspacePathPart; + } + + // Let's include UTM tags for production server + QString queryParams; + + if ( !activeWorkspacePathPart.isEmpty() ) + { + queryParams = activeWorkspacePathPart; + + // URL can not have two question marks, merge the tags with & + QString utms( utmTagAttention ); + utms.replace( "?", "&" ); + queryParams += utms; + } + else + { + queryParams = utmTagAttention; } - return MerginApi::defaultApiRoot() + "dashboard" + utmTagAttention; + return MerginApi::defaultApiRoot() + "dashboard" + queryParams; } QString InputHelp::privacyPolicyLink() const diff --git a/app/purchasing.cpp b/app/purchasing.cpp index 2a12b3ba5..38b3c6c8f 100644 --- a/app/purchasing.cpp +++ b/app/purchasing.cpp @@ -267,19 +267,6 @@ void Purchasing::onHasInAppPurchasesChanged() setSubscriptionBillingUrl( subscriptionBillingUrl ); } -QString Purchasing::subscriptionUrlWithWorkspace() -{ - int ws = mMerginApi->userInfo()->activeWorkspaceId(); - if ( ws >= 0 ) - { - return mSubscriptionManageUrl + QStringLiteral( "?workspace=%1" ).arg( ws ); - } - else - { - return mSubscriptionManageUrl; - } -} - bool Purchasing::hasInAppPurchases() const { return mHasInAppPurchases; diff --git a/app/purchasing.h b/app/purchasing.h index 5182cead7..7ce0ae6dc 100644 --- a/app/purchasing.h +++ b/app/purchasing.h @@ -253,7 +253,6 @@ class Purchasing : public QObject Q_INVOKABLE void purchase( const QString &planId ); Q_INVOKABLE void restore(); - Q_INVOKABLE QString subscriptionUrlWithWorkspace(); bool hasManageSubscriptionCapability() const; bool transactionPending() const; diff --git a/app/qml/CMakeLists.txt b/app/qml/CMakeLists.txt index d432d20dd..ca0fff811 100644 --- a/app/qml/CMakeLists.txt +++ b/app/qml/CMakeLists.txt @@ -130,13 +130,9 @@ set(MM_QML SettingsPanel.qml StakeoutPanel.qml StorageLimitDialog.qml - SubscribePage.qml - SubscribePlanItem.qml SwitchWorkspacePage.qml WorkspaceAccountPage.qml WhatsNewDialog.qml - WorkspaceSubscribePage.qml - WorkspaceSubscribePlanItem.qml main.qml PARENT_SCOPE ) diff --git a/app/qml/ProjectLimitDialog.qml b/app/qml/ProjectLimitDialog.qml index c941c6b75..21bbc64c0 100644 --- a/app/qml/ProjectLimitDialog.qml +++ b/app/qml/ProjectLimitDialog.qml @@ -76,7 +76,7 @@ Dialog { font.pixelSize: InputStyle.fontPixelSizeNormal font.underline: true color: InputStyle.fontColor - text: qsTr("Manage subscriptions") + text: qsTr("Manage account") visible: __merginApi.apiSupportsSubscriptions MouseArea { diff --git a/app/qml/ProjectPanel.qml b/app/qml/ProjectPanel.qml index c55bff52a..0b4caa47e 100644 --- a/app/qml/ProjectPanel.qml +++ b/app/qml/ProjectPanel.qml @@ -54,17 +54,7 @@ Item { } function manageSubscriptionPlans() { - if (__purchasing.hasInAppPurchases && (__purchasing.hasManageSubscriptionCapability || !__merginApi.subscriptionInfo.ownsActiveSubscription )) { - if ( __merginApi.serverType === MerginServerType.OLD ) { - stackView.push( subscribePanelComp ) - } - else if ( __merginApi.serverType === MerginServerType.SAAS ) { - stackView.push( workspaceSubscribePageComp ) - } - } - else { - Qt.openUrlExternally(__purchasing.subscriptionUrlWithWorkspace()); - } + Qt.openUrlExternally(__inputHelp.merginDashboardLink); } function getServiceInfo() { @@ -962,32 +952,6 @@ Item { } } - Component { - id: subscribePanelComp - - SubscribePage { - id: subscribePanel - height: root.height - width: root.width - onBackClicked: { - stackView.popOnePageOrClose() - } - onSubscribeClicked: { - stackView.popOnePageOrClose() - } - } - } - - Component { - id: workspaceSubscribePageComp - - WorkspaceSubscribePage { - id: subscribePanel - - onBack: stackView.popOnePageOrClose() - } - } - Component { id: projectWizardComp diff --git a/app/qml/StorageLimitDialog.qml b/app/qml/StorageLimitDialog.qml index 7b0f6795e..709065c40 100644 --- a/app/qml/StorageLimitDialog.qml +++ b/app/qml/StorageLimitDialog.qml @@ -105,7 +105,7 @@ Dialog { font.pixelSize: InputStyle.fontPixelSizeNormal font.underline: true color: InputStyle.fontColor - text: qsTr("Manage subscriptions") + text: qsTr("Manage account") visible: __merginApi.apiSupportsSubscriptions MouseArea { diff --git a/app/qml/SubscribePage.qml b/app/qml/SubscribePage.qml deleted file mode 100644 index 0bfb28ef5..000000000 --- a/app/qml/SubscribePage.qml +++ /dev/null @@ -1,168 +0,0 @@ -/*************************************************************************** - * * - * 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 QtQuick.Controls -import Qt5Compat.GraphicalEffects -import "." // import InputStyle singleton -import "./components" - -Rectangle { - id: root - visible: true - - signal backClicked - signal subscribeClicked - - //! If true and component is visible, busy indicator suppose to be on. Currently used only while fetching a recommendedPlan - property bool isBusy: __purchasing.individualPlan.id === "" || __purchasing.professionalPlan.id === "" - - onVisibleChanged: { - subscribeBusyIndicator.running = root.visible && root.isBusy - } - - Connections { - target: __purchasing - function onIndividualPlanChanged() { - if (!root.isBusy && root.visible) { - subscribeBusyIndicator.running = false - } - } - function onProfessionalPlanChanged() { - if (!root.isBusy && root.visible) { - subscribeBusyIndicator.running = false - } - } - } - - BusyIndicator { - id: subscribeBusyIndicator - width: root.width/8 - height: width - running: false - visible: running - anchors.centerIn: root - z: root.z + 1 - } - - // header - PanelHeader { - id: header - height: InputStyle.rowHeightHeader - width: parent.width - color: InputStyle.clrPanelMain - rowHeight: InputStyle.rowHeightHeader - titleText: qsTr("Subscribe") - - onBack: backClicked() - withBackButton: true - } - - Image { - id: merginLogo - anchors.top: header.bottom - antialiasing: true - source: InputStyle.mmLogoHorizontal - height: InputStyle.rowHeightHeader * 0.8 - width: parent.width - sourceSize.width: width - sourceSize.height: height - fillMode: Image.PreserveAspectFit - verticalAlignment: Text.AlignVCenter - horizontalAlignment: Text.AlignHCenter - } - - Column { - anchors.top: merginLogo.bottom - anchors.topMargin: InputStyle.smallGap - width: parent.width - anchors.horizontalCenter: parent.horizontalCenter - TabBar { - id: bar - width: root.width - 2 * InputStyle.rowHeightHeader - anchors.horizontalCenter: parent.horizontalCenter - spacing: 5 - - TabButton { - id: individualTabButton - - contentItem: Text { - color: bar.currentIndex === 0 ? "white" : InputStyle.highlightColor - text: qsTr("Individual") - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - font.pixelSize: InputStyle.fontPixelSizeNormal - } - - background: Rectangle { - color: bar.currentIndex === 0 ? InputStyle.highlightColor: "white" - border.color: InputStyle.highlightColor - border.width: 1 - } - } - TabButton { - id: professionalTabButton - - contentItem: Text { - color: bar.currentIndex === 1 ? "white" : InputStyle.highlightColor - text: qsTr("Professional") - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - font.pixelSize: InputStyle.fontPixelSizeNormal - } - - background: Rectangle { - color: bar.currentIndex === 1 ? InputStyle.highlightColor: "white" - border.color: InputStyle.highlightColor - border.width: 1 - } - } - } - - SwipeView { - id: view - - currentIndex: bar.currentIndex - anchors.top: bar.bottom - width: parent.width - anchors.horizontalCenter: parent.horizontalCenter - - SubscribePlanItem { - id: individualTab - plan: __purchasing.individualPlan - name: qsTr("Individual") - onSubscribeClicked: { - __purchasing.purchase( __purchasing.individualPlan.id ) - root.subscribeClicked() - } - } - SubscribePlanItem { - id: professionalTab - plan: __purchasing.professionalPlan - name: qsTr("Professional") - onSubscribeClicked: { - __purchasing.purchase( __purchasing.professionalPlan.id ) - root.subscribeClicked() - } - } - - } - } - - TextHyperlink { - id: textNotice - width: parent.width - height: InputStyle.rowHeightHeader - anchors.bottom: parent.bottom - anchors.bottomMargin: InputStyle.rowHeightHeader/2 - text: qsTr("Your Mergin subscription plan will renew automatically. You can cancel or change it at any time. %1Learn More%2") - .arg("") - .arg("") - } -} diff --git a/app/qml/SubscribePlanItem.qml b/app/qml/SubscribePlanItem.qml deleted file mode 100644 index cdad3e194..000000000 --- a/app/qml/SubscribePlanItem.qml +++ /dev/null @@ -1,105 +0,0 @@ -/*************************************************************************** - * * - * 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 QtQuick.Controls -import Qt5Compat.GraphicalEffects -import "." // import InputStyle singleton -import "./components" - -Item { - id: root - visible: true - - signal subscribeClicked - - - property var plan - property string name - - property bool hasPlan: __merginApi.subscriptionInfo.ownsActiveSubscription || !root.plan - - Column { - width: parent.width - spacing: 5 - leftPadding: InputStyle.rowHeightHeader - rightPadding: InputStyle.rowHeightHeader - - TextWithIcon { - width: parent.width - height: InputStyle.rowHeight - source: InputStyle.infoIcon - text: "Mergin " + root.name + " " + qsTr("Plan") - } - - TextWithIcon { - width: parent.width - height: InputStyle.rowHeight - source: InputStyle.todayIcon - text: hasPlan ? "Custom billing period" : root.plan.period /* Do not translate, only used for test subscriptions */ - } - - TextWithIcon { - width: parent.width - height: InputStyle.rowHeight - source: InputStyle.databaseIcon - text: hasPlan ? "Custom storage" : root.plan.storage /* Do not translate, only used for test subscriptions */ - } - - TextWithIcon { - width: parent.width - height: InputStyle.rowHeight - source: InputStyle.accountMultiIcon - text: qsTr("Unlimited collaborators") - } - - TextWithIcon { - width: parent.width - height: InputStyle.rowHeight - source: InputStyle.projectIcon - text: qsTr("Unlimited projects") - } - - TextWithIcon { - width: parent.width - height: InputStyle.rowHeight - source: InputStyle.envelopeIcon - text: qsTr("Email support") - } - - Button { - id: subscribeButton - width: root.width - 2 * InputStyle.rowHeightHeader - anchors.horizontalCenter: parent.horizontalCenter - - height: InputStyle.rowHeightHeader - text: hasPlan ? "Manage" : root.plan.price /* Do not translate, only used for test subscriptions */ - enabled: text !== '' - font.pixelSize: InputStyle.fontPixelSizeBig - - background: Rectangle { - color: InputStyle.highlightColor - } - - onClicked: subscribeClicked() - - contentItem: Text { - text: subscribeButton.text - font: subscribeButton.font - opacity: enabled ? 1.0 : 0.3 - color: "white" - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - elide: Text.ElideRight - } - - } - } - -} diff --git a/app/qml/WorkspaceAccountPage.qml b/app/qml/WorkspaceAccountPage.qml index 8191b0ea1..999b9a010 100644 --- a/app/qml/WorkspaceAccountPage.qml +++ b/app/qml/WorkspaceAccountPage.qml @@ -206,16 +206,40 @@ Page { } MMComponents.DelegateButton { - Layout.fillWidth: true btnWidth: width + height: InputStyle.rowHeightMedium - visible: root.apiSupportsSubscriptions && root.canAccessSubscription + text: qsTr("Manage account") + onClicked: root.managePlansClicked() + } + + Text { + Layout.fillWidth: true + Layout.preferredHeight: InputStyle.rowHeightHeader - text: qsTr("Subscriptions") + leftPadding: InputStyle.formSpacing - onClicked: root.managePlansClicked() + color: InputStyle.fontColor + linkColor: InputStyle.highlightColor + + wrapMode: Text.WordWrap + textFormat: Text.StyledText + + font.bold: true + font.pixelSize: InputStyle.fontPixelSizeNormal + + verticalAlignment: Qt.AlignVCenter + horizontalAlignment: Qt.AlignLeft + + visible: __iosUtils.isIos && root.apiSupportsSubscriptions && root.canAccessSubscription + + text: qsTr("You can also %1restore%2 your purchase.") + .arg("") + .arg("") + + onLinkActivated: __purchasing.restore() } // user profile diff --git a/app/qml/WorkspaceSubscribePage.qml b/app/qml/WorkspaceSubscribePage.qml deleted file mode 100644 index c4091a61e..000000000 --- a/app/qml/WorkspaceSubscribePage.qml +++ /dev/null @@ -1,155 +0,0 @@ -/*************************************************************************** - * * - * 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 QtQuick.Layouts -import QtQuick.Controls - -import "." // import InputStyle singleton -import "./components" as MMComponents - -Page { - id: root - - signal back - - header: MMComponents.PanelHeaderV2 { - width: parent.width - headerTitle: qsTr("Subscribe") - onBackClicked: root.back() - } - - ScrollView { - - anchors { - fill: parent - } - - contentWidth: availableWidth // only scroll vertically - - ColumnLayout { - - anchors { - fill: parent - leftMargin: InputStyle.outerFieldMargin - rightMargin: InputStyle.outerFieldMargin - } - - spacing: InputStyle.formSpacing - - TabBar { - id: bar - - Layout.fillWidth: true - Layout.topMargin: InputStyle.smallGap - Layout.preferredHeight: InputStyle.rowHeightMedium - - spacing: InputStyle.panelSpacing - - TabButton { - contentItem: Text { - color: bar.currentIndex === 0 ? "white" : InputStyle.highlightColor - text: qsTr("Individual") - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - font.pixelSize: InputStyle.fontPixelSizeNormal - } - - background: Rectangle { - color: bar.currentIndex === 0 ? InputStyle.highlightColor: "white" - border.color: InputStyle.highlightColor - border.width: 1 - radius: InputStyle.cornerRadius - } - } - - TabButton { - contentItem: Text { - color: bar.currentIndex === 1 ? "white" : InputStyle.highlightColor - text: qsTr("Professional") - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - font.pixelSize: InputStyle.fontPixelSizeNormal - } - - background: Rectangle { - color: bar.currentIndex === 1 ? InputStyle.highlightColor: "white" - border.color: InputStyle.highlightColor - border.width: 1 - radius: InputStyle.cornerRadius - } - } - } - - SwipeView { - currentIndex: bar.currentIndex - - Layout.fillWidth: true - Layout.preferredHeight: plan.height - - interactive: false - spacing: InputStyle.formSpacing - - WorkspaceSubscribePlanItem { - id: plan - plan: __purchasing.individualPlan - - onSubscribeClicked: { - __purchasing.purchase( __purchasing.individualPlan.id ) - root.back() - } - } - - WorkspaceSubscribePlanItem { - plan: __purchasing.professionalPlan - - onSubscribeClicked: { - __purchasing.purchase( __purchasing.professionalPlan.id ) - root.back() - } - } - } - - Text { - Layout.fillWidth: true - Layout.preferredHeight: InputStyle.rowHeightHeader - - color: InputStyle.fontColor - linkColor: InputStyle.highlightColor - - wrapMode: Text.WordWrap - textFormat: Text.StyledText - - font.bold: true - font.pixelSize: InputStyle.fontPixelSizeNormal - - verticalAlignment: Qt.AlignVCenter - horizontalAlignment: Qt.AlignHCenter - - visible: !__purchasing.transactionPending - - text: qsTr("You can also %1restore%2 your purchases.") - .arg("") - .arg("") - - onLinkActivated: __purchasing.restore() - } - - MMComponents.TextHyperlink { - Layout.fillWidth: true - Layout.preferredHeight: InputStyle.rowHeightHeader - Layout.bottomMargin: InputStyle.smallGap - - text: qsTr("Your Mergin subscription plan will renew automatically. You can cancel or change it at any time. %1Learn More%2") - .arg("") - .arg("") - } - } - } -} diff --git a/app/qml/WorkspaceSubscribePlanItem.qml b/app/qml/WorkspaceSubscribePlanItem.qml deleted file mode 100644 index 7bdc17540..000000000 --- a/app/qml/WorkspaceSubscribePlanItem.qml +++ /dev/null @@ -1,85 +0,0 @@ -/*************************************************************************** - * * - * 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 QtQuick.Controls - -import "." // import InputStyle singleton -import "./components" as MMComponents - -Item { - id: root - - signal subscribeClicked - - property var plan - property bool hasPlan: __merginApi.subscriptionInfo.ownsActiveSubscription || !root.plan - - height: childrenRect.height - // set width from parent - - Column { - width: parent.width - spacing: InputStyle.panelSpacing - - MMComponents.TextWithIcon { - width: parent.width - height: InputStyle.rowHeight - source: InputStyle.infoIcon - text: qsTr("Commercial use") - } - - MMComponents.TextWithIcon { - width: parent.width - height: InputStyle.rowHeight - source: InputStyle.todayIcon - text: hasPlan ? "Custom billing period" : root.plan.period /* Do not translate, only used for test subscriptions */ - } - - MMComponents.TextWithIcon { - width: parent.width - height: InputStyle.rowHeight - source: InputStyle.databaseIcon - text: hasPlan ? "Custom storage" : root.plan.storage /* Do not translate, only used for test subscriptions */ - } - - MMComponents.TextWithIcon { - width: parent.width - height: InputStyle.rowHeight - source: InputStyle.accountMultiIcon - text: qsTr("Unlimited seats") - } - - MMComponents.TextWithIcon { - width: parent.width - height: InputStyle.rowHeight - source: InputStyle.projectIcon - text: qsTr("Unlimited projects") - } - - MMComponents.TextWithIcon { - width: parent.width - height: InputStyle.rowHeight - source: InputStyle.envelopeIcon - text: qsTr("Email support") - } - - MMComponents.DelegateButton { - - width: parent.width - btnWidth: width - height: InputStyle.rowHeightMedium - - text: root.hasPlan ? "Manage" : root.plan.price /* Do not translate, only used for test subscriptions */ - enabled: text !== '' - - onClicked: root.subscribeClicked() - } - } -}