mirror of
https://git.jami.net/savoirfairelinux/jami-client-qt.git
synced 2025-03-28 14:56:19 +01:00
account: implement import-from-device using new API
- Implements new APIs - Implements import-from-device mechanism (creation wizard) - Minor refactoring of accountmodel and accountadapter Gitlab: #1695 Change-Id: Ib3c6301b82b19a25320dd703f2f7e941f8048a8e
This commit is contained in:
parent
82c876c0fa
commit
33da15daba
25 changed files with 820 additions and 347 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -7,6 +7,7 @@ doc/Doxyfile
|
|||
!.vscode/tasks.json
|
||||
!.vscode/launch.json
|
||||
!.vscode/extensions.json
|
||||
*.code-workspace
|
||||
|
||||
### VisualStudioCode Patch ###
|
||||
# Ignore all local history of files
|
||||
|
|
2
daemon
2
daemon
|
@ -1 +1 @@
|
|||
Subproject commit 597cde8d30814b5078e2ac8c8a0953dd471ec716
|
||||
Subproject commit 86d3bb664489077107e68b838e419f4cd6459859
|
|
@ -22,8 +22,11 @@
|
|||
#include "systemtray.h"
|
||||
#include "lrcinstance.h"
|
||||
#include "accountlistmodel.h"
|
||||
#include "wizardviewstepmodel.h"
|
||||
#include "global.h"
|
||||
#include "api/account.h"
|
||||
|
||||
#include <QtConcurrent/QtConcurrent>
|
||||
#include <QThreadPool>
|
||||
|
||||
AccountAdapter::AccountAdapter(AppSettingsManager* settingsManager,
|
||||
SystemTray* systemTray,
|
||||
|
@ -111,7 +114,10 @@ AccountAdapter::createJamiAccount(const QVariantMap& settings)
|
|||
&lrcInstance_->accountModel(),
|
||||
&lrc::api::AccountModel::accountAdded,
|
||||
[this, registeredName, settings](const QString& accountId) {
|
||||
lrcInstance_->accountModel().setAvatar(accountId, settings["avatar"].toString(), true,1);
|
||||
lrcInstance_->accountModel().setAvatar(accountId,
|
||||
settings["avatar"].toString(),
|
||||
true,
|
||||
1);
|
||||
Utils::oneShotConnect(&lrcInstance_->accountModel(),
|
||||
&lrc::api::AccountModel::accountDetailsChanged,
|
||||
[this](const QString& accountId) {
|
||||
|
@ -159,8 +165,9 @@ AccountAdapter::createJamiAccount(const QVariantMap& settings)
|
|||
|
||||
connectFailure();
|
||||
|
||||
auto futureResult = QtConcurrent::run([this, settings] {
|
||||
QThreadPool::globalInstance()->start([this, settings] {
|
||||
lrcInstance_->accountModel().createNewAccount(lrc::api::profile::Type::JAMI,
|
||||
{},
|
||||
settings["alias"].toString(),
|
||||
settings["archivePath"].toString(),
|
||||
settings["password"].toString(),
|
||||
|
@ -206,14 +213,14 @@ AccountAdapter::createSIPAccount(const QVariantMap& settings)
|
|||
|
||||
connectFailure();
|
||||
|
||||
auto futureResult = QtConcurrent::run([this, settings] {
|
||||
QThreadPool::globalInstance()->start([this, settings] {
|
||||
lrcInstance_->accountModel().createNewAccount(lrc::api::profile::Type::SIP,
|
||||
{},
|
||||
settings["alias"].toString(),
|
||||
settings["archivePath"].toString(),
|
||||
"",
|
||||
"",
|
||||
settings["username"].toString(),
|
||||
{});
|
||||
settings["username"].toString());
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -250,7 +257,7 @@ AccountAdapter::createJAMSAccount(const QVariantMap& settings)
|
|||
|
||||
connectFailure();
|
||||
|
||||
auto futureResult = QtConcurrent::run([this, settings] {
|
||||
QThreadPool::globalInstance()->start([this, settings] {
|
||||
lrcInstance_->accountModel().connectToAccountManager(settings["username"].toString(),
|
||||
settings["password"].toString(),
|
||||
settings["manager"].toString());
|
||||
|
@ -293,7 +300,7 @@ AccountAdapter::setCurrAccDisplayName(const QString& text)
|
|||
void
|
||||
AccountAdapter::setCurrentAccountAvatarFile(const QString& source)
|
||||
{
|
||||
auto futureResult = QtConcurrent::run([this, source]() {
|
||||
QThreadPool::globalInstance()->start([this, source]() {
|
||||
QPixmap image;
|
||||
if (!image.load(source)) {
|
||||
qWarning() << "Not a valid image file";
|
||||
|
@ -308,7 +315,7 @@ AccountAdapter::setCurrentAccountAvatarFile(const QString& source)
|
|||
void
|
||||
AccountAdapter::setCurrentAccountAvatarBase64(const QString& data)
|
||||
{
|
||||
auto futureResult = QtConcurrent::run([this, data]() {
|
||||
QThreadPool::globalInstance()->start([this, data]() {
|
||||
auto accountId = lrcInstance_->get_currentAccountId();
|
||||
lrcInstance_->accountModel().setAvatar(accountId, data, true, 1);
|
||||
});
|
||||
|
@ -339,9 +346,73 @@ AccountAdapter::exportToFile(const QString& accountId,
|
|||
void
|
||||
AccountAdapter::setArchivePasswordAsync(const QString& accountID, const QString& password)
|
||||
{
|
||||
auto futureResult = QtConcurrent::run([this, accountID, password] {
|
||||
QThreadPool::globalInstance()->start([this, accountID, password] {
|
||||
auto config = lrcInstance_->accountModel().getAccountConfig(accountID);
|
||||
config.archivePassword = password;
|
||||
lrcInstance_->accountModel().setAccountConfig(accountID, config);
|
||||
});
|
||||
}
|
||||
|
||||
void
|
||||
AccountAdapter::startImportAccount()
|
||||
{
|
||||
auto wizardModel = qApp->property("WizardViewStepModel").value<WizardViewStepModel*>();
|
||||
wizardModel->set_deviceAuthState(lrc::api::account::DeviceAuthState::INIT);
|
||||
wizardModel->set_deviceLinkDetails({});
|
||||
|
||||
// This will create an account with the ARCHIVE_URL configured to start the import process.
|
||||
importAccountId_ = lrcInstance_->accountModel().createDeviceImportAccount();
|
||||
}
|
||||
|
||||
void
|
||||
AccountAdapter::provideAccountAuthentication(const QString& password)
|
||||
{
|
||||
if (importAccountId_.isEmpty()) {
|
||||
qWarning() << "No import account to provide password to";
|
||||
return;
|
||||
}
|
||||
|
||||
auto wizardModel = qApp->property("WizardViewStepModel").value<WizardViewStepModel*>();
|
||||
wizardModel->set_deviceAuthState(lrc::api::account::DeviceAuthState::IN_PROGRESS);
|
||||
|
||||
Utils::oneShotConnect(
|
||||
&lrcInstance_->accountModel(),
|
||||
&lrc::api::AccountModel::accountAdded,
|
||||
[this](const QString& accountId) {
|
||||
Q_EMIT lrcInstance_->accountListChanged();
|
||||
Q_EMIT accountAdded(accountId,
|
||||
lrcInstance_->accountModel().getAccountList().indexOf(accountId));
|
||||
},
|
||||
this,
|
||||
&AccountAdapter::accountCreationFailed);
|
||||
|
||||
connectFailure();
|
||||
|
||||
QThreadPool::globalInstance()->start([this, password] {
|
||||
lrcInstance_->accountModel().provideAccountAuthentication(importAccountId_, password);
|
||||
});
|
||||
}
|
||||
|
||||
QString
|
||||
AccountAdapter::getImportErrorMessage(QVariantMap details)
|
||||
{
|
||||
QString errorString = details.value("error").toString();
|
||||
if (!errorString.isEmpty() && errorString != "none") {
|
||||
auto error = lrc::api::account::mapLinkDeviceError(errorString.toStdString());
|
||||
return lrc::api::account::getLinkDeviceString(error);
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
void
|
||||
AccountAdapter::cancelImportAccount()
|
||||
{
|
||||
auto wizardModel = qApp->property("WizardViewStepModel").value<WizardViewStepModel*>();
|
||||
wizardModel->set_deviceAuthState(lrc::api::account::DeviceAuthState::INIT);
|
||||
wizardModel->set_deviceLinkDetails({});
|
||||
|
||||
// Remove the account if it was created
|
||||
lrcInstance_->accountModel().removeAccount(importAccountId_);
|
||||
importAccountId_.clear();
|
||||
}
|
||||
|
|
|
@ -81,6 +81,13 @@ public:
|
|||
const bool& state);
|
||||
Q_INVOKABLE QStringList getDefaultModerators(const QString& accountId);
|
||||
|
||||
// New import account / link device functions
|
||||
// import: (note: Listen for: DeviceAuthStateChanged)
|
||||
Q_INVOKABLE void startImportAccount();
|
||||
Q_INVOKABLE void provideAccountAuthentication(const QString& password = {});
|
||||
Q_INVOKABLE QString getImportErrorMessage(QVariantMap details);
|
||||
Q_INVOKABLE void cancelImportAccount();
|
||||
|
||||
Q_SIGNALS:
|
||||
// Trigger other components to reconnect account related signals.
|
||||
void accountStatusChanged(QString accountId);
|
||||
|
@ -98,6 +105,9 @@ private:
|
|||
|
||||
QMetaObject::Connection registeredNameSavedConnection_;
|
||||
|
||||
// The account ID of the last used import account.
|
||||
QString importAccountId_;
|
||||
|
||||
AppSettingsManager* settingsManager_;
|
||||
SystemTray* systemTray_;
|
||||
};
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include "lrcinstance.h"
|
||||
|
||||
#include <QImage>
|
||||
#include <QRegularExpression>
|
||||
|
||||
class AsyncAvatarImageResponseRunnable : public AsyncImageResponseRunnable
|
||||
{
|
||||
|
@ -69,6 +70,16 @@ public:
|
|||
image = Utils::accountPhoto(lrcInstance_, imageId, requestedSize_);
|
||||
} else if (type == "contact") {
|
||||
image = Utils::contactPhoto(lrcInstance_, imageId, requestedSize_);
|
||||
} else if (type == "temporaryAccount") {
|
||||
// Check if imageId is a SHA-1 hash (jamiId or registered name)
|
||||
static const QRegularExpression sha1Pattern("^[0-9a-fA-F]{40}$");
|
||||
if (sha1Pattern.match(imageId).hasMatch()) {
|
||||
// If we only have a jamiId use default avatar
|
||||
image = Utils::fallbackAvatar("jami:" + imageId, QString(), requestedSize_);
|
||||
} else {
|
||||
// For registered usernames, use fallbackAvatar avatar with the name
|
||||
image = Utils::fallbackAvatar(QString(), imageId, requestedSize_);
|
||||
}
|
||||
} else {
|
||||
qWarning() << Q_FUNC_INFO << "Missing valid prefix in the image url";
|
||||
return;
|
||||
|
|
|
@ -28,7 +28,8 @@ Item {
|
|||
enum Mode {
|
||||
Account,
|
||||
Contact,
|
||||
Conversation
|
||||
Conversation,
|
||||
TemporaryAccount
|
||||
}
|
||||
property int mode: Avatar.Mode.Account
|
||||
property alias sourceSize: image.sourceSize
|
||||
|
@ -45,6 +46,8 @@ Item {
|
|||
return 'contact';
|
||||
case Avatar.Mode.Conversation:
|
||||
return 'conversation';
|
||||
case Avatar.Mode.TemporaryAccount:
|
||||
return 'temporaryAccount';
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -70,6 +70,21 @@ Item {
|
|||
property string transferThisCall: qsTr("Transfer this call")
|
||||
property string transferTo: qsTr("Transfer to")
|
||||
|
||||
// Device import/linking
|
||||
property string scanToImportAccount: qsTr("Scan this QR code on your other device to proceed with importing your account.")
|
||||
property string waitingForToken: qsTr("Please wait…")
|
||||
property string scanQRCode: qsTr("Scan QR code")
|
||||
property string connectingToDevice: qsTr("Action required.\nPlease confirm account on your old device.")
|
||||
property string confirmAccountImport: qsTr("Authenticating device")
|
||||
property string transferringAccount: qsTr("Transferring account…")
|
||||
property string cantScanQRCode: qsTr("If you are unable to scan the QR code, enter this token on your other device to proceed.")
|
||||
property string optionConfirm: qsTr("Confirm")
|
||||
property string optionTryAgain: qsTr("Try again")
|
||||
property string importFailed: qsTr("Import failed")
|
||||
property string importFromAnotherAccount: qsTr("Import from another account")
|
||||
property string connectToAccount: qsTr("Connect to account")
|
||||
property string authenticationError: qsTr("An authentication error occurred. Please check credentials and try again.")
|
||||
|
||||
// AccountMigrationDialog
|
||||
property string authenticationRequired: qsTr("Authentication required")
|
||||
property string migrationReason: qsTr("Your session has expired or been revoked on this device. Please enter your password.")
|
||||
|
@ -579,19 +594,8 @@ Item {
|
|||
// ImportFromDevicePage
|
||||
property string importButton: qsTr("Import")
|
||||
property string pin: qsTr("Enter the PIN code")
|
||||
property string importFromDeviceDescription: qsTr("A PIN code is required to use an existing Jami account on this device.")
|
||||
property string importStep1: qsTr("Step 1")
|
||||
property string importStep2: qsTr("Step 2")
|
||||
property string importStep3: qsTr("Step 3")
|
||||
property string importStep4: qsTr("Step 4")
|
||||
property string importStep1Desc: qsTr("Open the manage account tab in the settings of the previous device.")
|
||||
property string importStep2Desc: qsTr("Select the account to link.")
|
||||
property string importStep3Desc: qsTr("Select “Link new device.”")
|
||||
property string importStep4Desc: qsTr("The PIN code will expire in 10 minutes.")
|
||||
property string importPasswordDesc: qsTr("Fill if the account is password-encrypted.")
|
||||
|
||||
// LinkDevicesDialog
|
||||
property string pinTimerInfos: qsTr("The PIN code and the account password should be entered in the device within 10 minutes.")
|
||||
property string close: qsTr("Close")
|
||||
property string enterAccountPassword: qsTr("Enter account password")
|
||||
property string enterPasswordPinCode: qsTr("This account is password encrypted, enter the password to generate a PIN code.")
|
||||
|
|
|
@ -179,6 +179,12 @@ registerTypes(QQmlEngine* engine,
|
|||
QQmlEngine::setObjectOwnership(pluginStoreListModel, QQmlEngine::CppOwnership);
|
||||
REG_QML_SINGLETON<PluginStoreListModel>(REG_MODEL, "PluginStoreListModel", CREATE(pluginStoreListModel));
|
||||
|
||||
// WizardViewStepModel
|
||||
auto wizardViewStepModel = new WizardViewStepModel(lrcInstance, settingsManager, app);
|
||||
qApp->setProperty("WizardViewStepModel", QVariant::fromValue(wizardViewStepModel));
|
||||
QQmlEngine::setObjectOwnership(wizardViewStepModel, QQmlEngine::CppOwnership);
|
||||
REG_QML_SINGLETON<WizardViewStepModel>(REG_MODEL, "WizardViewStepModel", CREATE(wizardViewStepModel));
|
||||
|
||||
// Register app-level objects that are used by QML created objects.
|
||||
// These MUST be set prior to loading the initial QML file, in order to
|
||||
// be available to the QML adapter class factory creation methods.
|
||||
|
@ -205,7 +211,6 @@ registerTypes(QQmlEngine* engine,
|
|||
QML_REGISTERSINGLETON_TYPE(NS_ADAPTERS, TipsModel);
|
||||
QML_REGISTERSINGLETON_TYPE(NS_ADAPTERS, VideoDevices);
|
||||
QML_REGISTERSINGLETON_TYPE(NS_ADAPTERS, CurrentAccountToMigrate);
|
||||
QML_REGISTERSINGLETON_TYPE(NS_MODELS, WizardViewStepModel);
|
||||
QML_REGISTERSINGLETON_TYPE(NS_HELPERS, ImageDownloader);
|
||||
|
||||
// TODO: remove these
|
||||
|
@ -263,12 +268,12 @@ registerTypes(QQmlEngine* engine,
|
|||
// Enums
|
||||
QML_REGISTERUNCREATABLE(NS_ENUMS, Settings)
|
||||
QML_REGISTERUNCREATABLE(NS_ENUMS, NetworkManager)
|
||||
QML_REGISTERUNCREATABLE(NS_ENUMS, WizardViewStepModel)
|
||||
QML_REGISTERUNCREATABLE(NS_ENUMS, DeviceItemListModel)
|
||||
QML_REGISTERUNCREATABLE(NS_ENUMS, ModeratorListModel)
|
||||
QML_REGISTERUNCREATABLE(NS_ENUMS, VideoInputDeviceModel)
|
||||
QML_REGISTERUNCREATABLE(NS_ENUMS, VideoFormatResolutionModel)
|
||||
QML_REGISTERUNCREATABLE(NS_ENUMS, VideoFormatFpsModel)
|
||||
QML_REGISTERUNCREATABLE(NS_ENUMS, DeviceAuthStateEnum)
|
||||
|
||||
engine->addImageProvider(QLatin1String("qrImage"), new QrImageProvider(lrcInstance));
|
||||
engine->addImageProvider(QLatin1String("avatarimage"), new AvatarImageProvider(lrcInstance));
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
#pragma once
|
||||
|
||||
#include "quickimageproviderbase.h"
|
||||
#include "accountlistmodel.h"
|
||||
|
||||
#include <QPair>
|
||||
#include <QString>
|
||||
|
|
|
@ -42,7 +42,6 @@ BaseModalDialog {
|
|||
}
|
||||
stackedWidget.currentIndex = exportingSpinnerPage.pageIndex;
|
||||
spinnerMovie.playing = true;
|
||||
timerForExport.restart();
|
||||
}
|
||||
|
||||
function setExportPage(status, pin) {
|
||||
|
@ -69,25 +68,6 @@ BaseModalDialog {
|
|||
stackedWidget.height = exportingLayout.implicitHeight;
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: timerForExport
|
||||
|
||||
repeat: false
|
||||
interval: 200
|
||||
|
||||
onTriggered: {
|
||||
AccountAdapter.model.exportOnRing(LRCInstance.currentAccountId, passwordEdit.dynamicText);
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: NameDirectory
|
||||
|
||||
function onExportOnRingEnded(status, pin) {
|
||||
stackedWidget.setExportPage(status, pin);
|
||||
}
|
||||
}
|
||||
|
||||
onVisibleChanged: {
|
||||
if (visible) {
|
||||
if (CurrentAccount.hasArchivePassword) {
|
||||
|
|
|
@ -165,8 +165,7 @@ Utils::CreateStartupLink(const std::wstring& wstrAppName)
|
|||
#endif
|
||||
|
||||
if (desktopPath.isEmpty() || !(QFile::exists(desktopPath))) {
|
||||
qDebug() << "Error while attempting to locate .desktop file at"
|
||||
<< desktopPath;
|
||||
qDebug() << "Error while attempting to locate .desktop file at" << desktopPath;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -193,8 +192,7 @@ Utils::CreateStartupLink(const std::wstring& wstrAppName)
|
|||
if (QDir().mkdir(autoStartDir)) {
|
||||
qDebug() << "Created autostart directory:" << autoStartDir;
|
||||
} else {
|
||||
qWarning() << "Error while creating autostart directory:"
|
||||
<< autoStartDir;
|
||||
qWarning() << "Error while creating autostart directory:" << autoStartDir;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -283,7 +281,8 @@ Utils::CheckStartupLink(const std::wstring& wstrAppName)
|
|||
#else
|
||||
Q_UNUSED(wstrAppName)
|
||||
return (
|
||||
!QStandardPaths::locate(QStandardPaths::ConfigLocation, "autostart/net.jami.Jami.desktop").isEmpty());
|
||||
!QStandardPaths::locate(QStandardPaths::ConfigLocation, "autostart/net.jami.Jami.desktop")
|
||||
.isEmpty());
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -616,14 +615,16 @@ Utils::getProjectCredits()
|
|||
return {};
|
||||
}
|
||||
QTextStream in(&projectCreditsFile);
|
||||
return in.readAll().arg(
|
||||
QObject::tr("We would like to thank our contributors, whose efforts over many years have made this software what it is."),
|
||||
QObject::tr("Developers"),
|
||||
QObject::tr("Media"),
|
||||
QObject::tr("Community Management"),
|
||||
QObject::tr("Special thanks to"),
|
||||
QObject::tr("This is a list of people who have made a significant investment of time, with useful results, into Jami. Any such contributors who want to be added to the list should contact us.")
|
||||
);
|
||||
return in.readAll().arg(QObject::tr("We would like to thank our contributors, whose efforts "
|
||||
"over many years have made this software what it is."),
|
||||
QObject::tr("Developers"),
|
||||
QObject::tr("Media"),
|
||||
QObject::tr("Community Management"),
|
||||
QObject::tr("Special thanks to"),
|
||||
QObject::tr(
|
||||
"This is a list of people who have made a significant investment "
|
||||
"of time, with useful results, into Jami. Any such contributors "
|
||||
"who want to be added to the list should contact us."));
|
||||
}
|
||||
|
||||
inline QString
|
||||
|
@ -951,3 +952,13 @@ Utils::getTempSwarmAvatarPath()
|
|||
return QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + QDir::separator()
|
||||
+ "tmpSwarmImage";
|
||||
}
|
||||
|
||||
QVariantMap
|
||||
Utils::mapStringStringToVariantMap(const MapStringString& map)
|
||||
{
|
||||
QVariantMap variantMap;
|
||||
for (auto it = map.constBegin(); it != map.constEnd(); ++it) {
|
||||
variantMap.insert(it.key(), it.value());
|
||||
}
|
||||
return variantMap;
|
||||
}
|
||||
|
|
|
@ -120,4 +120,7 @@ QString generateUid();
|
|||
QString humanFileSize(qint64 fileSize);
|
||||
QString getDebugFilePath();
|
||||
|
||||
// Convert a MapStringString to a QVariantMap
|
||||
QVariantMap mapStringStringToVariantMap(const MapStringString& map);
|
||||
|
||||
} // namespace Utils
|
||||
|
|
|
@ -56,9 +56,11 @@ BaseView {
|
|||
case WizardViewStepModel.AccountCreationOption.CreateJamiAccount:
|
||||
case WizardViewStepModel.AccountCreationOption.CreateRendezVous:
|
||||
case WizardViewStepModel.AccountCreationOption.ImportFromBackup:
|
||||
case WizardViewStepModel.AccountCreationOption.ImportFromDevice:
|
||||
AccountAdapter.createJamiAccount(WizardViewStepModel.accountCreationInfo);
|
||||
break;
|
||||
case WizardViewStepModel.AccountCreationOption.ImportFromDevice:
|
||||
AccountAdapter.startImportAccount();
|
||||
break;
|
||||
case WizardViewStepModel.AccountCreationOption.ConnectToAccountManager:
|
||||
AccountAdapter.createJAMSAccount(WizardViewStepModel.accountCreationInfo);
|
||||
break;
|
||||
|
|
|
@ -17,9 +17,13 @@
|
|||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Dialogs
|
||||
import net.jami.Adapters 1.1
|
||||
import net.jami.Models 1.1
|
||||
import net.jami.Constants 1.1
|
||||
import net.jami.Enums 1.1
|
||||
import "../../commoncomponents"
|
||||
import "../../mainview/components"
|
||||
|
||||
Rectangle {
|
||||
id: root
|
||||
|
@ -27,30 +31,99 @@ Rectangle {
|
|||
property string errorText: ""
|
||||
property int preferredHeight: importFromDevicePageColumnLayout.implicitHeight + 2 * JamiTheme.preferredMarginSize
|
||||
|
||||
signal showThisPage
|
||||
// The token is used to generate the QR code and is also provided to the user as a backup if the QR
|
||||
// code cannot be scanned. It is a URI using the scheme "jami-auth".
|
||||
readonly property string tokenUri: WizardViewStepModel.deviceLinkDetails["token"] || ""
|
||||
|
||||
function initializeOnShowUp() {
|
||||
clearAllTextFields();
|
||||
property string jamiId: ""
|
||||
|
||||
function isPasswordWrong() {
|
||||
return WizardViewStepModel.deviceLinkDetails["auth_error"] !== undefined &&
|
||||
WizardViewStepModel.deviceLinkDetails["auth_error"] !== "" &&
|
||||
WizardViewStepModel.deviceLinkDetails["auth_error"] !== "none"
|
||||
}
|
||||
|
||||
function requiresPassword() {
|
||||
return WizardViewStepModel.deviceLinkDetails["auth_scheme"] === "password"
|
||||
}
|
||||
|
||||
function requiresConfirmationBeforeClosing() {
|
||||
const state = WizardViewStepModel.deviceAuthState
|
||||
return state !== DeviceAuthStateEnum.INIT &&
|
||||
state !== DeviceAuthStateEnum.DONE
|
||||
}
|
||||
|
||||
function isLoadingState() {
|
||||
const state = WizardViewStepModel.deviceAuthState
|
||||
return state === DeviceAuthStateEnum.INIT ||
|
||||
state === DeviceAuthStateEnum.CONNECTING ||
|
||||
state === DeviceAuthStateEnum.IN_PROGRESS
|
||||
}
|
||||
|
||||
signal showThisPage
|
||||
|
||||
function clearAllTextFields() {
|
||||
connectBtn.spinnerTriggered = false;
|
||||
errorText = "";
|
||||
}
|
||||
|
||||
function errorOccurred(errorMessage) {
|
||||
errorText = errorMessage;
|
||||
connectBtn.spinnerTriggered = false;
|
||||
}
|
||||
|
||||
MessageDialog {
|
||||
id: confirmCloseDialog
|
||||
|
||||
text: JamiStrings.linkDeviceCloseWarningTitle
|
||||
informativeText: JamiStrings.linkDeviceCloseWarningMessage
|
||||
buttons: MessageDialog.Ok | MessageDialog.Cancel
|
||||
|
||||
onButtonClicked: function(button) {
|
||||
if (button === MessageDialog.Ok) {
|
||||
AccountAdapter.cancelImportAccount();
|
||||
WizardViewStepModel.previousStep();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: WizardViewStepModel
|
||||
|
||||
function onMainStepChanged() {
|
||||
if (WizardViewStepModel.mainStep === WizardViewStepModel.MainSteps.AccountCreation && WizardViewStepModel.accountCreationOption === WizardViewStepModel.AccountCreationOption.ImportFromDevice) {
|
||||
if (WizardViewStepModel.mainStep === WizardViewStepModel.MainSteps.DeviceAuthorization) {
|
||||
clearAllTextFields();
|
||||
root.showThisPage();
|
||||
}
|
||||
}
|
||||
|
||||
function onDeviceAuthStateChanged() {
|
||||
switch (WizardViewStepModel.deviceAuthState) {
|
||||
case DeviceAuthStateEnum.TOKEN_AVAILABLE:
|
||||
// Token is available and displayed as QR code
|
||||
clearAllTextFields();
|
||||
break;
|
||||
case DeviceAuthStateEnum.CONNECTING:
|
||||
// P2P connection being established
|
||||
clearAllTextFields();
|
||||
break;
|
||||
case DeviceAuthStateEnum.AUTHENTICATING:
|
||||
jamiId = WizardViewStepModel.deviceLinkDetails["peer_id"] || "";
|
||||
if (jamiId.length > 0) {
|
||||
NameDirectory.lookupAddress(CurrentAccount.id, jamiId)
|
||||
}
|
||||
break;
|
||||
case DeviceAuthStateEnum.IN_PROGRESS:
|
||||
// Account archive is being transferred
|
||||
clearAllTextFields();
|
||||
break;
|
||||
case DeviceAuthStateEnum.DONE:
|
||||
// Final state - check for specific errors
|
||||
const error = AccountAdapter.getImportErrorMessage(WizardViewStepModel.deviceLinkDetails);
|
||||
if (error.length > 0) {
|
||||
errorOccurred(error)
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
color: JamiTheme.secondaryBackgroundColor
|
||||
|
@ -65,184 +138,276 @@ Rectangle {
|
|||
width: Math.max(508, root.width - 100)
|
||||
|
||||
Text {
|
||||
|
||||
text: JamiStrings.importAccountFromAnotherDevice
|
||||
text: JamiStrings.importFromAnotherAccount
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
Layout.topMargin: JamiTheme.preferredMarginSize
|
||||
Layout.preferredWidth: Math.min(360, root.width - JamiTheme.preferredMarginSize * 2)
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
color: JamiTheme.textColor
|
||||
|
||||
color: JamiTheme.textColor
|
||||
font.pixelSize: JamiTheme.wizardViewTitleFontPixelSize
|
||||
wrapMode: Text.WordWrap
|
||||
}
|
||||
|
||||
Text {
|
||||
|
||||
text: JamiStrings.importFromDeviceDescription
|
||||
Layout.preferredWidth: Math.min(360, root.width - JamiTheme.preferredMarginSize * 2)
|
||||
Layout.topMargin: JamiTheme.wizardViewDescriptionMarginSize
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
font.pixelSize: JamiTheme.wizardViewDescriptionFontPixelSize
|
||||
font.weight: Font.Medium
|
||||
color: JamiTheme.textColor
|
||||
wrapMode: Text.WordWrap
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
lineHeight: JamiTheme.wizardViewTextLineHeight
|
||||
}
|
||||
|
||||
Flow {
|
||||
spacing: 30
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
Layout.topMargin: JamiTheme.wizardViewBlocMarginSize
|
||||
Layout.preferredWidth: Math.min(step1.width * 2 + spacing, root.width - JamiTheme.preferredMarginSize * 2)
|
||||
|
||||
InfoBox {
|
||||
id: step1
|
||||
icoSource: JamiResources.settings_24dp_svg
|
||||
title: JamiStrings.importStep1
|
||||
description: JamiStrings.importStep1Desc
|
||||
icoColor: JamiTheme.buttonTintedBlue
|
||||
}
|
||||
|
||||
InfoBox {
|
||||
id: step2
|
||||
icoSource: JamiResources.person_24dp_svg
|
||||
title: JamiStrings.importStep2
|
||||
description: JamiStrings.importStep2Desc
|
||||
icoColor: JamiTheme.buttonTintedBlue
|
||||
}
|
||||
|
||||
InfoBox {
|
||||
id: step3
|
||||
icoSource: JamiResources.finger_select_svg
|
||||
title: JamiStrings.importStep3
|
||||
description: JamiStrings.importStep3Desc
|
||||
icoColor: JamiTheme.buttonTintedBlue
|
||||
}
|
||||
|
||||
InfoBox {
|
||||
id: step4
|
||||
icoSource: JamiResources.time_clock_svg
|
||||
title: JamiStrings.importStep4
|
||||
description: JamiStrings.importStep4Desc
|
||||
icoColor: JamiTheme.buttonTintedBlue
|
||||
}
|
||||
}
|
||||
|
||||
ModalTextEdit {
|
||||
id: pinFromDevice
|
||||
|
||||
objectName: "pinFromDevice"
|
||||
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
Layout.preferredWidth: Math.min(410, root.width - JamiTheme.preferredMarginSize * 2)
|
||||
Layout.topMargin: JamiTheme.wizardViewBlocMarginSize
|
||||
|
||||
focus: visible
|
||||
|
||||
placeholderText: JamiStrings.pin
|
||||
staticText: ""
|
||||
|
||||
KeyNavigation.up: backButton
|
||||
KeyNavigation.down: passwordFromDevice
|
||||
KeyNavigation.tab: KeyNavigation.down
|
||||
|
||||
onAccepted: passwordFromDevice.forceActiveFocus()
|
||||
}
|
||||
|
||||
Text {
|
||||
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
Layout.topMargin: JamiTheme.wizardViewBlocMarginSize
|
||||
|
||||
color: JamiTheme.textColor
|
||||
wrapMode: Text.WordWrap
|
||||
text: JamiStrings.importPasswordDesc
|
||||
Layout.maximumWidth: parent.width
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
font.pixelSize: JamiTheme.wizardViewDescriptionFontPixelSize
|
||||
font.weight: Font.Medium
|
||||
lineHeight: JamiTheme.wizardViewTextLineHeight
|
||||
text: {
|
||||
switch (WizardViewStepModel.deviceAuthState) {
|
||||
case DeviceAuthStateEnum.INIT:
|
||||
return JamiStrings.waitingForToken;
|
||||
case DeviceAuthStateEnum.TOKEN_AVAILABLE:
|
||||
return JamiStrings.scanToImportAccount;
|
||||
case DeviceAuthStateEnum.CONNECTING:
|
||||
return JamiStrings.connectingToDevice;
|
||||
case DeviceAuthStateEnum.AUTHENTICATING:
|
||||
return JamiStrings.confirmAccountImport;
|
||||
case DeviceAuthStateEnum.IN_PROGRESS:
|
||||
return JamiStrings.transferringAccount;
|
||||
case DeviceAuthStateEnum.DONE:
|
||||
return errorText.length > 0 ? JamiStrings.importFailed : "";
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
}
|
||||
wrapMode: Text.WrapAtWordBoundaryOrAnywhere
|
||||
color: JamiTheme.textColor
|
||||
}
|
||||
|
||||
PasswordTextEdit {
|
||||
id: passwordFromDevice
|
||||
// Confirmation form
|
||||
ColumnLayout {
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
Layout.maximumWidth: Math.min(parent.width - 40, 400)
|
||||
visible: WizardViewStepModel.deviceAuthState === DeviceAuthStateEnum.AUTHENTICATING
|
||||
spacing: JamiTheme.wizardViewPageLayoutSpacing
|
||||
|
||||
objectName: "passwordFromDevice"
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
Layout.preferredWidth: Math.min(410, root.width - JamiTheme.preferredMarginSize * 2)
|
||||
Layout.topMargin: JamiTheme.wizardViewMarginSize
|
||||
|
||||
placeholderText: JamiStrings.enterPassword
|
||||
|
||||
KeyNavigation.up: pinFromDevice
|
||||
KeyNavigation.down: {
|
||||
if (connectBtn.enabled)
|
||||
return connectBtn;
|
||||
else if (connectBtn.spinnerTriggered)
|
||||
return passwordFromDevice;
|
||||
return backButton;
|
||||
}
|
||||
KeyNavigation.tab: KeyNavigation.down
|
||||
|
||||
onAccepted: pinFromDevice.forceActiveFocus()
|
||||
}
|
||||
|
||||
SpinnerButton {
|
||||
id: connectBtn
|
||||
|
||||
TextMetrics {
|
||||
id: textSize
|
||||
font.weight: Font.Bold
|
||||
font.pixelSize: JamiTheme.wizardViewButtonFontPixelSize
|
||||
text: connectBtn.normalText
|
||||
Text {
|
||||
Layout.fillWidth: true
|
||||
font.pixelSize: JamiTheme.wizardViewDescriptionFontPixelSize
|
||||
lineHeight: JamiTheme.wizardViewTextLineHeight
|
||||
text: JamiStrings.connectToAccount
|
||||
wrapMode: Text.WrapAtWordBoundaryOrAnywhere
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
color: JamiTheme.textColor
|
||||
font.bold: true
|
||||
}
|
||||
|
||||
objectName: "importFromDevicePageConnectBtn"
|
||||
// Account Widget (avatar + username + ID)
|
||||
Rectangle {
|
||||
id: accountContainer
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
implicitWidth: accountLayout.implicitWidth + 40
|
||||
implicitHeight: accountLayout.implicitHeight + 40
|
||||
radius: 8
|
||||
color: JamiTheme.primaryBackgroundColor
|
||||
border.width: 1
|
||||
border.color: JamiTheme.tabbarBorderColor
|
||||
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
Layout.topMargin: JamiTheme.wizardViewBlocMarginSize
|
||||
Layout.bottomMargin: errorLabel.visible ? 0 : JamiTheme.wizardViewPageBackButtonMargins
|
||||
RowLayout {
|
||||
id: accountLayout
|
||||
anchors {
|
||||
centerIn: parent
|
||||
}
|
||||
spacing: 20
|
||||
|
||||
preferredWidth: textSize.width + 2 * JamiTheme.buttontextWizzardPadding + 1
|
||||
primary: true
|
||||
Avatar {
|
||||
id: accountAvatar
|
||||
showPresenceIndicator: false
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
Layout.preferredWidth: 48
|
||||
Layout.preferredHeight: 48
|
||||
mode: Avatar.Mode.TemporaryAccount
|
||||
imageId: name.text || jamiId
|
||||
}
|
||||
|
||||
spinnerTriggeredtext: JamiStrings.generatingAccount
|
||||
normalText: JamiStrings.importButton
|
||||
ColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
spacing: 4
|
||||
|
||||
enabled: pinFromDevice.dynamicText.length !== 0 && !spinnerTriggered
|
||||
Text {
|
||||
id: name
|
||||
visible: text !== undefined && text !== ""
|
||||
|
||||
KeyNavigation.tab: backButton
|
||||
KeyNavigation.up: passwordFromDevice
|
||||
KeyNavigation.down: backButton
|
||||
Connections {
|
||||
id: registeredNameFoundConnection
|
||||
target: NameDirectory
|
||||
enabled: jamiId.length > 0
|
||||
|
||||
onClicked: {
|
||||
spinnerTriggered = true;
|
||||
WizardViewStepModel.accountCreationInfo = JamiQmlUtils.setUpAccountCreationInputPara({
|
||||
"archivePin": pinFromDevice.dynamicText,
|
||||
"password": passwordFromDevice.dynamicText
|
||||
});
|
||||
WizardViewStepModel.nextStep();
|
||||
function onRegisteredNameFound(status, address, registeredName, requestedName) {
|
||||
if (address === jamiId && status === NameDirectory.LookupStatus.SUCCESS) {
|
||||
name.text = registeredName;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Text {
|
||||
id: userId
|
||||
text: jamiId
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Password
|
||||
PasswordTextEdit {
|
||||
id: passwordField
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 10
|
||||
Layout.rightMargin: 10
|
||||
Layout.topMargin: 10
|
||||
Layout.bottomMargin: 10
|
||||
visible: requiresPassword()
|
||||
placeholderText: JamiStrings.enterPassword
|
||||
echoMode: TextInput.Password
|
||||
|
||||
onAccepted: confirmButton.clicked()
|
||||
}
|
||||
|
||||
Text {
|
||||
id: passwordErrorField
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
Layout.maximumWidth: parent.width - 40
|
||||
visible: isPasswordWrong()
|
||||
text: JamiStrings.authenticationError
|
||||
font.pointSize: JamiTheme.tinyFontSize
|
||||
color: JamiTheme.redColor
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
wrapMode: Text.WrapAtWordBoundaryOrAnywhere
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
spacing: 16
|
||||
Layout.margins: 10
|
||||
|
||||
MaterialButton {
|
||||
id: confirmButton
|
||||
text: JamiStrings.optionConfirm
|
||||
primary: true
|
||||
enabled: !passwordField.visible || passwordField.dynamicText.length > 0
|
||||
onClicked: {
|
||||
AccountAdapter.provideAccountAuthentication(passwordField.visible ? passwordField.dynamicText : "");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Label {
|
||||
id: errorLabel
|
||||
// Show busy indicator when waiting for token
|
||||
BusyIndicator {
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
visible: isLoadingState()
|
||||
Layout.preferredWidth: 50
|
||||
Layout.preferredHeight: 50
|
||||
running: visible
|
||||
}
|
||||
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
Layout.bottomMargin: JamiTheme.wizardViewPageBackButtonMargins
|
||||
// QR Code container with frame
|
||||
Rectangle {
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
Layout.preferredWidth: qrLoader.Layout.preferredWidth + 40
|
||||
Layout.preferredHeight: qrLoader.Layout.preferredHeight + 40
|
||||
visible: WizardViewStepModel.deviceAuthState === DeviceAuthStateEnum.TOKEN_AVAILABLE
|
||||
color: JamiTheme.primaryBackgroundColor
|
||||
radius: 8
|
||||
border.width: 1
|
||||
border.color: JamiTheme.tabbarBorderColor
|
||||
|
||||
visible: errorText.length !== 0
|
||||
Loader {
|
||||
id: qrLoader
|
||||
anchors.centerIn: parent
|
||||
active: WizardViewStepModel.deviceAuthState === DeviceAuthStateEnum.TOKEN_AVAILABLE
|
||||
Layout.preferredWidth: Math.min(parent.parent.width - 60, 250)
|
||||
Layout.preferredHeight: Layout.preferredWidth
|
||||
|
||||
text: errorText
|
||||
sourceComponent: Image {
|
||||
width: qrLoader.Layout.preferredWidth
|
||||
height: qrLoader.Layout.preferredHeight
|
||||
smooth: false
|
||||
fillMode: Image.PreserveAspectFit
|
||||
source: "image://qrImage/raw_" + tokenUri
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
font.pixelSize: JamiTheme.textEditError
|
||||
color: JamiTheme.redColor
|
||||
// Token URI backup text
|
||||
ColumnLayout {
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
visible: tokenUri !== ""
|
||||
spacing: 8
|
||||
|
||||
Text {
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
Layout.maximumWidth: parent.parent.width - 40
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
text: JamiStrings.cantScanQRCode
|
||||
font.pixelSize: JamiTheme.wizardViewDescriptionFontPixelSize
|
||||
lineHeight: JamiTheme.wizardViewTextLineHeight
|
||||
color: JamiTheme.textColor
|
||||
wrapMode: Text.WrapAtWordBoundaryOrAnywhere
|
||||
}
|
||||
|
||||
TextArea {
|
||||
id: tokenUriTextArea
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
Layout.maximumWidth: parent.parent.width - 40
|
||||
text: tokenUri
|
||||
font.pointSize: JamiTheme.wizardViewDescriptionFontPixelSize
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
readOnly: true
|
||||
wrapMode: Text.WrapAtWordBoundaryOrAnywhere
|
||||
selectByMouse: true
|
||||
background: Rectangle {
|
||||
color: JamiTheme.primaryBackgroundColor
|
||||
radius: 5
|
||||
border.width: 1
|
||||
border.color: JamiTheme.tabbarBorderColor
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Error view
|
||||
ColumnLayout {
|
||||
id: errorColumn
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
Layout.maximumWidth: parent.width - 40
|
||||
visible: errorText !== ""
|
||||
spacing: 16
|
||||
|
||||
Text {
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
Layout.maximumWidth: parent.width
|
||||
text: errorText
|
||||
color: JamiTheme.textColor
|
||||
font.pointSize: JamiTheme.mediumFontSize
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
wrapMode: Text.WordWrap
|
||||
}
|
||||
|
||||
MaterialButton {
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
text: JamiStrings.optionTryAgain
|
||||
toolTipText: JamiStrings.optionTryAgain
|
||||
primary: true
|
||||
onClicked: {
|
||||
AccountAdapter.cancelImportAccount();
|
||||
WizardViewStepModel.previousStep();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BackButton {
|
||||
// Back button
|
||||
JamiPushButton {
|
||||
id: backButton
|
||||
QWKSetParentHitTestVisible {
|
||||
}
|
||||
|
||||
objectName: "importFromDevicePageBackButton"
|
||||
|
||||
|
@ -250,12 +415,18 @@ Rectangle {
|
|||
anchors.top: parent.top
|
||||
anchors.margins: JamiTheme.wizardViewPageBackButtonMargins
|
||||
|
||||
visible: !connectBtn.spinnerTriggered
|
||||
preferredSize: 36
|
||||
imageContainerWidth: 20
|
||||
source: JamiResources.ic_arrow_back_24dp_svg
|
||||
|
||||
KeyNavigation.tab: pinFromDevice
|
||||
KeyNavigation.up: connectBtn.enabled ? connectBtn : passwordFromDevice
|
||||
KeyNavigation.down: pinFromDevice
|
||||
visible: WizardViewStepModel.deviceAuthState !== DeviceAuthStateEnum.IN_PROGRESS
|
||||
|
||||
onClicked: WizardViewStepModel.previousStep()
|
||||
onClicked: {
|
||||
if (requiresConfirmationBeforeClosing()) {
|
||||
confirmCloseDialog.open();
|
||||
} else {
|
||||
WizardViewStepModel.previousStep();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
#include "appsettingsmanager.h"
|
||||
#include "lrcinstance.h"
|
||||
#include "global.h"
|
||||
|
||||
#include "api/accountmodel.h"
|
||||
|
||||
|
@ -46,17 +47,31 @@ WizardViewStepModel::WizardViewStepModel(LRCInstance* lrcInstance,
|
|||
|
||||
Q_EMIT accountIsReady(accountId);
|
||||
});
|
||||
|
||||
// Connect to account model signals to track import progress
|
||||
connect(&lrcInstance_->accountModel(),
|
||||
&AccountModel::deviceAuthStateChanged,
|
||||
this,
|
||||
[this](const QString& accountID, int state, const MapStringString& details) {
|
||||
set_deviceLinkDetails(Utils::mapStringStringToVariantMap(details));
|
||||
set_deviceAuthState(static_cast<lrc::api::account::DeviceAuthState>(state));
|
||||
});
|
||||
}
|
||||
|
||||
void
|
||||
WizardViewStepModel::startAccountCreationFlow(AccountCreationOption accountCreationOption)
|
||||
{
|
||||
using namespace lrc::api::account;
|
||||
set_accountCreationOption(accountCreationOption);
|
||||
if (accountCreationOption == AccountCreationOption::CreateJamiAccount
|
||||
|| accountCreationOption == AccountCreationOption::CreateRendezVous)
|
||||
if (accountCreationOption == AccountCreationOption::ImportFromDevice) {
|
||||
set_mainStep(MainSteps::DeviceAuthorization);
|
||||
Q_EMIT createAccountRequested(accountCreationOption);
|
||||
} else if (accountCreationOption == AccountCreationOption::CreateJamiAccount
|
||||
|| accountCreationOption == AccountCreationOption::CreateRendezVous) {
|
||||
set_mainStep(MainSteps::NameRegistration);
|
||||
else
|
||||
} else {
|
||||
set_mainStep(MainSteps::AccountCreation);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -80,6 +95,10 @@ WizardViewStepModel::previousStep()
|
|||
reset();
|
||||
break;
|
||||
}
|
||||
case MainSteps::DeviceAuthorization: {
|
||||
reset();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -88,4 +107,6 @@ WizardViewStepModel::reset()
|
|||
{
|
||||
set_accountCreationOption(AccountCreationOption::None);
|
||||
set_mainStep(MainSteps::Initial);
|
||||
set_deviceAuthState(lrc::api::account::DeviceAuthState::INIT);
|
||||
set_deviceLinkDetails({});
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "qtutils.h"
|
||||
#include "api/account.h" // Include for DeviceAuthState
|
||||
|
||||
#include <QObject>
|
||||
#include <QVariant>
|
||||
|
@ -29,6 +30,21 @@ class AccountAdapter;
|
|||
class LRCInstance;
|
||||
class AppSettingsManager;
|
||||
|
||||
class DeviceAuthStateEnum : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
enum State {
|
||||
INIT = static_cast<int>(lrc::api::account::DeviceAuthState::INIT),
|
||||
TOKEN_AVAILABLE = static_cast<int>(lrc::api::account::DeviceAuthState::TOKEN_AVAILABLE),
|
||||
CONNECTING = static_cast<int>(lrc::api::account::DeviceAuthState::CONNECTING),
|
||||
AUTHENTICATING = static_cast<int>(lrc::api::account::DeviceAuthState::AUTHENTICATING),
|
||||
IN_PROGRESS = static_cast<int>(lrc::api::account::DeviceAuthState::IN_PROGRESS),
|
||||
DONE = static_cast<int>(lrc::api::account::DeviceAuthState::DONE)
|
||||
};
|
||||
Q_ENUM(State)
|
||||
};
|
||||
|
||||
class WizardViewStepModel : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
@ -37,9 +53,10 @@ class WizardViewStepModel : public QObject
|
|||
|
||||
public:
|
||||
enum class MainSteps {
|
||||
Initial, // Initial welcome step.
|
||||
AccountCreation, // General account creation step.
|
||||
NameRegistration, // Name registration step : CreateJamiAccount, CreateRendezVous
|
||||
Initial, // Initial welcome step.
|
||||
AccountCreation, // General account creation step.
|
||||
NameRegistration, // Name registration step : CreateJamiAccount, CreateRendezVous
|
||||
DeviceAuthorization // Add new step for device authorization.
|
||||
};
|
||||
Q_ENUM(MainSteps)
|
||||
|
||||
|
@ -57,6 +74,8 @@ public:
|
|||
QML_PROPERTY(MainSteps, mainStep)
|
||||
QML_PROPERTY(AccountCreationOption, accountCreationOption)
|
||||
QML_PROPERTY(QVariantMap, accountCreationInfo)
|
||||
QML_PROPERTY(lrc::api::account::DeviceAuthState, deviceAuthState)
|
||||
QML_PROPERTY(QVariantMap, deviceLinkDetails)
|
||||
|
||||
public:
|
||||
static WizardViewStepModel* create(QQmlEngine*, QJSEngine*)
|
||||
|
|
|
@ -117,12 +117,14 @@ public Q_SLOTS:
|
|||
void slotAccountStatusChanged(const QString& accountID, const api::account::Status status);
|
||||
|
||||
/**
|
||||
* Emit exportOnRingEnded.
|
||||
* Emit deviceAuthStateChanged.
|
||||
* @param accountId
|
||||
* @param status
|
||||
* @param pin
|
||||
* @param state
|
||||
* @param details map
|
||||
*/
|
||||
void slotExportOnRingEnded(const QString& accountID, int status, const QString& pin);
|
||||
void slotDeviceAuthStateChanged(const QString& accountID,
|
||||
int state,
|
||||
const MapStringString& details);
|
||||
|
||||
/**
|
||||
* @param accountId
|
||||
|
@ -282,11 +284,12 @@ AccountModel::setAlias(const QString& accountId, const QString& alias, bool save
|
|||
accountInfo.profileInfo.alias = alias;
|
||||
|
||||
if (save)
|
||||
ConfigurationManager::instance().updateProfile(accountId,
|
||||
alias,
|
||||
"",
|
||||
"",
|
||||
5);// flag out of range to avoid updating avatar
|
||||
ConfigurationManager::instance()
|
||||
.updateProfile(accountId,
|
||||
alias,
|
||||
"",
|
||||
"",
|
||||
5); // flag out of range to avoid updating avatar
|
||||
Q_EMIT profileUpdated(accountId);
|
||||
}
|
||||
|
||||
|
@ -323,9 +326,30 @@ AccountModel::exportToFile(const QString& accountId,
|
|||
}
|
||||
|
||||
bool
|
||||
AccountModel::exportOnRing(const QString& accountId, const QString& password) const
|
||||
AccountModel::provideAccountAuthentication(const QString& accountId,
|
||||
const QString& credentialsFromUser) const
|
||||
{
|
||||
return ConfigurationManager::instance().exportOnRing(accountId, password);
|
||||
return ConfigurationManager::instance().provideAccountAuthentication(accountId,
|
||||
credentialsFromUser,
|
||||
"password");
|
||||
}
|
||||
|
||||
int32_t
|
||||
AccountModel::addDevice(const QString& accountId, const QString& token) const
|
||||
{
|
||||
return ConfigurationManager::instance().addDevice(accountId, token);
|
||||
}
|
||||
|
||||
bool
|
||||
AccountModel::confirmAddDevice(const QString& accountId, uint32_t operationId) const
|
||||
{
|
||||
return ConfigurationManager::instance().confirmAddDevice(accountId, operationId);
|
||||
}
|
||||
|
||||
bool
|
||||
AccountModel::cancelAddDevice(const QString& accountId, uint32_t operationId) const
|
||||
{
|
||||
return ConfigurationManager::instance().cancelAddDevice(accountId, operationId);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -403,9 +427,9 @@ AccountModelPimpl::AccountModelPimpl(AccountModel& linked,
|
|||
this,
|
||||
&AccountModelPimpl::slotVolatileAccountDetailsChanged);
|
||||
connect(&callbacksHandler,
|
||||
&CallbacksHandler::exportOnRingEnded,
|
||||
this,
|
||||
&AccountModelPimpl::slotExportOnRingEnded);
|
||||
&CallbacksHandler::deviceAuthStateChanged,
|
||||
&linked,
|
||||
&AccountModel::deviceAuthStateChanged);
|
||||
connect(&callbacksHandler,
|
||||
&CallbacksHandler::nameRegistrationEnded,
|
||||
this,
|
||||
|
@ -594,23 +618,13 @@ AccountModelPimpl::slotVolatileAccountDetailsChanged(const QString& accountId,
|
|||
}
|
||||
|
||||
void
|
||||
AccountModelPimpl::slotExportOnRingEnded(const QString& accountID, int status, const QString& pin)
|
||||
AccountModelPimpl::slotDeviceAuthStateChanged(const QString& accountId,
|
||||
int state,
|
||||
const MapStringString& details)
|
||||
{
|
||||
account::ExportOnRingStatus convertedStatus = account::ExportOnRingStatus::INVALID;
|
||||
switch (status) {
|
||||
case 0:
|
||||
convertedStatus = account::ExportOnRingStatus::SUCCESS;
|
||||
break;
|
||||
case 1:
|
||||
convertedStatus = account::ExportOnRingStatus::WRONG_PASSWORD;
|
||||
break;
|
||||
case 2:
|
||||
convertedStatus = account::ExportOnRingStatus::NETWORK_ERROR;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
Q_EMIT linked.exportOnRingEnded(accountID, convertedStatus, pin);
|
||||
// implement business logic here
|
||||
// can be bypassed with a signal to signal
|
||||
Q_EMIT linked.deviceAuthStateChanged(accountId, state, details);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -673,7 +687,11 @@ AccountModelPimpl::slotRegisteredNameFound(const QString& accountId,
|
|||
default:
|
||||
break;
|
||||
}
|
||||
Q_EMIT linked.registeredNameFound(accountId, requestedName, convertedStatus, address, registeredName);
|
||||
Q_EMIT linked.registeredNameFound(accountId,
|
||||
requestedName,
|
||||
convertedStatus,
|
||||
address,
|
||||
registeredName);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1041,32 +1059,47 @@ account::ConfProperties_t::toDetails() const
|
|||
|
||||
QString
|
||||
AccountModel::createNewAccount(profile::Type type,
|
||||
const MapStringString& config,
|
||||
const QString& displayName,
|
||||
const QString& archivePath,
|
||||
const QString& password,
|
||||
const QString& pin,
|
||||
const QString& uri,
|
||||
const MapStringString& config)
|
||||
const QString& uri)
|
||||
{
|
||||
// Get the template for the account type to prefill the details
|
||||
MapStringString details = type == profile::Type::SIP
|
||||
? ConfigurationManager::instance().getAccountTemplate("SIP")
|
||||
: ConfigurationManager::instance().getAccountTemplate("RING");
|
||||
using namespace libjami::Account;
|
||||
details[ConfProperties::TYPE] = type == profile::Type::SIP ? "SIP" : "RING";
|
||||
details[ConfProperties::DISPLAYNAME] = displayName;
|
||||
details[ConfProperties::ALIAS] = displayName;
|
||||
details[ConfProperties::UPNP_ENABLED] = "true";
|
||||
details[ConfProperties::ARCHIVE_PASSWORD] = password;
|
||||
details[ConfProperties::ARCHIVE_PIN] = pin;
|
||||
details[ConfProperties::ARCHIVE_PATH] = archivePath;
|
||||
if (type == profile::Type::SIP)
|
||||
details[ConfProperties::USERNAME] = uri;
|
||||
|
||||
// Add the supplied config to the details
|
||||
if (!config.isEmpty()) {
|
||||
for (MapStringString::const_iterator it = config.begin(); it != config.end(); it++) {
|
||||
details[it.key()] = it.value();
|
||||
}
|
||||
}
|
||||
|
||||
using namespace libjami::Account;
|
||||
|
||||
// Add the rest of the details if we are not creating an ephemeral account for linking
|
||||
// in which case the ARCHIVE_URL was set to "jami-auth" or the MANAGER_URI was set to
|
||||
// the account manager URI in the case of a remote account manager connection
|
||||
if (details[ConfProperties::ARCHIVE_URL].isEmpty()
|
||||
&& details[ConfProperties::MANAGER_URI].isEmpty()) {
|
||||
details[ConfProperties::TYPE] = type == profile::Type::SIP ? "SIP" : "RING";
|
||||
details[ConfProperties::DISPLAYNAME] = displayName;
|
||||
details[ConfProperties::ALIAS] = displayName;
|
||||
details[ConfProperties::UPNP_ENABLED] = "true";
|
||||
details[ConfProperties::ARCHIVE_PASSWORD] = password;
|
||||
details[ConfProperties::ARCHIVE_PIN] = pin;
|
||||
details[ConfProperties::ARCHIVE_PATH] = archivePath;
|
||||
|
||||
// Override the username with the provided URI if it's a SIP account
|
||||
if (type == profile::Type::SIP) {
|
||||
details[ConfProperties::USERNAME] = uri;
|
||||
}
|
||||
}
|
||||
|
||||
// Actually add the account and return the account ID
|
||||
QString accountId = ConfigurationManager::instance().addAccount(details);
|
||||
return accountId;
|
||||
}
|
||||
|
@ -1077,20 +1110,24 @@ AccountModel::connectToAccountManager(const QString& username,
|
|||
const QString& serverUri,
|
||||
const MapStringString& config)
|
||||
{
|
||||
MapStringString details = ConfigurationManager::instance().getAccountTemplate("RING");
|
||||
MapStringString details = config;
|
||||
using namespace libjami::Account;
|
||||
details[ConfProperties::TYPE] = "RING";
|
||||
details[ConfProperties::MANAGER_URI] = serverUri;
|
||||
details[ConfProperties::MANAGER_USERNAME] = username;
|
||||
details[ConfProperties::ARCHIVE_PASSWORD] = password;
|
||||
if (!config.isEmpty()) {
|
||||
for (MapStringString::const_iterator it = config.begin(); it != config.end(); it++) {
|
||||
details[it.key()] = it.value();
|
||||
}
|
||||
}
|
||||
return createNewAccount(profile::Type::JAMI, details);
|
||||
}
|
||||
|
||||
QString accountId = ConfigurationManager::instance().addAccount(details);
|
||||
return accountId;
|
||||
QString
|
||||
AccountModel::createDeviceImportAccount()
|
||||
{
|
||||
// auto details = ConfigurationManager::instance().getAccountTemplate("RING");
|
||||
MapStringString details;
|
||||
using namespace libjami::Account;
|
||||
details[ConfProperties::TYPE] = "RING";
|
||||
details[ConfProperties::ARCHIVE_URL] = "jami-auth";
|
||||
return createNewAccount(profile::Type::JAMI, details);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -188,9 +188,65 @@ struct ConfProperties_t
|
|||
MapStringString toDetails() const;
|
||||
};
|
||||
|
||||
// Possible account export status
|
||||
enum class ExportOnRingStatus { SUCCESS = 0, WRONG_PASSWORD = 1, NETWORK_ERROR = 2, INVALID };
|
||||
Q_ENUM_NS(ExportOnRingStatus)
|
||||
// The following statuses are used to track the status of
|
||||
// device-linking and account-import
|
||||
enum class DeviceAuthState {
|
||||
INIT = 0,
|
||||
TOKEN_AVAILABLE = 1,
|
||||
CONNECTING = 2,
|
||||
AUTHENTICATING = 3,
|
||||
IN_PROGRESS = 4,
|
||||
DONE = 5
|
||||
};
|
||||
Q_ENUM_NS(DeviceAuthState)
|
||||
|
||||
enum class DeviceLinkError {
|
||||
WRONG_PASSWORD, // auth_error, invalid_credentials
|
||||
NETWORK, // network
|
||||
TIMEOUT, // timeout
|
||||
STATE, // state
|
||||
CANCELED, // canceled
|
||||
UNKNOWN // fallback
|
||||
};
|
||||
|
||||
Q_ENUM_NS(DeviceLinkError)
|
||||
|
||||
inline DeviceLinkError
|
||||
mapLinkDeviceError(const std::string& error)
|
||||
{
|
||||
if (error == "auth_error" || error == "invalid_credentials")
|
||||
return DeviceLinkError::WRONG_PASSWORD;
|
||||
if (error == "network")
|
||||
return DeviceLinkError::NETWORK;
|
||||
if (error == "timeout")
|
||||
return DeviceLinkError::TIMEOUT;
|
||||
if (error == "state")
|
||||
return DeviceLinkError::STATE;
|
||||
if (error == "canceled")
|
||||
return DeviceLinkError::CANCELED;
|
||||
return DeviceLinkError::UNKNOWN;
|
||||
}
|
||||
|
||||
inline QString
|
||||
getLinkDeviceString(DeviceLinkError error)
|
||||
{
|
||||
switch (error) {
|
||||
case DeviceLinkError::WRONG_PASSWORD:
|
||||
return QObject::tr(
|
||||
"An authentication error occurred.\nPlease check credentials and try again.");
|
||||
case DeviceLinkError::NETWORK:
|
||||
return QObject::tr("A network error occurred.\nPlease verify your connection.");
|
||||
case DeviceLinkError::TIMEOUT:
|
||||
return QObject::tr("The operation has timed out.\nPlease try again.");
|
||||
case DeviceLinkError::STATE:
|
||||
return QObject::tr("An error occurred while exporting the account.\nPlease try again.");
|
||||
case DeviceLinkError::CANCELED:
|
||||
return QObject::tr("Operation was canceled.");
|
||||
case DeviceLinkError::UNKNOWN:
|
||||
default:
|
||||
return QObject::tr("An unexpected error occurred.\nPlease try again.");
|
||||
}
|
||||
}
|
||||
|
||||
enum class RegisterNameStatus {
|
||||
SUCCESS = 0,
|
||||
|
|
|
@ -112,13 +112,37 @@ public:
|
|||
Q_INVOKABLE bool exportToFile(const QString& accountId,
|
||||
const QString& path,
|
||||
const QString& password = {}) const;
|
||||
|
||||
/**
|
||||
* Call exportOnRing from the daemon
|
||||
* Provide authentication for an account
|
||||
* @param accountId
|
||||
* @param password
|
||||
* @param credentialsFromUser
|
||||
* @return if the authentication is successful
|
||||
*/
|
||||
Q_INVOKABLE bool provideAccountAuthentication(const QString& accountId,
|
||||
const QString& credentialsFromUser) const;
|
||||
|
||||
/**
|
||||
* @param accountId
|
||||
* @param uri
|
||||
* @return if the export is initialized
|
||||
*/
|
||||
Q_INVOKABLE bool exportOnRing(const QString& accountId, const QString& password) const;
|
||||
Q_INVOKABLE int32_t addDevice(const QString& accountId, const QString& token) const;
|
||||
|
||||
/**
|
||||
* Confirm the addition of a device
|
||||
* @param accountId
|
||||
* @param operationId
|
||||
*/
|
||||
Q_INVOKABLE bool confirmAddDevice(const QString& accountId, uint32_t operationId) const;
|
||||
|
||||
/**
|
||||
* Cancel the addition of a device
|
||||
* @param accountId
|
||||
* @param operationId
|
||||
*/
|
||||
Q_INVOKABLE bool cancelAddDevice(const QString& accountId, uint32_t operationId) const;
|
||||
|
||||
/**
|
||||
* Call removeAccount from the daemon
|
||||
* @param accountId to remove
|
||||
|
@ -141,7 +165,7 @@ public:
|
|||
* @param avatar
|
||||
* @throws out_of_range exception if account is not found
|
||||
*/
|
||||
void setAvatar(const QString& accountId, const QString& avatar, bool save = true, int flag =0);
|
||||
void setAvatar(const QString& accountId, const QString& avatar, bool save = true, int flag = 0);
|
||||
/**
|
||||
* Change the alias of an account
|
||||
* @param accountId
|
||||
|
@ -159,18 +183,7 @@ public:
|
|||
Q_INVOKABLE bool registerName(const QString& accountId,
|
||||
const QString& password,
|
||||
const QString& username);
|
||||
/**
|
||||
* Connect to JAMS to retrieve the account
|
||||
* @param username
|
||||
* @param password
|
||||
* @param serverUri
|
||||
* @param config
|
||||
* @return the account id
|
||||
*/
|
||||
static QString connectToAccountManager(const QString& username,
|
||||
const QString& password,
|
||||
const QString& serverUri,
|
||||
const MapStringString& config = MapStringString());
|
||||
|
||||
/**
|
||||
* Create a new Ring or SIP account
|
||||
* @param type determine if the new account will be a Ring account or a SIP one
|
||||
|
@ -184,12 +197,32 @@ public:
|
|||
* @return the created account
|
||||
*/
|
||||
static QString createNewAccount(profile::Type type,
|
||||
const MapStringString& config = MapStringString(),
|
||||
const QString& displayName = "",
|
||||
const QString& archivePath = "",
|
||||
const QString& password = "",
|
||||
const QString& pin = "",
|
||||
const QString& uri = "",
|
||||
const MapStringString& config = MapStringString());
|
||||
const QString& uri = "");
|
||||
|
||||
/**
|
||||
* Connect to JAMS to retrieve the account
|
||||
* @param username
|
||||
* @param password
|
||||
* @param serverUri
|
||||
* @param config
|
||||
* @return the account id
|
||||
*/
|
||||
static QString connectToAccountManager(const QString& username,
|
||||
const QString& password,
|
||||
const QString& serverUri,
|
||||
const MapStringString& config = MapStringString());
|
||||
|
||||
/**
|
||||
* Create a simple ephemeral account from a device import
|
||||
* @return the account id of the created account
|
||||
*/
|
||||
static QString createDeviceImportAccount();
|
||||
|
||||
/**
|
||||
* Set an account to the first position
|
||||
*/
|
||||
|
@ -296,14 +329,24 @@ Q_SIGNALS:
|
|||
void profileUpdated(const QString& accountID);
|
||||
|
||||
/**
|
||||
* Connect this signal to know when an account is exported on the DHT
|
||||
* Device authentication state has changed
|
||||
* @param accountID
|
||||
* @param status
|
||||
* @param pin
|
||||
* @param state
|
||||
* @param details map
|
||||
*/
|
||||
void exportOnRingEnded(const QString& accountID,
|
||||
account::ExportOnRingStatus status,
|
||||
const QString& pin);
|
||||
void deviceAuthStateChanged(const QString& accountID, int state, const MapStringString& details);
|
||||
|
||||
/**
|
||||
* Add device state has changed
|
||||
* @param accountID
|
||||
* @param operationId
|
||||
* @param state
|
||||
* @param details map
|
||||
*/
|
||||
void addDeviceStateChanged(const QString& accountID,
|
||||
uint32_t operationId,
|
||||
int state,
|
||||
const MapStringString& details);
|
||||
|
||||
/**
|
||||
* Name registration has ended
|
||||
|
|
|
@ -242,9 +242,9 @@ CallbacksHandler::CallbacksHandler(const Lrc& parent)
|
|||
Qt::QueuedConnection);
|
||||
|
||||
connect(&ConfigurationManager::instance(),
|
||||
&ConfigurationManagerInterface::exportOnRingEnded,
|
||||
&ConfigurationManagerInterface::deviceAuthStateChanged,
|
||||
this,
|
||||
&CallbacksHandler::slotExportOnRingEnded,
|
||||
&CallbacksHandler::slotDeviceAuthStateChanged,
|
||||
Qt::QueuedConnection);
|
||||
|
||||
connect(&ConfigurationManager::instance(),
|
||||
|
@ -546,7 +546,9 @@ CallbacksHandler::slotIncomingMessage(const QString& accountId,
|
|||
}
|
||||
|
||||
void
|
||||
CallbacksHandler::slotConferenceCreated(const QString& accountId, const QString& convId, const QString& callId)
|
||||
CallbacksHandler::slotConferenceCreated(const QString& accountId,
|
||||
const QString& convId,
|
||||
const QString& callId)
|
||||
{
|
||||
Q_EMIT conferenceCreated(accountId, convId, callId);
|
||||
}
|
||||
|
@ -678,9 +680,11 @@ CallbacksHandler::slotDeviceRevokationEnded(const QString& accountId,
|
|||
}
|
||||
|
||||
void
|
||||
CallbacksHandler::slotExportOnRingEnded(const QString& accountId, int status, const QString& pin)
|
||||
CallbacksHandler::slotDeviceAuthStateChanged(const QString& accountId,
|
||||
int state,
|
||||
const MapStringString& details)
|
||||
{
|
||||
Q_EMIT exportOnRingEnded(accountId, status, pin);
|
||||
Q_EMIT deviceAuthStateChanged(accountId, state, details);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -171,7 +171,9 @@ Q_SIGNALS:
|
|||
* Connect this signal to know when a new conference is created
|
||||
* @param callId of the conference
|
||||
*/
|
||||
void conferenceCreated(const QString& accountId, const QString& conversationId, const QString& callId);
|
||||
void conferenceCreated(const QString& accountId,
|
||||
const QString& conversationId,
|
||||
const QString& callId);
|
||||
void conferenceChanged(const QString& accountId, const QString& confId, const QString& state);
|
||||
/**
|
||||
* Connect this signal to know when a conference is removed
|
||||
|
@ -235,12 +237,12 @@ Q_SIGNALS:
|
|||
const QString& userPhoto);
|
||||
|
||||
/**
|
||||
* Emit exportOnRingEnded
|
||||
* Device authentication state has changed
|
||||
* @param accountId
|
||||
* @param status SUCCESS = 0, WRONG_PASSWORD = 1, NETWORK_ERROR = 2
|
||||
* @param pin
|
||||
* @param state
|
||||
* @param details map
|
||||
*/
|
||||
void exportOnRingEnded(const QString& accountId, int status, const QString& pin);
|
||||
void deviceAuthStateChanged(const QString& accountId, int state, const MapStringString& details);
|
||||
|
||||
/**
|
||||
* Name registration has ended
|
||||
|
@ -504,7 +506,9 @@ private Q_SLOTS:
|
|||
* @param callId of the conference
|
||||
* @param conversationId of the conference
|
||||
*/
|
||||
void slotConferenceCreated(const QString& accountId, const QString& conversationId, const QString& callId);
|
||||
void slotConferenceCreated(const QString& accountId,
|
||||
const QString& conversationId,
|
||||
const QString& callId);
|
||||
/**
|
||||
* Emit conferenceRemove
|
||||
* @param accountId
|
||||
|
@ -574,12 +578,14 @@ private Q_SLOTS:
|
|||
const QString& userPhoto);
|
||||
|
||||
/**
|
||||
* Emit exportOnRingEnded
|
||||
* Device authentication state has changed
|
||||
* @param accountId
|
||||
* @param status SUCCESS = 0, WRONG_PASSWORD = 1, NETWORK_ERROR = 2
|
||||
* @param pin
|
||||
* @param state
|
||||
* @param details map
|
||||
*/
|
||||
void slotExportOnRingEnded(const QString& accountId, int status, const QString& pin);
|
||||
void slotDeviceAuthStateChanged(const QString& accountId,
|
||||
int state,
|
||||
const MapStringString& details);
|
||||
|
||||
/**
|
||||
* Emit nameRegistrationEnded
|
||||
|
|
|
@ -36,11 +36,6 @@ NameDirectoryPrivate::NameDirectoryPrivate(NameDirectory* q)
|
|||
this,
|
||||
&NameDirectoryPrivate::slotRegisteredNameFound,
|
||||
Qt::QueuedConnection);
|
||||
connect(&configurationManager,
|
||||
&ConfigurationManagerInterface::exportOnRingEnded,
|
||||
this,
|
||||
&NameDirectoryPrivate::slotExportOnRingEnded,
|
||||
Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
NameDirectory::NameDirectory()
|
||||
|
@ -100,16 +95,6 @@ NameDirectoryPrivate::slotRegisteredNameFound(const QString& accountId,
|
|||
requestedName);
|
||||
}
|
||||
|
||||
// Export account has ended with pin generated
|
||||
void
|
||||
NameDirectoryPrivate::slotExportOnRingEnded(const QString& accountId, int status, const QString& pin)
|
||||
{
|
||||
LC_DBG << "Export on ring ended for account: " << accountId << "status: " << status
|
||||
<< "PIN: " << pin;
|
||||
|
||||
Q_EMIT q_ptr->exportOnRingEnded(static_cast<NameDirectory::ExportOnRingStatus>(status), pin);
|
||||
}
|
||||
|
||||
// Lookup a name
|
||||
bool
|
||||
NameDirectory::lookupName(const QString& accountId,
|
||||
|
|
|
@ -40,15 +40,16 @@ public:
|
|||
enum class LookupStatus { SUCCESS = 0, INVALID_NAME = 1, NOT_FOUND = 2, ERROR = 3 };
|
||||
Q_ENUM(LookupStatus)
|
||||
|
||||
enum class ExportOnRingStatus { SUCCESS = 0, WRONG_PASSWORD = 1, NETWORK_ERROR = 2, INVALID };
|
||||
Q_ENUM(ExportOnRingStatus)
|
||||
|
||||
// Singleton
|
||||
static NameDirectory& instance();
|
||||
|
||||
// Lookup
|
||||
Q_INVOKABLE bool lookupName(const QString& accountId, const QString& name, const QString& nameServiceURL = "") const;
|
||||
Q_INVOKABLE bool lookupAddress(const QString& accountId, const QString& address, const QString& nameServiceURL = "") const;
|
||||
Q_INVOKABLE bool lookupName(const QString& accountId,
|
||||
const QString& name,
|
||||
const QString& nameServiceURL = "") const;
|
||||
Q_INVOKABLE bool lookupAddress(const QString& accountId,
|
||||
const QString& address,
|
||||
const QString& nameServiceURL = "") const;
|
||||
|
||||
private:
|
||||
// Constructors & Destructors
|
||||
|
@ -70,8 +71,5 @@ Q_SIGNALS:
|
|||
const QString& address,
|
||||
const QString& registeredName,
|
||||
const QString& requestedName);
|
||||
|
||||
// Export account has ended with pin generated
|
||||
void exportOnRingEnded(NameDirectory::ExportOnRingStatus status, const QString& pin);
|
||||
};
|
||||
Q_DECLARE_METATYPE(NameDirectory*)
|
||||
|
|
|
@ -37,5 +37,4 @@ public Q_SLOTS:
|
|||
int status,
|
||||
const QString& address,
|
||||
const QString& registeredName);
|
||||
void slotExportOnRingEnded(const QString& accountId, int status, const QString& pin);
|
||||
};
|
||||
|
|
|
@ -150,11 +150,23 @@ public:
|
|||
QString(displayName.c_str()),
|
||||
QString(userPhoto.c_str()));
|
||||
}),
|
||||
exportable_callback<ConfigurationSignal::ExportOnRingEnded>(
|
||||
[this](const std::string& accountId, int status, const std::string& pin) {
|
||||
Q_EMIT this->exportOnRingEnded(QString(accountId.c_str()),
|
||||
status,
|
||||
QString(pin.c_str()));
|
||||
exportable_callback<ConfigurationSignal::AddDeviceStateChanged>(
|
||||
[this](const std::string& accountId,
|
||||
uint32_t operationId,
|
||||
int state,
|
||||
const std::map<std::string, std::string>& details) {
|
||||
Q_EMIT this->addDeviceStateChanged(QString(accountId.c_str()),
|
||||
operationId,
|
||||
state,
|
||||
convertMap(details));
|
||||
}),
|
||||
exportable_callback<ConfigurationSignal::DeviceAuthStateChanged>(
|
||||
[this](const std::string& accountId,
|
||||
int state,
|
||||
const std::map<std::string, std::string>& details) {
|
||||
Q_EMIT this->deviceAuthStateChanged(QString(accountId.c_str()),
|
||||
state,
|
||||
convertMap(details));
|
||||
}),
|
||||
exportable_callback<ConfigurationSignal::NameRegistrationEnded>(
|
||||
[this](const std::string& accountId, int status, const std::string& name) {
|
||||
|
@ -431,9 +443,28 @@ public Q_SLOTS: // METHODS
|
|||
path.toStdString());
|
||||
}
|
||||
|
||||
bool exportOnRing(const QString& accountId, const QString& password)
|
||||
bool provideAccountAuthentication(const QString& accountId,
|
||||
const QString& credentialsFromUser,
|
||||
const QString scheme = "password")
|
||||
{
|
||||
return libjami::exportOnRing(accountId.toStdString(), password.toStdString());
|
||||
return libjami::provideAccountAuthentication(accountId.toStdString(),
|
||||
credentialsFromUser.toStdString(),
|
||||
scheme.toStdString());
|
||||
}
|
||||
|
||||
int32_t addDevice(const QString& accountId, const QString& token)
|
||||
{
|
||||
return libjami::addDevice(accountId.toStdString(), token.toStdString());
|
||||
}
|
||||
|
||||
bool confirmAddDevice(const QString& accountId, uint32_t operationId)
|
||||
{
|
||||
return libjami::confirmAddDevice(accountId.toStdString(), operationId);
|
||||
}
|
||||
|
||||
bool cancelAddDevice(const QString& accountId, uint32_t operationId)
|
||||
{
|
||||
return libjami::cancelAddDevice(accountId.toStdString(), operationId);
|
||||
}
|
||||
|
||||
bool exportToFile(const QString& accountId,
|
||||
|
@ -498,8 +529,7 @@ public Q_SLOTS: // METHODS
|
|||
displayName.toStdString(),
|
||||
avatarPath.toStdString(),
|
||||
fileType.toStdString(),
|
||||
flag
|
||||
);
|
||||
flag);
|
||||
}
|
||||
|
||||
QStringList getAccountList()
|
||||
|
@ -1197,7 +1227,11 @@ Q_SIGNALS: // SIGNALS
|
|||
const QString& certId,
|
||||
const QString& status);
|
||||
void knownDevicesChanged(const QString& accountId, const MapStringString& devices);
|
||||
void exportOnRingEnded(const QString& accountId, int status, const QString& pin);
|
||||
void addDeviceStateChanged(const QString& accountId,
|
||||
uint32_t operationId,
|
||||
int state,
|
||||
const MapStringString& details);
|
||||
void deviceAuthStateChanged(const QString& accountId, int state, const MapStringString& details);
|
||||
void incomingAccountMessage(const QString& accountId,
|
||||
const QString& from,
|
||||
const QString msgId,
|
||||
|
|
Loading…
Add table
Reference in a new issue