mirror of
https://git.jami.net/savoirfairelinux/jami-client-qt.git
synced 2025-07-19 06:55:24 +02:00
link-device: apply new design and add QR code
GitLab: #1253 Change-Id: Ib47a081e4e5d714e98fb397732ff9232b62afc36
This commit is contained in:
parent
63c3d0bf2e
commit
ad35d108f2
8 changed files with 271 additions and 98 deletions
|
@ -436,7 +436,7 @@ Item {
|
|||
|
||||
// LinkedDevices
|
||||
property string tipLinkNewDevice: qsTr("Link a new device to this account")
|
||||
property string linkNewDevice: qsTr("Exporting account…")
|
||||
property string linkDevice: qsTr("Exporting account…")
|
||||
property string removeDevice: qsTr("Remove Device")
|
||||
property string sureToRemoveDevice: qsTr("Are you sure you wish to remove this device?")
|
||||
property string yourPinIs: qsTr("Your PIN is:")
|
||||
|
@ -575,13 +575,20 @@ Item {
|
|||
// LinkDevicesDialog
|
||||
property string pinTimerInfos: qsTr("The PIN and the account password should be entered in your device within 10 minutes.")
|
||||
property string close: qsTr("Close")
|
||||
property string enterAccountPassword: qsTr("Enter account's password")
|
||||
property string enterAccountPassword: qsTr("Enter account password")
|
||||
property string enterPasswordPinCode: qsTr("This account is password encrypted, enter the password to generate a PIN code.")
|
||||
property string addDevice: qsTr("Add Device")
|
||||
property string pinExpired: qsTr("PIN expired")
|
||||
property string onAnotherDevice: qsTr("On another device")
|
||||
property string onAnotherDeviceInstruction: qsTr("Install and launch Jami, select \"Import from another device\" and scan the QR code.")
|
||||
property string linkNewDevice: qsTr("Link new device")
|
||||
property string linkingInstructions: qsTr("In Jami, scan QR code or manually enter the PIN.")
|
||||
property string pinValidity: qsTr("The PIN code is valid for: ")
|
||||
|
||||
// PasswordDialog
|
||||
property string enterPassword: qsTr("Enter the password")
|
||||
property string enterPassword: qsTr("Enter password")
|
||||
property string enterCurrentPassword: qsTr("Enter current password")
|
||||
property string confirmRemoval: qsTr("Enter this account's password to confirm the removal of this device")
|
||||
property string confirmRemoval: qsTr("Enter account password to confirm the removal of this device")
|
||||
property string enterNewPassword: qsTr("Enter new password")
|
||||
property string confirmNewPassword: qsTr("Confirm new password")
|
||||
property string change: qsTr("Change")
|
||||
|
|
|
@ -643,6 +643,9 @@ Item {
|
|||
property int settingsMenuHeaderButtonHeight: 50
|
||||
property int settingsListViewsSpacing: 10
|
||||
|
||||
// Link Device
|
||||
property color pinBackgroundColor: "#D6E4EF"
|
||||
|
||||
// MaterialRadioButton
|
||||
property int radioImageSize: 30
|
||||
property color radioBackgroundColor: darkTheme ? "#303030" : "#F0EFEF"
|
||||
|
|
|
@ -33,7 +33,7 @@ public:
|
|||
instance)
|
||||
{}
|
||||
|
||||
enum class QrType { Account, Contact };
|
||||
enum class QrType { Account, Contact, Raw };
|
||||
|
||||
/*
|
||||
* Id should be string like account_0 (account index),
|
||||
|
@ -64,6 +64,8 @@ public:
|
|||
} catch (...) {
|
||||
}
|
||||
return {QrType::Contact, {}};
|
||||
} else if (list.contains("raw") && list.size() > 1) {
|
||||
return {QrType::Raw, list[1]};
|
||||
}
|
||||
return {QrType::Account, {}};
|
||||
}
|
||||
|
@ -73,26 +75,24 @@ public:
|
|||
Q_UNUSED(size);
|
||||
|
||||
QString uri;
|
||||
auto indexPair = getIndexFromID(id);
|
||||
auto [type, identifier] = getIndexFromID(id);
|
||||
|
||||
if (indexPair.first == QrType::Contact) {
|
||||
uri = indexPair.second;
|
||||
} else {
|
||||
if (indexPair.second.isEmpty())
|
||||
if (type == QrType::Account) {
|
||||
if (identifier.isEmpty())
|
||||
return QImage();
|
||||
auto accountId = indexPair.second;
|
||||
try {
|
||||
auto& accountInfo = lrcInstance_->getAccountInfo(accountId);
|
||||
auto& accountInfo = lrcInstance_->getAccountInfo(identifier);
|
||||
uri = accountInfo.profileInfo.uri;
|
||||
} catch (const std::out_of_range&) {
|
||||
qWarning() << "Couldn't get account info for id:" << accountId;
|
||||
qWarning() << "Couldn't get account info for id:" << identifier;
|
||||
return QImage();
|
||||
}
|
||||
}
|
||||
} else
|
||||
uri = identifier;
|
||||
|
||||
if (!requestedSize.isEmpty())
|
||||
return Utils::setupQRCode(uri, 0).scaled(requestedSize, Qt::KeepAspectRatio);
|
||||
return Utils::getQRCodeImage(uri, 0).scaled(requestedSize, Qt::KeepAspectRatio);
|
||||
else
|
||||
return Utils::setupQRCode(uri, 0);
|
||||
return Utils::getQRCodeImage(uri, 0);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -23,13 +23,16 @@ import net.jami.Models 1.1
|
|||
import net.jami.Adapters 1.1
|
||||
import net.jami.Constants 1.1
|
||||
import "../../commoncomponents"
|
||||
import "../../mainview/components"
|
||||
|
||||
BaseModalDialog {
|
||||
id: root
|
||||
|
||||
signal accepted
|
||||
|
||||
title: JamiStrings.addDevice
|
||||
title: JamiStrings.linkNewDevice
|
||||
|
||||
property bool darkTheme: UtilsAdapter.useApplicationTheme()
|
||||
|
||||
popupContent: StackLayout {
|
||||
id: stackedWidget
|
||||
|
@ -47,13 +50,11 @@ BaseModalDialog {
|
|||
function setExportPage(status, pin) {
|
||||
if (status === NameDirectory.ExportOnRingStatus.SUCCESS) {
|
||||
infoLabel.success = true;
|
||||
yourPinLabel.visible = true;
|
||||
exportedPIN.visible = true;
|
||||
infoLabel.text = JamiStrings.pinTimerInfos;
|
||||
pinRectangle.visible = true
|
||||
exportedPIN.text = pin;
|
||||
} else {
|
||||
infoLabel.success = false;
|
||||
infoLabelsRowLayout.visible = false;
|
||||
pinRectangle.success = false;
|
||||
infoLabel.visible = true;
|
||||
switch (status) {
|
||||
case NameDirectory.ExportOnRingStatus.WRONG_PASSWORD:
|
||||
infoLabel.text = JamiStrings.incorrectPassword;
|
||||
|
@ -86,15 +87,14 @@ BaseModalDialog {
|
|||
|
||||
function onExportOnRingEnded(status, pin) {
|
||||
stackedWidget.setExportPage(status, pin);
|
||||
countdownTimer.start();
|
||||
}
|
||||
}
|
||||
|
||||
onVisibleChanged: {
|
||||
if (visible) {
|
||||
infoLabel.text = JamiStrings.pinTimerInfos;
|
||||
if (CurrentAccount.hasArchivePassword) {
|
||||
stackedWidget.currentIndex = enterPasswordPage.pageIndex;
|
||||
passwordEdit.forceActiveFocus();
|
||||
} else {
|
||||
setGeneratingPage();
|
||||
}
|
||||
|
@ -107,14 +107,23 @@ BaseModalDialog {
|
|||
|
||||
readonly property int pageIndex: 0
|
||||
|
||||
Component.onCompleted: passwordEdit.forceActiveFocus()
|
||||
|
||||
onHeightChanged: {
|
||||
stackedWidget.height = passwordLayout.implicitHeight
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
id: passwordLayout
|
||||
spacing: JamiTheme.preferredMarginSize
|
||||
anchors.centerIn: parent
|
||||
|
||||
Label {
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
Layout.maximumWidth: root.width - 4 * JamiTheme.preferredMarginSize
|
||||
wrapMode: Text.Wrap
|
||||
|
||||
text: JamiStrings.enterAccountPassword
|
||||
text: JamiStrings.enterPasswordPinCode
|
||||
color: JamiTheme.textColor
|
||||
font.pointSize: JamiTheme.textFontSize
|
||||
font.kerning: true
|
||||
|
@ -122,70 +131,48 @@ BaseModalDialog {
|
|||
verticalAlignment: Text.AlignVCenter
|
||||
}
|
||||
|
||||
PasswordTextEdit {
|
||||
id: passwordEdit
|
||||
|
||||
firstEntry: true
|
||||
placeholderText: JamiStrings.password
|
||||
|
||||
RowLayout {
|
||||
Layout.topMargin: 10
|
||||
Layout.leftMargin: JamiTheme.cornerIconSize
|
||||
Layout.rightMargin: JamiTheme.cornerIconSize
|
||||
Layout.alignment: Qt.AlignLeft
|
||||
Layout.fillWidth: true
|
||||
|
||||
KeyNavigation.up: btnConfirm
|
||||
KeyNavigation.down: KeyNavigation.up
|
||||
|
||||
onDynamicTextChanged: {
|
||||
btnConfirm.enabled = dynamicText.length > 0;
|
||||
}
|
||||
onAccepted: btnConfirm.clicked()
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
spacing: JamiTheme.preferredMarginSize
|
||||
Layout.bottomMargin: JamiTheme.preferredMarginSize
|
||||
spacing: 16
|
||||
|
||||
MaterialButton {
|
||||
PasswordTextEdit {
|
||||
id: passwordEdit
|
||||
|
||||
firstEntry: true
|
||||
placeholderText: JamiStrings.password
|
||||
|
||||
Layout.alignment: Qt.AlignLeft
|
||||
Layout.fillWidth: true
|
||||
|
||||
KeyNavigation.up: btnConfirm
|
||||
KeyNavigation.down: KeyNavigation.up
|
||||
|
||||
onDynamicTextChanged: {
|
||||
btnConfirm.enabled = dynamicText.length > 0;
|
||||
btnConfirm.hoverEnabled = dynamicText.length > 0;
|
||||
}
|
||||
onAccepted: btnConfirm.clicked()
|
||||
}
|
||||
|
||||
JamiPushButton {
|
||||
id: btnConfirm
|
||||
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
height: 40
|
||||
width: 40
|
||||
preferredSize: 60
|
||||
|
||||
preferredWidth: JamiTheme.preferredFieldWidth / 2 - 8
|
||||
buttontextHeightMargin: JamiTheme.buttontextHeightMargin
|
||||
|
||||
color: enabled ? JamiTheme.buttonTintedBlack : JamiTheme.buttonTintedGrey
|
||||
hoveredColor: JamiTheme.buttonTintedBlackHovered
|
||||
pressedColor: JamiTheme.buttonTintedBlackPressed
|
||||
secondary: true
|
||||
autoAccelerator: true
|
||||
hoverEnabled: false
|
||||
enabled: false
|
||||
|
||||
text: JamiStrings.exportAccount
|
||||
imageColor: JamiTheme.tintedBlue
|
||||
source: JamiResources.check_box_24dp_svg
|
||||
|
||||
onClicked: stackedWidget.setGeneratingPage()
|
||||
}
|
||||
|
||||
MaterialButton {
|
||||
id: btnCancel
|
||||
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
|
||||
preferredWidth: JamiTheme.preferredFieldWidth / 2 - 8
|
||||
buttontextHeightMargin: JamiTheme.buttontextHeightMargin
|
||||
|
||||
color: JamiTheme.buttonTintedBlack
|
||||
hoveredColor: JamiTheme.buttonTintedBlackHovered
|
||||
pressedColor: JamiTheme.buttonTintedBlackPressed
|
||||
secondary: true
|
||||
autoAccelerator: true
|
||||
enabled: true
|
||||
|
||||
text: JamiStrings.optionCancel
|
||||
|
||||
onClicked: close()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -197,6 +184,11 @@ BaseModalDialog {
|
|||
|
||||
readonly property int pageIndex: 1
|
||||
|
||||
onHeightChanged: {
|
||||
stackedWidget.height = spinnerLayout.implicitHeight
|
||||
}
|
||||
|
||||
|
||||
ColumnLayout {
|
||||
id: spinnerLayout
|
||||
|
||||
|
@ -206,7 +198,7 @@ BaseModalDialog {
|
|||
Label {
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
|
||||
text: JamiStrings.linkNewDevice
|
||||
text: JamiStrings.linkDevice
|
||||
color: JamiTheme.textColor
|
||||
font.pointSize: JamiTheme.headerFontSize
|
||||
font.kerning: true
|
||||
|
@ -246,40 +238,171 @@ BaseModalDialog {
|
|||
ColumnLayout {
|
||||
id: exportingLayout
|
||||
|
||||
spacing: JamiTheme.preferredMarginSize
|
||||
|
||||
Label {
|
||||
id: yourPinLabel
|
||||
id: instructionLabel
|
||||
|
||||
Layout.maximumWidth: JamiTheme.preferredDialogWidth
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
|
||||
text: JamiStrings.yourPinIs
|
||||
color: JamiTheme.textColor
|
||||
font.pointSize: JamiTheme.headerFontSize
|
||||
padding: 8
|
||||
|
||||
wrapMode: Text.Wrap
|
||||
text: JamiStrings.linkingInstructions
|
||||
font.pointSize: JamiTheme.textFontSize
|
||||
font.kerning: true
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
|
||||
}
|
||||
|
||||
MaterialLineEdit {
|
||||
id: exportedPIN
|
||||
|
||||
padding: 0
|
||||
Rectangle {
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
|
||||
text: JamiStrings.pin
|
||||
wrapMode: Text.NoWrap
|
||||
border.width: 3
|
||||
border.color: JamiTheme.textColor
|
||||
radius: JamiTheme.primaryRadius
|
||||
color: darkTheme ? JamiTheme.textColor : JamiTheme.secondaryBackgroundColor
|
||||
width: 170
|
||||
height: 170
|
||||
|
||||
color: JamiTheme.textColor
|
||||
selectByMouse: true
|
||||
readOnly: true
|
||||
font.pointSize: JamiTheme.headerFontSize
|
||||
font.kerning: true
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
Image {
|
||||
id: qrImage
|
||||
|
||||
anchors.fill: parent
|
||||
anchors.margins: 10
|
||||
|
||||
mipmap: false
|
||||
smooth: false
|
||||
|
||||
source: "image://qrImage/raw_" + exportedPIN.text
|
||||
sourceSize.width: 150
|
||||
sourceSize.height: 150
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: pinRectangle
|
||||
|
||||
radius: 15
|
||||
color: darkTheme ? JamiTheme.tintedBlue : JamiTheme.pinBackgroundColor
|
||||
|
||||
width: exportedPIN.implicitWidth + 4 * JamiTheme.preferredMarginSize
|
||||
height: exportedPIN.implicitHeight + 2 * JamiTheme.preferredMarginSize
|
||||
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
Layout.margins: JamiTheme.preferredMarginSize
|
||||
|
||||
MaterialLineEdit {
|
||||
id: exportedPIN
|
||||
|
||||
padding: 0
|
||||
anchors.centerIn: parent
|
||||
|
||||
text: JamiStrings.pin
|
||||
wrapMode: Text.NoWrap
|
||||
|
||||
backgroundColor: darkTheme ? JamiTheme.tintedBlue : JamiTheme.pinBackgroundColor
|
||||
|
||||
color: darkTheme ? JamiTheme.textColor : JamiTheme.tintedBlue
|
||||
selectByMouse: true
|
||||
readOnly: true
|
||||
font.pointSize: JamiTheme.headerFontSize
|
||||
font.kerning: true
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
Layout.bottomMargin: JamiTheme.preferredMarginSize
|
||||
spacing: 0
|
||||
|
||||
Label {
|
||||
id: validityLabel
|
||||
|
||||
Layout.alignment: Qt.AlignRight
|
||||
|
||||
color: JamiTheme.textColor
|
||||
text: JamiStrings.pinValidity
|
||||
font.pointSize: JamiTheme.textFontSize
|
||||
font.kerning: true
|
||||
}
|
||||
|
||||
Label {
|
||||
id: countdownLabel
|
||||
|
||||
color: JamiTheme.textColor
|
||||
Layout.alignment: Qt.AlignLeft
|
||||
font.pointSize: JamiTheme.textFontSize
|
||||
font.kerning: true
|
||||
|
||||
text: "10:00"
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: countdownTimer
|
||||
interval: 1000
|
||||
repeat: true
|
||||
|
||||
property int remainingTime: 600
|
||||
|
||||
onTriggered: {
|
||||
remainingTime--
|
||||
|
||||
var minutes = Math.floor(remainingTime / 60)
|
||||
var seconds = remainingTime % 60
|
||||
countdownLabel.text = (minutes < 10 ? "0" : "") + minutes + ":" + (seconds < 10 ? "0" : "") + seconds
|
||||
|
||||
if (remainingTime <= 0) {
|
||||
validityLabel.visible = false
|
||||
countdownLabel.text = JamiStrings.pinExpired
|
||||
countdownLabel.color = JamiTheme.redColor
|
||||
countdownTimer.stop()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Label {
|
||||
id: otherDeviceLabel
|
||||
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
|
||||
color: JamiTheme.textColor
|
||||
text: JamiStrings.onAnotherDevice
|
||||
font.pointSize: JamiTheme.smallFontSize
|
||||
font.kerning: true
|
||||
font.bold: true
|
||||
}
|
||||
|
||||
Label {
|
||||
id: otherInstructionLabel
|
||||
|
||||
Layout.maximumWidth: JamiTheme.preferredDialogWidth
|
||||
Layout.bottomMargin: JamiTheme.preferredMarginSize
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
wrapMode: Text.Wrap
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
|
||||
color: JamiTheme.textColor
|
||||
text: JamiStrings.onAnotherDeviceInstruction
|
||||
font.pointSize: JamiTheme.smallFontSize
|
||||
font.kerning: true
|
||||
}
|
||||
|
||||
// Displays error messages
|
||||
Label {
|
||||
id: infoLabel
|
||||
|
||||
visible: false
|
||||
|
||||
property bool success: false
|
||||
property int borderWidth: success ? 1 : 0
|
||||
property int borderRadius: success ? 15 : 0
|
||||
|
@ -295,7 +418,6 @@ BaseModalDialog {
|
|||
padding: success ? 8 : 0
|
||||
|
||||
wrapMode: Text.Wrap
|
||||
text: JamiStrings.pinTimerInfos
|
||||
font.pointSize: success ? JamiTheme.textFontSize : JamiTheme.textFontSize + 3
|
||||
font.kerning: true
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
|
|
|
@ -39,6 +39,47 @@ SettingsPageBase {
|
|||
anchors.left: parent.left
|
||||
anchors.leftMargin: JamiTheme.preferredSettingsMarginSize
|
||||
|
||||
|
||||
|
||||
Text {
|
||||
id: linkDescription
|
||||
|
||||
Layout.alignment: Qt.AlignLeft
|
||||
Layout.fillWidth: true
|
||||
|
||||
text: JamiStrings.linkDescription
|
||||
color: JamiTheme.textColor
|
||||
horizontalAlignment: Text.AlignLeft
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
wrapMode: Text.WordWrap
|
||||
|
||||
font.pixelSize: JamiTheme.settingsDescriptionPixelSize
|
||||
font.kerning: true
|
||||
lineHeight: JamiTheme.wizardViewTextLineHeight
|
||||
}
|
||||
|
||||
MaterialButton {
|
||||
id: linkDeviceBtn
|
||||
|
||||
TextMetrics {
|
||||
id: linkDeviceBtnTextSize
|
||||
font.weight: Font.Bold
|
||||
font.pixelSize: JamiTheme.wizardViewButtonFontPixelSize
|
||||
text: linkDeviceBtn.text
|
||||
}
|
||||
|
||||
preferredWidth: linkDeviceBtnTextSize.width + 2 * JamiTheme.buttontextWizzardPadding
|
||||
Layout.bottomMargin: JamiTheme.preferredMarginSize
|
||||
|
||||
primary: true
|
||||
Layout.alignment: Qt.AlignLeft
|
||||
|
||||
toolTipText: JamiStrings.tipLinkNewDevice
|
||||
text: JamiStrings.linkNewDevice
|
||||
|
||||
onClicked: viewCoordinator.presentDialog(appWindow, "settingsview/components/LinkDeviceDialog.qml")
|
||||
}
|
||||
|
||||
Text {
|
||||
id: linkedDevicesTitle
|
||||
|
||||
|
|
|
@ -218,7 +218,7 @@ SettingsPageBase {
|
|||
Layout.alignment: Qt.AlignLeft
|
||||
|
||||
toolTipText: JamiStrings.tipLinkNewDevice
|
||||
text: JamiStrings.linkAnotherDevice
|
||||
text: JamiStrings.linkNewDevice
|
||||
|
||||
onClicked: viewCoordinator.presentDialog(appWindow, "settingsview/components/LinkDeviceDialog.qml")
|
||||
}
|
||||
|
|
|
@ -805,9 +805,9 @@ Utils::pixmapFromSvg(const QString& svg_resource, const QSize& size)
|
|||
}
|
||||
|
||||
QImage
|
||||
Utils::setupQRCode(QString ringID, int margin)
|
||||
Utils::getQRCodeImage(QString data, int margin)
|
||||
{
|
||||
auto qrcode = QRcode_encodeString(ringID.toStdString().c_str(),
|
||||
auto qrcode = QRcode_encodeString(data.toStdString().c_str(),
|
||||
0, // Let the version be decided by libqrencode
|
||||
QR_ECLEVEL_L, // Lowest level of error correction
|
||||
QR_MODE_8, // 8-bit data mode
|
||||
|
|
|
@ -119,7 +119,7 @@ QPixmap generateTintedPixmap(const QPixmap& pix, QColor color);
|
|||
QImage scaleAndFrame(const QImage photo, const QSize& size = defaultAvatarSize);
|
||||
QImage cropImage(const QImage& img);
|
||||
QPixmap pixmapFromSvg(const QString& svg_resource, const QSize& size);
|
||||
QImage setupQRCode(QString ringID, int margin);
|
||||
QImage getQRCodeImage(QString data, int margin);
|
||||
bool isImage(const QString& fileExt);
|
||||
QString generateUid();
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue