File indexing completed on 2024-12-01 04:37:02
0001 /* 0002 SPDX-FileCopyrightText: 2020-2024 Laurent Montel <montel@kde.org> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #include "roomwidget.h" 0008 #include "accountroomsettings.h" 0009 #include "conferencecalldialog/conferencecalldialog.h" 0010 #include "conferencecalldialog/conferencedirectcalldialog.h" 0011 #include "connection.h" 0012 #include "dialogs/addusersinroomdialog.h" 0013 #include "dialogs/autotranslateconfiguredialog.h" 0014 #include "dialogs/channelinfodialog.h" 0015 #include "dialogs/configurenotificationdialog.h" 0016 #include "dialogs/directchannelinfodialog.h" 0017 #include "dialogs/inviteusersdialog.h" 0018 #include "dialogs/searchmessagedialog.h" 0019 #include "dialogs/showattachmentdialog.h" 0020 #include "dialogs/showmentionsmessagesdialog.h" 0021 #include "dialogs/showpinnedmessagesdialog.h" 0022 #include "dialogs/showstarredmessagesdialog.h" 0023 #include "dialogs/showthreadsdialog.h" 0024 #include "discussions/showdiscussionsdialog.h" 0025 #include "exportmessages/exportmessagesdialog.h" 0026 #include "messagelinewidget.h" 0027 #include "messagelistview.h" 0028 #include "plugintextmessagewidget.h" 0029 #include "prunemessages/prunemessagesdialog.h" 0030 #include "rocketchataccount.h" 0031 #include "rocketchatbackend.h" 0032 #include "roomutil.h" 0033 #include "ruqolawidgets_debug.h" 0034 #include "usersinroomflowwidget.h" 0035 0036 #include "offlinewidget/offlinewidget.h" 0037 0038 #include "otr/otrwidget.h" 0039 #include "reconnectinfowidget.h" 0040 #include "roomcounterinfowidget.h" 0041 #include "roomwidgetbase.h" 0042 #include "ruqola_thread_message_widgets_debug.h" 0043 #include "teams/teamchannelsdialog.h" 0044 #include "teams/teaminfo.h" 0045 #include "threadwidget/threadmessagedialog.h" 0046 #include "video-conference/videoconferencejoinjob.h" 0047 #include "video-conference/videoconferencestartjob.h" 0048 #include "videoconference/videoconferencemessageinfomanager.h" 0049 0050 #include <KLocalizedString> 0051 #include <KMessageBox> 0052 0053 #include <QDesktopServices> 0054 #include <QDragEnterEvent> 0055 #include <QDropEvent> 0056 #include <QMimeData> 0057 #include <QPushButton> 0058 #include <QScrollBar> 0059 0060 #include "config-ruqola.h" 0061 #include "video-conference/videoconferencecapabilitiesjob.h" 0062 0063 #if HAVE_TEXT_TO_SPEECH 0064 #include <TextEditTextToSpeech/TextToSpeechContainerWidget> 0065 #endif 0066 0067 RoomWidget::RoomWidget(QWidget *parent) 0068 : QWidget(parent) 0069 , mRoomWidgetBase(new RoomWidgetBase(MessageListView::Mode::Editing, this)) 0070 , mRoomHeaderWidget(new RoomHeaderWidget(this)) 0071 , mUsersInRoomFlowWidget(new UsersInRoomFlowWidget(this)) 0072 , mRoomCounterInfoWidget(new RoomCounterInfoWidget(this)) 0073 0074 #if HAVE_TEXT_TO_SPEECH 0075 , mTextToSpeechWidget(new TextEditTextToSpeech::TextToSpeechContainerWidget(this)) 0076 #endif 0077 { 0078 auto mainLayout = new QVBoxLayout(this); 0079 mainLayout->setObjectName(QStringLiteral("mainLayout")); 0080 mainLayout->setContentsMargins({}); 0081 0082 mRoomHeaderWidget->setObjectName(QStringLiteral("mRoomHeaderWidget")); 0083 mainLayout->addWidget(mRoomHeaderWidget); 0084 0085 auto roomWidget = new QWidget(this); 0086 mainLayout->addWidget(roomWidget); 0087 mRoomWidgetLayout = new QVBoxLayout(roomWidget); 0088 mRoomWidgetLayout->setObjectName(QStringLiteral("roomWidgetLayout")); 0089 mRoomWidgetLayout->setContentsMargins({}); 0090 mRoomWidgetLayout->setSpacing(0); 0091 0092 mUsersInRoomFlowWidget->setObjectName(QStringLiteral("mUsersInRoomFlowWidget")); 0093 mRoomWidgetLayout->addWidget(mUsersInRoomFlowWidget); 0094 mUsersInRoomFlowWidget->setVisible(false); 0095 0096 mRoomCounterInfoWidget->setObjectName(QStringLiteral("mRoomCounterInfoWidget")); 0097 0098 connect(mRoomWidgetBase, &RoomWidgetBase::errorMessage, this, [this](const QString &message) { 0099 if (!mPluginTextMessageWidget) { 0100 createPluginTextMessateWidget(); 0101 } 0102 mPluginTextMessageWidget->slotShareError(message); 0103 }); 0104 connect(mRoomWidgetBase, &RoomWidgetBase::successMessage, this, [this](const QString &message) { 0105 if (!mPluginTextMessageWidget) { 0106 createPluginTextMessateWidget(); 0107 } 0108 mPluginTextMessageWidget->slotShareSuccess(message); 0109 }); 0110 0111 mRoomWidgetLayout->addWidget(mRoomCounterInfoWidget); 0112 0113 #if HAVE_TEXT_TO_SPEECH 0114 mTextToSpeechWidget->setObjectName(QStringLiteral("mTextToSpeechWidget")); 0115 mRoomWidgetLayout->addWidget(mTextToSpeechWidget); 0116 connect(mRoomWidgetBase, &RoomWidgetBase::textToSpeech, mTextToSpeechWidget, &TextEditTextToSpeech::TextToSpeechContainerWidget::say); 0117 #endif 0118 0119 mRoomWidgetLayout->addWidget(mRoomWidgetBase); 0120 connect(mRoomCounterInfoWidget, &RoomCounterInfoWidget::markAsRead, this, &RoomWidget::slotClearNotification); 0121 connect(mRoomCounterInfoWidget, &RoomCounterInfoWidget::jumpToUnreadMessage, this, &RoomWidget::slotJumpToUnreadMessage); 0122 connect(mRoomHeaderWidget, &RoomHeaderWidget::favoriteChanged, this, &RoomWidget::slotChangeFavorite); 0123 connect(mRoomHeaderWidget, &RoomHeaderWidget::encryptedChanged, this, &RoomWidget::slotEncryptedChanged); 0124 connect(mRoomHeaderWidget, &RoomHeaderWidget::goBackToRoom, this, &RoomWidget::slotGoBackToRoom); 0125 connect(mRoomHeaderWidget, &RoomHeaderWidget::listOfUsersChanged, this, &RoomWidget::slotShowListOfUsersInRoom); 0126 connect(mRoomHeaderWidget, &RoomHeaderWidget::searchMessageRequested, this, &RoomWidget::slotSearchMessages); 0127 connect(mRoomHeaderWidget, &RoomHeaderWidget::actionRequested, this, &RoomWidget::slotActionRequested); 0128 connect(mRoomHeaderWidget, &RoomHeaderWidget::channelInfoRequested, this, &RoomWidget::slotChannelInfoRequested); 0129 connect(mRoomWidgetBase, &RoomWidgetBase::loadHistory, this, &RoomWidget::slotLoadHistory); 0130 connect(mRoomWidgetBase, &RoomWidgetBase::createNewDiscussion, this, &RoomWidget::slotCreateNewDiscussion); 0131 connect(mRoomHeaderWidget, &RoomHeaderWidget::teamChannelsRequested, this, &RoomWidget::slotTeamChannelsRequested); 0132 connect(mRoomHeaderWidget, &RoomHeaderWidget::openTeam, this, &RoomWidget::slotOpenTeamRequested); 0133 connect(mRoomHeaderWidget, &RoomHeaderWidget::callRequested, this, &RoomWidget::slotCallRequested); 0134 setAcceptDrops(true); 0135 } 0136 0137 RoomWidget::~RoomWidget() 0138 { 0139 delete mRoom; 0140 } 0141 0142 void RoomWidget::createPluginTextMessateWidget() 0143 { 0144 mPluginTextMessageWidget = new PluginTextMessageWidget(this); 0145 mPluginTextMessageWidget->setObjectName(QStringLiteral("mPluginTextMessageWidget")); 0146 mRoomWidgetLayout->insertWidget(1, mPluginTextMessageWidget); 0147 } 0148 0149 // TODO using it 0150 void RoomWidget::createRoomReconnectInfoWidget() 0151 { 0152 mRoomReconnectInfoWidget = new ReconnectInfoWidget(this); 0153 mRoomReconnectInfoWidget->setObjectName(QStringLiteral("mRoomReconnectInfoWidget")); 0154 connect(mRoomReconnectInfoWidget, &ReconnectInfoWidget::tryReconnect, this, &RoomWidget::slotTryReconnect); 0155 // After mUsersInRoomFlowWidget 0156 mRoomWidgetLayout->insertWidget(1, mRoomReconnectInfoWidget); 0157 } 0158 0159 // TODO using it. 0160 void RoomWidget::createOffLineWidget() 0161 { 0162 mOffLineWidget = new OffLineWidget(this); 0163 mOffLineWidget->setObjectName(QStringLiteral("mOffLineWidget")); 0164 // After mUsersInRoomFlowWidget 0165 mRoomWidgetLayout->insertWidget(1, mOffLineWidget); 0166 } 0167 0168 // TODO using it. 0169 void RoomWidget::createOtrWidget() 0170 { 0171 mOtrWidget = new OtrWidget(this); 0172 mOtrWidget->setObjectName(QStringLiteral("mOtrWidget")); 0173 connect(mOtrWidget, &OtrWidget::closeOtr, this, &RoomWidget::slotCloseOtr); 0174 connect(mOtrWidget, &OtrWidget::refreshKeys, this, &RoomWidget::slotRefreshOtrKeys); 0175 // After mUsersInRoomFlowWidget 0176 mRoomWidgetLayout->insertWidget(1, mOtrWidget); 0177 } 0178 0179 void RoomWidget::slotLoadHistory() 0180 { 0181 mCurrentRocketChatAccount->loadHistory(mRoomWidgetBase->roomId()); 0182 } 0183 0184 void RoomWidget::slotChannelInfoRequested() 0185 { 0186 if (!mRoom) { 0187 return; 0188 } 0189 if (mRoomType == Room::RoomType::Direct) { 0190 DirectChannelInfoDialog dlg(mCurrentRocketChatAccount, this); 0191 dlg.setUserName(mRoom->name()); 0192 dlg.exec(); 0193 } else { 0194 QPointer<ChannelInfoDialog> dlg = new ChannelInfoDialog(mRoom, mCurrentRocketChatAccount, this); 0195 if (dlg->exec()) { 0196 const RocketChatRestApi::SaveRoomSettingsJob::SaveRoomSettingsInfo info = dlg->saveRoomSettingsInfo(); 0197 if (info.isValid()) { 0198 auto saveRoomSettingsJob = new RocketChatRestApi::SaveRoomSettingsJob(this); 0199 saveRoomSettingsJob->setSaveRoomSettingsInfo(info); 0200 mCurrentRocketChatAccount->restApi()->initializeRestApiJob(saveRoomSettingsJob); 0201 if (!saveRoomSettingsJob->start()) { 0202 qCDebug(RUQOLAWIDGETS_LOG) << "Impossible to start saveRoomSettingsJob"; 0203 } 0204 } 0205 } 0206 delete dlg; 0207 } 0208 } 0209 0210 void RoomWidget::slotActionRequested(RoomHeaderWidget::ChannelActionType type) 0211 { 0212 switch (type) { 0213 case RoomHeaderWidget::ShowMentions: 0214 slotShowMentions(); 0215 break; 0216 case RoomHeaderWidget::ShowPinned: 0217 slotPinnedMessages(); 0218 break; 0219 case RoomHeaderWidget::ShowStarred: 0220 slotStarredMessages(); 0221 break; 0222 case RoomHeaderWidget::ShowDiscussions: 0223 slotShowDiscussions(); 0224 break; 0225 case RoomHeaderWidget::ShowThreads: 0226 slotShowThreads(); 0227 break; 0228 case RoomHeaderWidget::ShowAttachment: 0229 slotShowFileAttachments(); 0230 break; 0231 case RoomHeaderWidget::Notification: 0232 slotConfigureNotification(); 0233 break; 0234 case RoomHeaderWidget::AutoTranslate: 0235 slotConfigureAutoTranslate(); 0236 break; 0237 case RoomHeaderWidget::InviteUsers: 0238 slotInviteUsers(); 0239 break; 0240 case RoomHeaderWidget::AddUsersInRoom: 0241 slotAddUsersInRoom(); 0242 break; 0243 case RoomHeaderWidget::VideoChat: 0244 slotVideoChat(); 0245 break; 0246 case RoomHeaderWidget::PruneMessages: 0247 slotPruneMessages(); 0248 break; 0249 case RoomHeaderWidget::ExportMessages: 0250 slotExportMessages(); 0251 break; 0252 case RoomHeaderWidget::OtrMessages: 0253 // TODO 0254 break; 0255 case RoomHeaderWidget::EncryptMessages: 0256 // TODO 0257 break; 0258 } 0259 } 0260 0261 void RoomWidget::slotPruneMessages() 0262 { 0263 if (!mRoom) { 0264 return; 0265 } 0266 QPointer<PruneMessagesDialog> dlg = new PruneMessagesDialog(mCurrentRocketChatAccount, this); 0267 dlg->setRoomName(mRoom->name()); 0268 if (dlg->exec()) { 0269 RocketChatRestApi::RoomsCleanHistoryJob::CleanHistoryInfo info = dlg->cleanHistoryInfo(); 0270 info.roomId = mRoomWidgetBase->roomId(); 0271 if (KMessageBox::ButtonCode::PrimaryAction 0272 == KMessageBox::questionTwoActions(this, 0273 i18n("Do you want really remove history?"), 0274 i18nc("@title:window", "Remove History"), 0275 KStandardGuiItem::remove(), 0276 KStandardGuiItem::cancel())) { 0277 mCurrentRocketChatAccount->cleanChannelHistory(info); 0278 } 0279 } 0280 delete dlg; 0281 } 0282 0283 void RoomWidget::slotExportMessages() 0284 { 0285 QPointer<ExportMessagesDialog> dlg = new ExportMessagesDialog(this); 0286 if (dlg->exec()) { 0287 RocketChatRestApi::RoomsExportJob::RoomsExportInfo info = dlg->roomExportInfo(); 0288 info.roomId = mRoomWidgetBase->roomId(); 0289 mCurrentRocketChatAccount->exportMessages(info); 0290 } 0291 delete dlg; 0292 } 0293 0294 void RoomWidget::slotVideoChat() 0295 { 0296 mCurrentRocketChatAccount->createJitsiConfCall(mRoomWidgetBase->roomId()); 0297 } 0298 0299 void RoomWidget::slotAddUsersInRoom() 0300 { 0301 QPointer<AddUsersInRoomDialog> dlg = new AddUsersInRoomDialog(mCurrentRocketChatAccount, this); 0302 if (dlg->exec()) { 0303 const QStringList users = dlg->userIds(); 0304 for (const QString &user : users) { 0305 mCurrentRocketChatAccount->addUserToRoom(user, mRoomWidgetBase->roomId(), mRoomType); 0306 } 0307 } 0308 delete dlg; 0309 } 0310 0311 void RoomWidget::slotInviteUsers() 0312 { 0313 InviteUsersDialog dlg(mCurrentRocketChatAccount, this); 0314 dlg.setRoomId(mRoomWidgetBase->roomId()); 0315 dlg.generateLink(); 0316 dlg.exec(); 0317 } 0318 0319 void RoomWidget::updateListView() 0320 { 0321 mRoomWidgetBase->updateListView(); 0322 } 0323 0324 void RoomWidget::slotConfigureAutoTranslate() 0325 { 0326 if (!mRoom) { 0327 return; 0328 } 0329 AutoTranslateConfigureDialog dlg(mCurrentRocketChatAccount, this); 0330 dlg.setRoom(mRoom); 0331 dlg.exec(); 0332 } 0333 0334 void RoomWidget::slotConfigureNotification() 0335 { 0336 if (!mRoom) { 0337 return; 0338 } 0339 ConfigureNotificationDialog dlg(mCurrentRocketChatAccount, this); 0340 dlg.setRoom(mRoom); 0341 dlg.exec(); 0342 } 0343 0344 void RoomWidget::slotStarredMessages() 0345 { 0346 if (!mRoom) { 0347 return; 0348 } 0349 QPointer<ShowStarredMessagesDialog> dlg = new ShowStarredMessagesDialog(mCurrentRocketChatAccount, this); 0350 dlg->setRoomId(mRoomWidgetBase->roomId()); 0351 dlg->setModel(mCurrentRocketChatAccount->listMessagesFilterProxyModel()); 0352 dlg->setRoom(mRoom); 0353 mCurrentRocketChatAccount->getListMessages(mRoomWidgetBase->roomId(), ListMessagesModel::StarredMessages); 0354 connect(dlg, &ShowListMessageBaseDialog::goToMessageRequested, this, &RoomWidget::slotGotoMessage); 0355 dlg->exec(); 0356 delete dlg; 0357 } 0358 0359 void RoomWidget::slotPinnedMessages() 0360 { 0361 if (!mRoom) { 0362 return; 0363 } 0364 QPointer<ShowPinnedMessagesDialog> dlg = new ShowPinnedMessagesDialog(mCurrentRocketChatAccount, this); 0365 dlg->setRoomId(mRoomWidgetBase->roomId()); 0366 dlg->setRoom(mRoom); 0367 dlg->setModel(mCurrentRocketChatAccount->listMessagesFilterProxyModel()); 0368 mCurrentRocketChatAccount->getListMessages(mRoomWidgetBase->roomId(), ListMessagesModel::PinnedMessages); 0369 connect(dlg, &ShowListMessageBaseDialog::goToMessageRequested, this, &RoomWidget::slotGotoMessage); 0370 dlg->exec(); 0371 delete dlg; 0372 } 0373 0374 void RoomWidget::slotShowMentions() 0375 { 0376 if (!mRoom) { 0377 return; 0378 } 0379 QPointer<ShowMentionsMessagesDialog> dlg = new ShowMentionsMessagesDialog(mCurrentRocketChatAccount, this); 0380 dlg->setRoomId(mRoomWidgetBase->roomId()); 0381 dlg->setModel(mCurrentRocketChatAccount->listMessagesFilterProxyModel()); 0382 dlg->setRoom(mRoom); 0383 mCurrentRocketChatAccount->getListMessages(mRoomWidgetBase->roomId(), ListMessagesModel::MentionsMessages); 0384 connect(dlg, &ShowListMessageBaseDialog::goToMessageRequested, this, &RoomWidget::slotGotoMessage); 0385 dlg->exec(); 0386 delete dlg; 0387 } 0388 0389 void RoomWidget::slotShowThreads() 0390 { 0391 if (!mRoom) { 0392 return; 0393 } 0394 QPointer<ShowThreadsDialog> dlg = new ShowThreadsDialog(mCurrentRocketChatAccount, this); 0395 dlg->setModel(mCurrentRocketChatAccount->listMessagesFilterProxyModel()); 0396 dlg->setRoomId(mRoomWidgetBase->roomId()); 0397 dlg->setRoom(mRoom); 0398 mCurrentRocketChatAccount->getListMessages(mRoomWidgetBase->roomId(), ListMessagesModel::ThreadsMessages); 0399 connect(dlg, &ShowListMessageBaseDialog::goToMessageRequested, this, &RoomWidget::slotGotoMessage); 0400 dlg->exec(); 0401 delete dlg; 0402 } 0403 0404 void RoomWidget::slotShowDiscussions() 0405 { 0406 auto dlg = new ShowDiscussionsDialog(mCurrentRocketChatAccount, this); 0407 dlg->setModel(mCurrentRocketChatAccount->discussionsFilterProxyModel()); 0408 dlg->setRoomId(mRoomWidgetBase->roomId()); 0409 mCurrentRocketChatAccount->discussionsInRoom(mRoomWidgetBase->roomId()); 0410 dlg->show(); 0411 } 0412 0413 void RoomWidget::slotShowFileAttachments() 0414 { 0415 auto dlg = new ShowAttachmentDialog(mCurrentRocketChatAccount, this); 0416 mCurrentRocketChatAccount->roomFiles(mRoomWidgetBase->roomId(), mRoomType); 0417 dlg->setModel(mCurrentRocketChatAccount->filesForRoomFilterProxyModel()); 0418 dlg->setRoomId(mRoomWidgetBase->roomId()); 0419 dlg->setRoomType(mRoomType); 0420 dlg->show(); 0421 } 0422 0423 void RoomWidget::slotSearchMessages() 0424 { 0425 if (!mRoom) { 0426 return; 0427 } 0428 SearchMessageDialog dlg(mCurrentRocketChatAccount, this); 0429 dlg.setRoomId(mRoomWidgetBase->roomId()); 0430 dlg.setRoom(mRoom); 0431 dlg.setModel(mCurrentRocketChatAccount->searchMessageFilterProxyModel()); 0432 connect(&dlg, &SearchMessageDialog::goToMessageRequested, this, &RoomWidget::slotGotoMessage); 0433 dlg.exec(); 0434 } 0435 0436 void RoomWidget::slotCallRequested() 0437 { 0438 if (!mRoom) { 0439 return; 0440 } 0441 if (mRoom->channelType() == Room::RoomType::Direct && mRoom->userNames().count() == 2) { 0442 QPointer<ConferenceDirectCallDialog> dlg = new ConferenceDirectCallDialog(mCurrentRocketChatAccount, this); 0443 dlg->setRoomId(mRoomWidgetBase->roomId()); 0444 dlg->setAllowRinging(mRoom->hasPermission(QStringLiteral("videoconf-ring-users"))); 0445 if (dlg->exec()) { 0446 #if 0 0447 auto conferenceInfoJob = new RocketChatRestApi::VideoConferenceInfoJob(this); 0448 conferenceInfoJob->setCallId(obj[QLatin1String("callId")].toString()); 0449 mCurrentRocketChatAccount->restApi()->initializeRestApiJob(conferenceInfoJob); 0450 connect(conferenceInfoJob, &RocketChatRestApi::VideoConferenceInfoJob::videoConferenceInfoDone, this, [this, callInfo](const QJsonObject &obj) { 0451 qDebug() << " info " << obj; 0452 VideoConferenceInfo info; 0453 info.parse(obj); 0454 }); 0455 if (!conferenceInfoJob->start()) { 0456 qCWarning(RUQOLAWIDGETS_LOG) << "Impossible to start VideoConferenceInfoJob job"; 0457 } 0458 #endif 0459 // TODO show conf call info 0460 } 0461 delete dlg; 0462 } else { 0463 auto job = new RocketChatRestApi::VideoConferenceCapabilitiesJob(this); 0464 mCurrentRocketChatAccount->restApi()->initializeRestApiJob(job); 0465 connect(job, &RocketChatRestApi::VideoConferenceCapabilitiesJob::noVideoConferenceProviderApps, this, [this] { 0466 KMessageBox::information(this, i18n("A workspace admin needs to install and configure a conference call apps."), i18n("Video Conference")); 0467 }); 0468 connect(job, &RocketChatRestApi::VideoConferenceCapabilitiesJob::videoConferenceCapabilitiesDone, this, [this](const QJsonObject &obj) { 0469 // qDebug() << "obj " << obj; 0470 // {"capabilities":{"cam":true,"mic":true,"title":true},"providerName":"jitsi","success":true} 0471 const QJsonObject capabilitiesObj = obj[QLatin1String("capabilities")].toObject(); 0472 const bool useCam = capabilitiesObj[QLatin1String("cam")].toBool(); 0473 const bool useMic = capabilitiesObj[QLatin1String("mic")].toBool(); 0474 ConferenceCallWidget::ConferenceCallStart callInfo; 0475 callInfo.useCamera = useCam; 0476 callInfo.useMic = useMic; 0477 0478 QPointer<ConferenceCallDialog> dlg = new ConferenceCallDialog(mCurrentRocketChatAccount, this); 0479 dlg->setConferenceCallInfo(callInfo); 0480 if (dlg->exec()) { 0481 const ConferenceCallWidget::ConferenceCallStart conferenceCallInfo = dlg->conferenceCallInfo(); 0482 0483 auto job = new RocketChatRestApi::VideoConferenceStartJob(this); 0484 RocketChatRestApi::VideoConferenceStartJob::VideoConferenceStartInfo startInfo; 0485 startInfo.roomId = mRoomWidgetBase->roomId(); 0486 startInfo.allowRinging = mRoom->hasPermission(QStringLiteral("videoconf-ring-users")); 0487 job->setInfo(startInfo); 0488 mCurrentRocketChatAccount->restApi()->initializeRestApiJob(job); 0489 connect(job, &RocketChatRestApi::VideoConferenceStartJob::videoConferenceStartDone, this, [this, conferenceCallInfo](const QJsonObject &obj) { 0490 // qDebug() << "obj " << obj; 0491 // {"data":{"callId":"63949ea24ef3f3baa9658f25","providerName":"jitsi","rid":"hE6RS3iv5ND5EGWC6","type":"videoconference"},"success":true} 0492 const QString callId{obj[QLatin1String("callId")].toString()}; 0493 mCurrentRocketChatAccount->videoConferenceMessageInfoManager()->addCallId(callId); 0494 auto conferenceJoinJob = new RocketChatRestApi::VideoConferenceJoinJob(this); 0495 RocketChatRestApi::VideoConferenceJoinJob::VideoConferenceJoinInfo joinInfo; 0496 joinInfo.callId = callId; 0497 joinInfo.useCamera = conferenceCallInfo.useCamera; 0498 joinInfo.useMicro = conferenceCallInfo.useMic; 0499 conferenceJoinJob->setInfo(joinInfo); 0500 mCurrentRocketChatAccount->restApi()->initializeRestApiJob(conferenceJoinJob); 0501 connect(conferenceJoinJob, &RocketChatRestApi::VideoConferenceJoinJob::videoConferenceJoinDone, this, [](const QJsonObject &joinObject) { 0502 // qDebug() << " join info " << obj; 0503 QDesktopServices::openUrl(QUrl(joinObject[QLatin1String("url")].toString())); 0504 }); 0505 if (!conferenceJoinJob->start()) { 0506 qCWarning(RUQOLAWIDGETS_LOG) << "Impossible to start VideoConferenceJoinJob job"; 0507 } 0508 }); 0509 if (!job->start()) { 0510 qCWarning(RUQOLAWIDGETS_LOG) << "Impossible to start VideoConferenceCapabilitiesJob job"; 0511 } 0512 } 0513 delete dlg; 0514 }); 0515 if (!job->start()) { 0516 qCWarning(RUQOLAWIDGETS_LOG) << "Impossible to start VideoConferenceCapabilitiesJob job"; 0517 } 0518 } 0519 } 0520 0521 void RoomWidget::slotOpenTeamRequested(const QString &teamId) 0522 { 0523 Q_EMIT mCurrentRocketChatAccount->openTeamNameRequested(teamId); 0524 } 0525 0526 void RoomWidget::slotTeamChannelsRequested() 0527 { 0528 if (!mRoom) { 0529 return; 0530 } 0531 TeamChannelsDialog dlg(mCurrentRocketChatAccount, this); 0532 dlg.setRoom(mRoom); 0533 dlg.exec(); 0534 } 0535 0536 void RoomWidget::slotCreateNewDiscussion(const QString &messageId, const QString &originalMessage) 0537 { 0538 mRoomWidgetBase->slotCreateNewDiscussion(messageId, originalMessage, mRoomHeaderWidget->roomName()); 0539 } 0540 0541 void RoomWidget::slotCreatePrivateDiscussion(const QString &userName) 0542 { 0543 Q_EMIT mCurrentRocketChatAccount->openLinkRequested(RoomUtil::generateUserLink(userName)); 0544 } 0545 0546 void RoomWidget::dragEnterEvent(QDragEnterEvent *event) 0547 { 0548 // Don't allow to drop element when it's blocked 0549 if (mRoom && mRoom->roomIsBlocked()) { 0550 return; 0551 } 0552 const QMimeData *mimeData = event->mimeData(); 0553 if (mimeData->hasUrls()) { 0554 event->accept(); 0555 } 0556 } 0557 0558 void RoomWidget::dropEvent(QDropEvent *event) 0559 { 0560 const QMimeData *mimeData = event->mimeData(); 0561 if (mimeData->hasUrls()) { 0562 mRoomWidgetBase->messageLineWidget()->handleMimeData(mimeData); 0563 } 0564 } 0565 0566 void RoomWidget::storeRoomSettings() 0567 { 0568 if (mCurrentRocketChatAccount) { 0569 if (mRoomWidgetBase->messageLineWidget()->text().isEmpty()) { 0570 auto *vbar = mRoomWidgetBase->messageListView()->verticalScrollBar(); 0571 if (vbar->value() != vbar->maximum()) { 0572 AccountRoomSettings::PendingTypedInfo info; 0573 info.scrollbarPosition = mRoomWidgetBase->messageListView()->verticalScrollBar()->value(); 0574 mCurrentRocketChatAccount->accountRoomSettings()->add(mRoomWidgetBase->roomId(), info); 0575 } else { 0576 mCurrentRocketChatAccount->accountRoomSettings()->remove(mRoomWidgetBase->roomId()); 0577 } 0578 } else { 0579 AccountRoomSettings::PendingTypedInfo info; 0580 info.text = mRoomWidgetBase->messageLineWidget()->text(); 0581 info.messageIdBeingEdited = mRoomWidgetBase->messageLineWidget()->messageIdBeingEdited(); 0582 info.scrollbarPosition = mRoomWidgetBase->messageListView()->verticalScrollBar()->value(); 0583 info.threadMessageId = mRoomWidgetBase->messageLineWidget()->threadMessageId(); 0584 info.quotePermalink = mRoomWidgetBase->messageLineWidget()->quotePermalink(); 0585 info.quoteText = mRoomWidgetBase->messageLineWidget()->quoteText(); 0586 mCurrentRocketChatAccount->accountRoomSettings()->add(mRoomWidgetBase->roomId(), info); 0587 } 0588 } 0589 } 0590 0591 void RoomWidget::clearBeforeSwitching() 0592 { 0593 mRoomWidgetBase->messageLineWidget()->setThreadMessageId({}); 0594 mRoomWidgetBase->messageLineWidget()->setQuoteMessage({}, {}); 0595 } 0596 0597 void RoomWidget::forceLineEditFocus() 0598 { 0599 mRoomWidgetBase->messageLineWidget()->setFocus(); 0600 } 0601 0602 void RoomWidget::setChannelSelected(const QString &roomId, Room::RoomType roomType) 0603 { 0604 storeRoomSettings(); 0605 setRoomId(roomId); 0606 setRoomType(roomType); 0607 clearBeforeSwitching(); 0608 const AccountRoomSettings::PendingTypedInfo currentPendingInfo = mCurrentRocketChatAccount->accountRoomSettings()->value(roomId); 0609 if (currentPendingInfo.isValid()) { 0610 mRoomWidgetBase->messageLineWidget()->setQuoteMessage(currentPendingInfo.quotePermalink, currentPendingInfo.quoteText); 0611 mRoomWidgetBase->messageLineWidget()->setThreadMessageId(currentPendingInfo.threadMessageId); 0612 mRoomWidgetBase->messageLineWidget()->setText(currentPendingInfo.text); 0613 mRoomWidgetBase->messageLineWidget()->setMessageIdBeingEdited(currentPendingInfo.messageIdBeingEdited); 0614 if (currentPendingInfo.scrollbarPosition != -1) { 0615 mRoomWidgetBase->messageListView()->verticalScrollBar()->setValue(currentPendingInfo.scrollbarPosition); 0616 } 0617 } else { 0618 mRoomWidgetBase->messageLineWidget()->setText(QString()); 0619 } 0620 mRoomWidgetBase->messageLineWidget()->setMode(mRoomWidgetBase->messageLineWidget()->messageIdBeingEdited().isEmpty() 0621 ? MessageLineWidget::EditingMode::NewMessage 0622 : MessageLineWidget::EditingMode::EditMessage); 0623 0624 mRoomWidgetBase->messageLineWidget()->setFocus(); 0625 } 0626 0627 void RoomWidget::slotUpdateRoomCounterInfoWidget() 0628 { 0629 if (mRoom) { 0630 mRoomCounterInfoWidget->setChannelCounterInfo(mRoom->channelCounterInfo()); 0631 } 0632 } 0633 0634 void RoomWidget::updateRoomHeader() 0635 { 0636 if (mRoom) { 0637 mRoomHeaderWidget->setRoomName(mRoom->displayRoomName()); 0638 mRoomHeaderWidget->setRoomAnnouncement(mRoom->displayAnnouncement()); 0639 mRoomHeaderWidget->setRoomTopic(mRoom->displayTopic()); 0640 mRoomHeaderWidget->setFavoriteStatus(mRoom->favorite()); 0641 mRoomHeaderWidget->setEncypted(mRoom->encrypted() && mRoom->hasPermission(QStringLiteral("edit-room"))); 0642 mRoomHeaderWidget->setIsDiscussion(mRoom->isDiscussionRoom()); 0643 mRoomHeaderWidget->setIsMainTeam(mRoom->teamInfo().mainTeam()); 0644 mRoomHeaderWidget->setTeamRoomInfo(mRoom->teamRoomInfo()); 0645 mRoomHeaderWidget->setIsDirectGroup((mRoom->channelType() == Room::RoomType::Direct) && mRoom->userNames().count() > 2); 0646 if (mRoom->roomId() == QLatin1String("%1%1").arg(mCurrentRocketChatAccount->userId())) { 0647 mRoomHeaderWidget->setCallEnabled(false); 0648 } else { 0649 mRoomHeaderWidget->setCallEnabled(true); 0650 } 0651 // TODO Description ? 0652 0653 mRoomWidgetBase->updateRoomReadOnly(mRoom); 0654 if (mRoom->channelCounterInfo().isValid() && mRoom->channelCounterInfo().unreadMessages() > 0) { 0655 mRoomCounterInfoWidget->animatedShow(); 0656 } else { 0657 mRoomCounterInfoWidget->animatedHide(); 0658 } 0659 } 0660 } 0661 0662 QString RoomWidget::roomId() const 0663 { 0664 return mRoomWidgetBase->roomId(); 0665 } 0666 0667 void RoomWidget::setRoomType(Room::RoomType roomType) 0668 { 0669 mRoomType = roomType; 0670 } 0671 0672 Room *RoomWidget::room() const 0673 { 0674 return mRoom; 0675 } 0676 0677 void RoomWidget::slotShowListOfUsersInRoom(bool checked) 0678 { 0679 mUsersInRoomFlowWidget->setVisible(checked); 0680 } 0681 0682 void RoomWidget::setRoomId(const QString &roomId) 0683 { 0684 mRoomWidgetBase->setRoomId(roomId); 0685 mRoom = mCurrentRocketChatAccount->room(mRoomWidgetBase->roomId()); 0686 if (mRoom) { 0687 connectRoom(); 0688 mRoomWidgetBase->messageLineWidget()->setRoomId(roomId); 0689 mRoomWidgetBase->messageListView()->setChannelSelected(mRoom); 0690 mUsersInRoomFlowWidget->setRoom(mRoom); 0691 mRoomHeaderWidget->setRoom(mRoom); 0692 } else { 0693 qCWarning(RUQOLAWIDGETS_LOG) << " Impossible to find room " << roomId; 0694 } 0695 } 0696 0697 void RoomWidget::connectRoom() 0698 { 0699 if (mRoom) { 0700 connect(mRoom, &Room::announcementChanged, this, [this]() { 0701 mRoomHeaderWidget->setRoomAnnouncement(mRoom->displayAnnouncement()); 0702 }); 0703 connect(mRoom, &Room::topicChanged, this, [this]() { 0704 mRoomHeaderWidget->setRoomTopic(mRoom->displayTopic()); 0705 }); 0706 connect(mRoom, &Room::nameChanged, this, [this]() { 0707 mRoomHeaderWidget->setRoomName(mRoom->displayRoomName()); 0708 }); 0709 connect(mRoom, &Room::fnameChanged, this, [this]() { 0710 mRoomHeaderWidget->setRoomName(mRoom->displayRoomName()); 0711 }); 0712 connect(mRoom, &Room::favoriteChanged, this, [this]() { 0713 mRoomHeaderWidget->setFavoriteStatus(mRoom->favorite()); 0714 }); 0715 connect(mRoom, &Room::encryptedChanged, this, [this]() { 0716 mRoomHeaderWidget->setEncypted(mRoom->encrypted()); 0717 }); 0718 // TODO verify it. 0719 connect(mRoom, &Room::teamInfoChanged, this, [this]() { 0720 mRoomHeaderWidget->setIsMainTeam(mRoom->teamInfo().mainTeam()); 0721 }); 0722 connect(mRoom, &Room::autoTranslateLanguageChanged, this, &RoomWidget::updateListView); 0723 connect(mRoom, &Room::autoTranslateChanged, this, &RoomWidget::updateListView); 0724 connect(mRoom, &Room::ignoredUsersChanged, this, &RoomWidget::updateListView); 0725 connect(mRoom, &Room::channelCounterInfoChanged, this, &RoomWidget::slotUpdateRoomCounterInfoWidget); 0726 connect(mRoom, &Room::highlightsWordChanged, this, &RoomWidget::updateListView); 0727 } 0728 slotUpdateRoomCounterInfoWidget(); 0729 updateRoomHeader(); 0730 } 0731 0732 void RoomWidget::slotJumpToUnreadMessage(qint64 numberOfMessage) 0733 { 0734 MessagesModel *roomMessageModel = mCurrentRocketChatAccount->messageModelForRoom(mRoomWidgetBase->roomId()); 0735 if (roomMessageModel->rowCount() >= numberOfMessage) { 0736 const QString messageId = roomMessageModel->messageIdFromIndex(roomMessageModel->rowCount() - numberOfMessage); 0737 mRoomWidgetBase->messageListView()->goToMessage(messageId); 0738 } else { 0739 RocketChatRestApi::ChannelHistoryJob::ChannelHistoryInfo info; 0740 switch (mRoomType) { 0741 case Room::RoomType::Channel: 0742 info.channelType = RocketChatRestApi::ChannelHistoryJob::Channel; 0743 break; 0744 case Room::RoomType::Direct: 0745 info.channelType = RocketChatRestApi::ChannelHistoryJob::Direct; 0746 break; 0747 case Room::RoomType::Private: 0748 info.channelType = RocketChatRestApi::ChannelHistoryJob::Groups; 0749 break; 0750 case Room::RoomType::Unknown: 0751 qCWarning(RUQOLAWIDGETS_LOG) << " Problem with room type "; 0752 break; 0753 } 0754 if (mRoomType == Room::RoomType::Unknown) { 0755 return; 0756 } 0757 auto job = new RocketChatRestApi::ChannelHistoryJob(this); 0758 info.count = numberOfMessage - roomMessageModel->rowCount() + 1; 0759 info.roomId = mRoomWidgetBase->roomId(); 0760 const qint64 endDateTime = roomMessageModel->lastTimestamp(); 0761 info.latestMessage = QDateTime::fromMSecsSinceEpoch(endDateTime, Qt::UTC).toString(Qt::ISODateWithMs); 0762 // qDebug() << " info.latestMessage " << info.latestMessage; 0763 job->setChannelHistoryInfo(info); 0764 mCurrentRocketChatAccount->restApi()->initializeRestApiJob(job); 0765 connect(job, &RocketChatRestApi::ChannelHistoryJob::channelHistoryDone, this, [this, numberOfMessage, roomMessageModel](const QJsonObject &obj) { 0766 mCurrentRocketChatAccount->rocketChatBackend()->processIncomingMessages(obj.value(QLatin1String("messages")).toArray(), true, true); 0767 // qDebug() << " obj " << obj; 0768 // qDebug() << " roomMessageModel->rowCount() " << roomMessageModel->rowCount(); 0769 // qDebug() << " numberOfMessage " << numberOfMessage; 0770 // qDebug() << " initialRowCount " << (roomMessageModel->rowCount() - numberOfMessage); 0771 0772 const QString messageId = roomMessageModel->messageIdFromIndex(roomMessageModel->rowCount() - numberOfMessage); 0773 mRoomWidgetBase->messageListView()->goToMessage(messageId); 0774 }); 0775 if (!job->start()) { 0776 qCDebug(RUQOLAWIDGETS_LOG) << "Impossible to start ChannelHistoryJob"; 0777 } 0778 } 0779 } 0780 0781 void RoomWidget::scrollToMessageId(const QString &messageId) 0782 { 0783 slotGotoMessage(messageId, {}); 0784 } 0785 0786 void RoomWidget::slotGotoMessage(const QString &messageId, const QString &messageDateTimeUtc) 0787 { 0788 MessageListView *messageListView = mRoomWidgetBase->messageListView(); 0789 auto messageModel = qobject_cast<MessagesModel *>(messageListView->model()); 0790 Q_ASSERT(messageModel); 0791 const QModelIndex index = messageModel->indexForMessage(messageId); 0792 if (index.isValid()) { 0793 messageListView->scrollTo(index); 0794 } else /* if (!messageDateTimeUtc.isEmpty())*/ { 0795 RocketChatRestApi::ChannelHistoryJob::ChannelHistoryInfo info; 0796 switch (mRoomType) { 0797 case Room::RoomType::Channel: 0798 info.channelType = RocketChatRestApi::ChannelHistoryJob::Channel; 0799 break; 0800 case Room::RoomType::Direct: 0801 info.channelType = RocketChatRestApi::ChannelHistoryJob::Direct; 0802 break; 0803 case Room::RoomType::Private: 0804 info.channelType = RocketChatRestApi::ChannelHistoryJob::Groups; 0805 break; 0806 case Room::RoomType::Unknown: 0807 qCWarning(RUQOLAWIDGETS_LOG) << " Problem with room type "; 0808 break; 0809 } 0810 if (mRoomType == Room::RoomType::Unknown) { 0811 return; 0812 } 0813 auto job = new RocketChatRestApi::ChannelHistoryJob(this); 0814 info.roomId = mRoomWidgetBase->roomId(); 0815 const qint64 endDateTime = messageModel->lastTimestamp(); 0816 info.latestMessage = QDateTime::fromMSecsSinceEpoch(endDateTime, Qt::UTC).toString(Qt::ISODateWithMs); 0817 info.oldestMessage = messageDateTimeUtc; 0818 info.inclusive = true; 0819 info.count = 5000; 0820 // qDebug() << " info " << info; 0821 job->setChannelHistoryInfo(info); 0822 mCurrentRocketChatAccount->restApi()->initializeRestApiJob(job); 0823 connect(job, &RocketChatRestApi::ChannelHistoryJob::channelHistoryDone, this, [messageId, messageModel, messageListView, this](const QJsonObject &obj) { 0824 mCurrentRocketChatAccount->rocketChatBackend()->processIncomingMessages(obj.value(QLatin1String("messages")).toArray(), true, true); 0825 const QModelIndex index = messageModel->indexForMessage(messageId); 0826 if (index.isValid()) { 0827 messageListView->scrollTo(index); 0828 } else { 0829 qCWarning(RUQOLAWIDGETS_LOG) << "Message not found:" << messageId; 0830 } 0831 }); 0832 if (!job->start()) { 0833 qCDebug(RUQOLAWIDGETS_LOG) << "Impossible to start ChannelHistoryJob"; 0834 } 0835 } 0836 } 0837 0838 void RoomWidget::slotClearNotification() 0839 { 0840 mCurrentRocketChatAccount->markRoomAsRead(mRoomWidgetBase->roomId()); 0841 } 0842 0843 void RoomWidget::slotEncryptedChanged(bool b) 0844 { 0845 RocketChatRestApi::SaveRoomSettingsJob::SaveRoomSettingsInfo info; 0846 info.encrypted = b; 0847 info.roomId = mRoomWidgetBase->roomId(); 0848 info.roomType = mRoom ? mRoom->roomFromRoomType(mRoom->channelType()) : QString(); 0849 info.mSettingsWillBeChanged |= RocketChatRestApi::SaveRoomSettingsJob::SaveRoomSettingsInfo::Encrypted; 0850 auto saveRoomSettingsJob = new RocketChatRestApi::SaveRoomSettingsJob(this); 0851 saveRoomSettingsJob->setSaveRoomSettingsInfo(info); 0852 mCurrentRocketChatAccount->restApi()->initializeRestApiJob(saveRoomSettingsJob); 0853 if (!saveRoomSettingsJob->start()) { 0854 qCDebug(RUQOLAWIDGETS_LOG) << "Impossible to start saveRoomSettingsJob"; 0855 } 0856 } 0857 0858 void RoomWidget::slotChangeFavorite(bool b) 0859 { 0860 mCurrentRocketChatAccount->changeFavorite(mRoomWidgetBase->roomId(), b); 0861 } 0862 0863 Room::RoomType RoomWidget::roomType() const 0864 { 0865 return mRoomType; 0866 } 0867 0868 void RoomWidget::setCurrentRocketChatAccount(RocketChatAccount *account) 0869 { 0870 if (mCurrentRocketChatAccount) { 0871 disconnect(mCurrentRocketChatAccount, &RocketChatAccount::openThreadRequested, this, &RoomWidget::slotOpenThreadRequested); 0872 disconnect(mCurrentRocketChatAccount, &RocketChatAccount::displayReconnectWidget, this, &RoomWidget::slotDisplayReconnectWidget); 0873 disconnect(mCurrentRocketChatAccount, &RocketChatAccount::loginStatusChanged, this, &RoomWidget::slotLoginStatusChanged); 0874 disconnect(mCurrentRocketChatAccount, &RocketChatAccount::needUpdateMessageView, this, &RoomWidget::updateListView); 0875 } 0876 0877 mCurrentRocketChatAccount = account; 0878 mRoomWidgetBase->setCurrentRocketChatAccount(account); 0879 connect(mCurrentRocketChatAccount, &RocketChatAccount::openThreadRequested, this, &RoomWidget::slotOpenThreadRequested); 0880 connect(mCurrentRocketChatAccount, &RocketChatAccount::displayReconnectWidget, this, &RoomWidget::slotDisplayReconnectWidget); 0881 connect(mCurrentRocketChatAccount, &RocketChatAccount::loginStatusChanged, this, &RoomWidget::slotLoginStatusChanged); 0882 connect(mCurrentRocketChatAccount, &RocketChatAccount::needUpdateMessageView, this, &RoomWidget::updateListView); 0883 // TODO verify if we need to show or not reconnect widget 0884 mRoomHeaderWidget->setCurrentRocketChatAccount(account); 0885 mUsersInRoomFlowWidget->setCurrentRocketChatAccount(account); 0886 } 0887 0888 void RoomWidget::slotLoginStatusChanged() 0889 { 0890 const auto loginStatus = mCurrentRocketChatAccount->loginStatus(); 0891 if (loginStatus == DDPAuthenticationManager::LoggedIn) { 0892 if (mRoomReconnectInfoWidget) { 0893 mRoomReconnectInfoWidget->hide(); 0894 } 0895 } 0896 } 0897 0898 void RoomWidget::slotGoBackToRoom() 0899 { 0900 if (mRoom) { 0901 Q_EMIT selectChannelRequested(mRoom->parentRid()); 0902 } 0903 } 0904 0905 void RoomWidget::slotOpenThreadRequested(const QString &threadMessageId, 0906 const QString &threadMessagePreview, 0907 bool threadIsFollowing, 0908 const Message &threadMessage) 0909 { 0910 qCDebug(RUQOLA_THREAD_MESSAGE_WIDGETS_LOG) << "threadMessageId: " << threadMessageId; 0911 auto dlg = new ThreadMessageDialog(mCurrentRocketChatAccount, this); 0912 ThreadMessageWidget::ThreadMessageInfo info; 0913 info.threadMessageId = threadMessageId; 0914 info.threadMessagePreview = threadMessagePreview; 0915 info.threadIsFollowing = threadIsFollowing; 0916 info.room = mRoom; 0917 info.messageThread = threadMessage; 0918 dlg->setThreadMessageInfo(info); 0919 dlg->show(); 0920 } 0921 0922 void RoomWidget::setLayoutSpacing(int spacing) 0923 { 0924 mRoomWidgetBase->layout()->setSpacing(spacing); 0925 } 0926 0927 void RoomWidget::slotTryReconnect() 0928 { 0929 mCurrentRocketChatAccount->reconnectToServer(); 0930 } 0931 0932 void RoomWidget::slotDisplayReconnectWidget(int seconds) 0933 { 0934 // Disable for the moment it seems to create some problems 0935 // FIXME mRoomReconnectInfoWidget->setReconnectSecondDelay(seconds); 0936 } 0937 0938 void RoomWidget::slotCloseOtr() 0939 { 0940 mCurrentRocketChatAccount->ddp()->streamNotifyUserOtrEnd(roomId(), mCurrentRocketChatAccount->userId()); 0941 } 0942 0943 void RoomWidget::slotRefreshOtrKeys() 0944 { 0945 // TODO 0946 } 0947 0948 #include "moc_roomwidget.cpp"