From 03d6596b8d6b45d83658f04a9a809d80cf901c2e Mon Sep 17 00:00:00 2001
From: Andreas Traczyk <andreas.traczyk@savoirfairelinux.com>
Date: Wed, 13 Nov 2019 12:59:52 -0500
Subject: [PATCH] messaging: save/restore draft messages

Change-Id: I6609cccdcc5e6ab4c86cad112d4a7c22900d2bfb
---
 callwidget.cpp               | 32 ++++++++++++++++++++++----------
 conversationitemdelegate.cpp | 26 ++++++++++++++++++++++++++
 lrcinstance.h                | 17 +++++++++++++++++
 messagewebview.cpp           | 33 +++++++++++++++++++++++++++++++--
 messagewebview.h             |  4 ++++
 smartlistmodel.cpp           |  2 ++
 smartlistmodel.h             |  3 ++-
 7 files changed, 104 insertions(+), 13 deletions(-)

diff --git a/callwidget.cpp b/callwidget.cpp
index ddb01db..2676918 100644
--- a/callwidget.cpp
+++ b/callwidget.cpp
@@ -976,18 +976,30 @@ CallWidget::setupChatView(const lrc::api::conversation::Info& convInfo)
     ui->sendContactRequestButton->setVisible(shouldShowSendContactRequestBtn);
 
     ui->messageView->setMessagesVisibility(false);
-    Utils::oneShotConnect(ui->messageView, &MessageWebView::messagesCleared,
-        [this, convInfo] {
-            auto convModel = LRCInstance::getCurrentConversationModel();
-            ui->messageView->printHistory(*convModel, convInfo.interactions);
-            Utils::oneShotConnect(ui->messageView, &MessageWebView::messagesLoaded,
-                [this] {
-                    ui->messageView->setMessagesVisibility(true);
+    Utils::oneShotConnect(ui->messageView, &MessageWebView::sendMessageContentSaved,
+        [this, &convInfo, &accountInfo, lastConvUid = lastConvUid_](const QString& content) {
+            if (!lastConvUid.empty()) {
+                LRCInstance::setContentDraft(
+                    lastConvUid.c_str(), accountInfo.id.c_str(), content);
+            }
+            Utils::oneShotConnect(ui->messageView, &MessageWebView::messagesCleared,
+                [this, &convInfo] {
+                    auto convModel = LRCInstance::getCurrentConversationModel();
+                    ui->messageView->printHistory(*convModel, convInfo.interactions);
+                    Utils::oneShotConnect(ui->messageView, &MessageWebView::messagesLoaded,
+                        [this] {
+                            ui->messageView->setMessagesVisibility(true);
+                        });
+                    setConversationProfileData(convInfo);
                 });
-            setConversationProfileData(convInfo);
+            ui->messageView->setInvitation(false);
+            ui->messageView->clear();
+            auto restoredContent = LRCInstance::getContentDraft(
+                convInfo.uid.c_str(), accountInfo.id.c_str());
+            ui->messageView->setSendMessageContent(restoredContent);
+            ui->smartList->update();
         });
-    ui->messageView->setInvitation(false);
-    ui->messageView->clear();
+    ui->messageView->requestSendMessageContent();
 }
 
 void
diff --git a/conversationitemdelegate.cpp b/conversationitemdelegate.cpp
index 3733a76..eba9000 100644
--- a/conversationitemdelegate.cpp
+++ b/conversationitemdelegate.cpp
@@ -272,6 +272,32 @@ ConversationItemDelegate::paintConversationItem(QPainter* painter,
     }
 
     // bottom-right: last interaction snippet or call state (if in call)
+    auto draft = index.data(static_cast<int>(SmartListModel::Role::Draft)).value<QString>();
+    if (!draft.isEmpty()) {
+        painter->save();
+        uint cp = 0x270F;
+        auto emojiString = QString::fromUcs4(&cp, 1);
+        QFont emojiMsgFont(QStringLiteral("Segoe UI Emoji"));
+        emojiMsgFont.setPointSize(scalingRatio > 1.0 ? fontSize_ - 2 : fontSize_);
+
+        QString text{ tr("Draft") };
+        int widthText{ QFontMetrics(font).width(text) };
+        int widthEmoji{ QFontMetrics(emojiMsgFont).width(emojiString) };
+        int margin { 4 };
+
+        painter->setFont(font);
+        painter->setPen(QColor(207, 83, 0));
+        painter->drawText(rectInfo2, Qt::AlignVCenter | Qt::AlignRight, text);
+
+        rectInfo2.moveTop(rectInfo2.top() - 2);
+        painter->setOpacity(0.7);
+        painter->setFont(emojiMsgFont);
+        painter->drawText(rectInfo2.right() - widthText - widthEmoji - margin, rectInfo2.y(),
+                          widthEmoji, rectInfo2.height(), Qt::AlignVCenter, emojiString);
+        painter->restore();
+        return;
+    }
+
     if (index.data(static_cast<int>(SmartListModel::Role::InCall)).value<bool>()) {
         QString callStateStr = index.data(static_cast<int>(SmartListModel::Role::CallStateStr)).value<QString>();
         if (!callStateStr.isNull()) {
diff --git a/lrcinstance.h b/lrcinstance.h
index 82d14c6..056f0f4 100644
--- a/lrcinstance.h
+++ b/lrcinstance.h
@@ -338,6 +338,22 @@ public:
             f();
         }
     }
+
+    static QString getContentDraft(const QString& convUid,
+                                   const QString& accountId)
+    {
+        auto draftKey = accountId + "_" + convUid;
+        return instance().contentDrafts_[draftKey];
+    }
+
+    static void setContentDraft(const QString& convUid,
+                                const QString& accountId,
+                                const QString& content)
+    {
+        auto draftKey = accountId + "_" + convUid;
+        instance().contentDrafts_[draftKey] = content;
+    }
+
 signals:
     void accountListChanged();
 
@@ -355,4 +371,5 @@ private:
     AccountListModel accountListModel_;
     std::string selectedAccountId_;
     std::string selectedConvUid_;
+    MapStringString contentDrafts_;
 };
diff --git a/messagewebview.cpp b/messagewebview.cpp
index 0553c84..e22923b 100644
--- a/messagewebview.cpp
+++ b/messagewebview.cpp
@@ -457,6 +457,21 @@ MessageWebView::displayNavbar(bool display)
     page()->runJavaScript(s, QWebEngineScript::MainWorld);
 }
 
+void
+MessageWebView::requestSendMessageContent()
+{
+    QString s = QString::fromLatin1("requestSendMessageContent();");
+    page()->runJavaScript(s, QWebEngineScript::MainWorld);
+}
+
+void
+MessageWebView::setSendMessageContent(const QString& content)
+{
+    QString s = QString::fromLatin1("setSendMessageContent(`%1`);")
+        .arg(content);
+    page()->runJavaScript(s, QWebEngineScript::MainWorld);
+}
+
 // JS bridging incoming
 Q_INVOKABLE int
 PrivateBridging::log(const QString& arg)
@@ -715,7 +730,7 @@ PrivateBridging::emitPasteKeyDetected()
     return 0;
 }
 
-int
+Q_INVOKABLE int
 PrivateBridging::openAudioRecorder(int spikePosX, int spikePosY)
 {
     //call the open audio recorder function in messageweview
@@ -729,7 +744,7 @@ PrivateBridging::openAudioRecorder(int spikePosX, int spikePosY)
     return 0;
 }
 
-int
+Q_INVOKABLE int
 PrivateBridging::openVideoRecorder(int spikePosX, int spikePosY)
 {
     //call the open video recorder function in messageweview
@@ -741,4 +756,18 @@ PrivateBridging::openVideoRecorder(int spikePosX, int spikePosY)
         qDebug() << "JS bridging - exception during openVideoRecorder!";
     }
     return 0;
+}
+
+Q_INVOKABLE int
+PrivateBridging::saveSendMessageContent(const QString& arg)
+{
+    try {
+        if (auto messageView = qobject_cast<MessageWebView*>(this->parent())) {
+            emit messageView->sendMessageContentSaved(arg);
+        }
+    } catch (...) {
+        qDebug() << "JS bridging - exception during saveSendMessageContent!";
+    }
+    return 0;
+
 }
\ No newline at end of file
diff --git a/messagewebview.h b/messagewebview.h
index d782aff..3573ec4 100644
--- a/messagewebview.h
+++ b/messagewebview.h
@@ -53,6 +53,7 @@ public:
     Q_INVOKABLE int emitPasteKeyDetected();
     Q_INVOKABLE int openAudioRecorder(int spikePosX,int spikePosY);
     Q_INVOKABLE int openVideoRecorder(int spikePosX,int spikePosY);
+    Q_INVOKABLE int saveSendMessageContent(const QString& arg);
 };
 
 class MessageWebView : public QWebEngineView
@@ -97,6 +98,8 @@ public:
     void updateChatviewFrame(bool accountEnabled, bool isBanned, bool isTemporary,
                              const QString& alias, const QString& bestId);
     void displayNavbar(bool display);
+    void requestSendMessageContent();
+    void setSendMessageContent(const QString& content);
 
 protected:
 
@@ -114,6 +117,7 @@ signals:
     void textSelectedReady();
     void pasteKeyDetected();
     void invitationAccepted();
+    void sendMessageContentSaved(const QString& content);
 
 private slots:
     void slotLoadFinished();
diff --git a/smartlistmodel.cpp b/smartlistmodel.cpp
index 234917d..0c326d0 100644
--- a/smartlistmodel.cpp
+++ b/smartlistmodel.cpp
@@ -239,6 +239,8 @@ SmartListModel::getConversationItemData(const conversation::Info& item,
     }
     case Role::SectionName:
         return QVariant(QString());
+    case Role::Draft:
+        return LRCInstance::getContentDraft(item.uid.c_str(), accountInfo.id.c_str());
     }
     return QVariant();
 }
diff --git a/smartlistmodel.h b/smartlistmodel.h
index 76657ac..108e08b 100644
--- a/smartlistmodel.h
+++ b/smartlistmodel.h
@@ -58,7 +58,8 @@ public:
         InCall,
         CallStateStr,
         SectionName,
-        AccountId
+        AccountId,
+        Draft
     };
 
     explicit SmartListModel(const std::string& accId,
-- 
GitLab