From bf3d11e5c4975f08f21769da6a15689e7589d4b3 Mon Sep 17 00:00:00 2001 From: NickVs2015 Date: Wed, 25 Mar 2026 14:48:32 +0300 Subject: [PATCH] feat: renewal new status logic (#2409) * fix: renewal add status logic * fix: wakeup activity resumed android --- .../src/org/amnezia/vpn/AmneziaActivity.kt | 18 ++++++++++++++- client/core/controllers/coreController.cpp | 4 ++-- .../controllers/api/apiConfigsController.cpp | 6 +++++ .../ui/controllers/api/apiConfigsController.h | 1 + .../controllers/api/apiSettingsController.cpp | 9 +++++++- client/ui/models/api/apiAccountInfoModel.cpp | 12 +--------- client/ui/models/api/apiAccountInfoModel.h | 3 --- client/ui/models/servers_model.cpp | 17 ++++++++++++++ client/ui/models/servers_model.h | 3 +++ client/ui/qml/Components/ServersListView.qml | 22 +++---------------- .../Components/SubscriptionExpiredDrawer.qml | 2 -- .../PageSettingsApiAvailableCountries.qml | 20 +++-------------- 12 files changed, 61 insertions(+), 56 deletions(-) diff --git a/client/android/src/org/amnezia/vpn/AmneziaActivity.kt b/client/android/src/org/amnezia/vpn/AmneziaActivity.kt index ccdc22140..e0a576ad5 100644 --- a/client/android/src/org/amnezia/vpn/AmneziaActivity.kt +++ b/client/android/src/org/amnezia/vpn/AmneziaActivity.kt @@ -296,9 +296,25 @@ class AmneziaActivity : QtActivity() { hasWindowFocus = hasFocus Log.d(TAG, "Window focus changed: hasFocus=$hasFocus") - // Cancel pending operations if window loses focus if (!hasFocus) { + // Cancel pending operations if window loses focus resumeHandler.removeCallbacksAndMessages(null) + } else if (isActivityResumed && Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) { + window.decorView.apply { + invalidate() + resumeHandler.postDelayed({ + if (isActivityResumed && hasWindowFocus && !isFinishing && !isDestroyed) { + sendTouch(1f, 1f) + } + }, 50) + resumeHandler.postDelayed({ + if (isActivityResumed && hasWindowFocus && !isFinishing && !isDestroyed) { + sendTouch(2f, 2f) + requestLayout() + invalidate() + } + }, 150) + } } } diff --git a/client/core/controllers/coreController.cpp b/client/core/controllers/coreController.cpp index 390baf5a8..dde6ffb29 100644 --- a/client/core/controllers/coreController.cpp +++ b/client/core/controllers/coreController.cpp @@ -153,8 +153,8 @@ void CoreController::initControllers() m_apiConfigsController.reset(new ApiConfigsController(m_serversModel, m_apiServicesModel, m_settings)); m_engine->rootContext()->setContextProperty("ApiConfigsController", m_apiConfigsController.get()); - connect(m_apiConfigsController.get(), &ApiConfigsController::subscriptionExpiredOnServer, - m_apiAccountInfoModel.get(), &ApiAccountInfoModel::setSubscriptionExpiredByServer); + connect(m_apiConfigsController.get(), &ApiConfigsController::subscriptionRefreshNeeded, + this, [this]() { m_apiSettingsController->getAccountInfo(false); }); m_apiNewsController.reset(new ApiNewsController(m_newsModel, m_settings, m_serversModel, this)); m_engine->rootContext()->setContextProperty("ApiNewsController", m_apiNewsController.get()); diff --git a/client/ui/controllers/api/apiConfigsController.cpp b/client/ui/controllers/api/apiConfigsController.cpp index df0d16837..987d92408 100644 --- a/client/ui/controllers/api/apiConfigsController.cpp +++ b/client/ui/controllers/api/apiConfigsController.cpp @@ -723,6 +723,7 @@ bool ApiConfigsController::updateServiceFromGateway(const int serverIndex, const } bool isTestPurchase = apiConfig.value(apiDefs::key::isTestPurchase).toBool(false); + bool wasSubscriptionExpired = m_serversModel->data(serverIndex, ServersModel::IsSubscriptionExpiredRole).toBool(); QByteArray responseBody; ErrorCode errorCode = executeRequest(QString("%1v1/config"), apiPayload, responseBody, isTestPurchase); @@ -749,6 +750,11 @@ bool ApiConfigsController::updateServiceFromGateway(const int serverIndex, const newServerConfig.insert(config_key::nameOverriddenByUser, true); } m_serversModel->editServer(newServerConfig, serverIndex); + + if (wasSubscriptionExpired) { + emit subscriptionRefreshNeeded(); + } + if (reloadServiceConfig) { emit reloadServerFromApiFinished(tr("API config reloaded")); } else if (newCountryName.isEmpty()) { diff --git a/client/ui/controllers/api/apiConfigsController.h b/client/ui/controllers/api/apiConfigsController.h index 8ca775b86..ca5598e1e 100644 --- a/client/ui/controllers/api/apiConfigsController.h +++ b/client/ui/controllers/api/apiConfigsController.h @@ -44,6 +44,7 @@ public slots: signals: void errorOccurred(ErrorCode errorCode); void subscriptionExpiredOnServer(); + void subscriptionRefreshNeeded(); void installServerFromApiFinished(const QString &message); void changeApiCountryFinished(const QString &message); diff --git a/client/ui/controllers/api/apiSettingsController.cpp b/client/ui/controllers/api/apiSettingsController.cpp index 4e343a98b..78ac5c240 100644 --- a/client/ui/controllers/api/apiSettingsController.cpp +++ b/client/ui/controllers/api/apiSettingsController.cpp @@ -78,6 +78,13 @@ bool ApiSettingsController::getAccountInfo(bool reload) QJsonObject accountInfo = QJsonDocument::fromJson(responseBody).object(); m_apiAccountInfoModel->updateModel(accountInfo, serverConfig); + QString subscriptionEndDate = accountInfo.value(apiDefs::key::subscriptionEndDate).toString(); + if (!subscriptionEndDate.isEmpty()) { + apiConfig.insert(apiDefs::key::subscriptionEndDate, subscriptionEndDate); + serverConfig.insert(configKey::apiConfig, apiConfig); + m_serversModel->editServer(serverConfig, processedIndex); + } + if (reload) { updateApiCountryModel(); updateApiDevicesModel(); @@ -115,7 +122,7 @@ void ApiSettingsController::getRenewalLink() } QJsonObject responseJson = QJsonDocument::fromJson(responseBody).object(); - QString url = responseJson.value("url").toString(); + QString url = responseJson.value("renewal_url").toString(); if (!url.isEmpty()) { emit renewalLinkReceived(url); } diff --git a/client/ui/models/api/apiAccountInfoModel.cpp b/client/ui/models/api/apiAccountInfoModel.cpp index 3bd6c80ca..b5fd6f556 100644 --- a/client/ui/models/api/apiAccountInfoModel.cpp +++ b/client/ui/models/api/apiAccountInfoModel.cpp @@ -78,7 +78,6 @@ QVariant ApiAccountInfoModel::data(const QModelIndex &index, int role) const } case IsSubscriptionExpiredRole: { if (m_accountInfoData.configType == apiDefs::ConfigType::AmneziaFreeV3) return false; - if (m_isSubscriptionExpiredByServer) return true; if (m_accountInfoData.subscriptionEndDate.isEmpty()) return false; return apiUtils::isSubscriptionExpired(m_accountInfoData.subscriptionEndDate); } @@ -87,7 +86,7 @@ QVariant ApiAccountInfoModel::data(const QModelIndex &index, int role) const if (m_accountInfoData.subscriptionEndDate.isEmpty()) return false; if (apiUtils::isSubscriptionExpired(m_accountInfoData.subscriptionEndDate)) return false; QDateTime endDate = QDateTime::fromString(m_accountInfoData.subscriptionEndDate, Qt::ISODateWithMs); - return endDate <= QDateTime::currentDateTimeUtc().addDays(30); + return endDate <= QDateTime::currentDateTimeUtc().addDays(10); } } @@ -98,8 +97,6 @@ void ApiAccountInfoModel::updateModel(const QJsonObject &accountInfoObject, cons { beginResetModel(); - m_isSubscriptionExpiredByServer = false; - AccountInfoData accountInfoData; m_availableCountries = accountInfoObject.value(apiDefs::key::availableCountries).toArray(); @@ -124,13 +121,6 @@ void ApiAccountInfoModel::updateModel(const QJsonObject &accountInfoObject, cons endResetModel(); } -void ApiAccountInfoModel::setSubscriptionExpiredByServer() -{ - beginResetModel(); - m_isSubscriptionExpiredByServer = true; - endResetModel(); -} - QVariant ApiAccountInfoModel::data(const QString &roleString) { QModelIndex modelIndex = index(0); diff --git a/client/ui/models/api/apiAccountInfoModel.h b/client/ui/models/api/apiAccountInfoModel.h index fb04079c6..882a9c729 100644 --- a/client/ui/models/api/apiAccountInfoModel.h +++ b/client/ui/models/api/apiAccountInfoModel.h @@ -33,8 +33,6 @@ public: public slots: void updateModel(const QJsonObject &accountInfoObject, const QJsonObject &serverConfig); QVariant data(const QString &roleString); - void setSubscriptionExpiredByServer(); - QJsonArray getAvailableCountries(); QJsonArray getIssuedConfigsInfo(); @@ -62,7 +60,6 @@ private: }; AccountInfoData m_accountInfoData; - bool m_isSubscriptionExpiredByServer = false; QJsonArray m_availableCountries; QJsonArray m_issuedConfigsInfo; QJsonObject m_supportInfo; diff --git a/client/ui/models/servers_model.cpp b/client/ui/models/servers_model.cpp index 3af2a09a5..70d5541cc 100644 --- a/client/ui/models/servers_model.cpp +++ b/client/ui/models/servers_model.cpp @@ -179,6 +179,20 @@ QVariant ServersModel::data(const QModelIndex &index, int role) const case AdEndpointRole: { return apiConfig.value(apiDefs::key::serviceInfo).toObject().value(apiDefs::key::adEndpoint).toString(); } + case IsSubscriptionExpiredRole: { + if (configVersion != apiDefs::ConfigSource::AmneziaGateway) return false; + QString endDate = apiConfig.value(apiDefs::key::subscriptionEndDate).toString(); + if (endDate.isEmpty()) return false; + return apiUtils::isSubscriptionExpired(endDate); + } + case IsSubscriptionExpiringSoonRole: { + if (configVersion != apiDefs::ConfigSource::AmneziaGateway) return false; + QString endDate = apiConfig.value(apiDefs::key::subscriptionEndDate).toString(); + if (endDate.isEmpty()) return false; + if (apiUtils::isSubscriptionExpired(endDate)) return false; + QDateTime endDateTime = QDateTime::fromString(endDate, Qt::ISODateWithMs); + return endDateTime <= QDateTime::currentDateTimeUtc().addDays(10); + } } return QVariant(); @@ -443,6 +457,9 @@ QHash ServersModel::roleNames() const roles[AdDescriptionRole] = "adDescription"; roles[AdEndpointRole] = "adEndpoint"; + roles[IsSubscriptionExpiredRole] = "isSubscriptionExpired"; + roles[IsSubscriptionExpiringSoonRole] = "isSubscriptionExpiringSoon"; + return roles; } diff --git a/client/ui/models/servers_model.h b/client/ui/models/servers_model.h index 66779bc2e..6aba7d37c 100644 --- a/client/ui/models/servers_model.h +++ b/client/ui/models/servers_model.h @@ -52,6 +52,9 @@ public: AdDescriptionRole, AdEndpointRole, + IsSubscriptionExpiredRole, + IsSubscriptionExpiringSoonRole, + HasAmneziaDns }; diff --git a/client/ui/qml/Components/ServersListView.qml b/client/ui/qml/Components/ServersListView.qml index 47eceb3f8..69c6acada 100644 --- a/client/ui/qml/Components/ServersListView.qml +++ b/client/ui/qml/Components/ServersListView.qml @@ -19,15 +19,6 @@ ListViewType { id: root property int selectedIndex: ServersModel.defaultIndex - property int expiredServerIndex: -1 - property bool expiringSoon: false - - Connections { - target: ApiAccountInfoModel - function onModelReset() { - root.expiringSoon = ApiAccountInfoModel.data("isSubscriptionExpiringSoon") - } - } anchors.top: serversMenuHeader.bottom anchors.right: parent.right @@ -44,13 +35,6 @@ ListViewType { } } - Connections { - target: ApiConfigsController - function onSubscriptionExpiredOnServer() { - root.expiredServerIndex = ServersModel.defaultIndex - } - } - delegate: Item { id: menuContentDelegate objectName: "menuContentDelegate" @@ -143,14 +127,14 @@ ListViewType { } CaptionTextType { - visible: isServerFromGatewayApi && (index === root.expiredServerIndex || (root.expiringSoon && index === root.selectedIndex && index !== root.expiredServerIndex)) + visible: isServerFromGatewayApi && (isSubscriptionExpired || isSubscriptionExpiringSoon) Layout.fillWidth: true Layout.leftMargin: 64 Layout.bottomMargin: 8 - text: index === root.expiredServerIndex ? qsTr("Subscription expired. Please renew.") : qsTr("Subscription expiring soon.") - color: index === root.expiredServerIndex ? AmneziaStyle.color.vibrantRed : AmneziaStyle.color.goldenApricot + text: isSubscriptionExpired ? qsTr("Subscription expired. Please renew.") : qsTr("Subscription expiring soon.") + color: isSubscriptionExpired ? AmneziaStyle.color.vibrantRed : AmneziaStyle.color.goldenApricot wrapMode: Text.WordWrap } diff --git a/client/ui/qml/Components/SubscriptionExpiredDrawer.qml b/client/ui/qml/Components/SubscriptionExpiredDrawer.qml index 97fb01b85..8be6b805a 100644 --- a/client/ui/qml/Components/SubscriptionExpiredDrawer.qml +++ b/client/ui/qml/Components/SubscriptionExpiredDrawer.qml @@ -3,8 +3,6 @@ pragma ComponentBehavior: Bound import QtQuick import QtQuick.Controls import QtQuick.Layouts -import Qt5Compat.GraphicalEffects - import PageEnum 1.0 import Style 1.0 diff --git a/client/ui/qml/Pages2/PageSettingsApiAvailableCountries.qml b/client/ui/qml/Pages2/PageSettingsApiAvailableCountries.qml index 93599d960..d7aded663 100644 --- a/client/ui/qml/Pages2/PageSettingsApiAvailableCountries.qml +++ b/client/ui/qml/Pages2/PageSettingsApiAvailableCountries.qml @@ -21,34 +21,20 @@ PageType { property bool subscriptionExpired: false property bool subscriptionExpiringSoon: false function updateSubscriptionState() { - root.subscriptionExpiringSoon = ApiAccountInfoModel.data("isSubscriptionExpiringSoon") + root.subscriptionExpired = ServersModel.getProcessedServerData("isSubscriptionExpired") + root.subscriptionExpiringSoon = ServersModel.getProcessedServerData("isSubscriptionExpiringSoon") } Component.onCompleted: { root.updateSubscriptionState() } - Connections { - target: ApiAccountInfoModel - function onModelReset() { - root.updateSubscriptionState() - } - } - Connections { target: ServersModel function onProcessedServerChanged() { root.processedServer = proxyServersModel.get(0) - } - } - - Connections { - target: ApiConfigsController - - function onSubscriptionExpiredOnServer() { - root.subscriptionExpired = true - root.subscriptionExpiringSoon = false + root.updateSubscriptionState() } }