enlarge video size if single file sent

wait for chat messages model to be reset before changing chat (fix #LINQT-2011)
This commit is contained in:
Gaelle Braud 2025-10-02 11:38:07 +02:00
parent 924224abc5
commit 8a2e842cd7
7 changed files with 151 additions and 27 deletions

View file

@ -81,31 +81,53 @@ void EventLogList::connectItem(const QSharedPointer<EventLogCore> &item) {
} }
} }
void EventLogList::setIsUpdating(bool updating) {
if (mIsUpdating != updating) {
mIsUpdating = updating;
emit isUpdatingChanged();
}
}
void EventLogList::setChatCore(QSharedPointer<ChatCore> core) { void EventLogList::setChatCore(QSharedPointer<ChatCore> core) {
if (mChatCore != core) { auto updateChatCore = [this](QSharedPointer<ChatCore> core) {
if (mChatCore) { if (mChatCore != core) {
disconnect(mChatCore.get(), &ChatCore::eventsInserted, this, nullptr); if (mChatCore) {
disconnect(mChatCore.get(), &ChatCore::eventsInserted, this, nullptr);
disconnect(mChatCore.get(), &ChatCore::eventListCleared, this, nullptr);
}
mChatCore = core;
if (mChatCore) {
connect(mChatCore.get(), &ChatCore::eventListCleared, this, [this] { resetData(); });
connect(mChatCore.get(), &ChatCore::eventsInserted, this,
[this](QList<QSharedPointer<EventLogCore>> list) {
auto eventsList = getSharedList<EventLogCore>();
for (auto &event : list) {
auto it = std::find_if(
eventsList.begin(), eventsList.end(),
[event](const QSharedPointer<EventLogCore> item) { return item == event; });
if (it == eventsList.end()) {
connectItem(event);
add(event);
int index;
get(event.get(), &index);
emit eventInserted(index, new EventLogGui(event));
}
}
});
}
lUpdate();
emit chatGuiChanged();
} }
mChatCore = core; };
if (mChatCore) { if (mIsUpdating) {
connect(mChatCore.get(), &ChatCore::eventListCleared, this, [this] { resetData(); }); connect(this, &EventLogList::isUpdatingChanged, this, [this, core, updateChatCore] {
connect(mChatCore.get(), &ChatCore::eventsInserted, this, [this](QList<QSharedPointer<EventLogCore>> list) { if (!mIsUpdating) {
auto eventsList = getSharedList<EventLogCore>(); updateChatCore(core);
for (auto &event : list) { disconnect(this, &EventLogList::isUpdatingChanged, this, nullptr);
auto it = std::find_if(eventsList.begin(), eventsList.end(), }
[event](const QSharedPointer<EventLogCore> item) { return item == event; }); });
if (it == eventsList.end()) { } else {
connectItem(event); updateChatCore(core);
add(event);
int index;
get(event.get(), &index);
emit eventInserted(index, new EventLogGui(event));
}
}
});
}
lUpdate();
emit chatGuiChanged();
} }
} }
@ -160,15 +182,19 @@ void EventLogList::setSelf(QSharedPointer<EventLogList> me) {
mCoreModelConnection->makeConnectToCore(&EventLogList::lUpdate, [this]() { mCoreModelConnection->makeConnectToCore(&EventLogList::lUpdate, [this]() {
mustBeInMainThread(log().arg(Q_FUNC_INFO)); mustBeInMainThread(log().arg(Q_FUNC_INFO));
if (mChatCore) qDebug() << "reset messages model for chat core" << mChatCore << mChatCore->getTitle();
setIsUpdating(true);
beginResetModel(); beginResetModel();
mList.clear(); mList.clear();
if (!mChatCore) { if (!mChatCore) {
endResetModel(); endResetModel();
setIsUpdating(false);
return; return;
} }
auto chatModel = mChatCore->getModel(); auto chatModel = mChatCore->getModel();
if (!chatModel) { if (!chatModel) {
endResetModel(); endResetModel();
setIsUpdating(false);
return; return;
} }
mCoreModelConnection->invokeToModel([this, chatModel]() { mCoreModelConnection->invokeToModel([this, chatModel]() {
@ -193,6 +219,7 @@ void EventLogList::setSelf(QSharedPointer<EventLogList> me) {
for (auto i : *events) for (auto i : *events)
mList << i.template objectCast<QObject>(); mList << i.template objectCast<QObject>();
endResetModel(); endResetModel();
setIsUpdating(false);
}); });
}); });
}); });

