diff --git a/Linphone/core/chat/message/EventLogCore.cpp b/Linphone/core/chat/message/EventLogCore.cpp index 4f3749a43..920333486 100644 --- a/Linphone/core/chat/message/EventLogCore.cpp +++ b/Linphone/core/chat/message/EventLogCore.cpp @@ -65,6 +65,10 @@ QString EventLogCore::getEventLogId() { QSharedPointer EventLogCore::getChatMessageCore() { return mChatMessageCore; } +ChatMessageGui *EventLogCore::getChatMessageGui() { + return mChatMessageCore ? new ChatMessageGui(mChatMessageCore) : nullptr; +} + QSharedPointer EventLogCore::getCallHistoryCore() { return mCallHistoryCore; } diff --git a/Linphone/core/chat/message/EventLogCore.hpp b/Linphone/core/chat/message/EventLogCore.hpp index 85b93ab4d..aea5cb80e 100644 --- a/Linphone/core/chat/message/EventLogCore.hpp +++ b/Linphone/core/chat/message/EventLogCore.hpp @@ -35,12 +35,13 @@ #include class ChatMessageCore; +class ChatMessageGui; class EventLogCore : public QObject, public AbstractObject { Q_OBJECT Q_PROPERTY(LinphoneEnums::EventLogType type MEMBER mEventLogType CONSTANT) - Q_PROPERTY(ChatMessageCore *chatMessage READ getChatMessageCorePointer CONSTANT) + Q_PROPERTY(ChatMessageGui *chatMessageGui READ getChatMessageGui CONSTANT) // Q_PROPERTY(NotifyCore *notification MEMBER mNotifyCore CONSTANT) Q_PROPERTY(CallHistoryCore *callLog READ getCallHistoryCorePointer CONSTANT) Q_PROPERTY(bool important MEMBER mImportant CONSTANT) @@ -55,6 +56,7 @@ public: void setSelf(QSharedPointer me); QString getEventLogId(); QSharedPointer getChatMessageCore(); + ChatMessageGui *getChatMessageGui(); QSharedPointer getCallHistoryCore(); bool isHandled() const { return mHandled; diff --git a/Linphone/core/sound-player/SoundPlayerCore.cpp b/Linphone/core/sound-player/SoundPlayerCore.cpp index 1115d35df..c1d0cf9be 100644 --- a/Linphone/core/sound-player/SoundPlayerCore.cpp +++ b/Linphone/core/sound-player/SoundPlayerCore.cpp @@ -105,6 +105,9 @@ void SoundPlayerCore::buildInternalPlayer(QSharedPointer me) { mSoundPlayerModelConnection->makeConnectToCore(&SoundPlayerCore::lPlay, [this]() { mSoundPlayerModelConnection->invokeToModel([this] { mSoundPlayerModel->play(mSource); }); }); + mSoundPlayerModelConnection->makeConnectToCore(&SoundPlayerCore::lRestart, [this]() { + mSoundPlayerModelConnection->invokeToModel([this] { mSoundPlayerModel->play(mSource, true); }); + }); mSoundPlayerModelConnection->makeConnectToCore(&SoundPlayerCore::lSeek, [this](int offset) { mSoundPlayerModelConnection->invokeToModel([this, offset] { mSoundPlayerModel->seek(mSource, offset); }); }); @@ -150,6 +153,7 @@ void SoundPlayerCore::handleEof() { if (mForceClose) { mForceClose = false; lStop(); + emit eofReached(); } } diff --git a/Linphone/core/sound-player/SoundPlayerCore.hpp b/Linphone/core/sound-player/SoundPlayerCore.hpp index 90e1b3c37..19abaed63 100644 --- a/Linphone/core/sound-player/SoundPlayerCore.hpp +++ b/Linphone/core/sound-player/SoundPlayerCore.hpp @@ -71,6 +71,7 @@ signals: bool lOpen(); void lPause(); bool lPlay(); + bool lRestart(); void lStop(bool force = false); void lSeek(int offset); void lRefreshPosition(); @@ -79,6 +80,7 @@ signals: void playing(); void stopped(); void errorChanged(QString error); + void eofReached(); void sourceChanged(const QString &source); void playbackStateChanged(LinphoneEnums::PlaybackState playbackState); diff --git a/Linphone/core/sound-player/SoundPlayerGui.cpp b/Linphone/core/sound-player/SoundPlayerGui.cpp index 6761a4ccc..d7e26d0d2 100644 --- a/Linphone/core/sound-player/SoundPlayerGui.cpp +++ b/Linphone/core/sound-player/SoundPlayerGui.cpp @@ -30,6 +30,7 @@ SoundPlayerGui::SoundPlayerGui(QObject *parent) : QObject(parent) { if (mCore) connect(mCore.get(), &SoundPlayerCore::stopped, this, &SoundPlayerGui::stopped); if (mCore) connect(mCore.get(), &SoundPlayerCore::positionChanged, this, &SoundPlayerGui::positionChanged); if (mCore) connect(mCore.get(), &SoundPlayerCore::errorChanged, this, &SoundPlayerGui::errorChanged); + if (mCore) connect(mCore.get(), &SoundPlayerCore::eofReached, this, &SoundPlayerGui::eofReached); } SoundPlayerGui::SoundPlayerGui(QSharedPointer core) { App::getInstance()->mEngine->setObjectOwnership(this, QQmlEngine::JavaScriptOwnership); diff --git a/Linphone/core/sound-player/SoundPlayerGui.hpp b/Linphone/core/sound-player/SoundPlayerGui.hpp index c93e9ab9b..2ccc54440 100644 --- a/Linphone/core/sound-player/SoundPlayerGui.hpp +++ b/Linphone/core/sound-player/SoundPlayerGui.hpp @@ -45,6 +45,7 @@ signals: void stopped(); void positionChanged(); void errorChanged(QString error); + void eofReached(); private: DECLARE_ABSTRACT_OBJECT diff --git a/Linphone/model/sound-player/SoundPlayerModel.cpp b/Linphone/model/sound-player/SoundPlayerModel.cpp index f0b5e3d2f..0e5780521 100644 --- a/Linphone/model/sound-player/SoundPlayerModel.cpp +++ b/Linphone/model/sound-player/SoundPlayerModel.cpp @@ -78,8 +78,9 @@ bool SoundPlayerModel::open(QString source) { // return false; } -bool SoundPlayerModel::play(QString source) { +bool SoundPlayerModel::play(QString source, bool fromStart) { if (source == "") return false; + if (fromStart) stop(); if (!open(source)) { qWarning() << QStringLiteral("Unable to open: `%1`").arg(source); //: Unable to open: `%1` diff --git a/Linphone/model/sound-player/SoundPlayerModel.hpp b/Linphone/model/sound-player/SoundPlayerModel.hpp index a43a99d5e..421bbfeec 100644 --- a/Linphone/model/sound-player/SoundPlayerModel.hpp +++ b/Linphone/model/sound-player/SoundPlayerModel.hpp @@ -44,7 +44,7 @@ public: bool open(QString source); void pause(); - bool play(QString source); + bool play(QString source, bool fromStart = false); void stop(bool force = false); void seek(QString source, int offset); diff --git a/Linphone/view/Control/Display/Chat/ChatAudioContent.qml b/Linphone/view/Control/Display/Chat/ChatAudioContent.qml index 37c6d5dc3..f30fa2e2a 100644 --- a/Linphone/view/Control/Display/Chat/ChatAudioContent.qml +++ b/Linphone/view/Control/Display/Chat/ChatAudioContent.qml @@ -10,6 +10,7 @@ import UtilsCpp Item { id: mainItem property ChatMessageContentGui chatMessageContentGui + // used for creating a voice recording message property var chatMessageObj property ChatMessageGui chatMessage: chatMessageObj && chatMessageObj.value || null property bool isPlaying : soudPlayerLoader.item && soudPlayerLoader.item.core.playbackState === LinphoneEnums.PlaybackState.PlayingState @@ -19,7 +20,14 @@ Item { signal voiceRecordingMessageCreationRequested(RecorderGui recorderGui) signal stopRecording() - + signal endOfFileReached() + // auto play if follows a voice recording + function requestPlaying() { + if(soudPlayerLoader.item) { + soudPlayerLoader.item.play(true) + } + } + function createVoiceMessageInChat(chat) { if (recorderLoader.item) { mainItem.chatMessageObj = UtilsCpp.createVoiceRecordingMessage(recorderLoader.item, chat) @@ -44,10 +52,12 @@ Item { id: soundPlayerGui source: mainItem.chatMessageContentGui && mainItem.chatMessageContentGui.core.filePath - function play(){ - if(mainItem.isPlaying){// Pause the play + function play(restartIfPlaying){ + if(mainItem.isPlaying && (restartIfPlaying === undefined || !restartIfPlaying)){// Pause the play soundPlayerGui.core.lPause() - }else{// Play the audio + } else if (restartIfPlaying) { //Play from scratch + soundPlayerGui.core.lRestart() + } else {// Play the audio soundPlayerGui.core.lPlay() } } @@ -67,6 +77,9 @@ Item { //: Error UtilsCpp.showInformationPopup(qsTr("information_popup_error_title"), error, false) } + onEofReached: { + mainItem.endOfFileReached() + } } } diff --git a/Linphone/view/Control/Display/Chat/ChatMessage.qml b/Linphone/view/Control/Display/Chat/ChatMessage.qml index d431379cb..d531a6fda 100644 --- a/Linphone/view/Control/Display/Chat/ChatMessage.qml +++ b/Linphone/view/Control/Display/Chat/ChatMessage.qml @@ -37,6 +37,9 @@ Control.Control { signal showImdnStatusForMessageRequested() signal replyToMessageRequested() signal forwardMessageRequested() + signal endOfVoiceRecordingReached() + signal requestAutoPlayVoiceRecording() + onRequestAutoPlayVoiceRecording: chatBubbleContent.requestAutoPlayVoiceRecording() Timer { id: hightlightTimer @@ -254,6 +257,7 @@ Control.Control { onMouseEvent: (event) => { mainItem.handleDefaultMouseEvent(event) } + onEndOfVoiceRecordingReached: mainItem.endOfVoiceRecordingReached() } RowLayout { Layout.preferredHeight: childrenRect.height diff --git a/Linphone/view/Control/Display/Chat/ChatMessageContent.qml b/Linphone/view/Control/Display/Chat/ChatMessageContent.qml index e9306f3cc..f67d1930f 100644 --- a/Linphone/view/Control/Display/Chat/ChatMessageContent.qml +++ b/Linphone/view/Control/Display/Chat/ChatMessageContent.qml @@ -17,6 +17,8 @@ ColumnLayout { signal lastSelectedTextChanged(string selectedText) // signal conferenceIcsCopied() signal mouseEvent(MouseEvent event) + signal endOfVoiceRecordingReached() + signal requestAutoPlayVoiceRecording() property string selectedText property color textColor @@ -36,11 +38,19 @@ ColumnLayout { chatMessageGui: mainItem.chatMessageGui } delegate: ChatAudioContent { + id: audioContent // Layout.fillWidth: true width: Math.round(269 * DefaultStyle.dp) height: Math.round(48 * DefaultStyle.dp) Layout.preferredHeight: height chatMessageContentGui: modelData + onEndOfFileReached: mainItem.endOfVoiceRecordingReached() + Connections { + target: mainItem + function onRequestAutoPlayVoiceRecording() { + audioContent.requestPlaying() + } + } // width: conferenceList.width // onMouseEvent: (event) => mainItem.mouseEvent(event) } diff --git a/Linphone/view/Control/Display/Chat/ChatMessagesListView.qml b/Linphone/view/Control/Display/Chat/ChatMessagesListView.qml index 81d64301a..73ea41e11 100644 --- a/Linphone/view/Control/Display/Chat/ChatMessagesListView.qml +++ b/Linphone/view/Control/Display/Chat/ChatMessagesListView.qml @@ -17,6 +17,7 @@ ListView { signal replyToMessageRequested(ChatMessageGui chatMessage) signal forwardMessageRequested(ChatMessageGui chatMessage) signal requestHighlight(int indexToHighlight) + signal requestAutoPlayVoiceRecording(int indexToPlay) property string filterText onFilterTextChanged: { @@ -174,6 +175,11 @@ ListView { } width: mainItem.width property var previousIndex: index - 1 + property ChatMessageGui nextChatMessage: index >= (mainItem.count - 1) + ? null + : eventLogProxy.getEventAtIndex(index+1) + ? eventLogProxy.getEventAtIndex(index+1).core.chatMessageGui + : null property var previousFromAddress: eventLogProxy.getEventAtIndex(index-1)?.core.chatMessage?.fromAddress backgroundColor: isRemoteMessage ? DefaultStyle.main2_100 : DefaultStyle.main1_100 isFirstMessage: !previousFromAddress || previousFromAddress !== modelData.core.fromAddress @@ -186,6 +192,9 @@ ListView { onShowImdnStatusForMessageRequested: mainItem.showImdnStatusForMessageRequested(modelData) onReplyToMessageRequested: mainItem.replyToMessageRequested(modelData) onForwardMessageRequested: mainItem.forwardMessageRequested(modelData) + onEndOfVoiceRecordingReached: { + if (nextChatMessage && nextChatMessage.core.isVoiceRecording) mainItem.requestAutoPlayVoiceRecording(index + 1) + } Connections { target: mainItem function onRequestHighlight(indexToHighlight) { @@ -193,6 +202,11 @@ ListView { requestHighlight() } } + function onRequestAutoPlayVoiceRecording(indexToPlay) { + if (indexToPlay === index) { + chatMessageDelegate.requestAutoPlayVoiceRecording() + } + } } } }