ChatForm::ChatForm(Friend* chatFriend) : f(chatFriend) , callId{0}, isTyping{false} { nameLabel->setText(f->getDisplayedName()); avatar->setPixmap(QPixmap(":/img/contact_dark.svg"), Qt::transparent); statusMessageLabel = new CroppingLabel(); statusMessageLabel->setObjectName("statusLabel"); statusMessageLabel->setFont(Style::getFont(Style::Medium)); statusMessageLabel->setMinimumHeight(Style::getFont(Style::Medium).pixelSize()); statusMessageLabel->setTextFormat(Qt::PlainText); callConfirm = nullptr; offlineEngine = new OfflineMsgEngine(f); typingTimer.setSingleShot(true); netcam = nullptr; callDurationTimer = nullptr; disableCallButtonsTimer = nullptr; chatWidget->setTypingNotification(ChatMessage::createTypingNotification()); headTextLayout->addWidget(statusMessageLabel); headTextLayout->addStretch(); callDuration = new QLabel(); headTextLayout->addWidget(callDuration, 1, Qt::AlignCenter); callDuration->hide(); loadHistoryAction = menu.addAction(QString(), this, SLOT(onLoadHistory())); connect(Core::getInstance(), &Core::fileSendStarted, this, &ChatForm::startFileSend); connect(sendButton, &QPushButton::clicked, this, &ChatForm::onSendTriggered); connect(fileButton, &QPushButton::clicked, this, &ChatForm::onAttachClicked); connect(screenshotButton, &QPushButton::clicked, this, &ChatForm::onScreenshotClicked); connect(callButton, &QPushButton::clicked, this, &ChatForm::onCallTriggered); connect(videoButton, &QPushButton::clicked, this, &ChatForm::onVideoCallTriggered); connect(msgEdit, &ChatTextEdit::enterPressed, this, &ChatForm::onSendTriggered); connect(msgEdit, &ChatTextEdit::textChanged, this, &ChatForm::onTextEditChanged); connect(Core::getInstance(), &Core::fileSendFailed, this, &ChatForm::onFileSendFailed); connect(this, SIGNAL(chatAreaCleared()), getOfflineMsgEngine(), SLOT(removeAllReciepts())); connect(&typingTimer, &QTimer::timeout, this, [=]{ Core::getInstance()->sendTyping(f->getFriendID(), false); isTyping = false; } ); connect(nameLabel, &CroppingLabel::textChanged, this, [=](QString text, QString orig) { if (text != orig) emit aliasChanged(text); } ); setAcceptDrops(true); retranslateUi(); Translator::registerHandler(std::bind(&ChatForm::retranslateUi, this), this); }
void ChatForm::SendMessageStr(QString msg) { if (msg.isEmpty()) return; bool isAction = msg.startsWith(ACTION_PREFIX, Qt::CaseInsensitive); if (isAction) msg.remove(0, ACTION_PREFIX.length()); QList<CString> splittedMsg = Core::splitMessage(msg, TOX_MAX_MESSAGE_LENGTH); QDateTime timestamp = QDateTime::currentDateTime(); for (CString& c_msg : splittedMsg) { QString qt_msg = CString::toString(c_msg.data(), c_msg.size()); QString qt_msg_hist = qt_msg; if (isAction) qt_msg_hist = ACTION_PREFIX + qt_msg; bool status = !Settings::getInstance().getFauxOfflineMessaging(); ChatMessage::Ptr ma = addSelfMessage(qt_msg, isAction, timestamp, false); int rec; if (isAction) rec = Core::getInstance()->sendAction(f->getFriendID(), qt_msg); else rec = Core::getInstance()->sendMessage(f->getFriendID(), qt_msg); Profile* profile = Nexus::getProfile(); if (profile->isHistoryEnabled()) { auto* offMsgEngine = getOfflineMsgEngine(); profile->getHistory()->addNewMessage(f->getToxId().publicKey, qt_msg_hist, Core::getInstance()->getSelfId().publicKey, timestamp, status, Core::getInstance()->getUsername(), [offMsgEngine,rec,ma](int64_t id) { offMsgEngine->registerReceipt(rec, id, ma); }); } else { // TODO: Make faux-offline messaging work partially with the history disabled ma->markAsSent(QDateTime::currentDateTime()); } msgEdit->setLastMessage(msg); //set last message only when sending it Widget::getInstance()->updateFriendActivity(f); } }
void ChatForm::SendMessageStr(QString msg) { if (msg.isEmpty()) return; bool isAction = msg.startsWith("/me ", Qt::CaseInsensitive); if (isAction) msg = msg = msg.right(msg.length() - 4); QList<CString> splittedMsg = Core::splitMessage(msg, TOX_MAX_MESSAGE_LENGTH); QDateTime timestamp = QDateTime::currentDateTime(); for (CString& c_msg : splittedMsg) { QString qt_msg = CString::toString(c_msg.data(), c_msg.size()); QString qt_msg_hist = qt_msg; if (isAction) qt_msg_hist = "/me " + qt_msg; bool status = !Settings::getInstance().getFauxOfflineMessaging(); int id = HistoryKeeper::getInstance()->addChatEntry(f->getToxId().publicKey, qt_msg_hist, Core::getInstance()->getSelfId().publicKey, timestamp, status, Core::getInstance()->getUsername()); ChatMessage::Ptr ma = addSelfMessage(qt_msg, isAction, timestamp, false); int rec; if (isAction) rec = Core::getInstance()->sendAction(f->getFriendID(), qt_msg); else rec = Core::getInstance()->sendMessage(f->getFriendID(), qt_msg); getOfflineMsgEngine()->registerReceipt(rec, id, ma); msgEdit->setLastMessage(msg); //set last message only when sending it Widget::getInstance()->updateFriendActivity(f); } }
void ChatForm::loadHistory(QDateTime since, bool processUndelivered) { QDateTime now = historyBaselineDate.addMSecs(-1); if (since > now) return; if (!earliestMessage.isNull()) { if (earliestMessage < since) return; if (earliestMessage < now) { now = earliestMessage; now = now.addMSecs(-1); } } auto msgs = HistoryKeeper::getInstance()->getChatHistory(HistoryKeeper::ctSingle, f->getToxID().publicKey, since, now); ToxId storedPrevId = previousId; ToxId prevId; QList<ChatLine::Ptr> historyMessages; QDate lastDate(1,0,0); for (const auto &it : msgs) { // Show the date every new day QDateTime msgDateTime = it.timestamp.toLocalTime(); QDate msgDate = msgDateTime.date(); if (msgDate > lastDate) { lastDate = msgDate; historyMessages.append(ChatMessage::createChatInfoMessage(msgDate.toString(Settings::getInstance().getDateFormat()), ChatMessage::INFO, QDateTime())); } // Show each messages ToxId authorId = ToxId(it.sender); QString authorStr = authorId.isActiveProfile() ? Core::getInstance()->getUsername() : resolveToxID(authorId); bool isAction = it.message.startsWith("/me ", Qt::CaseInsensitive); ChatMessage::Ptr msg = ChatMessage::createChatMessage(authorStr, isAction ? it.message.right(it.message.length() - 4) : it.message, isAction ? ChatMessage::ACTION : ChatMessage::NORMAL, authorId.isActiveProfile(), QDateTime()); if (!isAction && (prevId == authorId) && (prevMsgDateTime.secsTo(msgDateTime) < getChatLog()->repNameAfter) ) msg->hideSender(); prevId = authorId; prevMsgDateTime = msgDateTime; if (it.isSent || !authorId.isActiveProfile()) { msg->markAsSent(msgDateTime); } else { if (processUndelivered) { int rec; if (!isAction) rec = Core::getInstance()->sendMessage(f->getFriendID(), msg->toString()); else rec = Core::getInstance()->sendAction(f->getFriendID(), msg->toString()); getOfflineMsgEngine()->registerReceipt(rec, it.id, msg); } } historyMessages.append(msg); } previousId = storedPrevId; int savedSliderPos = chatWidget->verticalScrollBar()->maximum() - chatWidget->verticalScrollBar()->value(); earliestMessage = since; chatWidget->insertChatlineOnTop(historyMessages); savedSliderPos = chatWidget->verticalScrollBar()->maximum() - savedSliderPos; chatWidget->verticalScrollBar()->setValue(savedSliderPos); }
ChatForm::ChatForm(Friend* chatFriend) : f(chatFriend) , isTyping(false) { Core* core = Core::getInstance(); coreav = core->getAv(); nameLabel->setText(f->getDisplayedName()); avatar->setPixmap(QPixmap(":/img/contact_dark.svg")); statusMessageLabel = new CroppingLabel(); statusMessageLabel->setObjectName("statusLabel"); statusMessageLabel->setFont(Style::getFont(Style::Medium)); statusMessageLabel->setMinimumHeight(Style::getFont(Style::Medium).pixelSize()); statusMessageLabel->setTextFormat(Qt::PlainText); statusMessageLabel->setContextMenuPolicy(Qt::CustomContextMenu); callConfirm = nullptr; offlineEngine = new OfflineMsgEngine(f); typingTimer.setSingleShot(true); callDurationTimer = nullptr; disableCallButtonsTimer = nullptr; chatWidget->setTypingNotification(ChatMessage::createTypingNotification()); headTextLayout->addWidget(statusMessageLabel); headTextLayout->addStretch(); callDuration = new QLabel(); headTextLayout->addWidget(callDuration, 1, Qt::AlignCenter); callDuration->hide(); chatWidget->setMinimumHeight(50); connect(this, &GenericChatForm::messageInserted, this, &ChatForm::onMessageInserted); loadHistoryAction = menu.addAction(QString(), this, SLOT(onLoadHistory())); copyStatusAction = statusMessageMenu.addAction(QString(), this, SLOT(onCopyStatusMessage())); connect(core, &Core::fileSendStarted, this, &ChatForm::startFileSend); connect(sendButton, &QPushButton::clicked, this, &ChatForm::onSendTriggered); connect(fileButton, &QPushButton::clicked, this, &ChatForm::onAttachClicked); connect(screenshotButton, &QPushButton::clicked, this, &ChatForm::onScreenshotClicked); connect(callButton, &QPushButton::clicked, this, &ChatForm::onCallTriggered); connect(videoButton, &QPushButton::clicked, this, &ChatForm::onVideoCallTriggered); connect(msgEdit, &ChatTextEdit::enterPressed, this, &ChatForm::onSendTriggered); connect(msgEdit, &ChatTextEdit::textChanged, this, &ChatForm::onTextEditChanged); connect(core, &Core::fileSendFailed, this, &ChatForm::onFileSendFailed); connect(core, &Core::friendStatusChanged, this, &ChatForm::onFriendStatusChanged); connect(this, &ChatForm::chatAreaCleared, getOfflineMsgEngine(), &OfflineMsgEngine::removeAllReceipts); connect(statusMessageLabel, &CroppingLabel::customContextMenuRequested, this, [&](const QPoint& pos) { if (!statusMessageLabel->text().isEmpty()) { QWidget* sender = static_cast<QWidget*>(this->sender()); statusMessageMenu.exec(sender->mapToGlobal(pos)); } } ); connect(&typingTimer, &QTimer::timeout, this, [=]{ Core::getInstance()->sendTyping(f->getFriendID(), false); isTyping = false; } ); connect(nameLabel, &CroppingLabel::editFinished, this, [=](const QString& newName) { nameLabel->setText(newName); emit aliasChanged(newName); } ); setAcceptDrops(true); disableCallButtons(); retranslateUi(); Translator::registerHandler(std::bind(&ChatForm::retranslateUi, this), this); }