diff --git a/resources/qml/MessageInput.qml b/resources/qml/MessageInput.qml index a1220599..17e1198d 100644 --- a/resources/qml/MessageInput.qml +++ b/resources/qml/MessageInput.qml @@ -17,14 +17,18 @@ Rectangle { spacing: 16 ImageButton { + visible: TimelineManager.callsSupported Layout.alignment: Qt.AlignBottom hoverEnabled: true width: 22 height: 22 - image: ":/icons/icons/ui/place-call.png" + image: TimelineManager.isOnCall ? ":/icons/icons/ui/end-call.png" : ":/icons/icons/ui/place-call.png" + ToolTip.visible: hovered + ToolTip.text: TimelineManager.isOnCall ? qsTr("Hang up") : qsTr("Place a call") Layout.topMargin: 8 Layout.bottomMargin: 8 Layout.leftMargin: 16 + onClicked: TimelineManager.timeline.input.callButton() } ImageButton { @@ -35,7 +39,10 @@ Rectangle { image: ":/icons/icons/ui/paper-clip-outline.png" Layout.topMargin: 8 Layout.bottomMargin: 8 + Layout.leftMargin: TimelineManager.callsSupported ? 0 : 16 onClicked: TimelineManager.timeline.input.openFileSelection() + ToolTip.visible: hovered + ToolTip.text: qsTr("Send a file") Rectangle { anchors.fill: parent @@ -112,6 +119,8 @@ Rectangle { image: ":/icons/icons/ui/smile.png" Layout.topMargin: 8 Layout.bottomMargin: 8 + ToolTip.visible: hovered + ToolTip.text: qsTr("Emoji") } ImageButton { @@ -123,6 +132,8 @@ Rectangle { Layout.topMargin: 8 Layout.bottomMargin: 8 Layout.rightMargin: 16 + ToolTip.visible: hovered + ToolTip.text: qsTr("Send") onClicked: { TimelineManager.timeline.input.send(); textArea.clear(); diff --git a/resources/qml/NhekoBusyIndicator.qml b/resources/qml/NhekoBusyIndicator.qml index 8889989a..89a40dd5 100644 --- a/resources/qml/NhekoBusyIndicator.qml +++ b/resources/qml/NhekoBusyIndicator.qml @@ -6,8 +6,8 @@ BusyIndicator { id: control contentItem: Item { - implicitWidth: Math.min(parent.height, parent.width) - implicitHeight: implicitWidth + implicitWidth: 64 + implicitHeight: 64 Item { id: item diff --git a/src/ChatPage.cpp b/src/ChatPage.cpp index e09041e7..c703d95f 100644 --- a/src/ChatPage.cpp +++ b/src/ChatPage.cpp @@ -268,38 +268,6 @@ ChatPage::ChatPage(QSharedPointer userSettings, QWidget *parent) this, SIGNAL(unreadMessages(int))); - connect(text_input_, &TextInputWidget::callButtonPress, this, [this]() { - if (callManager_->onActiveCall()) { - callManager_->hangUp(); - } else { - if (auto roomInfo = cache::singleRoomInfo(current_room_.toStdString()); - roomInfo.member_count != 2) { - showNotification("Calls are limited to 1:1 rooms."); - } else { - std::vector members( - cache::getMembers(current_room_.toStdString())); - const RoomMember &callee = - members.front().user_id == utils::localUser() ? members.back() - : members.front(); - auto dialog = new dialogs::PlaceCall( - callee.user_id, - callee.display_name, - QString::fromStdString(roomInfo.name), - QString::fromStdString(roomInfo.avatar_url), - userSettings_, - MainWindow::instance()); - connect(dialog, &dialogs::PlaceCall::voice, this, [this]() { - callManager_->sendInvite(current_room_, false); - }); - connect(dialog, &dialogs::PlaceCall::video, this, [this]() { - callManager_->sendInvite(current_room_, true); - }); - utils::centerWidget(dialog, MainWindow::instance()); - dialog->show(); - } - } - }); - connect( this, &ChatPage::updateGroupsInfo, communitiesList_, &CommunitiesList::setCommunities); diff --git a/src/ChatPage.h b/src/ChatPage.h index 41c6f276..7eb37f04 100644 --- a/src/ChatPage.h +++ b/src/ChatPage.h @@ -88,6 +88,7 @@ public: static ChatPage *instance() { return instance_; } QSharedPointer userSettings() { return userSettings_; } + CallManager *callManager() { return callManager_; } void deleteConfigs(); CommunitiesList *communitiesList() { return communitiesList_; } diff --git a/src/TextInputWidget.cpp b/src/TextInputWidget.cpp index 232c0cad..1a856abb 100644 --- a/src/TextInputWidget.cpp +++ b/src/TextInputWidget.cpp @@ -431,15 +431,6 @@ TextInputWidget::TextInputWidget(QWidget *parent) topLayout_->setSpacing(0); topLayout_->setContentsMargins(13, 1, 13, 0); -#ifdef GSTREAMER_AVAILABLE - callBtn_ = new FlatButton(this); - changeCallButtonState(webrtc::State::DISCONNECTED); - connect(&WebRTCSession::instance(), - &WebRTCSession::stateChanged, - this, - &TextInputWidget::changeCallButtonState); -#endif - QIcon send_file_icon; send_file_icon.addFile(":/icons/icons/ui/paper-clip-outline.png"); @@ -508,9 +499,6 @@ TextInputWidget::TextInputWidget(QWidget *parent) emojiBtn_->setIcon(emoji_icon); emojiBtn_->setIconSize(QSize(ButtonHeight, ButtonHeight)); -#ifdef GSTREAMER_AVAILABLE - topLayout_->addWidget(callBtn_); -#endif topLayout_->addWidget(sendFileBtn_); topLayout_->addWidget(input_); topLayout_->addWidget(emojiBtn_); @@ -518,9 +506,6 @@ TextInputWidget::TextInputWidget(QWidget *parent) setLayout(topLayout_); -#ifdef GSTREAMER_AVAILABLE - connect(callBtn_, &FlatButton::clicked, this, &TextInputWidget::callButtonPress); -#endif connect(sendMessageBtn_, &FlatButton::clicked, input_, &FilteredTextEdit::submit); connect(sendFileBtn_, SIGNAL(clicked()), this, SLOT(openFileSelection())); connect(emojiBtn_, @@ -570,18 +555,3 @@ TextInputWidget::paintEvent(QPaintEvent *) style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this); } - -void -TextInputWidget::changeCallButtonState(webrtc::State state) -{ - QIcon icon; - if (state == webrtc::State::ICEFAILED || state == webrtc::State::DISCONNECTED) { - callBtn_->setToolTip(tr("Place a call")); - icon.addFile(":/icons/icons/ui/place-call.png"); - } else { - callBtn_->setToolTip(tr("Hang up")); - icon.addFile(":/icons/icons/ui/end-call.png"); - } - callBtn_->setIcon(icon); - callBtn_->setIconSize(QSize(ButtonHeight * 1.1, ButtonHeight * 1.1)); -} diff --git a/src/TextInputWidget.h b/src/TextInputWidget.h index 44419547..9613f209 100644 --- a/src/TextInputWidget.h +++ b/src/TextInputWidget.h @@ -26,7 +26,6 @@ #include #include -#include "WebRTCSession.h" #include "dialogs/PreviewUploadOverlay.h" #include "emoji/PickButton.h" #include "popups/SuggestionsPopup.h" @@ -155,7 +154,6 @@ public: public slots: void focusLineEdit() { input_->setFocus(); } - void changeCallButtonState(webrtc::State); private slots: void addSelectedEmoji(const QString &emoji); @@ -163,8 +161,6 @@ private slots: signals: void heightChanged(int height); - void callButtonPress(); - void sendJoinRoomRequest(const QString &room); void sendInviteRoomRequest(const QString &userid, const QString &reason); void sendKickRoomRequest(const QString &userid, const QString &reason); @@ -185,7 +181,6 @@ private: LoadingIndicator *spinner_; - FlatButton *callBtn_; FlatButton *sendFileBtn_; FlatButton *sendMessageBtn_; emoji::PickButton *emojiBtn_; diff --git a/src/timeline/InputBar.cpp b/src/timeline/InputBar.cpp index bd8f6414..dc287f94 100644 --- a/src/timeline/InputBar.cpp +++ b/src/timeline/InputBar.cpp @@ -12,13 +12,16 @@ #include #include "Cache.h" +#include "CallManager.h" #include "ChatPage.h" #include "Logging.h" +#include "MainWindow.h" #include "MatrixClient.h" #include "Olm.h" #include "TimelineModel.h" #include "UserSettingsPage.h" #include "Utils.h" +#include "dialogs/PlaceCall.h" #include "dialogs/PreviewUploadOverlay.h" #include "blurhash.hpp" @@ -511,3 +514,45 @@ InputBar::showPreview(const QMimeData &source, QString path, const QStringList & }); }); } + +void +InputBar::callButton() +{ + auto callManager_ = ChatPage::instance()->callManager(); + if (callManager_->onActiveCall()) { + callManager_->hangUp(); + } else { + auto current_room_ = room->roomId(); + if (auto roomInfo = cache::singleRoomInfo(current_room_.toStdString()); + roomInfo.member_count != 2) { + ChatPage::instance()->showNotification("Calls are limited to 1:1 rooms."); + } else { + std::vector members( + cache::getMembers(current_room_.toStdString())); + const RoomMember &callee = members.front().user_id == utils::localUser() + ? members.back() + : members.front(); + auto dialog = + new dialogs::PlaceCall(callee.user_id, + callee.display_name, + QString::fromStdString(roomInfo.name), + QString::fromStdString(roomInfo.avatar_url), + ChatPage::instance()->userSettings(), + MainWindow::instance()); + connect(dialog, + &dialogs::PlaceCall::voice, + callManager_, + [callManager_, current_room_]() { + callManager_->sendInvite(current_room_, false); + }); + connect(dialog, + &dialogs::PlaceCall::video, + callManager_, + [callManager_, current_room_]() { + callManager_->sendInvite(current_room_, true); + }); + utils::centerWidget(dialog, MainWindow::instance()); + dialog->show(); + } + } +} diff --git a/src/timeline/InputBar.h b/src/timeline/InputBar.h index 35e3f8a4..a52a3904 100644 --- a/src/timeline/InputBar.h +++ b/src/timeline/InputBar.h @@ -27,6 +27,7 @@ public slots: void updateState(int selectionStart, int selectionEnd, int cursorPosition, QString text); void openFileSelection(); bool uploading() const { return uploading_; } + void callButton(); signals: void insertText(QString text); diff --git a/src/timeline/TimelineViewManager.cpp b/src/timeline/TimelineViewManager.cpp index f949498d..1392c505 100644 --- a/src/timeline/TimelineViewManager.cpp +++ b/src/timeline/TimelineViewManager.cpp @@ -244,6 +244,26 @@ TimelineViewManager::TimelineViewManager(CallManager *callManager, ChatPage *par &CallManager::newVideoCallState, this, &TimelineViewManager::videoCallChanged); + + connect(&WebRTCSession::instance(), + &WebRTCSession::stateChanged, + this, + &TimelineViewManager::onCallChanged); +} + +bool +TimelineViewManager::isOnCall() const +{ + return callManager_->onActiveCall(); +} +bool +TimelineViewManager::callsSupported() const +{ +#ifdef GSTREAMER_AVAILABLE + return true; +#else + return false; +#endif } void @@ -506,122 +526,6 @@ TimelineViewManager::queueReactionMessage(const QString &reactedEvent, const QSt timeline_->redactEvent(selfReactedEvent); } } - -void -TimelineViewManager::queueImageMessage(const QString &roomid, - const QString &filename, - const std::optional &file, - const QString &url, - const QString &mime, - uint64_t dsize, - const QSize &dimensions, - const QString &blurhash) -{ - mtx::events::msg::Image image; - image.info.mimetype = mime.toStdString(); - image.info.size = dsize; - image.info.blurhash = blurhash.toStdString(); - image.body = filename.toStdString(); - image.info.h = dimensions.height(); - image.info.w = dimensions.width(); - - if (file) - image.file = file; - else - image.url = url.toStdString(); - - auto model = models.value(roomid); - if (!model->reply().isEmpty()) { - image.relates_to.in_reply_to.event_id = model->reply().toStdString(); - model->resetReply(); - } - - model->sendMessageEvent(image, mtx::events::EventType::RoomMessage); -} - -void -TimelineViewManager::queueFileMessage( - const QString &roomid, - const QString &filename, - const std::optional &encryptedFile, - const QString &url, - const QString &mime, - uint64_t dsize) -{ - mtx::events::msg::File file; - file.info.mimetype = mime.toStdString(); - file.info.size = dsize; - file.body = filename.toStdString(); - - if (encryptedFile) - file.file = encryptedFile; - else - file.url = url.toStdString(); - - auto model = models.value(roomid); - if (!model->reply().isEmpty()) { - file.relates_to.in_reply_to.event_id = model->reply().toStdString(); - model->resetReply(); - } - - model->sendMessageEvent(file, mtx::events::EventType::RoomMessage); -} - -void -TimelineViewManager::queueAudioMessage(const QString &roomid, - const QString &filename, - const std::optional &file, - const QString &url, - const QString &mime, - uint64_t dsize) -{ - mtx::events::msg::Audio audio; - audio.info.mimetype = mime.toStdString(); - audio.info.size = dsize; - audio.body = filename.toStdString(); - audio.url = url.toStdString(); - - if (file) - audio.file = file; - else - audio.url = url.toStdString(); - - auto model = models.value(roomid); - if (!model->reply().isEmpty()) { - audio.relates_to.in_reply_to.event_id = model->reply().toStdString(); - model->resetReply(); - } - - model->sendMessageEvent(audio, mtx::events::EventType::RoomMessage); -} - -void -TimelineViewManager::queueVideoMessage(const QString &roomid, - const QString &filename, - const std::optional &file, - const QString &url, - const QString &mime, - uint64_t dsize) -{ - mtx::events::msg::Video video; - video.info.mimetype = mime.toStdString(); - video.info.size = dsize; - video.body = filename.toStdString(); - - if (file) - video.file = file; - else - video.url = url.toStdString(); - - auto model = models.value(roomid); - if (!model->reply().isEmpty()) { - video.relates_to.in_reply_to.event_id = model->reply().toStdString(); - model->resetReply(); - } - - model->sendMessageEvent(video, mtx::events::EventType::RoomMessage); -} - void TimelineViewManager::queueCallMessage(const QString &roomid, const mtx::events::msg::CallInvite &callInvite) diff --git a/src/timeline/TimelineViewManager.h b/src/timeline/TimelineViewManager.h index 02e0e132..371e9af2 100644 --- a/src/timeline/TimelineViewManager.h +++ b/src/timeline/TimelineViewManager.h @@ -41,6 +41,8 @@ class TimelineViewManager : public QObject Q_PROPERTY(QString callPartyName READ callPartyName NOTIFY callPartyChanged) Q_PROPERTY(QString callPartyAvatarUrl READ callPartyAvatarUrl NOTIFY callPartyChanged) Q_PROPERTY(bool isMicMuted READ isMicMuted NOTIFY micMuteChanged) + Q_PROPERTY(bool isOnCall READ isOnCall NOTIFY onCallChanged) + Q_PROPERTY(bool callsSupported READ callsSupported CONSTANT) public: TimelineViewManager(CallManager *callManager, ChatPage *parent = nullptr); @@ -95,6 +97,7 @@ signals: void videoCallChanged(); void callPartyChanged(); void micMuteChanged(); + void onCallChanged(); public slots: void updateReadReceipts(const QString &room_id, const std::vector &event_ids); @@ -104,38 +107,14 @@ public slots: void setHistoryView(const QString &room_id); void updateColorPalette(); void queueReactionMessage(const QString &reactedEvent, const QString &reactionKey); - void queueImageMessage(const QString &roomid, - const QString &filename, - const std::optional &file, - const QString &url, - const QString &mime, - uint64_t dsize, - const QSize &dimensions, - const QString &blurhash); - void queueFileMessage(const QString &roomid, - const QString &filename, - const std::optional &file, - const QString &url, - const QString &mime, - uint64_t dsize); - void queueAudioMessage(const QString &roomid, - const QString &filename, - const std::optional &file, - const QString &url, - const QString &mime, - uint64_t dsize); - void queueVideoMessage(const QString &roomid, - const QString &filename, - const std::optional &file, - const QString &url, - const QString &mime, - uint64_t dsize); void queueCallMessage(const QString &roomid, const mtx::events::msg::CallInvite &); void queueCallMessage(const QString &roomid, const mtx::events::msg::CallCandidates &); void queueCallMessage(const QString &roomid, const mtx::events::msg::CallAnswer &); void queueCallMessage(const QString &roomid, const mtx::events::msg::CallHangUp &); void updateEncryptedDescriptions(); + bool isOnCall() const; + bool callsSupported() const; void enableBackButton() {