View file

@ -48,6 +48,8 @@ public:
void connectItem(const QSharedPointer<EventLogCore> &item); void connectItem(const QSharedPointer<EventLogCore> &item);
void disconnectItem(const QSharedPointer<EventLogCore> &item); void disconnectItem(const QSharedPointer<EventLogCore> &item);
void setIsUpdating(bool updating);
int findFirstUnreadIndex(); int findFirstUnreadIndex();
void findChatMessageWithFilter(QString filter, void findChatMessageWithFilter(QString filter,
@ -66,12 +68,14 @@ signals:
void messageWithFilterFound(int index); void messageWithFilterFound(int index);
void listAboutToBeReset(); void listAboutToBeReset();
void chatGuiChanged(); void chatGuiChanged();
void isUpdatingChanged();
private: private:
QString mFilter; QString mFilter;
QSharedPointer<ChatCore> mChatCore; QSharedPointer<ChatCore> mChatCore;
QSharedPointer<SafeConnection<ChatCore, ChatModel>> mChatModelConnection; QSharedPointer<SafeConnection<ChatCore, ChatModel>> mChatModelConnection;
QSharedPointer<SafeConnection<EventLogList, CoreModel>> mCoreModelConnection; QSharedPointer<SafeConnection<EventLogList, CoreModel>> mCoreModelConnection;
bool mIsUpdating = false;
DECLARE_ABSTRACT_OBJECT DECLARE_ABSTRACT_OBJECT
}; };

View file

