1
0
mirror of https://github.com/qTox/qTox.git synced 2024-03-22 14:00:36 +08:00

fix: Status reflection for friend calls

This commit is contained in:
Nils Fenner 2016-08-29 09:07:23 +02:00 committed by Diadlo
parent 7b60a5dd36
commit 917812daaa
No known key found for this signature in database
GPG Key ID: 5AF9F2E29107C727
15 changed files with 512 additions and 558 deletions

View File

@ -175,7 +175,9 @@ bool CoreAV::anyActiveCalls() const
*/
bool CoreAV::isCallActive(const Friend* f) const
{
return f && calls.contains(f->getFriendID());
return f && calls.contains(f->getFriendID())
? !(calls[f->getFriendID()].inactive)
: false;
}
/**

View File

@ -17,63 +17,65 @@
along with qTox. If not, see <http://www.gnu.org/licenses/>.
*/
#include <QDebug>
#include <QBoxLayout>
#include <QScrollBar>
#include <QFileDialog>
#include <QMessageBox>
#include <QPushButton>
#include <QMimeData>
#include <QFileInfo>
#include <QDragEnterEvent>
#include <QBitmap>
#include <QScreen>
#include <QTemporaryFile>
#include "chatform.h"
#include <QApplication>
#include <QGuiApplication>
#include <QStyle>
#include <QSplitter>
#include <QBitmap>
#include <QBoxLayout>
#include <QClipboard>
#include <QDebug>
#include <QDragEnterEvent>
#include <QFileDialog>
#include <QFileInfo>
#include <QMessageBox>
#include <QMimeData>
#include <QPushButton>
#include <QScreen>
#include <QScrollBar>
#include <QSplitter>
#include <QStyle>
#include <QTemporaryFile>
#include <cassert>
#include "chatform.h"
#include "audio/audio.h"
#include "core/core.h"
#include "core/coreav.h"
#include "friend.h"
#include "widget/style.h"
#include "persistence/settings.h"
#include "core/cstring.h"
#include "widget/tool/callconfirmwidget.h"
#include "widget/friendwidget.h"
#include "widget/form/loadhistorydialog.h"
#include "widget/tool/chattextedit.h"
#include "widget/widget.h"
#include "widget/maskablepixmapwidget.h"
#include "widget/tool/croppinglabel.h"
#include "chatlog/chatmessage.h"
#include "chatlog/content/filetransferwidget.h"
#include "chatlog/chatlinecontentproxy.h"
#include "chatlog/content/text.h"
#include "chatlog/chatlog.h"
#include "video/netcamview.h"
#include "persistence/offlinemsgengine.h"
#include "widget/tool/screenshotgrabber.h"
#include "widget/tool/flyoutoverlaywidget.h"
#include "widget/translator.h"
#include "video/videosource.h"
#include "video/camerasource.h"
#include "nexus.h"
#include "persistence/profile.h"
#include"audio/audio.h"
#include"chatlog/chatlinecontentproxy.h"
#include"chatlog/chatlog.h"
#include"chatlog/chatmessage.h"
#include"chatlog/content/filetransferwidget.h"
#include"chatlog/content/text.h"
#include"core/core.h"
#include"core/coreav.h"
#include"core/cstring.h"
#include"friend.h"
#include"nexus.h"
#include"nexus.h"
#include"persistence/offlinemsgengine.h"
#include"persistence/profile.h"
#include"persistence/settings.h"
#include"video/camerasource.h"
#include"video/netcamview.h"
#include"video/videosource.h"
#include"widget/form/loadhistorydialog.h"
#include"widget/friendwidget.h"
#include"widget/maskablepixmapwidget.h"
#include"widget/style.h"
#include"widget/tool/callconfirmwidget.h"
#include"widget/tool/chattextedit.h"
#include"widget/tool/croppinglabel.h"
#include"widget/tool/flyoutoverlaywidget.h"
#include"widget/tool/screenshotgrabber.h"
#include"widget/translator.h"
#include"widget/widget.h"
const QString ChatForm::ACTION_PREFIX = QStringLiteral("/me ");
ChatForm::ChatForm(Friend* chatFriend)
: f(chatFriend)
, callDuration(new QLabel(this))
, isTyping(false)
{
Core* core = Core::getInstance();
coreav = core->getAv();
nameLabel->setText(f->getDisplayedName());
avatar->setPixmap(QPixmap(":/img/contact_dark.svg"));
@ -91,9 +93,9 @@ ChatForm::ChatForm(Friend* chatFriend)
typingTimer.setSingleShot(true);
callDurationTimer = nullptr;
disableCallButtonsTimer = nullptr;
chatWidget->setTypingNotification(ChatMessage::createTypingNotification());
chatWidget->setMinimumHeight(50);
headTextLayout->addWidget(statusMessageLabel);
headTextLayout->addStretch();
@ -101,44 +103,72 @@ ChatForm::ChatForm(Friend* chatFriend)
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)
{
const Core* core = Core::getInstance();
connect(core, &Core::fileReceiveRequested,
this, &ChatForm::onFileRecvRequest);
connect(core, &Core::friendAvatarChanged,
this, &ChatForm::onAvatarChange);
connect(core, &Core::friendAvatarRemoved,
this, &ChatForm::onAvatarRemoved);
connect(core, &Core::fileSendStarted,
this, &ChatForm::startFileSend);
connect(core, &Core::fileSendFailed,
this, &ChatForm::onFileSendFailed);
connect(core, &Core::receiptRecieved,
this, &ChatForm::onReceiptReceived);
connect(core, &Core::friendMessageReceived,
this, &ChatForm::onFriendMessageReceived);
connect(core, &Core::friendTypingChanged,
this, &ChatForm::onFriendTypingChanged);
const CoreAV* av = core->getAv();
connect(av, &CoreAV::avInvite, this, &ChatForm::onAvInvite);
connect(av, &CoreAV::avStart, this, &ChatForm::onAvStart);
connect(av, &CoreAV::avEnd, this, &ChatForm::onAvEnd);
connect(sendButton, &QPushButton::clicked,
this, &ChatForm::onSendTriggered);
connect(fileButton, &QPushButton::clicked,
this, &ChatForm::onAttachClicked);
connect(screenshotButton, &QPushButton::clicked,
this, &ChatForm::onScreenshotClicked);
connect(callButton, &QAbstractButton::clicked,
this, &ChatForm::onCallTriggered);
connect(videoButton, &QAbstractButton::clicked,
this, &ChatForm::onVideoCallTriggered);
connect(micButton, &QAbstractButton::clicked,
this, &ChatForm::onMicMuteToggle);
connect(volButton, &QAbstractButton::clicked,
this, &ChatForm::onVolMuteToggle);
connect(msgEdit, &ChatTextEdit::enterPressed,
this, &ChatForm::onSendTriggered);
connect(msgEdit, &ChatTextEdit::textChanged,
this, &ChatForm::onTextEditChanged);
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, [=]{
});
connect(&typingTimer, &QTimer::timeout, this, [=] {
Core::getInstance()->sendTyping(f->getFriendID(), false);
isTyping = false;
} );
connect(nameLabel, &CroppingLabel::editFinished, this, [=](const QString& newName)
{
});
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);
}
@ -147,14 +177,13 @@ ChatForm::~ChatForm()
{
Translator::unregister(this);
delete netcam;
delete callConfirm;
delete offlineEngine;
}
void ChatForm::setStatusMessage(QString newMessage)
{
statusMessageLabel->setText(newMessage);
statusMessageLabel->setToolTip(Qt::convertFromPlainText(newMessage, Qt::WhiteSpaceNormal)); // for overlength messsages
// for long messsages
statusMessageLabel->setToolTip(Qt::convertFromPlainText(newMessage, Qt::WhiteSpaceNormal));
}
void ChatForm::onSendTriggered()
@ -197,6 +226,7 @@ void ChatForm::onAttachClicked()
if (paths.isEmpty())
return;
Core* core = Core::getInstance();
for (QString path : paths)
{
QFile file(path);
@ -207,11 +237,13 @@ void ChatForm::onAttachClicked()
tr("qTox wasn't able to open %1").arg(QFileInfo(path).fileName()));
continue;
}
if (file.isSequential())
{
QMessageBox::critical(this,
tr("Bad idea"),
tr("You're trying to send a special (sequential) file, that's not going to work!"));
tr("You're trying to send a sequential file,"
" which is not going to work!"));
file.close();
continue;
}
@ -219,7 +251,8 @@ void ChatForm::onAttachClicked()
file.close();
QFileInfo fi(path);
emit sendFile(f->getFriendID(), fi.fileName(), path, filesize);
core->sendFile(f->getFriendID(), fi.fileName(), path,
filesize);
}
}
@ -277,13 +310,12 @@ void ChatForm::onFileRecvRequest(ToxFile file)
Widget::getInstance()->updateFriendActivity(f);
}
void ChatForm::onAvInvite(uint32_t FriendId, bool video)
void ChatForm::onAvInvite(uint32_t friendId, bool video)
{
if (FriendId != f->getFriendID())
if (friendId != f->getFriendID())
return;
qDebug() << "onAvInvite";
disableCallButtons();
callConfirm = new CallConfirmWidget(video ? videoButton : callButton, *f);
insertChatMessage(ChatMessage::createChatInfoMessage(tr("%1 calling").arg(f->getDisplayedName()),
ChatMessage::INFO,
QDateTime::currentDateTime()));
@ -293,35 +325,25 @@ void ChatForm::onAvInvite(uint32_t FriendId, bool video)
{
uint32_t friendId = f->getFriendID();
qDebug() << "automatic call answer";
CoreAV* coreav = Core::getInstance()->getAv();
QMetaObject::invokeMethod(coreav, "answerCall", Qt::QueuedConnection, Q_ARG(uint32_t, friendId));
onAvStart(friendId,video);
}
else
{
if (video)
{
callConfirm = new CallConfirmWidget(videoButton, *f);
videoButton->setObjectName("yellow");
videoButton->setToolTip(tr("Accept video call"));
videoButton->style()->polish(videoButton);
connect(videoButton, &QPushButton::clicked, this, &ChatForm::onAnswerCallTriggered);
}
else
{
callConfirm = new CallConfirmWidget(callButton, *f);
callButton->setObjectName("yellow");
callButton->setToolTip(tr("Accept audio call"));
callButton->style()->polish(callButton);
connect(callButton, &QPushButton::clicked, this, &ChatForm::onAnswerCallTriggered);
}
callConfirm->show();
if (f->getFriendWidget()->chatFormIsSet(false))
callConfirm->show();
connect(callConfirm.data(), &CallConfirmWidget::accepted,
this, &ChatForm::onAnswerCallTriggered);
connect(callConfirm.data(), &CallConfirmWidget::rejected,
this, &ChatForm::onRejectCallTriggered);
connect(callConfirm, &CallConfirmWidget::accepted, this, &ChatForm::onAnswerCallTriggered);
connect(callConfirm, &CallConfirmWidget::rejected, this, &ChatForm::onRejectCallTriggered);
insertChatMessage(ChatMessage::createChatInfoMessage(
tr("%1 calling").arg(f->getDisplayedName()),
ChatMessage::INFO,
QDateTime::currentDateTime()));
Widget::getInstance()->newFriendMessageAlert(FriendId, false);
Widget::getInstance()->newFriendMessageAlert(friendId, false);
Audio& audio = Audio::getInstance();
audio.startLoop();
audio.playMono16Sound(Audio::getSound(Audio::Sound::IncomingCall));
@ -333,44 +355,12 @@ void ChatForm::onAvStart(uint32_t FriendId, bool video)
if (FriendId != f->getFriendID())
return;
qDebug() << "onAvStart";
audioInputFlag = true;
audioOutputFlag = true;
disableCallButtons();
if (video)
{
videoButton->setObjectName("red");
videoButton->setToolTip(tr("End video call"));
videoButton->style()->polish(videoButton);
connect(videoButton, SIGNAL(clicked()),
this, SLOT(onHangupCallTriggered()));
showNetcam();
}
else
{
callButton->setObjectName("red");
callButton->setToolTip(tr("End audio call"));
callButton->style()->polish(callButton);
connect(callButton, SIGNAL(clicked()),
this, SLOT(onHangupCallTriggered()));
hideNetcam();
}
micButton->setObjectName("green");
micButton->style()->polish(micButton);
micButton->setToolTip(tr("Mute microphone"));
volButton->setObjectName("green");
volButton->style()->polish(volButton);
volButton->setToolTip(tr("Mute call"));
connect(micButton, SIGNAL(clicked()),
this, SLOT(onMicMuteToggle()));
connect(volButton, SIGNAL(clicked()),
this, SLOT(onVolMuteToggle()));
updateCallButtons();
startCounter();
}
@ -379,39 +369,32 @@ void ChatForm::onAvEnd(uint32_t FriendId)
if (FriendId != f->getFriendID())
return;
qDebug() << "onAvEnd";
delete callConfirm;
callConfirm = nullptr;
//Fixes an OS X bug with ending a call while in full screen
if (netcam && netcam->isFullScreen())
netcam->showNormal();
Audio::getInstance().stopLoop();
enableCallButtons();
updateCallButtons();
stopCounter();
hideNetcam();
}
void ChatForm::showOutgoingCall(bool video)
{
audioInputFlag = true;
audioOutputFlag = true;
disableCallButtons();
if (video)
{
videoButton->setObjectName("yellow");
videoButton->style()->polish(videoButton);
videoButton->setStyleSheet(Style::getStylesheet(QStringLiteral(":/ui/videoButton/videoButton.css")));
videoButton->setToolTip(tr("Cancel video call"));
connect(videoButton, &QPushButton::clicked,
this, &ChatForm::onCancelCallTriggered);
}
else
{
callButton->setObjectName("yellow");
callButton->style()->polish(callButton);
callButton->setStyleSheet(Style::getStylesheet(QStringLiteral(":/ui/callButton/callButton.css")));
callButton->setToolTip(tr("Cancel audio call"));
connect(callButton, &QPushButton::clicked,
this, &ChatForm::onCancelCallTriggered);
}
addSystemInfoMessage(tr("Calling %1").arg(f->getDisplayedName()),
@ -423,216 +406,121 @@ void ChatForm::showOutgoingCall(bool video)
void ChatForm::onAnswerCallTriggered()
{
qDebug() << "onAnswerCallTriggered";
if (callConfirm)
{
delete callConfirm;
callConfirm = nullptr;
}
delete callConfirm;
Audio::getInstance().stopLoop();
disableCallButtons();
updateCallButtons();
if (!coreav->answerCall(f->getFriendID()))
CoreAV* av = Core::getInstance()->getAv();
if (!av->answerCall(f->getFriendID()))
{
enableCallButtons();
updateCallButtons();
stopCounter();
hideNetcam();
return;
}
onAvStart(f->getFriendID(), coreav->isCallActive(f));
}
void ChatForm::onHangupCallTriggered()
{
qDebug() << "onHangupCallTriggered";
//Fixes an OS X bug with ending a call while in full screen
if (netcam && netcam->isFullScreen())
netcam->showNormal();
audioInputFlag = false;
audioOutputFlag = false;
coreav->cancelCall(f->getFriendID());
stopCounter();
enableCallButtons();
hideNetcam();
onAvStart(f->getFriendID(), av->isCallVideoEnabled(f));
}
void ChatForm::onRejectCallTriggered()
{
qDebug() << "onRejectCallTriggered";
if (callConfirm)
{
delete callConfirm;
callConfirm = nullptr;
}
delete callConfirm;
Audio::getInstance().stopLoop();
audioInputFlag = false;
audioOutputFlag = false;
coreav->cancelCall(f->getFriendID());
enableCallButtons();
stopCounter();
CoreAV* av = Core::getInstance()->getAv();
av->cancelCall(f->getFriendID());
}
void ChatForm::onCallTriggered()
{
qDebug() << "onCallTriggered";
disableCallButtons();
if (coreav->startCall(f->getFriendID(), false))
CoreAV* av = Core::getInstance()->getAv();
if (av->isCallActive(f))
{
av->cancelCall(f->getFriendID());
}
else if (av->startCall(f->getFriendID(), false))
{
showOutgoingCall(false);
else
enableCallButtons();
}
}
void ChatForm::onVideoCallTriggered()
{
qDebug() << "onVideoCallTriggered";
disableCallButtons();
if (coreav->startCall(f->getFriendID(), true))
CoreAV* av = Core::getInstance()->getAv();
if (av->isCallActive(f))
{
// TODO: We want to activate video on the active call.
if (av->isCallVideoEnabled(f))
av->cancelCall(f->getFriendID());
}
else if (av->startCall(f->getFriendID(), true))
{
showOutgoingCall(true);
}
}
void ChatForm::updateCallButtons()
{
CoreAV* av = Core::getInstance()->getAv();
if (av->isCallActive(f))
{
callButton->setObjectName("red");
callButton->setToolTip(tr("End audio call"));
if (av->isCallVideoEnabled(f))
{
videoButton->setObjectName("red");
videoButton->setToolTip(tr("End video call"));
}
}
else
enableCallButtons();
}
void ChatForm::onCancelCallTriggered()
{
qDebug() << "onCancelCallTriggered";
if (!coreav->cancelCall(f->getFriendID()))
qWarning() << "Failed to cancel a call! Assuming we're not in call";
enableCallButtons();
stopCounter();
hideNetcam();
}
void ChatForm::enableCallButtons()
{
qDebug() << "enableCallButtons";
audioInputFlag = false;
audioOutputFlag = false;
disableCallButtons();
if (disableCallButtonsTimer == nullptr)
{
disableCallButtonsTimer = new QTimer();
connect(disableCallButtonsTimer, SIGNAL(timeout()),
this, SLOT(onEnableCallButtons()));
disableCallButtonsTimer->start(1500); // 1.5sec
qDebug() << "timer started!!";
}
}
const Status fs = f->getStatus();
callButton->setEnabled(fs != Status::Offline);
videoButton->setEnabled(fs != Status::Offline);
void ChatForm::disableCallButtons()
{
// Prevents race enable / disable / onEnable, when it should be disabled
if (disableCallButtonsTimer)
{
disableCallButtonsTimer->stop();
delete disableCallButtonsTimer;
disableCallButtonsTimer = nullptr;
if (callButton->isEnabled())
{
callButton->setObjectName("green");
callButton->setToolTip(tr("Start audio call"));
}
if (videoButton->isEnabled())
{
videoButton->setObjectName("green");
videoButton->setToolTip(tr("Start video call"));
}
}
micButton->setObjectName("grey");
micButton->style()->polish(micButton);
micButton->setToolTip("");
micButton->disconnect();
volButton->setObjectName("grey");
volButton->style()->polish(volButton);
volButton->setToolTip("");
volButton->disconnect();
callButton->setStyleSheet(Style::getStylesheet(QStringLiteral(":/ui/callButton/callButton.css")));
videoButton->setStyleSheet(Style::getStylesheet(QStringLiteral(":/ui/videoButton/videoButton.css")));
callButton->setObjectName("grey");
callButton->style()->polish(callButton);
callButton->setToolTip("");
callButton->disconnect();
videoButton->setObjectName("grey");
videoButton->style()->polish(videoButton);
videoButton->setToolTip("");
videoButton->disconnect();
}
void ChatForm::onEnableCallButtons()
{
audioInputFlag = false;
audioOutputFlag = false;
callButton->setObjectName("green");
callButton->style()->polish(callButton);
callButton->setToolTip(tr("Start audio call"));
videoButton->setObjectName("green");
videoButton->style()->polish(videoButton);
videoButton->setToolTip(tr("Start video call"));
connect(callButton, SIGNAL(clicked()),
this, SLOT(onCallTriggered()));
connect(videoButton, SIGNAL(clicked()),
this, SLOT(onVideoCallTriggered()));
if (disableCallButtonsTimer != nullptr)
{
disableCallButtonsTimer->stop();
delete disableCallButtonsTimer;
disableCallButtonsTimer = nullptr;
}
updateMuteMicButton();
updateMuteVolButton();
}
void ChatForm::onMicMuteToggle()
{
if (audioInputFlag)
{
coreav->toggleMuteCallInput(f);
if (micButton->objectName() == "red")
{
micButton->setObjectName("green");
micButton->setToolTip(tr("Mute microphone"));
}
else
{
micButton->setObjectName("red");
micButton->setToolTip(tr("Unmute microphone"));
}
CoreAV* av = Core::getInstance()->getAv();
Style::repolish(micButton);
}
av->toggleMuteCallInput(f);
updateMuteMicButton();
}
void ChatForm::onVolMuteToggle()
{
if (audioOutputFlag)
{
coreav->toggleMuteCallOutput(f);
if (volButton->objectName() == "red")
{
volButton->setObjectName("green");
volButton->setToolTip(tr("Mute call"));
}
else
{
volButton->setObjectName("red");
volButton->setToolTip(tr("Unmute call"));
}
CoreAV* av = Core::getInstance()->getAv();
Style::repolish(volButton);
}
av->toggleMuteCallOutput(f);
updateMuteVolButton();
}
void ChatForm::onFileSendFailed(uint32_t FriendId, const QString &fname)
void ChatForm::onFileSendFailed(uint32_t friendId, const QString &fname)
{
if (FriendId != f->getFriendID())
if (friendId != f->getFriendID())
return;
addSystemInfoMessage(tr("Failed to send file \"%1\"").arg(fname), ChatMessage::ERROR, QDateTime::currentDateTime());
@ -644,19 +532,76 @@ void ChatForm::onFriendStatusChanged(uint32_t friendId, Status status)
if(friendId != f->getFriendID())
return;
Status old = oldStatus.value(friendId, Status::Offline);
if (status == Status::Offline)
{
// Hide the "is typing" message when a friend goes offline
setFriendTyping(false);
}
else
{
QTimer::singleShot(250, this, SLOT(onDeliverOfflineMessages()));
}
if (old != Status::Offline && status == Status::Offline)
disableCallButtons();
else if (old == Status::Offline && status != Status::Offline)
enableCallButtons();
updateCallButtons();
oldStatus[friendId] = status;
if (Settings::getInstance().getStatusChangeNotificationEnabled())
{
QString fStatus = "";
switch (status)
{
case Status::Away:
fStatus = tr("away", "contact status"); break;
case Status::Busy:
fStatus = tr("busy", "contact status"); break;
case Status::Offline:
fStatus = tr("offline", "contact status"); break;
case Status::Online:
fStatus = tr("online", "contact status"); break;
}
addSystemInfoMessage(tr("%1 is now %2", "e.g. \"Dubslow is now online\"")
.arg(f->getDisplayedName()).arg(fStatus),
ChatMessage::INFO, QDateTime::currentDateTime());
}
}
void ChatForm::onAvatarChange(uint32_t FriendId, const QPixmap &pic)
void ChatForm::onFriendTypingChanged(quint32 friendId, bool isTyping)
{
if (FriendId != f->getFriendID())
if (friendId == f->getFriendID())
setFriendTyping(isTyping);
}
void ChatForm::onFriendNameChanged(const QString& name)
{
if (sender() == f)
setName(name);
}
void ChatForm::onFriendMessageReceived(quint32 friendId, const QString& message,
bool isAction)
{
if (friendId != f->getFriendID())
return;
QDateTime timestamp = QDateTime::currentDateTime();
addMessage(f->getToxId(), message, isAction, timestamp, true);
}
void ChatForm::onStatusMessage(const QString& message)
{
if (sender() == f)
setStatusMessage(message);
}
void ChatForm::onReceiptReceived(quint32 friendId, int receipt)
{
if (friendId == f->getFriendID())
f->getChatForm()->getOfflineMsgEngine()->dischargeReceipt(receipt);
}
void ChatForm::onAvatarChange(uint32_t friendId, const QPixmap &pic)
{
if (friendId != f->getFriendID())
return;
avatar->setPixmap(pic);
@ -680,6 +625,7 @@ void ChatForm::dropEvent(QDropEvent *ev)
{
if (ev->mimeData()->hasUrls())
{
Core* core = Core::getInstance();
for (QUrl url : ev->mimeData()->urls())
{
QFileInfo info(url.path());
@ -690,26 +636,34 @@ void ChatForm::dropEvent(QDropEvent *ev)
SendMessageStr(url.toString());
continue;
}
if (!file.exists() || !file.open(QIODevice::ReadOnly))
{
info.setFile(url.toLocalFile());
file.setFileName(info.absoluteFilePath());
if (!file.exists() || !file.open(QIODevice::ReadOnly))
{
QMessageBox::warning(this, tr("Unable to open"), tr("qTox wasn't able to open %1").arg(info.fileName()));
QMessageBox::warning(this, tr("Unable to open"),
tr("qTox wasn't able to open %1")
.arg(info.fileName()));
continue;
}
}
if (file.isSequential())
{
QMessageBox::critical(0, tr("Bad idea"), tr("You're trying to send a special (sequential) file, that's not going to work!"));
QMessageBox::critical(0, tr("Bad idea"),
tr("You're trying to send a sequential"
" file, which is not going to work!"));
file.close();
continue;
}
file.close();
if (info.exists())
Core::getInstance()->sendFile(f->getFriendID(), info.fileName(), info.absoluteFilePath(), info.size());
core->sendFile(f->getFriendID(), info.fileName(),
info.absoluteFilePath(), info.size());
}
}
}
@ -722,6 +676,23 @@ void ChatForm::onAvatarRemoved(uint32_t FriendId)
avatar->setPixmap(QPixmap(":/img/contact_dark.svg"));
}
void ChatForm::clearChatArea(bool notInForm)
{
GenericChatForm::clearChatArea(notInForm);
f->getChatForm()->getOfflineMsgEngine()->removeAllReceipts();
}
void ChatForm::onDeliverOfflineMessages()
{
f->getChatForm()->getOfflineMsgEngine()->deliverOfflineMsgs();
}
void ChatForm::onLoadChatHistory()
{
if (sender() == f)
loadHistory(QDateTime::currentDateTime().addDays(-7), true);
}
// TODO: Split on smaller methods (style)
void ChatForm::loadHistory(QDateTime since, bool processUndelivered)
{
@ -870,7 +841,8 @@ void ChatForm::onScreenshotTaken(const QPixmap &pixmap) {
file.close();
QFileInfo fi(file);
emit sendFile(f->getFriendID(), fi.fileName(), fi.filePath(), filesize);
Core::getInstance()->sendFile(f->getFriendID(), fi.fileName(),
fi.filePath(), filesize);
}
else
{
@ -894,8 +866,10 @@ void ChatForm::onLoadHistory()
}
}
void ChatForm::onMessageInserted()
void ChatForm::insertChatMessage(ChatMessage::Ptr msg)
{
GenericChatForm::insertChatMessage(msg);
if (netcam && bodySplitter->sizes()[1] == 0)
netcam->setShowMessages(true, true);
}
@ -911,12 +885,59 @@ void ChatForm::onCopyStatusMessage()
}
}
void ChatForm::updateMuteMicButton()
{
const CoreAV* av = Core::getInstance()->getAv();
micButton->setEnabled(av->isCallActive(f));
if (micButton->isEnabled())
{
if (av->isCallInputMuted(f))
{
micButton->setObjectName("red");
micButton->setToolTip(tr("Unmute microphone"));
}
else
{
micButton->setObjectName("green");
micButton->setToolTip(tr("Mute microphone"));
}
}
micButton->setStyleSheet(Style::getStylesheet(QStringLiteral(":/ui/micButton/micButton.css")));
}
void ChatForm::updateMuteVolButton()
{
const CoreAV* av = Core::getInstance()->getAv();
volButton->setEnabled(av->isCallActive(f));
if (videoButton->isEnabled())
{
if (av->isCallOutputMuted(f))
{
volButton->setObjectName("red");
volButton->setToolTip(tr("Unmute call"));
}
else
{
volButton->setObjectName("green");
volButton->setToolTip(tr("Mute call"));
}
}
volButton->setStyleSheet(Style::getStylesheet(QStringLiteral(":/ui/volButton/volButton.css")));
}
void ChatForm::startCounter()
{
if (!callDurationTimer)
{
callDurationTimer = new QTimer();
connect(callDurationTimer, SIGNAL(timeout()), this, SLOT(onUpdateTime()));
connect(callDurationTimer, &QTimer::timeout,
this, &ChatForm::onUpdateTime);
callDurationTimer->start(1000);
timeElapsed.start();
callDuration->show();
@ -1062,15 +1083,8 @@ void ChatForm::retranslateUi()
loadHistoryAction->setText(tr("Load chat history..."));
copyStatusAction->setText(tr("Copy"));
if (volObjectName == QStringLiteral("green"))
volButton->setToolTip(tr("Mute call"));
else if (volObjectName == QStringLiteral("red"))
volButton->setToolTip(tr("Unmute call"));
if (micObjectName == QStringLiteral("green"))
micButton->setToolTip(tr("Mute microphone"));
else if (micObjectName == QStringLiteral("red"))
micButton->setToolTip(tr("Unmute microphone"));
updateMuteMicButton();
updateMuteVolButton();
if (netcam)
netcam->setShowMessages(chatWidget->isVisible());

View File

@ -56,77 +56,81 @@ public:
static const QString ACTION_PREFIX;
signals:
void sendFile(uint32_t friendId, QString, QString, long long);
void aliasChanged(const QString& alias);
public slots:
void startFileSend(ToxFile file);
void onFileRecvRequest(ToxFile file);
void onAvInvite(uint32_t FriendId, bool video);
void onAvStart(uint32_t FriendId, bool video);
void onAvEnd(uint32_t FriendId);
void onAvatarChange(uint32_t FriendId, const QPixmap& pic);
void onAvatarRemoved(uint32_t FriendId);
void onAvInvite(uint32_t friendId, bool video);
void onAvStart(uint32_t friendId, bool video);
void onAvEnd(uint32_t friendId);
void onAvatarChange(uint32_t friendId, const QPixmap& pic);
void onAvatarRemoved(uint32_t friendId);
private slots:
void clearChatArea(bool notInForm) override final;
void onDeliverOfflineMessages();
void onLoadChatHistory();
void onSendTriggered();
void onTextEditChanged();
void onAttachClicked();
void onCallTriggered();
void onVideoCallTriggered();
void onAnswerCallTriggered();
void onHangupCallTriggered();
void onCancelCallTriggered();
void onRejectCallTriggered();
void onMicMuteToggle();
void onVolMuteToggle();
void onFileSendFailed(uint32_t FriendId, const QString &fname);
void onFriendStatusChanged(uint32_t friendId, Status status);
void onFileSendFailed(uint32_t friendId, const QString &fname);
void onFriendStatusChanged(quint32 friendId, Status status);
void onFriendTypingChanged(quint32 friendId, bool isTyping);
void onFriendNameChanged(const QString& name);
void onFriendMessageReceived(quint32 friendId, const QString& message,
bool isAction);
void onStatusMessage(const QString& message);
void onReceiptReceived(quint32 friendId, int receipt);
void onLoadHistory();
void onUpdateTime();
void onEnableCallButtons();
void onScreenshotClicked();
void onScreenshotTaken(const QPixmap &pixmap);
void doScreenshot();
void onMessageInserted();
void onCopyStatusMessage();
private:
void updateMuteMicButton();
void updateMuteVolButton();
void retranslateUi();
void showOutgoingCall(bool video);
void startCounter();
void stopCounter();
QString secondsToDHMS(quint32 duration);
void enableCallButtons();
void disableCallButtons();
void updateCallButtons();
void SendMessageStr(QString msg);
protected:
virtual GenericNetCamView* createNetcam() final override;
// drag & drop
virtual void dragEnterEvent(QDragEnterEvent* ev) final override;
virtual void dropEvent(QDropEvent* ev) final override;
virtual void hideEvent(QHideEvent* event) final override;
virtual void showEvent(QShowEvent* event) final override;
GenericNetCamView* createNetcam() final override;
void insertChatMessage(ChatMessage::Ptr msg) final override;
void dragEnterEvent(QDragEnterEvent* ev) final override;
void dropEvent(QDropEvent* ev) final override;
void hideEvent(QHideEvent* event) final override;
void showEvent(QShowEvent* event) final override;
private:
CoreAV* coreav;
Friend* f;
CroppingLabel *statusMessageLabel;
QMenu statusMessageMenu;
QLabel *callDuration;
QTimer *callDurationTimer;
QTimer typingTimer;
QTimer *disableCallButtonsTimer;
QElapsedTimer timeElapsed;
OfflineMsgEngine *offlineEngine;
QAction* loadHistoryAction;
QAction* copyStatusAction;
QHash<uint, FileTransferInstance*> ftransWidgets;
QMap<uint32_t, Status> oldStatus;
CallConfirmWidget *callConfirm;
QPointer<CallConfirmWidget> callConfirm;
bool isTyping;
};

View File

@ -87,7 +87,7 @@ protected slots:
void onEmoteInsertRequested(QString str);
void onSaveLogClicked();
void onCopyLogClicked();
void clearChatArea(bool);
virtual void clearChatArea(bool);
void clearChatArea();
void onSelectAllClicked();
void showFileMenu();
@ -104,7 +104,7 @@ protected:
void hideNetcam();
virtual GenericNetCamView* createNetcam() = 0;
QString resolveToxId(const ToxId &id);
void insertChatMessage(ChatMessage::Ptr msg);
virtual void insertChatMessage(ChatMessage::Ptr msg);
void adjustFileMenuPosition();
virtual void hideEvent(QHideEvent* event) override;
virtual void showEvent(QShowEvent *) override;

View File

@ -47,7 +47,10 @@
*/
GroupChatForm::GroupChatForm(Group* chatGroup)
: group(chatGroup), inCall{false}
: audioInputFlag(false)
, audioOutputFlag(false)
, group(chatGroup)
, inCall(false)
{
nusersLabel = new QLabel();
@ -301,15 +304,16 @@ void GroupChatForm::onMicMuteToggle()
{
if (audioInputFlag)
{
CoreAV* av = Core::getInstance()->getAv();
if (micButton->objectName() == "red")
{
Core::getInstance()->getAv()->muteCallInput(group, false);
av->muteCallInput(group, false);
micButton->setObjectName("green");
micButton->setToolTip(tr("Mute microphone"));
}
else
{
Core::getInstance()->getAv()->muteCallInput(group, true);
av->muteCallInput(group, true);
micButton->setObjectName("red");
micButton->setToolTip(tr("Unmute microphone"));
}
@ -322,15 +326,16 @@ void GroupChatForm::onVolMuteToggle()
{
if (audioOutputFlag)
{
CoreAV* av = Core::getInstance()->getAv();
if (volButton->objectName() == "red")
{
Core::getInstance()->getAv()->muteCallOutput(group, false);
av->muteCallOutput(group, false);
volButton->setObjectName("green");
volButton->setToolTip(tr("Mute call"));
}
else
{
Core::getInstance()->getAv()->muteCallOutput(group, true);
av->muteCallOutput(group, true);
volButton->setObjectName("red");
volButton->setToolTip(tr("Unmute call"));
}
@ -396,9 +401,10 @@ void GroupChatForm::keyPressEvent(QKeyEvent* ev)
// Push to talk (CTRL+P)
if (ev->key() == Qt::Key_P && (ev->modifiers() & Qt::ControlModifier) && inCall)
{
if (Core::getInstance()->getAv()->isGroupCallInputMuted(group))
CoreAV* av = Core::getInstance()->getAv();
if (!av->isGroupCallInputMuted(group))
{
Core::getInstance()->getAv()->muteCallInput(group, false);
av->muteCallInput(group, false);
micButton->setObjectName("green");
micButton->style()->polish(micButton);
Style::repolish(micButton);
@ -414,9 +420,10 @@ void GroupChatForm::keyReleaseEvent(QKeyEvent* ev)
// Push to talk (CTRL+P)
if (ev->key() == Qt::Key_P && (ev->modifiers() & Qt::ControlModifier) && inCall)
{
if (!Core::getInstance()->getAv()->isGroupCallInputMuted(group))
CoreAV* av = Core::getInstance()->getAv();
if (av->isGroupCallInputMuted(group))
{
Core::getInstance()->getAv()->muteCallInput(group, true);
av->muteCallInput(group, true);
micButton->setObjectName("red");
micButton->style()->polish(micButton);
Style::repolish(micButton);

View File

@ -60,6 +60,10 @@ private:
void retranslateUi();
private:
// TODO: flags are deprecated -> remove
bool audioInputFlag;
bool audioOutputFlag;
Group* group;
QList<QLabel*> peerLabels;
QMap<int, QTimer*> peerAudioTimers;

View File

@ -59,6 +59,7 @@ CallConfirmWidget::CallConfirmWidget(const QWidget *Anchor, const Friend& f) :
rectRatio(static_cast<qreal>(rectH)/static_cast<qreal>(rectW))
{
setWindowFlags(Qt::SubWindow);
setAttribute(Qt::WA_DeleteOnClose);
QPalette palette;
palette.setColor(QPalette::WindowText, Qt::white);

View File

@ -44,10 +44,10 @@ public slots:
void reposition();
protected:
virtual void paintEvent(QPaintEvent* event) final override;
virtual void showEvent(QShowEvent* event) final override;
virtual void hideEvent(QHideEvent* event) final override;
virtual bool eventFilter(QObject *, QEvent* event) final override;
void paintEvent(QPaintEvent* event) final;
void showEvent(QShowEvent* event) final;
void hideEvent(QHideEvent* event) final;
bool eventFilter(QObject *, QEvent* event) final;
private:
const QWidget* anchor;

View File

@ -76,7 +76,7 @@ void CroppingLabel::setEditable(bool editable)
unsetCursor();
}
void CroppingLabel::setEdlideMode(Qt::TextElideMode elide)
void CroppingLabel::setElideMode(Qt::TextElideMode elide)
{
elideMode = elide;
}

View File

@ -32,7 +32,7 @@ public:
void editBegin();
void setEditable(bool editable);
void setEdlideMode(Qt::TextElideMode elide);
void setElideMode(Qt::TextElideMode elide);
void setText(const QString& text);
QString fullText();

View File

@ -955,26 +955,11 @@ void Widget::addFriend(int friendId, const QString &userId)
contactListWidget->addFriendWidget(widget, Status::Offline, s.getFriendCircleID(userToxId));
Core* core = Nexus::getCore();
CoreAV* coreav = core->getAv();
connect(&s, &Settings::compactLayoutChanged, widget, &GenericChatroomWidget::compactChange);
connect(newfriend, &Friend::displayedNameChanged, this, &Widget::onFriendDisplayChanged);
connect(widget, SIGNAL(chatroomWidgetClicked(GenericChatroomWidget*, bool)), this, SLOT(onChatroomWidgetClicked(GenericChatroomWidget*, bool)));
connect(widget, &FriendWidget::chatroomWidgetClicked, this, &Widget::onChatroomWidgetClicked);
connect(widget, &FriendWidget::chatroomWidgetClicked, friendForm, &ChatForm::focusInput);
connect(widget, &FriendWidget::copyFriendIdToClipboard, this, &Widget::copyFriendIdToClipboard);
connect(widget, SIGNAL(removeFriend(int)), this, SLOT(removeFriend(int)));
connect(widget, SIGNAL(copyFriendIdToClipboard(int)), this, SLOT(copyFriendIdToClipboard(int)));
connect(widget, SIGNAL(chatroomWidgetClicked(GenericChatroomWidget*)), friendForm, SLOT(focusInput()));
connect(friendForm, &GenericChatForm::sendMessage, core, &Core::sendMessage);
connect(friendForm, &GenericChatForm::sendAction, core, &Core::sendAction);
connect(friendForm, &ChatForm::sendFile, core, &Core::sendFile);
connect(friendForm, &ChatForm::aliasChanged, widget, &FriendWidget::setAlias);
connect(core, &Core::fileReceiveRequested, friendForm, &ChatForm::onFileRecvRequest);
connect(coreav, &CoreAV::avInvite, friendForm, &ChatForm::onAvInvite, Qt::BlockingQueuedConnection);
connect(coreav, &CoreAV::avStart, friendForm, &ChatForm::onAvStart, Qt::BlockingQueuedConnection);
connect(coreav, &CoreAV::avEnd, friendForm, &ChatForm::onAvEnd, Qt::BlockingQueuedConnection);
connect(core, &Core::friendAvatarChanged, friendForm, &ChatForm::onAvatarChange);
connect(core, &Core::friendAvatarRemoved, friendForm, &ChatForm::onAvatarRemoved);
connect(core, &Core::friendAvatarChanged, widget, &FriendWidget::onAvatarChange);
connect(core, &Core::friendAvatarRemoved, widget, &FriendWidget::onAvatarRemoved);
// Try to get the avatar from the cache
QPixmap avatar = Nexus::getProfile()->loadAvatar(userId);
@ -1155,8 +1140,6 @@ void Widget::onFriendMessageReceived(int friendId, const QString& message, bool
return;
QDateTime timestamp = QDateTime::currentDateTime();
f->getChatForm()->addMessage(f->getToxId(), message, isAction, timestamp, true);
Profile* profile = Nexus::getProfile();
if (profile->isHistoryEnabled())
profile->getHistory()->addNewMessage(f->getToxId().publicKey, isAction ? ChatForm::ACTION_PREFIX + f->getDisplayedName() + " " + message : message,

View File

@ -1,83 +1,63 @@
QPushButton#green
QAbstractButton
{
background-color: #6bc260;
border-radius: 5px;
border: none;
background-image: url(":/ui/callButton/callButton.svg");
background-repeat: none;
background-position: center;
border: none;
border-radius: 5px;
width: 50px;
height: 40px;
}
QPushButton#green:hover
{
background-color: #79c76f;
}
QPushButton#green:pressed
{
background-color: #51b244;
}
QPushButton#red
{
background-color: #c84e4e;
background-image: url(":/ui/callButton/callButton.svg");
background-repeat: none;
background-position: center;
border: none;
border-radius: 5px;
width: 50px;
height: 40px;
}
QPushButton#red:hover
{
background-color: #e87474;
}
QPushButton#red:pressed
{
background-color: #df3b3b;
}
QPushButton#yellow
{
background-color: #e6e465;
background-image: url(":/ui/callButton/callButton.svg");
background-repeat: none;
background-position: center;
border: none;
border-radius: 5px;
width: 50px;
height: 40px;
}
QPushButton#yellow:hover
{
background-color: #e8e774;
}
QPushButton#yellow:pressed
{
background-color: #e3e155;
}
QPushButton#grey
QAbstractButton:disabled
{
background-color: #919191;
background-image: url(":/ui/callButton/callButton.svg");
background-repeat: none;
background-position: center;
border: none;
border-radius: 5px;
width: 50px;
height: 40px;
}
QPushButton:focus
QAbstractButton:focus
{
outline: none;
}
QAbstractButton#green
{
background-color: #6bc260;
}
QAbstractButton#green:hover
{
background-color: #79c76f;
}
QAbstractButton#green:pressed
{
background-color: #51b244;
}
QAbstractButton#red
{
background-color: #c84e4e;
}
QAbstractButton#red:hover
{
background-color: #e87474;
}
QAbstractButton#red:pressed
{
background-color: #df3b3b;
}
QAbstractButton#yellow
{
background-color: #e6e465;
}
QAbstractButton#yellow:hover
{
background-color: #e8e774;
}
QAbstractButton#yellow:pressed
{
background-color: #e3e155;
}

View File

@ -1,38 +1,27 @@
QPushButton#green
QAbstractButton
{
background-color: transparent;
background-image: url(":/ui/micButton/micButton.png");
background-repeat: none;
border: none;
width: 22px;
height: 18px;
}
QPushButton#green:hover
QAbstractButton:disabled
{
background-image:url(":/ui/micButton/micButtonHover.png");
}
QPushButton#red
{
background-color: transparent;
background-image: url(":/ui/micButton/micButtonPressed.png");
background-repeat: none;
border: none;
width: 22px;
height: 18px;
}
QPushButton#grey
{
background-color: transparent;
background-image: url(":/ui/micButton/micButtonDisabled.png");
background-repeat: none;
border: none;
width: 22px;
height: 18px;
}
QPushButton:focus {
QAbstractButton:focus
{
outline: none;
}
QAbstractButton#green:hover
{
background-image: url(":/ui/micButton/micButtonHover.png");
}
QAbstractButton#red
{
background-image: url(":/ui/micButton/micButtonPressed.png");
}

View File

@ -1,82 +1,63 @@
QPushButton#green
QAbstractButton
{
background-color: #6bc260;
background-image: url(":/ui/videoButton/videoButton.svg");
background-repeat: none;
background-position: center;
border: none;
border-radius: 5px;
width: 50px;
height: 40px;
}
QPushButton#green:hover
QAbstractButton:disabled
{
background-color: #919191;
}
QAbstractButton:focus
{
outline: none;
}
QAbstractButton#green
{
background-color: #6bc260;
}
QAbstractButton#green:hover
{
background-color: #79c76f;
}
QPushButton#green:pressed
QAbstractButton#green:pressed
{
background-color: #51b244;
}
QPushButton#red
QAbstractButton#red
{
background-color: #c84e4e;
background-image: url(":/ui/videoButton/videoButton.svg");
background-repeat: none;
background-position: center;
border: none;
border-radius: 5px;
width: 50px;
height: 40px;
}
QPushButton#red:hover
QAbstractButton#red:hover
{
background-color: #e87474;
}
QPushButton#red:pressed
QAbstractButton#red:pressed
{
background-color: #df3b3b;
}
QPushButton#yellow
QAbstractButton#yellow
{
background-color: #e6e465;
background-image: url(":/ui/videoButton/videoButton.svg");
background-repeat: none;
background-position: center;
border: none;
border-radius: 5px;
width: 50px;
height: 40px;
}
QPushButton#yellow:hover
QAbstractButton#yellow:hover
{
background-color: #e8e774;
}
QPushButton#yellow:pressed
QAbstractButton#yellow:pressed
{
background-color: #e3e155;
}
QPushButton#grey
{
background-color: #919191;
background-image: url(":/ui/videoButton/videoButton.svg");
background-repeat: none;
background-position: center;
border: none;
border-radius: 5px;
width: 50px;
height: 40px;
}
QPushButton:focus
{
outline: none;
}

View File

@ -1,38 +1,27 @@
QPushButton#green
QAbstractButton
{
background-color: transparent;
background-image: url(":/ui/volButton/volButton.png");
background-repeat: none;
border: none;
width: 22px;
height: 18px;
}
QPushButton#green:hover
QAbstractButton:disabled
{
background-image: url(":/ui/volButton/volButtonDisabled.png");
}
QAbstractButton:focus
{
outline: none;
}
QAbstractButton#green:hover
{
background-image: url(":/ui/volButton/volButtonHover.png");
}
QPushButton#red
QAbstractButton#red
{
background-color: transparent;
background-image: url(":/ui/volButton/volButtonPressed.png");
background-repeat: none;
border: none;
width: 22px;
height: 18px;
}
QPushButton#grey
{
background-color: transparent;
background-image: url(":/ui/volButton/volButtonDisabled.png");
background-repeat: none;
border: none;
width: 22px;
height: 18px;
}
QPushButton:focus {
outline: none;
}