only load 20 elements each time in chat messages list to improve perf

fix image error ui
black rectangle on unstarted video

fix text edit loses focus when message sent (#LINQT-2009)

try to fix wrong message spinner icon #LINQT-2010

hide security parameters #LINQT-2019

fix open contextual menu component to open settings/help pages #LINQT-2021/2022

fix muted status not visible on local preview #LINQT-2023
This commit is contained in:
Gaelle Braud 2025-10-07 11:40:06 +02:00
parent 7e5f037332
commit c4db4d132d
17 changed files with 89 additions and 30 deletions

View file

@ -136,6 +136,41 @@ void EventLogList::setChatGui(ChatGui *chat) {
setChatCore(chatCore); setChatCore(chatCore);
} }
void EventLogList::setDisplayItemsStep(int displayItemsStep) {
if (mDisplayItemsStep != displayItemsStep) {
mDisplayItemsStep = displayItemsStep;
emit displayItemsStepChanged();
}
}
void EventLogList::displayMore() {
if (!mChatCore) return;
auto chatModel = mChatCore->getModel();
if (!chatModel) return;
mCoreModelConnection->invokeToModel([this, chatModel]() {
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
int maxSize = chatModel->getHistorySizeEvents();
int totalItemsCount = mList.count();
auto newCount = std::min(totalItemsCount + mDisplayItemsStep, maxSize);
if (newCount <= totalItemsCount) {
return;
}
auto linphoneLogs = chatModel->getHistoryRange(totalItemsCount, newCount);
QList<QSharedPointer<EventLogCore>> *events = new QList<QSharedPointer<EventLogCore>>();
for (auto it : linphoneLogs) {
auto model = EventLogCore::create(it);
events->push_back(model);
}
mCoreModelConnection->invokeToCore([this, events, newCount] {
int currentCount = mList.count();
for (auto &event : *events) {
connectItem(event);
add(event);
}
});
});
}
int EventLogList::findFirstUnreadIndex() { int EventLogList::findFirstUnreadIndex() {
auto eventList = getSharedList<EventLogCore>(); auto eventList = getSharedList<EventLogCore>();
auto it = std::find_if(eventList.begin(), eventList.end(), [](const QSharedPointer<EventLogCore> item) { auto it = std::find_if(eventList.begin(), eventList.end(), [](const QSharedPointer<EventLogCore> item) {
@ -199,7 +234,8 @@ void EventLogList::setSelf(QSharedPointer<EventLogList> me) {
} }
mCoreModelConnection->invokeToModel([this, chatModel]() { mCoreModelConnection->invokeToModel([this, chatModel]() {
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO)); mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
auto linphoneLogs = chatModel->getHistory(); qDebug() << "update history till" << mDisplayItemsStep;
auto linphoneLogs = chatModel->getHistoryRange(0, mDisplayItemsStep);
QList<QSharedPointer<EventLogCore>> *events = new QList<QSharedPointer<EventLogCore>>(); QList<QSharedPointer<EventLogCore>> *events = new QList<QSharedPointer<EventLogCore>>();
for (auto it : linphoneLogs) { for (auto it : linphoneLogs) {
auto model = EventLogCore::create(it); auto model = EventLogCore::create(it);

View file

@ -52,6 +52,9 @@ public:
int findFirstUnreadIndex(); int findFirstUnreadIndex();
void displayMore();
void setDisplayItemsStep(int displayItemsStep);
void findChatMessageWithFilter(QString filter, void findChatMessageWithFilter(QString filter,
QSharedPointer<EventLogCore> startEvent, QSharedPointer<EventLogCore> startEvent,
bool forward = true, bool forward = true,
@ -69,6 +72,7 @@ signals:
void listAboutToBeReset(); void listAboutToBeReset();
void chatGuiChanged(); void chatGuiChanged();
void isUpdatingChanged(); void isUpdatingChanged();
void displayItemsStepChanged();
private: private:
QString mFilter; QString mFilter;
@ -76,6 +80,7 @@ private:
QSharedPointer<SafeConnection<ChatCore, ChatModel>> mChatModelConnection; QSharedPointer<SafeConnection<ChatCore, ChatModel>> mChatModelConnection;
QSharedPointer<SafeConnection<EventLogList, CoreModel>> mCoreModelConnection; QSharedPointer<SafeConnection<EventLogList, CoreModel>> mCoreModelConnection;
bool mIsUpdating = false; bool mIsUpdating = false;
int mDisplayItemsStep = 0;
DECLARE_ABSTRACT_OBJECT DECLARE_ABSTRACT_OBJECT
}; };

View file

@ -43,6 +43,8 @@ void EventLogProxy::setSourceModel(QAbstractItemModel *model) {
if (newEventLogList) { if (newEventLogList) {
connect(newEventLogList, &EventLogList::listAboutToBeReset, this, &EventLogProxy::listAboutToBeReset); connect(newEventLogList, &EventLogList::listAboutToBeReset, this, &EventLogProxy::listAboutToBeReset);
connect(newEventLogList, &EventLogList::chatGuiChanged, this, &EventLogProxy::chatGuiChanged); connect(newEventLogList, &EventLogList::chatGuiChanged, this, &EventLogProxy::chatGuiChanged);
connect(this, &EventLogProxy::displayItemsStepChanged, newEventLogList,
[this, newEventLogList] { newEventLogList->setDisplayItemsStep(mDisplayItemsStep); });
connect(newEventLogList, &EventLogList::eventInserted, this, connect(newEventLogList, &EventLogList::eventInserted, this,
[this, newEventLogList](int index, EventLogGui *event) { [this, newEventLogList](int index, EventLogGui *event) {
invalidate(); invalidate();
@ -90,6 +92,13 @@ QSharedPointer<EventLogCore> EventLogProxy::getEventCoreAtIndex(int i) {
return getItemAt<SortFilterList, EventLogList, EventLogCore>(i); return getItemAt<SortFilterList, EventLogList, EventLogCore>(i);
} }
void EventLogProxy::displayMore() {
auto model = getListModel<EventLogList>();
if (model) {
model->displayMore();
}
}
void EventLogProxy::loadUntil(int index) { void EventLogProxy::loadUntil(int index) {
auto confInfoList = getListModel<EventLogList>(); auto confInfoList = getListModel<EventLogList>();
if (mMaxDisplayItems < index) setMaxDisplayItems(index + mDisplayItemsStep); if (mMaxDisplayItems < index) setMaxDisplayItems(index + mDisplayItemsStep);

View file

@ -44,6 +44,7 @@ public:
void setSourceModel(QAbstractItemModel *sourceModel) override; void setSourceModel(QAbstractItemModel *sourceModel) override;
Q_INVOKABLE void displayMore() override;
Q_INVOKABLE void loadUntil(int index); Q_INVOKABLE void loadUntil(int index);
Q_INVOKABLE EventLogGui *getEventAtIndex(int i); Q_INVOKABLE EventLogGui *getEventAtIndex(int i);
QSharedPointer<EventLogCore> getEventCoreAtIndex(int i); QSharedPointer<EventLogCore> getEventCoreAtIndex(int i);

View file

@ -45,7 +45,7 @@ public:
// Helper for setting the limit with sorted/filtered list // Helper for setting the limit with sorted/filtered list
void setSourceModels(SortFilterProxy *firstList); void setSourceModels(SortFilterProxy *firstList);
Q_INVOKABLE void displayMore(); Q_INVOKABLE virtual void displayMore();
Q_INVOKABLE QVariant getAt(const int &index) const; Q_INVOKABLE QVariant getAt(const int &index) const;
Q_INVOKABLE QVariantList getAll() const; Q_INVOKABLE QVariantList getAll() const;
virtual int getCount() const; virtual int getCount() const;

View file

@ -61,11 +61,11 @@ std::list<std::shared_ptr<linphone::Content>> ChatModel::getSharedDocuments() co
} }
std::list<std::shared_ptr<linphone::EventLog>> ChatModel::getHistory() const { std::list<std::shared_ptr<linphone::EventLog>> ChatModel::getHistory() const {
int filter = mMonitor->hasCapability((int)linphone::ChatRoom::Capabilities::Conference) return mMonitor->getHistoryEvents(0);
? static_cast<int>(linphone::ChatRoom::HistoryFilter::ChatMessage) | }
static_cast<int>(linphone::ChatRoom::HistoryFilter::InfoNoDevice)
: static_cast<int>(linphone::ChatRoom::HistoryFilter::ChatMessage); std::list<std::shared_ptr<linphone::EventLog>> ChatModel::getHistoryRange(int begin, int end) {
return mMonitor->getHistory(0, filter); return mMonitor->getHistoryRangeEvents(begin, end);
} }
std::list<std::shared_ptr<linphone::ChatMessage>> ChatModel::getChatMessageHistory() const { std::list<std::shared_ptr<linphone::ChatMessage>> ChatModel::getChatMessageHistory() const {
@ -78,6 +78,10 @@ std::list<std::shared_ptr<linphone::ChatMessage>> ChatModel::getChatMessageHisto
return res; return res;
} }
int ChatModel::getHistorySizeEvents() {
return mMonitor->getHistoryEventsSize();
}
QString ChatModel::getIdentifier() const { QString ChatModel::getIdentifier() const {
return Utils::coreStringToAppString(mMonitor->getIdentifier()); return Utils::coreStringToAppString(mMonitor->getIdentifier());
} }
@ -123,9 +127,6 @@ int ChatModel::getUnreadMessagesCount() const {
void ChatModel::markAsRead() { void ChatModel::markAsRead() {
mMonitor->markAsRead(); mMonitor->markAsRead();
for (auto &message : getChatMessageHistory()) {
message->markAsRead();
}
emit messagesRead(); emit messagesRead();
} }

View file

@ -49,7 +49,9 @@ public:
std::list<std::shared_ptr<linphone::Content>> getSharedMedias() const; std::list<std::shared_ptr<linphone::Content>> getSharedMedias() const;
std::list<std::shared_ptr<linphone::Content>> getSharedDocuments() const; std::list<std::shared_ptr<linphone::Content>> getSharedDocuments() const;
std::list<std::shared_ptr<linphone::EventLog>> getHistory() const; std::list<std::shared_ptr<linphone::EventLog>> getHistory() const;
std::list<std::shared_ptr<linphone::EventLog>> getHistoryRange(int begin, int end);
std::list<std::shared_ptr<linphone::ChatMessage>> getChatMessageHistory() const; std::list<std::shared_ptr<linphone::ChatMessage>> getChatMessageHistory() const;
int getHistorySizeEvents();
QString getIdentifier() const; QString getIdentifier() const;
void deleteHistory(); void deleteHistory();
void deleteMessage(std::shared_ptr<linphone::ChatMessage> message); void deleteMessage(std::shared_ptr<linphone::ChatMessage> message);

View file

@ -20,6 +20,11 @@ Item {
property int conferenceLayout: call ? call.core.conferenceVideoLayout : LinphoneEnums.ConferenceLayout.ActiveSpeaker property int conferenceLayout: call ? call.core.conferenceVideoLayout : LinphoneEnums.ConferenceLayout.ActiveSpeaker
property int participantDeviceCount: conference ? conference.core.participantDeviceCount : -1 property int participantDeviceCount: conference ? conference.core.participantDeviceCount : -1
property int lastConfLayoutBeforeSharing: -1 property int lastConfLayoutBeforeSharing: -1
property string localAddress: call
? call.conference
? call.conference.core.me.core.sipAddress
: call.core.localAddress
: ""
onParticipantDeviceCountChanged: { onParticipantDeviceCountChanged: {
setConferenceLayout() setConferenceLayout()
} }

View file

@ -453,7 +453,6 @@ ListView {
id: mouseArea id: mouseArea
hoverEnabled: true hoverEnabled: true
anchors.fill: parent anchors.fill: parent
focus: true
acceptedButtons: Qt.RightButton | Qt.LeftButton acceptedButtons: Qt.RightButton | Qt.LeftButton
onContainsMouseChanged: { onContainsMouseChanged: {
if (containsMouse) if (containsMouse)

View file

@ -317,7 +317,8 @@ Control.Control {
: "" : ""
BusyIndicator { BusyIndicator {
anchors.fill: parent anchors.fill: parent
z: parent.z + 1 Layout.preferredWidth: visible ? 14 * DefaultStyle.dp : 0
Layout.preferredHeight: visible ? 14 * DefaultStyle.dp : 0
visible: mainItem.msgState === LinphoneEnums.ChatMessageState.StateIdle visible: mainItem.msgState === LinphoneEnums.ChatMessageState.StateIdle
|| mainItem.msgState === LinphoneEnums.ChatMessageState.StateInProgress || mainItem.msgState === LinphoneEnums.ChatMessageState.StateInProgress
|| mainItem.msgState === LinphoneEnums.ChatMessageState.StateFileTransferInProgress || mainItem.msgState === LinphoneEnums.ChatMessageState.StateFileTransferInProgress

View file

@ -48,11 +48,6 @@ ListView {
eventLogProxy.markIndexAsRead(index) eventLogProxy.markIndexAsRead(index)
}) })
} }
onChatChanged: {
lastItemVisible = false
forceActiveFocus()
}
Button { Button {
visible: !mainItem.lastItemVisible visible: !mainItem.lastItemVisible
@ -77,15 +72,15 @@ ListView {
chat.core.lMarkAsRead() chat.core.lMarkAsRead()
} }
onAtYBeginningChanged: if (atYBeginning) { onAtYBeginningChanged: if (atYBeginning) {
if (eventLogProxy.haveMore) eventLogProxy.displayMore()
eventLogProxy.displayMore()
} }
model: EventLogProxy { model: EventLogProxy {
id: eventLogProxy id: eventLogProxy
chatGui: mainItem.chat chatGui: mainItem.chat
filterText: mainItem.filterText filterText: mainItem.filterText
initialDisplayItems: 10 initialDisplayItems: 20
displayItemsStep: 20
onEventInserted: (index, gui) => { onEventInserted: (index, gui) => {
if (!mainItem.visible) return if (!mainItem.visible) return
if(mainItem.lastItemVisible) { if(mainItem.lastItemVisible) {

View file

@ -70,7 +70,7 @@ Item {
Image { Image {
anchors.fill: image anchors.fill: image
z: image.z + 1 z: image.z + 1
visible: image.status == Image.Error || image.status == Image.Null visible: image.status == Image.Error || image.status == Image.Null || image.frameCount === 0
source: AppIcons.fileImage source: AppIcons.fileImage
sourceSize.width: mainItem.width sourceSize.width: mainItem.width
sourceSize.height: mainItem.height sourceSize.height: mainItem.height

View file

@ -11,7 +11,7 @@ import 'qrc:/qt/qml/Linphone/view/Control/Tool/Helper/utils.js' as Utils
Rectangle { Rectangle {
id: mainItem id: mainItem
color: "transparent"//DefaultStyle.grey_1000 color: DefaultStyle.grey_1000
property ChatMessageContentGui contentGui property ChatMessageContentGui contentGui
property string filePath: contentGui && contentGui.core.filePath property string filePath: contentGui && contentGui.core.filePath
property var fillMode: playbackState === MediaPlayer.PlayingState ? VideoOutput.PreserveAspectFit : VideoOutput.PreserveAspectCrop property var fillMode: playbackState === MediaPlayer.PlayingState ? VideoOutput.PreserveAspectFit : VideoOutput.PreserveAspectCrop

View file

@ -147,7 +147,6 @@ Flickable {
} }
} }
onSearchTextChanged: { onSearchTextChanged: {
console.log("search texte changed, loading…")
loading = true loading = true
} }

View file

@ -24,7 +24,7 @@ AbstractSettingsMenu {
//: "Affichage" //: "Affichage"
//{title: qsTr("settings_user_interface_title"), layout: "DisplaySettingsLayout"}, //{title: qsTr("settings_user_interface_title"), layout: "DisplaySettingsLayout"},
//: "Security" //: "Security"
{title: qsTr("settings_security_title"), layout: "SecuritySettingsLayout"}, // {title: qsTr("settings_security_title"), layout: "SecuritySettingsLayout"},
//: "Réseau" //: "Réseau"
{title: qsTr("settings_network_title"), layout: "NetworkSettingsLayout"}, {title: qsTr("settings_network_title"), layout: "NetworkSettingsLayout"},
//: "Paramètres avancés" //: "Paramètres avancés"

View file

@ -471,7 +471,10 @@ Item {
icon.height: Math.round(32 * DefaultStyle.dp) icon.height: Math.round(32 * DefaultStyle.dp)
text: qsTr("settings_title") text: qsTr("settings_title")
icon.source: AppIcons.settings icon.source: AppIcons.settings
onClicked: openContextualMenuComponent(settingsPageComponent) onClicked: {
var page = settingsPageComponent.createObject(parent);
openContextualMenuComponent(page)
}
KeyNavigation.up: visibleChildren.length KeyNavigation.up: visibleChildren.length
!= 0 ? settingsMenuButton.getPreviousItem( != 0 ? settingsMenuButton.getPreviousItem(
2) : null 2) : null
@ -503,8 +506,10 @@ Item {
//: "Aide" //: "Aide"
text: qsTr("help_title") text: qsTr("help_title")
icon.source: AppIcons.question icon.source: AppIcons.question
onClicked: openContextualMenuComponent( onClicked: {
helpPageComponent) var page = helpPageComponent.createObject(parent);
openContextualMenuComponent(page)
}
KeyNavigation.up: visibleChildren.length KeyNavigation.up: visibleChildren.length
!= 0 ? settingsMenuButton.getPreviousItem( != 0 ? settingsMenuButton.getPreviousItem(
4) : null 4) : null

View file

@ -68,8 +68,9 @@ AbstractSettingsLayout {
toValidate: true toValidate: true
Connections { Connections {
enabled: account
target: account.core target: account.core
function onMwiServerAddressAddressChanged() { function onMwiServerAddressChanged() {
if (mwiServerAddressField.text != mwiServerAddressField.propertyOwnerGui.core[mwiServerAddressField.propertyName]) if (mwiServerAddressField.text != mwiServerAddressField.propertyOwnerGui.core[mwiServerAddressField.propertyName])
mwiServerAddressField.text = mwiServerAddressField.propertyOwnerGui.core[mwiServerAddressField.propertyName] mwiServerAddressField.text = mwiServerAddressField.propertyOwnerGui.core[mwiServerAddressField.propertyName]
} }
@ -80,14 +81,14 @@ AbstractSettingsLayout {
propertyName: "voicemailAddress" propertyName: "voicemailAddress"
propertyOwnerGui: account propertyOwnerGui: account
//: "URI de messagerie vocale" //: "URI de messagerie vocale"
title: qsTr("account_settings_voicemail_uri_title") title: qsTr("account_settings_voicemail_uri_title")
Layout.fillWidth: true Layout.fillWidth: true
toValidate: true toValidate: true
Connections { Connections {
enabled: account
target: account.core target: account.core
function onVoicemailAddressAddressChanged() { function onVoicemailAddressChanged() {
if (voicemailAddressField.text != voicemailAddressField.propertyOwnerGui.core[voicemailAddressField.propertyName]) if (voicemailAddressField.text != voicemailAddressField.propertyOwnerGui.core[voicemailAddressField.propertyName])
voicemailAddressField.text = voicemailAddressField.propertyOwnerGui.core[voicemailAddressField.propertyName] voicemailAddressField.text = voicemailAddressField.propertyOwnerGui.core[voicemailAddressField.propertyName]
} }