@ -69,6 +69,7 @@ list(APPEND _LINPHONEAPP_QML_FILES
view/Control/Display/Chat/FileView.qml view/Control/Display/Chat/FileView.qml
view/Control/Display/Chat/ImageFileView.qml view/Control/Display/Chat/ImageFileView.qml
view/Control/Display/Chat/AnimatedImageFileView.qml view/Control/Display/Chat/AnimatedImageFileView.qml
view/Control/Display/Chat/VideoFileView.qml
view/Control/Display/Contact/Avatar.qml view/Control/Display/Contact/Avatar.qml
view/Control/Display/Contact/Contact.qml view/Control/Display/Contact/Contact.qml
view/Control/Display/Contact/Presence.qml view/Control/Display/Contact/Presence.qml

View file

@ -2,6 +2,8 @@ import QtQuick
import QtQuick.Effects import QtQuick.Effects
import QtQuick.Layouts import QtQuick.Layouts
import QtQuick.Controls.Basic as Control import QtQuick.Controls.Basic as Control
import QtMultimedia
import Linphone import Linphone
import UtilsCpp import UtilsCpp
@ -98,12 +100,27 @@ ColumnLayout {
Layout.alignment: Qt.AlignHCenter Layout.alignment: Qt.AlignHCenter
fillMode: Image.PreserveAspectFit fillMode: Image.PreserveAspectFit
} }
VideoFileView {
id: singleVideoFile
visible: mainItem.filescontentProxy.count === 1 && UtilsCpp.isVideo(contentGui.core.filePath)
contentGui: mainItem.filescontentProxy.count === 1
? mainItem.filescontentProxy.getChatMessageContentAtIndex(0)
: null
width: Math.round(285 * DefaultStyle.dp)
height: Math.round(285 * DefaultStyle.dp)
Layout.preferredWidth: videoOutput.contentRect.width
Layout.preferredHeight: videoOutput.contentRect.height
Layout.alignment: Qt.AlignHCenter
fillMode: VideoOutput.PreserveAspectFit
}
// FILES // FILES
ChatFilesGridLayout { ChatFilesGridLayout {
id: messageFilesList id: messageFilesList
visible: mainItem.filescontentProxy.count > 0 visible: mainItem.filescontentProxy.count > 0
&& !singleImageFile.visible && !singleImageFile.visible
&& !singleAnimatedImageFile.visible && !singleAnimatedImageFile.visible
&& !singleVideoFile.visible
Layout.fillWidth: visible Layout.fillWidth: visible
Layout.fillHeight: visible Layout.fillHeight: visible
maxWidth: Math.round(115*3 * DefaultStyle.dp) maxWidth: Math.round(115*3 * DefaultStyle.dp)

View file

@ -93,13 +93,16 @@ ListView {
markIndexAsRead(index) markIndexAsRead(index)
} }
} }
onModelAboutToBeReset: loading = true onModelAboutToBeReset: {
onModelReset: Qt.callLater(function() { loading = true
}
onModelReset: {
loading = false loading = false
var index = eventLogProxy.findFirstUnreadIndex() var index = eventLogProxy.findFirstUnreadIndex()
positionViewAtIndex(index, ListView.Beginning) positionViewAtIndex(index, ListView.Beginning)
eventLogProxy.markIndexAsRead(index) eventLogProxy.markIndexAsRead(index)
}) }
onChatGuiChanged: forceLayout()
onIndexWithFilterFound: (index) => { onIndexWithFilterFound: (index) => {
if (index !== -1) { if (index !== -1) {
currentIndex = index currentIndex = index

View file

@ -0,0 +1,72 @@
import QtQuick
import QtQuick.Controls as Control
import QtQuick.Layouts
import QtMultimedia
import Linphone
import UtilsCpp
import 'qrc:/qt/qml/Linphone/view/Control/Tool/Helper/utils.js' as Utils
// =============================================================================
Rectangle {
id: mainItem
color: "transparent"//DefaultStyle.grey_1000
property ChatMessageContentGui contentGui
property string filePath: contentGui && contentGui.core.filePath
property var fillMode: playbackState === MediaPlayer.PlayingState ? VideoOutput.PreserveAspectFit : VideoOutput.PreserveAspectCrop
property alias videoOutput: output
property string source: mediaPlayer.source
MediaPlayer {
id: mediaPlayer
source: UtilsCpp.isVideo(mainItem.filePath) ? "file:///" + mainItem.filePath : ""
position: 100
videoOutput: output
}
VideoOutput {
id: output
fillMode: mainItem.fillMode
endOfStreamPolicy: VideoOutput.KeepLastFrame
width: mainItem.width
height: mainItem.height
Component.onCompleted: {
// We need to start the video so the content rect of the
// video output is updated
mediaPlayer.play()
mediaPlayer.pause()
}
Text {
z: parent.z + 1
property int timeDisplayed: mediaPlayer.playbackState === MediaPlayer.PlayingState ? mediaPlayer.position : mediaPlayer.duration
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.bottomMargin: Math.round(6 * DefaultStyle.dp)
anchors.leftMargin: Math.round(6 * DefaultStyle.dp)
text: UtilsCpp.formatDuration(timeDisplayed)
color: DefaultStyle.grey_0
font {
pixelSize: Typography.d1.pixelSize
weight: Typography.d1.weight
}
}
}
MouseArea {
propagateComposedEvents: false
enabled: mainItem.visible
anchors.fill: parent
hoverEnabled: false
acceptedButtons: Qt.LeftButton
onClicked: (mouse) => {
mouse.accepted = true
mediaPlayer.playbackState === MediaPlayer.PlayingState ? mediaPlayer.pause() : mediaPlayer.play()
}
}
EffectImage {
anchors.centerIn: parent
visible: mediaPlayer.playbackState !== MediaPlayer.PlayingState
width: Math.round(24 * DefaultStyle.dp)
height: Math.round(24 * DefaultStyle.dp)
imageSource: AppIcons.playFill
colorizationColor: DefaultStyle.main2_0
}
}

View file

@ -12,7 +12,7 @@ MessageInfosLayout {
tabbarModel: chatMessageGui ? chatMessageGui.core.imdnStatusListAsString : [] tabbarModel: chatMessageGui ? chatMessageGui.core.imdnStatusListAsString : []
listModel: ImdnStatusProxy { listModel: ImdnStatusProxy {
imdnStatusList: chatMessageGui ? chatMessageGui.core.imdnStatusList : [] imdnStatusList: chatMessageGui ? chatMessageGui.core.imdnStatusList : []
filter: chatMessageGui && chatMessageGui.core.imdnStatusAsSingletons[mainItem.tabbar.currentIndex]?.state || "" filter: chatMessageGui && chatMessageGui.core.imdnStatusAsSingletons[mainItem.tabbar.currentIndex]?.state || LinphoneEnums.ChatMessageState.StateIdle
} }
listView.delegate: Item { listView.delegate: Item {