Commit a6badad4 authored by Andreas Traczyk's avatar Andreas Traczyk

refacto: use new lrc database adaptations

Gitlab: #407
Change-Id: Iaf8df3e4648df4adf26a3b5e437ecaf306b34fd4
parent 76320730
......@@ -863,6 +863,33 @@ CallWidget::showChatView(const std::string& accountId, const lrc::api::conversat
setupChatView(convInfo);
}
void
CallWidget::setConversationProfileData(const lrc::api::conversation::Info& convInfo)
{
auto convModel = LRCInstance::getCurrentConversationModel();
auto accInfo = &LRCInstance::getCurrentAccountInfo();
auto contactUri = convInfo.participants.front();
try {
auto& contact = accInfo->contactModel->getContact(contactUri);
auto bestName = Utils::bestNameForConversation(convInfo, *convModel);
ui->messageView->setInvitation(
(contact.profileInfo.type == lrc::api::profile::Type::PENDING),
bestName,
contactUri
);
if (!contact.profileInfo.avatar.empty()) {
ui->messageView->setSenderImage(contactUri, contact.profileInfo.avatar);
} else {
auto avatar = Utils::conversationPhoto(convInfo.uid, *accInfo);
QByteArray ba;
QBuffer bu(&ba);
avatar.save(&bu, "PNG");
std::string avatarString = ba.toBase64().toStdString();
ui->messageView->setSenderImage(contactUri, avatarString);
}
} catch (...) {}
}
void
CallWidget::setupChatView(const lrc::api::conversation::Info& convInfo)
{
......@@ -898,8 +925,6 @@ CallWidget::setupChatView(const lrc::api::conversation::Info& convInfo)
ui->sendContactRequestButton->setVisible(shouldShowSendContactRequestBtn);
ui->messageView->setMessagesVisibility(false);
ui->messageView->clear();
ui->messageView->setInvitation(false);
Utils::oneShotConnect(ui->messageView, &MessageWebView::messagesCleared,
[this, convInfo] {
auto convModel = LRCInstance::getCurrentConversationModel();
......@@ -908,33 +933,10 @@ CallWidget::setupChatView(const lrc::api::conversation::Info& convInfo)
[this] {
ui->messageView->setMessagesVisibility(true);
});
// Contact Avatars
auto accInfo = &LRCInstance::getCurrentAccountInfo();
auto contactUri = convInfo.participants.front();
try {
auto& contact = accInfo->contactModel->getContact(contactUri);
auto bestName = Utils::bestNameForConversation(convInfo, *convModel);
ui->messageView->setInvitation(
(contact.profileInfo.type == lrc::api::profile::Type::PENDING),
bestName,
accInfo->contactModel->getContactProfileId(contact.profileInfo.uri)
);
if (!contact.profileInfo.avatar.empty()) {
ui->messageView->setSenderImage(
accInfo->contactModel->getContactProfileId(contactUri),
contact.profileInfo.avatar);
} else {
auto avatar = Utils::conversationPhoto(convInfo.uid, *accInfo);
QByteArray ba;
QBuffer bu(&ba);
avatar.save(&bu, "PNG");
std::string avatarString = ba.toBase64().toStdString();
ui->messageView->setSenderImage(
accInfo->contactModel->getContactProfileId(contactUri),
avatarString);
}
} catch (...) {}
setConversationProfileData(convInfo);
});
ui->messageView->setInvitation(false);
ui->messageView->clear();
}
void
......@@ -1272,15 +1274,21 @@ CallWidget::connectAccount(const std::string& accId)
auto& contactModel = LRCInstance::getCurrentAccountInfo().contactModel;
disconnect(contactAddedConnection_);
contactAddedConnection_ = connect(contactModel.get(), &lrc::api::ContactModel::contactAdded,
[this, &contactModel](const std::string & contactId) {
[this, &contactModel](const std::string & contactUri) {
auto convModel = LRCInstance::getCurrentConversationModel();
auto currentConversation = Utils::getConversationFromUid(LRCInstance::getSelectedConvUid(),
*convModel);
if (currentConversation == convModel->allFilteredConversations().end()) {
return;
}
if (contactId == contactModel.get()->getContact((*currentConversation).participants.at(0)).profileInfo.uri) {
if (contactUri == contactModel.get()->getContact((*currentConversation).participants.at(0)).profileInfo.uri) {
// update call screen
auto avatarImg = QPixmap::fromImage(imageForConv((*currentConversation).uid));
ui->callingPhoto->setPixmap(avatarImg);
ui->callerPhoto->setPixmap(avatarImg);
// update conversation
ui->messageView->clear();
setConversationProfileData(*currentConversation);
ui->messageView->printHistory(*convModel, currentConversation->interactions);
}
});
......
......@@ -72,6 +72,7 @@ public slots:
void settingsButtonClicked();
void showChatView(const QModelIndex& nodeIdx);
void showChatView(const std::string & accountId, const lrc::api::conversation::Info & convInfo);
void setConversationProfileData(const lrc::api::conversation::Info & convInfo);
void setupChatView(const lrc::api::conversation::Info& convInfo);
void slotAcceptInviteClicked(const QModelIndex& index);
void slotBlockInviteClicked(const QModelIndex& index);
......
......@@ -22,6 +22,7 @@
#include <QApplication>
#include <QPainter>
#include <QPixmap>
#include <QSvgRenderer>
// Client
#include "smartlistmodel.h"
......@@ -35,6 +36,11 @@
ConversationItemDelegate::ConversationItemDelegate(QObject* parent)
: QItemDelegate(parent)
{
QSvgRenderer svgRenderer(QString(":/images/icons/ic_baseline-search-24px.svg"));
searchIcon_ = new QPixmap(QSize(sizeImage_, sizeImage_));
searchIcon_->fill(Qt::transparent);
QPainter pixPainter(searchIcon_);
svgRenderer.render(&pixPainter);
}
void
......@@ -59,92 +65,99 @@ ConversationItemDelegate::paint(QPainter* painter
highlightMap_[index.row()] = option.state & QStyle::State_MouseOver;
}
using namespace lrc::api;
auto type = Utils::toEnum<profile::Type>(
index.data(static_cast<int>(SmartListModel::Role::ContactType)).value<int>()
);
// One does not simply keep the highlighted state drawn when the context
// menu is open
QColor presenceBorderColor = Qt::white;
auto rowHighlight = highlightMap_.find(index.row());
if (selected) {
painter->fillRect(option.rect, RingTheme::smartlistSelection_);
presenceBorderColor = RingTheme::smartlistSelection_;
} else if (rowHighlight != highlightMap_.end() && (*rowHighlight).second) {
painter->fillRect(option.rect, RingTheme::smartlistHighlight_);
presenceBorderColor = RingTheme::smartlistHighlight_;
}
auto convUid = index.data(static_cast<int>(SmartListModel::Role::UID)).value<QString>().toStdString();
auto conversation = Utils::getConversationFromUid(convUid, *LRCInstance::getCurrentConversationModel());
if (LRCInstance::getCurrentCallModel()->hasCall(conversation->callId)) {
auto color = QColor(RingTheme::blue_.lighter(180));
presenceBorderColor = color;
color.setAlpha(128);
painter->fillRect(option.rect, color);
QString uriStr = index.data(static_cast<int>(SmartListModel::Role::URI)).value<QString>();
if (not (type == profile::Type::TEMPORARY and uriStr.isEmpty())) {
auto rowHighlight = highlightMap_.find(index.row());
if (selected) {
painter->fillRect(option.rect, RingTheme::smartlistSelection_);
} else if (rowHighlight != highlightMap_.end() && (*rowHighlight).second) {
painter->fillRect(option.rect, RingTheme::smartlistHighlight_);
}
auto convUid = index.data(static_cast<int>(SmartListModel::Role::UID)).value<QString>().toStdString();
auto conversation = Utils::getConversationFromUid(convUid, *LRCInstance::getCurrentConversationModel());
if (LRCInstance::getCurrentCallModel()->hasCall(conversation->callId)) {
auto color = QColor(RingTheme::blue_.lighter(180));
color.setAlpha(128);
painter->fillRect(option.rect, color);
}
}
QRect &rect = opt.rect;
// Avatar drawing
opt.decorationSize = QSize(sizeImage_, sizeImage_);
opt.decorationPosition = QStyleOptionViewItem::Left;
opt.decorationAlignment = Qt::AlignCenter;
QRect rectAvatar(dx_ + rect.left(), rect.top() + dy_, sizeImage_, sizeImage_);
drawDecoration(painter, opt, rectAvatar,
QPixmap::fromImage(index.data(Qt::DecorationRole).value<QImage>())
.scaled(sizeImage_, sizeImage_, Qt::KeepAspectRatio, Qt::SmoothTransformation));
if (type == profile::Type::TEMPORARY and uriStr.isEmpty()) {
// Search icon
drawDecoration(painter, opt, rectAvatar, *searchIcon_);
} else {
// Avatar drawing
drawDecoration(painter, opt, rectAvatar,
QPixmap::fromImage(index.data(Qt::DecorationRole).value<QImage>())
.scaled(sizeImage_, sizeImage_, Qt::KeepAspectRatio, Qt::SmoothTransformation));
}
QFont font(painter->font());
// If there's unread messages, a message count is displayed
if (auto messageCount = index.data(static_cast<int>(SmartListModel::Role::UnreadMessagesCount)).toInt()) {
QString messageCountText = (messageCount > 9) ? "9+" : QString::number(messageCount);
qreal fontSize = messageCountText.count() > 1 ? 7 : 8;
font.setPointSize(fontSize);
// ellipse
QPainterPath ellipse;
qreal ellipseHeight = sizeImage_ / 6;
qreal ellipseWidth = ellipseHeight;
QPointF ellipseCenter(rectAvatar.right() - ellipseWidth + 1, rectAvatar.top() + ellipseHeight + 1);
QRect ellipseRect(ellipseCenter.x() - ellipseWidth, ellipseCenter.y() - ellipseHeight,
ellipseWidth * 2, ellipseHeight * 2);
ellipse.addRoundedRect(ellipseRect, ellipseWidth, ellipseHeight);
painter->fillPath(ellipse, RingTheme::notificationRed_);
// text
painter->setPen(Qt::white);
painter->setOpacity(1);
painter->setFont(font);
ellipseRect.setTop(ellipseRect.top() - 2);
painter->drawText(ellipseRect, Qt::AlignCenter, messageCountText);
}
if (type != profile::Type::TEMPORARY) {
// If there's unread messages, a message count is displayed
if (auto messageCount = index.data(static_cast<int>(SmartListModel::Role::UnreadMessagesCount)).toInt()) {
QString messageCountText = (messageCount > 9) ? "9+" : QString::number(messageCount);
qreal fontSize = messageCountText.count() > 1 ? 7 : 8;
font.setPointSize(fontSize);
// ellipse
QPainterPath ellipse;
qreal ellipseHeight = sizeImage_ / 6;
qreal ellipseWidth = ellipseHeight;
QPointF ellipseCenter(rectAvatar.right() - ellipseWidth + 1, rectAvatar.top() + ellipseHeight + 1);
QRect ellipseRect(ellipseCenter.x() - ellipseWidth, ellipseCenter.y() - ellipseHeight,
ellipseWidth * 2, ellipseHeight * 2);
ellipse.addRoundedRect(ellipseRect, ellipseWidth, ellipseHeight);
painter->fillPath(ellipse, RingTheme::notificationRed_);
// text
painter->setPen(Qt::white);
painter->setOpacity(1);
painter->setFont(font);
ellipseRect.setTop(ellipseRect.top() - 2);
painter->drawText(ellipseRect, Qt::AlignCenter, messageCountText);
}
// Presence indicator
if (index.data(static_cast<int>(SmartListModel::Role::Presence)).value<bool>()) {
qreal radius = sizeImage_ / 6;
QPainterPath outerCircle, innerCircle;
QPointF center(rectAvatar.right() - radius + 2, (rectAvatar.bottom() - radius) + 1 + 2);
qreal outerCRadius = radius;
qreal innerCRadius = outerCRadius * 0.75;
outerCircle.addEllipse(center, outerCRadius, outerCRadius);
innerCircle.addEllipse(center, innerCRadius, innerCRadius);
painter->fillPath(outerCircle, presenceBorderColor);
painter->fillPath(innerCircle, RingTheme::presenceGreen_);
// Presence indicator
if (index.data(static_cast<int>(SmartListModel::Role::Presence)).value<bool>()) {
qreal radius = sizeImage_ / 6;
QPainterPath outerCircle, innerCircle;
QPointF center(rectAvatar.right() - radius + 2, (rectAvatar.bottom() - radius) + 1 + 2);
qreal outerCRadius = radius;
qreal innerCRadius = outerCRadius * 0.75;
outerCircle.addEllipse(center, outerCRadius, outerCRadius);
innerCircle.addEllipse(center, innerCRadius, innerCRadius);
painter->fillPath(outerCircle, Qt::white);
painter->fillPath(innerCircle, RingTheme::presenceGreen_);
}
}
using namespace lrc::api;
auto type = Utils::toEnum<profile::Type>(
index.data(static_cast<int>(SmartListModel::Role::ContactType)).value<int>()
);
switch (type) {
case profile::Type::TEMPORARY:
case profile::Type::RING:
case profile::Type::SIP:
case profile::Type::TEMPORARY:
paintConversationItem(painter, option, rect, index);
paintConversationItem(painter, option, rect, index,
type == profile::Type::TEMPORARY);
break;
case profile::Type::PENDING:
paintRingInviteConversationItem(painter, option, rect, index);
paintInvitationItem(painter, option, rect, index);
break;
default:
paintConversationItem(painter, option, rect, index);
paintConversationItem(painter, option, rect, index, true);
break;
}
}
......@@ -162,7 +175,8 @@ void
ConversationItemDelegate::paintConversationItem(QPainter* painter,
const QStyleOptionViewItem& option,
const QRect& rect,
const QModelIndex& index) const
const QModelIndex& index,
const bool isTemporary) const
{
Q_UNUSED(option);
QFont font(painter->font());
......@@ -186,9 +200,16 @@ ConversationItemDelegate::paintConversationItem(QPainter* painter,
auto topMargin = 4;
auto bottomMargin = 8;
int rect1Width;
if (!isTemporary) {
rect1Width = rect.width() - leftMargin - infoTextWidth_ - infoTextWidthModifier - 8;
} else {
rect1Width = rect.width() - leftMargin - rightMargin;
}
QRect rectName1(rect.left() + leftMargin,
rect.top() + topMargin,
rect.width() - leftMargin - infoTextWidth_ - infoTextWidthModifier - 8,
rect1Width,
rect.height() / 2 - 2);
QRect rectName2(rectName1.left(),
......@@ -196,16 +217,6 @@ ConversationItemDelegate::paintConversationItem(QPainter* painter,
rectName1.width(),
rectName1.height() - bottomMargin + infoText2HeightModifier);
QRect rectInfo1(rectName1.left() + rectName1.width(),
rect.top() + topMargin,
infoTextWidth_ - rightMargin + infoTextWidthModifier + 2,
rect.height() / 2 - 2);
QRect rectInfo2(rectInfo1.left(),
rectInfo1.top() + rectInfo1.height() - infoText2HeightModifier,
rectInfo1.width(),
rectInfo1.height() - bottomMargin + infoText2HeightModifier + 4);
QFontMetrics fontMetrics(font);
// The name is displayed at the avatar's right
......@@ -232,6 +243,20 @@ ConversationItemDelegate::paintConversationItem(QPainter* painter,
painter->drawText(rectName2, Qt::AlignVCenter | Qt::AlignLeft, idStr);
}
if (isTemporary) {
return;
}
QRect rectInfo1(rectName1.left() + rectName1.width(),
rect.top() + topMargin,
infoTextWidth_ - rightMargin + infoTextWidthModifier + 2,
rect.height() / 2 - 2);
QRect rectInfo2(rectInfo1.left(),
rectInfo1.top() + rectInfo1.height() - infoText2HeightModifier,
rectInfo1.width(),
rectInfo1.height() - bottomMargin + infoText2HeightModifier + 4);
// top-right: last interaction date/time
QString lastUsedStr = index.data(static_cast<int>(SmartListModel::Role::LastInteractionDate)).value<QString>();
if (!lastUsedStr.isNull()) {
......@@ -268,11 +293,6 @@ ConversationItemDelegate::paintConversationItem(QPainter* painter,
}
}
interactionStr = QString::fromUcs4(&emojiless.at(0), emojiless.size());
// remove everythin after 'call'
auto indexOfCallStr = interactionStr.lastIndexOf(QString("call"), -1, Qt::CaseInsensitive);
if (indexOfCallStr != -1) {
interactionStr = interactionStr.left(indexOfCallStr + 4);
}
} else {
QFont emojiMsgFont(QStringLiteral("Segoe UI Emoji"));
emojiMsgFont.setItalic(false);
......@@ -289,10 +309,10 @@ ConversationItemDelegate::paintConversationItem(QPainter* painter,
}
void
ConversationItemDelegate::paintRingInviteConversationItem(QPainter* painter,
const QStyleOptionViewItem& option,
const QRect& rect,
const QModelIndex& index) const
ConversationItemDelegate::paintInvitationItem(QPainter* painter,
const QStyleOptionViewItem& option,
const QRect& rect,
const QModelIndex& index) const
{
QFont font(painter->font());
QPen pen(painter->pen());
......
......@@ -34,8 +34,15 @@ protected:
QSize sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const;
private:
void paintConversationItem(QPainter* painter, const QStyleOptionViewItem& option, const QRect& rect, const QModelIndex& index) const;
void paintRingInviteConversationItem(QPainter* painter, const QStyleOptionViewItem& option, const QRect& rect, const QModelIndex& index) const;
void paintConversationItem(QPainter* painter,
const QStyleOptionViewItem& option,
const QRect& rect,
const QModelIndex& index,
const bool isTemporary) const;
void paintInvitationItem( QPainter* painter,
const QStyleOptionViewItem& option,
const QRect& rect,
const QModelIndex& index) const;
constexpr static int sizeImage_ = 48;
constexpr static int cellHeight_ = 60;
......@@ -44,5 +51,7 @@ private:
constexpr static int fontSize_ = 11;
constexpr static int infoTextWidth_ = 176;
QPixmap* searchIcon_;
mutable std::map<int, bool> highlightMap_;
};
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z"/><path d="M0 0h24v24H0z" fill="none"/></svg>
\ No newline at end of file
......@@ -48,17 +48,21 @@
using namespace lrc::api;
using migrateCallback = std::function<void()>;
class LRCInstance : public QObject
{
Q_OBJECT
public:
static LRCInstance& instance() {
static LRCInstance instance_;
static LRCInstance& instance(migrateCallback willMigrate = {},
migrateCallback didMigrate = {}) {
static LRCInstance instance_(willMigrate, didMigrate);
return instance_;
};
static void init() {
instance();
static void init(migrateCallback willMigrate = {},
migrateCallback didMigrate = {}) {
instance(willMigrate, didMigrate);
};
static Lrc& getAPI() {
return *(instance().lrc_);
......@@ -174,6 +178,10 @@ public:
return instance().getCurrentAccountInfo().confProperties;
}
static void subscribeToDebugReceived() {
instance().lrc_->subscribeToDebugReceived();
}
signals:
/// emit once at least one valid account is loaded
void accountOnBoarded();
......@@ -182,8 +190,9 @@ private:
std::unique_ptr<Lrc> lrc_;
AccountListModel accountListModel_;
LRCInstance() {
lrc_ = std::make_unique<Lrc>();
LRCInstance(migrateCallback willMigrateCb = {},
migrateCallback didMigrateCb = {}) {
lrc_ = std::make_unique<Lrc>(willMigrateCb, didMigrateCb);
};
std::string selectedAccountId_;
......
......@@ -19,24 +19,23 @@
#include "mainwindow.h"
#include "globalinstances.h"
#include "downloadmanager.h"
#include "lrcinstance.h"
#include "pixbufmanipulator.h"
#include "runguard.h"
#include "utils.h"
#include "splashscreen.h"
#include <QApplication>
#include <QFile>
#include <QMessageBox>
#include "globalinstances.h"
#include <QFontDatabase>
#include <QLibraryInfo>
#include <QTranslator>
#include <ciso646>
#include "downloadmanager.h"
#include "lrcinstance.h"
#include "pixbufmanipulator.h"
#include "runguard.h"
#include "utils.h"
#ifdef Q_OS_WIN
#include <windows.h>
#endif
......@@ -134,35 +133,6 @@ main(int argc, char* argv[])
auto startMinimized = false;
QString uri = "";
#if defined _MSC_VER && !COMPILE_ONLY
gnutls_global_init();
#endif
GlobalInstances::setPixmapManipulator(std::make_unique<PixbufManipulator>());
LRCInstance::init();
QFile debugFile(qApp->applicationDirPath() + "/" + "jami.log");
for (auto string : QCoreApplication::arguments()) {
if (string.startsWith("jami:")) {
uri = string;
} else {
if (string == "-m" || string == "--minimized") {
startMinimized = true;
}
if (string == "-f" || string == "--file") {
debugFile.open(QIODevice::WriteOnly | QIODevice::Truncate);
debugFile.close();
fileDebug(debugFile);
}
#ifdef _MSC_VER
if (string == "-c" || string == "--vsconsole") {
vsConsoleDebug();
}
#endif
}
}
auto appDir = qApp->applicationDirPath() + "/";
const auto locale_name = QLocale::system().name();
const auto locale_lang = locale_name.split('_')[0];
......@@ -206,6 +176,63 @@ main(int argc, char* argv[])
}
#endif
#if defined _MSC_VER && !COMPILE_ONLY
gnutls_global_init();
#endif
GlobalInstances::setPixmapManipulator(std::make_unique<PixbufManipulator>());
SplashScreen* splash = new SplashScreen();
std::atomic_bool isMigrating = false;
LRCInstance::init(
[&splash, &a, &isMigrating] {
splash->setupUI(
QPixmap(":/images/logo-jami-standard-coul.png"),
QString("Jami - ") + QObject::tr("Migration needed"),
QObject::tr("Migration in progress... This may take a while."),
QColor(232, 232, 232)
);
splash->show();
isMigrating = true;
while (isMigrating) {
a.processEvents();
}
},
[&splash, &isMigrating] {
while (!isMigrating) {
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
isMigrating = false;
});
splash->hide();
LRCInstance::subscribeToDebugReceived();
QFile debugFile(qApp->applicationDirPath() + "/" + "jami.log");
for (auto string : QCoreApplication::arguments()) {
if (string.startsWith("jami:")) {
uri = string;
} else {
if (string == "-m" || string == "--minimized") {
startMinimized = true;
}
auto dbgFile = string == "-f" || string == "--file";
auto dbgConsole = string == "-c" || string == "--vsconsole";
if (dbgFile || dbgConsole) {
if (dbgFile) {
debugFile.open(QIODevice::WriteOnly | QIODevice::Truncate);
debugFile.close();
fileDebug(debugFile);
}
#ifdef _MSC_VER
if (dbgConsole) {
vsConsoleDebug();
}
#endif
}
}
}
QFontDatabase::addApplicationFont(":/images/FontAwesome.otf");
MainWindow::instance().createThumbBar();
......@@ -218,9 +245,12 @@ main(int argc, char* argv[])
}
QObject::connect(&a, &QApplication::aboutToQuit, [&guard] { guard.release(); });
splash->finish(&MainWindow::instance());
splash->deleteLater();
auto ret = a.exec();
LRCInstance::reset();
#ifdef Q_OS_WIN
FreeConsole();
#endif
......@@ -230,4 +260,4 @@ main(int argc, char* argv[])
GlobalSystemTray::instance().hide();
return ret;
}
}
\ No newline at end of file
......@@ -311,6 +311,9 @@ MessageWebView::printNewInteraction(lrc::api::ConversationModel& conversationMod
const lrc::api::interaction::Info& interaction)
{
auto interactionObject = interactionToJsonInteractionObject(conversationModel, msgId, interaction).toUtf8();
if (interactionObject.isEmpty()) {
return;
}
QString s = QString::fromLatin1("addMessage(%1);")
.arg(interactionObject.constData());