feature: added error handling and minor ui fixes

This commit is contained in:
vladimir.kuznetsov 2025-02-10 15:10:59 +07:00
parent 42d3d9b98a
commit 07baf0ed65
16 changed files with 101 additions and 53 deletions

View file

@ -213,21 +213,6 @@ void ApiController::updateServerConfigFromApi(const QString &installationUuid, c
}
}
ErrorCode ApiController::getAccountInfo(const QString &userCountryCode, const QString &serviceType, const QJsonObject &authData,
QByteArray &responseBody)
{
GatewayController gatewayController(m_gatewayEndpoint, m_isDevEnvironment, requestTimeoutMsecs);
QJsonObject apiPayload;
apiPayload[configKey::userCountryCode] = userCountryCode;
apiPayload[configKey::serviceType] = serviceType;
apiPayload[configKey::authData] = authData;
ErrorCode errorCode = gatewayController.post(QString("%1v1/account_info"), apiPayload, responseBody);
return errorCode;
}
ErrorCode ApiController::getServicesList(QByteArray &responseBody)
{
GatewayController gatewayController(m_gatewayEndpoint, m_isDevEnvironment, requestTimeoutMsecs);

View file

@ -18,9 +18,6 @@ public:
public slots:
void updateServerConfigFromApi(const QString &installationUuid, const int serverIndex, QJsonObject serverConfig);
ErrorCode getAccountInfo(const QString &userCountryCode, const QString &serviceType, const QJsonObject &authData,
QByteArray &responseBody);
ErrorCode getServicesList(QByteArray &responseBody);
ErrorCode getConfigForService(const QString &installationUuid, const QString &userCountryCode, const QString &serviceType,
const QString &protocol, const QString &serverCountryCode, const QJsonObject &authData,

View file

@ -48,8 +48,13 @@ ApiConfigsController::ApiConfigsController(const QSharedPointer<ServersModel> &s
{
}
void ApiConfigsController::exportNativeConfig(const QString &serverCountryCode, const QString &fileName)
bool ApiConfigsController::exportNativeConfig(const QString &serverCountryCode, const QString &fileName)
{
if (fileName.isEmpty()) {
emit errorOccurred(ErrorCode::PermissionsError);
return false;
}
GatewayController gatewayController(m_settings->getGatewayEndpoint(), m_settings->isDevGatewayEnv(), apiDefs::requestTimeoutMsecs);
auto serverConfigObject = m_serversModel->getServerConfig(m_serversModel->getProcessedServerIndex());
@ -67,14 +72,16 @@ void ApiConfigsController::exportNativeConfig(const QString &serverCountryCode,
QByteArray responseBody;
ErrorCode errorCode = gatewayController.post(QString("%1v1/native_config"), apiPayload, responseBody);
// // if (errorCode != ErrorCode::NoError) {
// // }
if (errorCode != ErrorCode::NoError) {
emit errorOccurred(errorCode);
return false;
}
QJsonObject jsonConfig = QJsonDocument::fromJson(responseBody).object();
QString nativeConfig = jsonConfig.value(configKey::config).toString();
SystemController::saveFile(fileName, nativeConfig);
return true;
}
ApiConfigsController::ApiPayloadData ApiConfigsController::generateApiPayloadData(const QString &protocol)

View file

@ -11,10 +11,13 @@ class ApiConfigsController : public QObject
Q_OBJECT
public:
ApiConfigsController(const QSharedPointer<ServersModel> &serversModel, const std::shared_ptr<Settings> &settings,
QObject *parent = nullptr);
QObject *parent = nullptr);
public slots:
void exportNativeConfig(const QString &serverCountryCode, const QString &fileName);
bool exportNativeConfig(const QString &serverCountryCode, const QString &fileName);
signals:
void errorOccurred(ErrorCode errorCode);
private:
struct ApiPayloadData

View file

@ -1,5 +1,6 @@
#include "apiSettingsController.h"
#include "core/api/apiUtils.h"
#include "core/controllers/gatewayController.h"
namespace
@ -49,10 +50,13 @@ bool ApiSettingsController::getAccountInfo()
apiPayload[configKey::authData] = authData;
QByteArray responseBody;
ErrorCode errorCode = gatewayController.post(QString("%1v1/account_info"), apiPayload, responseBody);
if (errorCode != ErrorCode::NoError) {
// emit errorOccured(errorCode);
return false;
if (apiUtils::getConfigType(serverConfig) == apiDefs::ConfigType::AmneziaPremiumV2) {
ErrorCode errorCode = gatewayController.post(QString("%1v1/account_info"), apiPayload, responseBody);
if (errorCode != ErrorCode::NoError) {
emit errorOccurred(errorCode);
return false;
}
}
QJsonObject accountInfo = QJsonDocument::fromJson(responseBody).object();

View file

@ -20,6 +20,9 @@ public slots:
bool getAccountInfo();
void updateApiCountryModel();
signals:
void errorOccurred(ErrorCode errorCode);
private:
QSharedPointer<ServersModel> m_serversModel;
QSharedPointer<ApiAccountInfoModel> m_apiAccountInfoModel;

View file

@ -12,9 +12,6 @@ namespace
namespace configKey
{
constexpr char availableCountries[] = "available_countries";
// constexpr char serverCountryCode[] = "server_country_code";
// constexpr char serverCountryName[] = "server_country_name";
// constexpr char lastUpdated[] = "last_updated";
constexpr char activeDeviceCount[] = "active_device_count";
constexpr char maxDeviceCount[] = "max_device_count";
constexpr char subscriptionEndDate[] = "subscription_end_date";
@ -38,12 +35,23 @@ QVariant ApiAccountInfoModel::data(const QModelIndex &index, int role) const
switch (role) {
case SubscriptionStatusRole: {
if (m_accountInfoData.configType == apiDefs::ConfigType::AmneziaFreeV3) {
return tr("Active");
}
return apiUtils::isSubscriptionExpired(m_accountInfoData.subscriptionEndDate) ? tr("Inactive") : tr("Active");
}
case EndDateRole: {
if (m_accountInfoData.configType == apiDefs::ConfigType::AmneziaFreeV3) {
return "";
}
return QDateTime::fromString(m_accountInfoData.subscriptionEndDate, Qt::ISODate).toLocalTime().toString("d MMM yyyy");
}
case ConnectedDevicesRole: {
if (m_accountInfoData.configType == apiDefs::ConfigType::AmneziaFreeV3) {
return "";
}
return tr("%1 out of %2").arg(m_accountInfoData.activeDeviceCount).arg(m_accountInfoData.maxDeviceCount);
}
case ServiceDescriptionRole: {
@ -55,6 +63,9 @@ QVariant ApiAccountInfoModel::data(const QModelIndex &index, int role) const
"more. YouTube is not included in the free plan.");
}
}
case IsComponentVisibleRole: {
return m_accountInfoData.configType == apiDefs::ConfigType::AmneziaPremiumV2;
}
}
return QVariant();
@ -67,15 +78,6 @@ void ApiAccountInfoModel::updateModel(const QJsonObject &accountInfoObject, cons
AccountInfoData accountInfoData;
m_availableCountries = accountInfoObject.value(configKey::availableCountries).toArray();
// for (const auto &country : availableCountries) {
// auto countryObject = country.toObject();
// CountryInfo countryInfo;
// countryInfo.serverCountryCode = countryObject.value(configKey::serverCountryCode).toString();
// countryInfo.serverCountryName = countryObject.value(configKey::serverCountryName).toString();
// countryInfo.lastUpdated = countryObject.value(configKey::lastUpdated).toString();
// accountInfoData.AvailableCountries.push_back(countryInfo);
// }
accountInfoData.activeDeviceCount = accountInfoObject.value(configKey::activeDeviceCount).toInt();
accountInfoData.maxDeviceCount = accountInfoObject.value(configKey::maxDeviceCount).toInt();
@ -106,6 +108,16 @@ QJsonArray ApiAccountInfoModel::getAvailableCountries()
return m_availableCountries;
}
QString ApiAccountInfoModel::getTelegramBotLink()
{
if (m_accountInfoData.configType == apiDefs::ConfigType::AmneziaFreeV3) {
return tr("amnezia_free_support_bot");
} else if (m_accountInfoData.configType == apiDefs::ConfigType::AmneziaPremiumV2) {
return tr("amnezia_premium_support_bot");
}
return "";
}
QHash<int, QByteArray> ApiAccountInfoModel::roleNames() const
{
QHash<int, QByteArray> roles;
@ -113,6 +125,7 @@ QHash<int, QByteArray> ApiAccountInfoModel::roleNames() const
roles[EndDateRole] = "endDate";
roles[ConnectedDevicesRole] = "connectedDevices";
roles[ServiceDescriptionRole] = "serviceDescription";
roles[IsComponentVisibleRole] = "isComponentVisible";
return roles;
}

View file

@ -16,7 +16,8 @@ public:
SubscriptionStatusRole = Qt::UserRole + 1,
ConnectedDevicesRole,
ServiceDescriptionRole,
EndDateRole
EndDateRole,
IsComponentVisibleRole
};
explicit ApiAccountInfoModel(QObject *parent = nullptr);
@ -30,6 +31,7 @@ public slots:
QVariant data(const QString &roleString);
QJsonArray getAvailableCountries();
QString getTelegramBotLink();
protected:
QHash<int, QByteArray> roleNames() const override;

View file

@ -116,8 +116,11 @@ ListView {
PageController.goToPage(PageEnum.PageSettingsApiAvailableCountries)
} else {
PageController.showBusyIndicator(true)
ApiSettingsController.getAccountInfo()
let result = ApiSettingsController.getAccountInfo()
PageController.showBusyIndicator(false)
if (!result) {
return
}
PageController.goToPage(PageEnum.PageSettingsApiServerInfo)
}

View file

@ -303,8 +303,11 @@ PageType {
PageController.goToPage(PageEnum.PageSettingsApiAvailableCountries)
} else {
PageController.showBusyIndicator(true)
ApiSettingsController.getAccountInfo()
let result = ApiSettingsController.getAccountInfo()
PageController.showBusyIndicator(false)
if (!result) {
return
}
PageController.goToPage(PageEnum.PageSettingsApiServerInfo)
}

View file

@ -89,12 +89,15 @@ PageType {
actionButtonImage: "qrc:/images/controls/settings.svg"
headerText: root.processedServer.name
descriptionText: ApiServicesModel.getSelectedServiceData("serviceDescription")
descriptionText: qsTr("Locations for connection")
actionButtonFunction: function() {
PageController.showBusyIndicator(true)
ApiSettingsController.getAccountInfo()
let result = ApiSettingsController.getAccountInfo()
PageController.showBusyIndicator(false)
if (!result) {
return
}
PageController.goToPage(PageEnum.PageSettingsApiServerInfo)
}

View file

@ -75,8 +75,12 @@ PageType {
}
if (fileName !== "") {
PageController.showBusyIndicator(true)
ApiConfigsController.exportNativeConfig(countryCode, fileName)
let result = ApiConfigsController.exportNativeConfig(countryCode, fileName)
PageController.showBusyIndicator(false)
if (result) {
PageController.showNotificationMessage(qsTr("Config file saved"))
}
}
}
}

View file

@ -141,16 +141,20 @@ PageType {
}
footer: ColumnLayout {
id: footer
width: listView.width
spacing: 0
readonly property bool isVisibleForAmneziaFree: ApiAccountInfoModel.data("isComponentVisible")
LabelWithButtonType {
id: vpnKey
Layout.fillWidth: true
Layout.topMargin: 32
visible: false
visible: footer.isVisibleForAmneziaFree
text: qsTr("Subscription key")
rightImageSource: "qrc:/images/controls/chevron-right.svg"
@ -160,12 +164,13 @@ PageType {
}
DividerType {
visible: false
visible: footer.isVisibleForAmneziaFree
}
LabelWithButtonType {
Layout.fillWidth: true
Layout.topMargin: vpnKey.visible ? 0 : 32
visible: footer.isVisibleForAmneziaFree
text: qsTr("Configuration files")
@ -178,10 +183,13 @@ PageType {
}
}
DividerType {}
DividerType {
visible: footer.isVisibleForAmneziaFree
}
LabelWithButtonType {
Layout.fillWidth: true
Layout.topMargin: footer.isVisibleForAmneziaFree ? 0 : 32
text: qsTr("Support")
rightImageSource: "qrc:/images/controls/chevron-right.svg"

View file

@ -44,12 +44,14 @@ PageType {
LabelWithButtonType {
Layout.fillWidth: true
readonly property string telegramBotLink: ApiAccountInfoModel.getTelegramBotLink()
text: qsTr("Telegram")
descriptionText: qsTr("@amnezia_premium_support_bot")
descriptionText: "@" + telegramBotLink
rightImageSource: "qrc:/images/controls/external-link.svg"
clickedFunction: function() {
Qt.openUrlExternally(qsTr("https://t.me/amnezia_premium_support_bot"))
Qt.openUrlExternally("https://t.me/" + telegramBotLink)
}
}

View file

@ -96,8 +96,11 @@ PageType {
if (ServersModel.getProcessedServerData("isServerFromGatewayApi")) {
PageController.showBusyIndicator(true)
ApiSettingsController.getAccountInfo()
let result = ApiSettingsController.getAccountInfo()
PageController.showBusyIndicator(false)
if (!result) {
return
}
PageController.goToPage(PageEnum.PageSettingsApiServerInfo)
} else {

View file

@ -224,6 +224,14 @@ PageType {
}
}
Connections {
target: ApiSettingsController
function onErrorOccurred(error) {
PageController.showErrorMessage(error)
}
}
StackViewType {
id: tabBarStackView
objectName: "tabBarStackView"