Commit ae95e721 authored by Ming Rui Zhang's avatar Ming Rui Zhang Committed by Sébastien Blin
Browse files

qml: add user profile page

Change-Id: If2404505a4b8d45b3d3498ff71b8dbfbebe928c3
parent f86db31f
......@@ -171,7 +171,9 @@ HEADERS += ./src/aboutdialog.h \
./src/widgethelpers.h \
./src/recordwidget.h \
./src/networkmanager.h \
./src/connectivitymonitor.h
./src/connectivitymonitor.h \
./src/userprofile.h \
./src/qmlclipboardadapter.h
SOURCES += ./src/aboutdialog.cpp \
./src/banneditemwidget.cpp \
./src/conversationsfilterwidget.cpp \
......@@ -237,7 +239,8 @@ SOURCES += ./src/aboutdialog.cpp \
./src/widgethelpers.cpp \
./src/recordwidget.cpp \
./src/networkmanager.cpp \
./src/connectivitymonitor.cpp
./src/connectivitymonitor.cpp \
./src/userprofile.cpp
FORMS += ./src/aboutdialog.ui \
./src/advancedsipsettingwidget.ui \
./src/callwidget.ui \
......
......@@ -2,5 +2,6 @@
<qresource prefix="/">
<file>src/KeyBoardShortcutTable.qml</file>
<file>src/KeyBoardShortcutKey.qml</file>
<file>src/UserProfileCard.qml</file>
</qresource>
</RCC>
import QtQuick 2.9
import QtQuick.Controls 2.2
import QtQuick.Controls.Styles 1.4
import QtQuick.Layouts 1.3
import MyQClipboard 1.0
/*
* Every QML object can be assigned an id and an objectName that other objects can use to refer to the object.
* The difference between the two is that the id is for referencing the object within QML,
* while the objectName is required for referencing the object from C++
*/
ColumnLayout {
id: mainColumnLayout
property int minWidth: 560
property int minHeight: 600
property int textFontSize: 10
property string userImageSource: "qrc:/qtquickplugin/images/template_image.png"
property string qrImageSource: "qrc:/qtquickplugin/images/template_image.png"
property string userNameText: "Text"
property string registeredNameText: "Text"
property string uriText: "Text"
spacing: 2
Rectangle {
id: profileRectangle
Layout.alignment: Qt.AlignCenter
Layout.minimumWidth: minWidth
Layout.minimumHeight: minHeight
Layout.maximumWidth: minWidth * 2
Layout.maximumHeight: minHeight * 2
color: "white"
radius: 30
MouseArea {
// trick: in future qt version, use popup() instead of open()
// for menu item (will not auto close)
anchors.fill: parent
propagateComposedEvents: true
onClicked: {
if(Qt.platform.os == "windows") {
registeredNameContextMenu.close()
idContextMenu.close()
}
}
}
QClipboard{
id: clipboard
}
ColumnLayout {
id: profileRectColumnLayout
anchors.fill: parent
anchors.centerIn: parent
Rectangle {
id: userRectangle
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
Layout.minimumWidth: 500
Layout.minimumHeight: 200
Layout.maximumHeight: 1000
Layout.maximumWidth: 1000
color: "#ffffff"
RowLayout {
id: userRectRowLayout
anchors.fill: parent
Image {
id: userImage
anchors.verticalCenter: userRectangle.verticalCenter
anchors.left: userRectangle.left
Layout.fillWidth: true
Layout.fillHeight :true
Layout.maximumWidth: 150
Layout.maximumHeight: 150
fillMode: Image.PreserveAspectFit
source: userImageSource
cache: false
}
Text {
id: userName
anchors.verticalCenter: userRectangle.verticalCenter
anchors.left: userImage.right
anchors.leftMargin: 25
Layout.fillWidth: true
Layout.fillHeight :true
Layout.maximumWidth: 300
Layout.maximumHeight: t_metrics_userName.tightBoundingRect.height
text: userNameText
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignLeft
wrapMode: Text.WordWrap
font.pointSize: 20
elide: Text.ElideRight
TextMetrics {
id: t_metrics_userName
font: userName.font
text: userName.text
}
}
}
}
Rectangle {
id: informationRectangle
anchors.top: userRectangle.bottom
anchors.topMargin: 10
Layout.minimumWidth: 500
Layout.minimumHeight: 300
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
color: "#ffffff"
Text {
id: inforElement
anchors.left: informationRectangle.left
anchors.top: informationRectangle.top
anchors.topMargin: 30
anchors.leftMargin: 20
width: t_metrics_info.tightBoundingRect.width
height: t_metrics_info.tightBoundingRect.height
text: qsTr("Information")
font.pointSize: textFontSize
TextMetrics {
id: t_metrics_info
font: inforElement.font
text: inforElement.text
}
}
ColumnLayout {
id: infoRectColumnLayout
anchors.top: informationRectangle.top
anchors.topMargin: 70
anchors.left: informationRectangle.left
anchors.leftMargin: 60
Rectangle {
id: subInfoRect
Layout.minimumWidth: 400
Layout.minimumHeight: 200
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
RowLayout {
id: registerNameRowLayout
Rectangle {
id: registerNameRect
Layout.minimumWidth: subInfoRect.width
Layout.minimumHeight: Math.max(registeredNameElement.height, registeredName.height)
Label {
id: registeredNameElement
anchors.left: parent.left
anchors.verticalCenter: parent.verticalCenter
text: "Username"
fontSizeMode: Text.Fit
font.pointSize: textFontSize
minimumPointSize: textFontSize - 2
color: "#828282"
MouseArea {
anchors.fill: parent
cursorShape: Qt.IBeamCursor
acceptedButtons: Qt.NoButton
}
background: Rectangle {
border.width: 0
}
}
TextArea {
id: registeredName
anchors.left: registeredNameElement.right
anchors.leftMargin: 10
text: registeredNameText
verticalAlignment: Text.AlignVCenter
font.pointSize: textFontSize
color: "black"
readOnly: true
selectByMouse: true
MouseArea {
anchors.fill: parent
propagateComposedEvents: true
cursorShape: Qt.IBeamCursor
acceptedButtons: Qt.RightButton
onClicked: {
if (mouse.button === Qt.RightButton && Qt.platform.os == "windows") {
// make menu pos at mouse
var relativeMousePos = mapToItem(registeredName, mouse.x, mouse.y)
registeredNameContextMenu.x = relativeMousePos.x
registeredNameContextMenu.y = relativeMousePos.y
registeredNameContextMenu.open()
}
}
}
Menu {
id: registeredNameContextMenu
MenuItem {
id: registeredNameItem
text: qsTr("Copy")
background: Rectangle {
id: registeredNameContextMenuBackRect
implicitWidth: 150
implicitHeight: 30
border.width: 1
border.color: "black"
color: registeredNameItem.down ? "#e0e0e0" :"#fdfdfd"
MouseArea {
anchors.fill: parent;
hoverEnabled: true;
onPressed: { registeredNameContextMenuBackRect.color = "#c0c0c0"; }
onReleased: { registeredNameContextMenuBackRect.color = "#e0e0e0"; clipboard.setText(registeredName.selectedText); reset();}
onEntered: { registeredNameContextMenuBackRect.color = "#c7c7c7"; }
onExited: { registeredNameContextMenuBackRect.color = Qt.binding(function() { return registeredNameItem.down ? "#e0e0e0" :"#fdfdfd" }); }
function reset(){
registeredName.deselect()
registeredNameContextMenu.close()
}
}
}
}
background: Rectangle {
implicitWidth: 150
implicitHeight: 30
}
}
background: Rectangle {
border.width: 0
color: "transparent"
}
}
}
}
RowLayout {
id: idRowLayout
anchors.top: registerNameRowLayout.bottom
Rectangle {
id: idRect
Layout.minimumWidth: subInfoRect.width
Layout.minimumHeight: Math.max(idElement.height, idText.height)
Label {
id: idElement
anchors.left: parent.left
anchors.leftMargin: registeredNameElement.width - idElement.width
anchors.verticalCenter: parent.verticalCenter
text: "ID"
fontSizeMode: Text.Fit
font.pointSize: textFontSize
minimumPointSize: textFontSize - 2
color: "#828282"
MouseArea {
anchors.fill: parent
cursorShape: Qt.IBeamCursor
acceptedButtons: Qt.NoButton
}
background: Rectangle {
border.width: 0
}
}
TextField {
id: idText
anchors.left: idElement.right
anchors.leftMargin: 10
text: uriText
verticalAlignment: Text.AlignVCenter
font.pointSize: textFontSize
color: "black"
readOnly: true
selectByMouse: true
MouseArea {
anchors.fill: parent
propagateComposedEvents: true
cursorShape: Qt.IBeamCursor
acceptedButtons: Qt.RightButton
onClicked: {
if (mouse.button === Qt.RightButton && Qt.platform.os == "windows") {
// make menu pos at mouse
var relativeMousePos = mapToItem(idText, mouse.x, mouse.y)
idContextMenu.x = relativeMousePos.x
idContextMenu.y = relativeMousePos.y
idContextMenu.open()
}
}
}
Menu {
id: idContextMenu
MenuItem {
id: idItem
text: qsTr("Copy")
background: Rectangle {
id: idBackRect
implicitWidth: 150
implicitHeight: 30
color: idItem.down ? "#e0e0e0" :"#fdfdfd"
border.width: 1
border.color: "black"
MouseArea {
anchors.fill: parent;
hoverEnabled: true;
onPressed: { idBackRect.color = "#c0c0c0"; }
onReleased: { idBackRect.color = "#e0e0e0"; clipboard.setText(idText.selectedText); reset();}
onEntered: { idBackRect.color = "#c7c7c7"; }
onExited: { idBackRect.color = Qt.binding(function() { return idItem.down ? "#e0e0e0" :"#fdfdfd" }); }
function reset(){
idText.deselect()
idContextMenu.close()
}
}
}
}
background: Rectangle {
implicitWidth: 150
implicitHeight: 30
}
}
background: Rectangle {
border.width: 0
}
}
}
}
RowLayout {
id: qrRowLayout
anchors.top: idRowLayout.bottom
anchors.topMargin: 6
Rectangle {
id: qrRect
Layout.minimumWidth: subInfoRect.width
Layout.minimumHeight: qrElement.height
Label {
id: qrElement
anchors.left: parent.left
anchors.leftMargin: registeredNameElement.width - qrElement.width
anchors.verticalCenter: parent.verticalCenter
text: "QR Code"
fontSizeMode: Text.Fit
font.pointSize: textFontSize
minimumPointSize: textFontSize - 2
color: "#828282"
MouseArea {
anchors.fill: parent
cursorShape: Qt.IBeamCursor
acceptedButtons: Qt.NoButton
}
background: Rectangle {
border.width: 0
}
}
Image {
id: qrImage
anchors.left: qrElement.right
anchors.leftMargin: 20
fillMode: Image.PreserveAspectFit
source: qrImageSource
sourceSize.width: 150
sourceSize.height: 150
cache: false
}
}
}
}
}
}
}
}
}
......@@ -40,6 +40,7 @@
#include "ringthemeutils.h"
#include "settingskey.h"
#include "aboutdialog.h"
#include "userprofile.h"
#include "globalinstances.h"
......@@ -415,14 +416,13 @@ CallWidget::setupSmartListContextMenu(const QPoint& pos)
// separator
menu.addSeparator();
// copy number(infohash)
auto copyNumberAction = new QAction(tr("Copy number"), this);
menu.addAction(copyNumberAction);
connect(copyNumberAction, &QAction::triggered,
[contact]() {
QApplication::clipboard()->setText(
QString::fromStdString(contact.profileInfo.uri)
);
// show user profile
auto profileShowingAction = new QAction(tr("Profile"), this);
menu.addAction(profileShowingAction);
connect(profileShowingAction, &QAction::triggered,
[conversation, this]() {
UserProfile userProfile(conversation, qobject_cast<MainWindow*>(this->parent()->parent()->parent()));
userProfile.getContainer()->exec();
});
}
smartListModel_->isContextMenuOpen = true;
......@@ -430,45 +430,6 @@ CallWidget::setupSmartListContextMenu(const QPoint& pos)
smartListModel_->isContextMenuOpen = false;
}
void
CallWidget::setupQRCode(QString ringID)
{
auto rcode = QRcode_encodeString(ringID.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
1);
if (not rcode) {
qWarning() << "Failed to generate QR code: " << strerror(errno);
return;
}
auto margin = 5;
int qrwidth = rcode->width + margin * 2;
QImage result(QSize(qrwidth, qrwidth), QImage::Format_Mono);
QPainter painter;
painter.begin(&result);
painter.setClipRect(QRect(0, 0, qrwidth, qrwidth));
painter.setPen(QPen(Qt::black, 0.1, Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin));
painter.setBrush(Qt::black);
painter.fillRect(QRect(0, 0, qrwidth, qrwidth), Qt::white);
unsigned char* p;
p = rcode->data;
for(int y = 0; y < rcode->width; y++) {
unsigned char* row = (p + (y * rcode->width));
for(int x = 0; x < rcode->width; x++) {
if(*(row + x) & 0x1) {
painter.drawRect(margin + x, margin + y, 1, 1);
}
}
}
painter.end();
QRcode_free(rcode);
ui->qrLabel->setPixmap(QPixmap::fromImage(result.scaled(QSize(qrSize_, qrSize_),
Qt::KeepAspectRatio)));
}
void
CallWidget::on_smartList_clicked(const QModelIndex& index)
{
......@@ -864,7 +825,8 @@ CallWidget::setSelectedAccount(const std::string& accountId)
auto isRingAccount = accountInfo.profileInfo.type == lrc::api::profile::Type::RING;
if (isRingAccount) {
ui->ringIdLabel->setText(QString::fromStdString(id));
setupQRCode(QString::fromStdString(accountInfo.profileInfo.uri));
ui->qrLabel->setPixmap(QPixmap::fromImage(Utils::setupQRCode(QString::fromStdString(accountInfo.profileInfo.uri), 5).scaled(QSize(qrSize_, qrSize_),
Qt::KeepAspectRatio)));
}
updateSmartList();
......
......@@ -110,7 +110,6 @@ private:
void conversationsButtonClicked();
void invitationsButtonClicked();
void setupSmartListContextMenu(const QPoint &pos);
void setupQRCode(QString ringID);
void backToWelcomePage();
void selectConversation(const QModelIndex& index);
......
......@@ -28,6 +28,7 @@
#include "utils.h"
#include "splashscreen.h"
#include "aboutdialog.h"
#include "qmlclipboardadapter.h"
#include <QApplication>
#include <QFile>
......@@ -296,9 +297,12 @@ main(int argc, char* argv[])
QObject::connect(&a, &QApplication::aboutToQuit, [&guard] { exitApp(guard); });
// for deployment only
// for deployment and register types
qmlRegisterType<QmlClipboardAdapter>("MyQClipboard", 1, 0, "QClipboard");
QQmlApplicationEngine engine;
engine.load(QUrl(QStringLiteral("qrc:/src/KeyBoardShortcutTable.qml")));
engine.load(QUrl(QStringLiteral("qrc:/src/UserProfileCard.qml")));
auto ret = a.exec();
......
/***************************************************************************
* Copyright (C) 2019 by Savoir-faire Linux *
* Author: Mingrui Zhang <mingrui.zhang@savoirfairelinux.com> *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 3 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
**************************************************************************/
//https://ruedigergad.com/2011/08/06/qml-and-clipboard-interaction/
#pragma once
#include <QApplication>
#include <QClipboard>
#include <QObject>
class QmlClipboardAdapter : public QObject
{
Q_OBJECT
public:
explicit QmlClipboardAdapter(QObject* parent = nullptr) : QObject(parent) {
clipboard_ = QApplication::clipboard();
}
Q_INVOKABLE void setText(QString text) {
clipboard_->setText(text, QClipboard::Clipboard);
}
private:
QClipboard* clipboard_;
};
/***************************************************************************
* Copyright (C) 2019 by Savoir-faire Linux *
* Author: Mingrui Zhang <mingrui.zhang@savoirfairelinux.com> *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 3 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
**************************************************************************/
#include "userprofile.h"
UserProfile::UserProfile(lrc::api::conversation::Info convInfo, QWidget* parent) :
QmlPopupWidget(QUrl(QStringLiteral("")), parent)
{